summaryrefslogtreecommitdiff
path: root/io-module/mts_supercap.c
blob: 6cd984187d4b22921d9566cb43e29c058ae2815c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133


#include "mts_supercap.h"

extern struct gpio_pin *gpio_pin_by_attr_name(const char *name);

static supercap_info_t supercap = {
		.name = "Super Cap",
		.label_monitor = "supercap-monitor",
        .signal = SIGPWR,
		.pid    = 0,
		.pwf_count = 0,
		.pin_is_one = 0,

};

ssize_t mts_attr_show_supercap_monitor(struct device *dev,
			struct device_attribute *attr,
			char *buf)
{
	int ret;

	//button_info_t *button = button_by_monitor_name(attr->attr.name);

	//if (!button) {
	//	return -ENODEV;
	//}

	mutex_lock(&mts_io_mutex);

	ret = sprintf(buf, "%d %d\n", supercap.pid, supercap.signal);

	mutex_unlock(&mts_io_mutex);

	return ret;
}

ssize_t mts_attr_store_supercap_monitor(struct device *dev,
		struct device_attribute *attr, const char *buf, size_t count)
{
	pid_t pid;
	int signal;
	int result = sscanf(buf, "%i %i", &pid, &signal);

	//button_info_t *button = button_by_monitor_name(attr->attr.name);

	//if (!button) {
	//	return -ENODEV;
	//}

	if (result != 2) {
		return -EINVAL;
	}

	if(result == 2) {
		mutex_lock(&mts_io_mutex);

		supercap.pid = pid;
		supercap.signal = signal;

		mutex_unlock(&mts_io_mutex);
	}

	return count;
}

static void supercap_worker(struct work_struct *ignored);

static DECLARE_DELAYED_WORK(supercap_work, supercap_worker);

static void supercap_worker(struct work_struct *ignored)
{
	struct gpio_pin *pin;
	struct pid *vpid;
	int running_on_cap = 0;

	mutex_lock(&mts_io_mutex);

	pin = gpio_pin_by_attr_name("power-fail");

	if (pin) {
		running_on_cap = !gpio_get_value(pin->pin.gpio);
	}

	if (supercap.pid > 0) {
		vpid = find_vpid(supercap.pid);
	}

    if (vpid) {
        if (running_on_cap == 0 && supercap.pwf_count == 0) {
            schedule_delayed_work(&supercap_work, SUPERCAP_CHECK_INTERVAL);
        }
        else if ( (supercap.pwf_count >= 0) && (supercap.pwf_count < SUPERCAP_TOTAL_INTERVALS) ) {
            /* check if 90% of checks were running_on_cap == 1 */
            supercap.pwf_count++;
            if (running_on_cap == 1) {
        	    supercap.pin_is_one++;
            }
            if (supercap.pin_is_one >= 45) {
            	/* send configured signal to reset handler pid */
            	log_debug("Super Cap positives %d long signal", supercap.pin_is_one);
                kill_pid(vpid, supercap.signal, 1);
                /* reset and start over since hit the reset condition (maybe we should clean up and go away?) */
                supercap.pwf_count = 0;
                supercap.pin_is_one = 0;
            }
        }
        else if (supercap.pwf_count == SUPERCAP_TOTAL_INTERVALS) {
        	/* reset and start over since didn't reach 90% at total intervals */
        	supercap.pwf_count = 0;
        	supercap.pin_is_one = 0;
        }
    } /* vpid */

    mutex_unlock(&mts_io_mutex);

    schedule_delayed_work(&supercap_work, SUPERCAP_CHECK_INTERVAL);

}

void init_supercap_worker(void) {
	supercap_worker(NULL);
}

void cleanup_supercap_worker(void) {
	cancel_delayed_work_sync(&supercap_work);
}


DEVICE_ATTR_MTS(dev_attr_supercap_monitor,
		supercap.label_monitor,
		mts_attr_show_supercap_monitor,
		mts_attr_store_supercap_monitor);