summaryrefslogtreecommitdiff
path: root/io-module/mts_supercap.c
blob: e028408810d395f45635ee0f011b47158b863cc2 (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


#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;

	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 */

    schedule_delayed_work(&supercap_work, SUPERCAP_CHECK_INTERVAL);

}

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

void cleanup_sepercap_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);