-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathapp.c
251 lines (218 loc) · 7.48 KB
/
app.c
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
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
/**************************************************************************************************
* app.c
*
* Description
* ===========
* Server-instance that serves ADC (MCP3008) data to clients. Uses Servkit IPC-communication.
*
* Details
* =======
* Author: Jelle De Vleeschouwer
* Copyright (C) 2017 Jelle De Vleeschouwer
*
**************************************************************************************************/
#include <ctype.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include "mcp3008.h"
#include "libquickserv.h"
/* Utilities */
#define EVER (;;)
#define IGNORE(x) (void)(x)
#define ZALLOC(size) calloc(1, (size_t)(size));
#define ERROR(var) fprintf(stderr, var)
#ifdef DBG_APP
#define dbg printf
#else
#define dbg(...)
#endif
/* Defaults */
#define POLL_TIMEOUT (5)
#define SEAT_PRESSURE_TRESH (512) // [0, 1023]
#define PAPER_PRESSURE_TRESH (512) // [0, 1023]
#define SERVER_PATH "/tmp/server.sock"
/* Constants */
#define PAPER_CHANNEL (MCP3008_CH0)
#define SEAT_CHANNEL (MCP3008_CH4)
#define MSG_LEN (64)
/* Static variables */
static int paper_pressure_tresh = 0;
static int seat_pressure_tresh = 0;
static time_t poll_timeout = 0;
static char *server_path = NULL;
static QUICKSERV_SERVER server = NULL;
static QUICKSERV_CLIENT client = NULL;
/* Callback when new client is accepted */
static void client_accept(QUICKSERV_CLIENT __client)
{
printf("Client connected to server\n");
client = __client;
}
/* Callback when new data is received from clients */
static void client_handler(QUICKSERV_CLIENT __client, uint8_t *data, int len, void *arg)
{
/* XXX: NOT IMPLEMENTED: we don't accept requests from client ATM. */
}
/* Send an actual message throug quickserv if client is connected */
static void server_send_notification(char *msg)
{
int ret = 0;
if (client) {
ret = quickserv_server_send(server, client, (uint8_t *)msg, strlen(msg));
if (ret == strlen(msg)) {
dbg("INFO: Sent notification to client: SUCCESS\n");
} else {
ERROR("ERROR: Failed to send notification to client\n");
exit(255);
}
} else {
dbg("INFO: No client connected, cannot send notification\n");
}
}
/* Notify a change in seat pressure to main application */
static void notify_seat_change(int seat_occupied)
{
static int seat_state = 0;
char msg[MSG_LEN] = "{ \"SEAT\" : ";
if (seat_state != seat_occupied) {
snprintf(msg + strlen(msg), MSG_LEN, "\"%d\" }", seat_occupied);
server_send_notification(msg);
dbg("Notify: %s\n", msg);
}
seat_state = seat_occupied;
}
/* Notify a change in paper pressure to main application */
static void notify_paper_change(int paper_available)
{
static int paper_state = 0;
char msg[MSG_LEN] = "{ \"PAPER\" : ";
if (paper_state != paper_available) {
snprintf(msg + strlen(msg), MSG_LEN, "\"%d\" }", paper_available);
server_send_notification(msg);
dbg("Notify: %s\n", msg);
}
paper_state = paper_available;
}
/* Measure pressure of toilet paper on the right ADC channel */
static uint16_t toilet_paper_pressure(void)
{
return mcp3008_readChannel(PAPER_CHANNEL, MCP3008_SE);
}
/* Measure pressure of toilet seat on the right ADC channel */
static uint16_t toilet_seat_pressure(void)
{
return mcp3008_readChannel(SEAT_CHANNEL, MCP3008_SE);
}
/* Do the mathzzz.... *cugh* */
static void parse_pressures(uint16_t seat_pressure, uint16_t paper_pressure)
{
if (seat_pressure < seat_pressure_tresh) {
notify_seat_change(0); // 1: occupied
} else {
notify_seat_change(1); // 0: not occupied
}
if (paper_pressure < paper_pressure_tresh) {
notify_paper_change(0); // 0: paper not available
} else {
notify_paper_change(1); // 1: paper available
}
}
/* Print out a help menu */
static void help(void)
{
printf("Usage:\n ./app [options]\n\n");
printf("Options:\n\n");
printf(" -h : Print out this help menu\n");
printf(" -f filepath : Path where server has to open it's socket\n");
printf(" -t timeout : Interval of 'timout' seconds between measurements\n");
printf(" -s seat_tresh : Treshold of seat pressure before sitting is detected\n");
printf(" -p paper_tresh : Treshold of paper pressure before paper is detected\n");
printf("\n");
}
/* Changes server path dynamically (!!!TOTALLY UNSAFE!!!) #Yolo */
static void set_server_path(const char *path)
{
if (server_path)
free(server_path);
server_path = ZALLOC(strlen(path) + 1);
strcpy(server_path, path);
}
/* Parse command-line options */
static void parse_options(int argc, char * const argv[])
{
int c = 0;
poll_timeout = POLL_TIMEOUT;
seat_pressure_tresh = SEAT_PRESSURE_TRESH;
paper_pressure_tresh = PAPER_PRESSURE_TRESH;
set_server_path(SERVER_PATH);
opterr = 0;
while ((c = getopt(argc, argv, "t:s:p:h")) != -1) {
switch(c) {
case 'f':
set_server_path(optarg);
dbg("Setting server path: %s\n", server_path);
break;
case 't':
poll_timeout = atoi(optarg);
dbg("Setting timeout: %d\n", (int)poll_timeout);
break;
case 's':
seat_pressure_tresh = atoi(optarg);
dbg("Setting seat pressure treshold: %d\n", seat_pressure_tresh);
break;
case 'p':
paper_pressure_tresh = atoi(optarg);
dbg("Setting paper pressure treshold: %d\n", paper_pressure_tresh);
break;
case 'h':
help();
exit(0);
break;
case '?':
if (optopt == 't' || optopt == 's' || optopt == 'p')
fprintf(stderr, "Option -%c requires an argument.\n", optopt);
else
fprintf(stderr, "Unknown option character '\\x%x'.\n", optopt);
break;
default:
help();
exit(0);
}
}
}
/* Do a new measurement and parse results */
void measure(void *arg)
{
parse_pressures(toilet_paper_pressure(), toilet_seat_pressure());
}
int main(int argc, char * const argv[])
{
/* Parse command-line arguments */
parse_options(argc, argv);
/* Initialize interface for SPI with MCP3008 */
if (mcp3008_init(16)) {
fprintf(stderr, "Could not initialize SPI interface with A/D converter\n");
exit(255);
}
/* Initialize quickserv */
quickserv_init();
/* Open quickserv-server */
server = quickserv_server_open(server_path, client_handler, NULL);
if (server) {
dbg("Open server succesfully at: %s\n", server_path);
}
/* Install callback to capture new connections */
quickserv_server_install_connect_cb(server, client_accept);
/* Trigger measurement every 'timeout' seconds */
quickserv_addtimer(1000 * poll_timeout, QUICKSERV_TIMER_RETRIGGER, measure, NULL);
/* Enter libevquick event loop */
quickserv_loop();
/* Cleanup resources required for MCP3008 */
mcp3008_stop();
return 0;
}
/**************************************************************************************************
* app.c
**************************************************************************************************/