SmartCradle v1
Baby smart cradle
main.c
Go to the documentation of this file.
1
10#include <stdio.h>
11#include <stdlib.h>
12#include <unistd.h>
13#include <pthread.h>
14#include <sched.h>
15#include <errno.h>
16#include <stdio.h>
17#include <string.h>
18#include <mqueue.h>
19#include <sys/mman.h>
20#include <sys/shm.h>
21#include <sys/stat.h>
22#include <linux/types.h>
23#include <signal.h>
24#include <sys/time.h>
25#include <string.h>
26#include "../inc/database.h"
27#include "../inc/microphone.h"
28#include "../inc/livestream.h"
29#include "../inc/motor.h"
30#include "../inc/dht.h"
31
32#define SHMEMOBJ_NAME "/shLocalDaemon"
33#define MSGQOBJ_NAME "/mqLocalDaemon"
34#define MAX_MSG_LEN 10
35mqd_t msgq_id;
36struct mq_attr msgq_attr;
38#define streamPrio 2
39#define motorPrio 2
40#define updateDatabasePrio 3
41#define sensorPrio 4
43#define motorTimeout 10
44#define sensorSample 10
46_Bool motorFlag = 0;
47_Bool streamFlag = 0;
48_Bool sensorFlag = 0;
50pthread_mutex_t motorFlag_mutex = PTHREAD_MUTEX_INITIALIZER;
51pthread_mutex_t streamFlag_mutex = PTHREAD_MUTEX_INITIALIZER;
52pthread_mutex_t sensorFlag_mutex = PTHREAD_MUTEX_INITIALIZER;
57pid_t daemonPID;
66void initThread(int priority, pthread_attr_t *pthread_attr, struct sched_param *pthread_param);
67
73void checkErrors(int status);
74
80static void signalHandler(int signo)
81{
82 switch (signo)
83 {
84 case (SIGALRM): //Timer has ended
85 pthread_mutex_lock(&motorFlag_mutex);
86 motorFlag = 0;
87 send_swing_flag(motorFlag); //Update the motor flag on the database
88 pthread_mutex_unlock(&motorFlag_mutex);
89 printf("Motor flag was updated in the database.\n");
90 break;
91
92 case (SIGUSR1): //Signal received from Daemon
93 send_notification_flag(1); //Update notification flag on the database
94 printf("Notification flag was updated in the database.\n");
95 break;
96
97 case (SIGINT):
98 case (SIGTERM):
99 printf("Terminating program...\n");
100 mq_unlink(MSGQOBJ_NAME); //unlink msgQ
101 stopMotor(); //stop motor
102 stopLivestream(); //stop livestream
103 remMotor(); //remove motor device driver
104 remDHT11(); //remove sensor device driver
105 kill(daemonPID,SIGTERM); //kill daemon
106 if(Py_IsInitialized())
107 Py_FinalizeEx(); //close python interpreter
108 exit(1);
109 break;
110 }
111}
112
119void *tReadSensor(void *arg)
120{
121 dht11_t sensorSampling;
122 float temperature = 0;
123 float humidity = 0;
124
125 u_int8_t samplingTries = 0;
126
127 while(1)
128 {
129 do{
130 if(readDHT11(&sensorSampling)) //Read from the sensor
131 {
132 //Sampling successful
133 samplingTries = 0;
134 printf("Sensor sampling successful:\n");
135 }
136 else
137 {
138 //Sampling failed
139 samplingTries++;
140 fprintf(stderr,"Failed to sample sensor...Trying again in 5 seconds.\n");
141 sleep(5);
142 }
143 }while(samplingTries > 0 && samplingTries < 3); //Upon failure tries a maximum of 3 times before going to sleep
144
145 if(!samplingTries) //If sampling was successful
146 {
147 temperature = sensorSampling.TemperatureI + (float)(sensorSampling.TemperatureD)/100;
148 humidity = sensorSampling.HumidityI + (float)(sensorSampling.HumidityD)/100;
149
150 printf("\tTemperature: %.2f \ÂșC \n \tHumidity: %.2f \%\n", temperature, humidity);
151
152 //If the temperature or humidity values are different from those on the database, update them
153 if( (temperature != databaseTemperature) || (humidity != databaseHumidity) )
154 {
155 pthread_mutex_lock(&sensorFlag_mutex);
156 databaseTemperature = temperature;
157 databaseHumidity = humidity;
158 sensorFlag = 1;
159 pthread_mutex_unlock(&sensorFlag_mutex);
160 }
161 }
162 else if(samplingTries == 3) //If sampling failed the 3 attempts
163 {
164 samplingTries = 0;
165 fprintf(stderr,"Failed to sample sensor 3 times. Ignoring...\n");
166 }
167
168 /* Sleep for sensorSample minutes */
169 sleep(60 * sensorSample);
170 }
171}
172
176void *tStartStopStream (void *arg)
177{
178 while(1)
179 {
180 if(streamFlag && !getStreamStatus()) //If streamFlag is on
181 {
183 printf("Livestream has started.\n");
184 }
185 else if(!streamFlag && getStreamStatus()) //If streamFlag is off
186 {
188 printf("Livestream has stopped.\n");
189 }
190 }
191}
192
196void *tStartStopMotor (void *arg)
197{
198 struct itimerval itv;
199 while(1)
200 {
201 if(motorFlag && !getMotorStatus()) //If motorFlag is on
202 {
203 if(startMotor())
204 {
205 itv.it_interval.tv_sec = 8; //60 * motorTimeout;
206 itv.it_interval.tv_usec = 0;
207 itv.it_value.tv_sec = 8; //60 * motorTimeout;
208 itv.it_value.tv_usec = 0;
209 setitimer (ITIMER_REAL, &itv, NULL); //Start timer
210 printf("Motor has started.\n");
211 }
212 else
213 fprintf(stderr, "Error when starting motor.\n");
214 }
215 else if(!motorFlag && getMotorStatus()) //If motorFlag is off
216 {
217 if(stopMotor())
218 {
219 itv.it_interval.tv_sec = 0;
220 itv.it_interval.tv_usec = 0;
221 itv.it_value.tv_sec = 0;
222 itv.it_value.tv_usec = 0;
223 setitimer (ITIMER_REAL, &itv, NULL); //Stop timer
224 printf("Motor has stopped.\n");
225 }
226 else
227 fprintf(stderr, "Error when stopping motor.\n");
228 }
229 }
230}
231
239void *tUpdateDatabase(void *arg)
240{
241 int ret;
242 _Bool dMotorFlag, dStreamFlag;
243 Py_Initialize(); //Initialize the Python Interpreter
244 ret = initDatabase(); //Initialize the Database functions
245 if(ret == -ERROR)
246 {
247 fprintf(stderr, "In initDatabase()\n");
248 exit(1);
249 }
250 while(1)
251 {
252 /*
253 * Update temperature and humidity
254 * in the database
255 */
256 pthread_mutex_lock(&sensorFlag_mutex);
257 if(sensorFlag)
258 {
259 sensorFlag = 0;
261 printf("Temperature and Humidity were updated in the database.\n");
262 }
263 pthread_mutex_unlock(&sensorFlag_mutex);
264
265 /*
266 * Update motorFlag with the value
267 * from the database
268 */
269 dMotorFlag = get_swing_flag();
270 pthread_mutex_lock(&motorFlag_mutex);
271 motorFlag = dMotorFlag;
272 pthread_mutex_unlock(&motorFlag_mutex);
273
274 /*
275 * Update streamFlag with the value
276 * from the database. If it changes,
277 * the new value is sent to the daemon
278 * via message queue
279 */
280 dStreamFlag = get_live_flag();
281 pthread_mutex_lock(&streamFlag_mutex);
282 if(streamFlag != dStreamFlag)
283 {
284 printf("Sending livestream flag update to daemon...\n");
285 char *msg;
286 msg = malloc(4);
287 if(msg == NULL)
288 fprintf(stderr,"malloc() got error.\n");
289 else
290 {
291 //Set up the command LV-x
292 if(dStreamFlag)
293 strcpy(msg,"LV-1");
294 else
295 strcpy(msg,"LV-0");
296
297 ret = mq_send(msgq_id, msg, strlen(msg)+1, 1); //Send to the message queue
298 if(ret != 0)
299 {
300 fprintf(stderr,"mq_send() got error %d\n",ret);
301 errno=ret;
302 perror("mq_send()");
303 }
304 free(msg);
305 }
306 }
307 streamFlag = dStreamFlag;
308 pthread_mutex_unlock(&streamFlag_mutex);
309
310 /* Sleep for 5 seconds */
311 sleep(5);
312 }
313 mq_close(msgq_id);
314 Py_FinalizeEx(); // for redundancy purposes
315}
316
317int main (int argc, char *argv[])
318{
319 int ret;
320
321 msgq_attr.mq_flags = 0;
322 msgq_attr.mq_maxmsg = 1;
323 msgq_attr.mq_msgsize = 5;
324 msgq_attr.mq_curmsgs = 0;
325 msgq_id = mq_open(MSGQOBJ_NAME, O_WRONLY | O_CREAT | O_EXCL | O_NONBLOCK, S_IRWXU | S_IRWXG | S_IRWXO, &msgq_attr);
326 if(errno == EEXIST) //If the message queue already exists
327 {
328 mq_unlink(MSGQOBJ_NAME); //Unlink the message queue
329 msgq_id = mq_open(MSGQOBJ_NAME, O_RDWR | O_CREAT | O_EXCL, S_IRWXU | S_IRWXG | S_IRWXO, NULL);
330 }
331 if (msgq_id == (mqd_t)-1) {
332 perror("In mq_open()");
333 exit(1);
334 }
335
336 pid_t my_pid = getpid();
337 printf("PID: %d\n",my_pid);
338
339 /*
340 * Open shared memory to drop PID for Daemon
341 * and read Daemon's PID
342 */
343 int fd;
344 fd = shm_open(SHMEMOBJ_NAME, O_RDWR | O_CREAT | O_EXCL, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);
345 if(fd < 0)
346 {
347 mq_unlink(MSGQOBJ_NAME);
348 fprintf(stderr, "Error %s in shm_open()\n",errno);
349 exit(1);
350 }
351 ftruncate(fd, sizeof(pid_t));
352 void* ptr;
353 ptr = mmap(0, sizeof(pid_t),PROT_WRITE | PROT_READ, MAP_SHARED, fd, 0);
354 if(ptr == (void *)-1)
355 {
356 mq_unlink(MSGQOBJ_NAME);
357 shm_unlink(SHMEMOBJ_NAME);
358 fprintf(stderr, "Error %s in mmap()\n",errno);
359 exit(1);
360 }
361 sprintf(ptr, "%d", my_pid);
362
363 /*
364 * Set Python Path to current Working Path
365 */
366 setenv("PYTHONPATH",".",1);
367
368 /*
369 * Call the Daemon
370 */
371 system("./daemon.elf");
372
373 /*
374 * Read Daemon's PID
375 */
376 daemonPID = atoi((char*)ptr);
377 ret = munmap(0, sizeof(pid_t));
378 if(ret < 0)
379 {
380 mq_unlink(MSGQOBJ_NAME);
381 kill(daemonPID, SIGTERM);
382 fprintf(stderr, "Error %s in munmap()\n",errno);
383 exit(1);
384 }
385 ret = shm_unlink(SHMEMOBJ_NAME);
386 if(ret < 0)
387 {
388 mq_unlink(MSGQOBJ_NAME);
389 kill(daemonPID, SIGTERM);
390 fprintf(stderr, "Error %s in shm_unlink()\n",errno);
391 exit(1);
392 }
393
394 /*
395 * Define the signal handler
396 * @ SIGALRM for the motor timeout
397 * @ SIGUSR for the notification generation request
398 * from the Daemon
399 * @ SIGINT to kill the program upon receiving CTRL + C
400 */
401 signal(SIGALRM, signalHandler);
402 signal(SIGUSR1, signalHandler);
403 signal(SIGINT, signalHandler);
404 signal(SIGTERM, signalHandler);
405
406 /*
407 * Call the initialization functions for the modules
408 * @ DHT11 Sensor
409 * @ Motor Driver
410 */
411 initDHT11();
412 initMotor();
413
414 /*
415 * Threads initialization with predefined priorities:
416 *
417 * @ tReadSensor with priority sensorPrio
418 * @ tStartStopStream with priority streamPrio
419 * @ tStartStopMotor with priority motorPrio
420 * @ tUpdateDatabase with priority updateDatabasePrio
421 *
422 * Create threads and detach them
423 */
424 int anyError=0;
425 pthread_attr_t thread_attr;
426 struct sched_param thread_param;
427
428 pthread_t readSensorID, StartStopStreamID, updateDatabaseID, StartStopMotorID;
429
430 pthread_attr_init (&thread_attr);
431 pthread_attr_getschedparam (&thread_attr, &thread_param);
432
433 initThread(sensorPrio,&thread_attr,&thread_param);
434 anyError = pthread_create (&readSensorID, &thread_attr, tReadSensor, NULL);
435 checkErrors(anyError); //Check for errors when creating thread
436
437 initThread(streamPrio,&thread_attr,&thread_param);
438 anyError = pthread_create (&StartStopStreamID, &thread_attr, tStartStopStream, NULL);
439 checkErrors(anyError); //Check for errors when creating thread
440
441 initThread(motorPrio,&thread_attr,&thread_param);
442 anyError = pthread_create (&StartStopMotorID, &thread_attr, tStartStopMotor, NULL);
443 checkErrors(anyError); //Check for errors when creating thread
444
445 initThread(updateDatabasePrio,&thread_attr,&thread_param);
446 anyError = pthread_create (&updateDatabaseID, &thread_attr, tUpdateDatabase, NULL);
447 checkErrors(anyError); //Check for errors when creating thread
448
449 pthread_detach (updateDatabaseID);
450 pthread_detach(StartStopStreamID);
451 pthread_detach (StartStopMotorID);
452 pthread_detach (readSensorID);
453
454 while(1){}
455}
456
457void initThread(int priority, pthread_attr_t *pthread_attr, struct sched_param *pthread_param)
458{
459 int min = sched_get_priority_min (SCHED_RR);
460 int max = sched_get_priority_max (SCHED_RR);
461
462 if(priority < min || priority > max) //If priority exceeds the limits
463 {
464 fprintf(stderr,"Thread priorities not valid.\n");
465 perror("initThread()");
466 exit(1);
467 }
468 pthread_param->sched_priority = priority;
469 pthread_attr_setschedparam(&pthread_attr, &pthread_param); //Set the thread's priority
470}
471
472void checkErrors(int status)
473{
474 if(status)
475 {
476 fprintf(stderr,"pthread_create() got error %d\n",status);
477 errno=status;
478 perror("pthread_create()");
479 exit(1);
480 }
481}
int send_swing_flag(int swing_flag)
Update swing flag in database.
Definition: database.c:105
int send_notification_flag(int notification_flag)
Update notification flag in database.
Definition: database.c:89
int send_temp_hum(float temp, float hum)
Update temperature and humidity in database.
Definition: database.c:16
int initDatabase()
Initializes all the functions.
Definition: database.c:121
int get_swing_flag()
Get the swing flag from database.
Definition: database.c:32
int get_live_flag()
Get the live flag from database.
Definition: database.c:60
void remDHT11(void)
Removes the sensor device driver.
Definition: dht.c:21
int readDHT11(dht11_t *data)
Sample from the sensor.
Definition: dht.c:25
void initDHT11(void)
Loads the sensor device driver.
Definition: dht.c:17
_Bool getStreamStatus()
Get the Streaming Status object.
Definition: livestream.c:41
void stopLivestream()
Stop the livestream.
Definition: livestream.c:31
void startLivestream()
Start the livestream.
Definition: livestream.c:16
void initThread(int priority, pthread_attr_t *pthread_attr, struct sched_param *pthread_param)
Initializes the thread parameters with defined priority.
Definition: main.c:457
mqd_t msgq_id
Definition: main.c:35
void * tStartStopStream(void *arg)
Controls the livestream depending on livestream flag value.
Definition: main.c:176
_Bool motorFlag
Definition: main.c:46
struct mq_attr msgq_attr
Definition: main.c:36
#define sensorSample
Definition: main.c:44
#define motorPrio
Definition: main.c:39
float databaseTemperature
Definition: main.c:54
pthread_mutex_t streamFlag_mutex
Definition: main.c:51
_Bool sensorFlag
Definition: main.c:48
float databaseHumidity
Definition: main.c:55
static void signalHandler(int signo)
Proces signal handler.
Definition: main.c:80
void * tUpdateDatabase(void *arg)
Update values to/from database.
Definition: main.c:239
#define SHMEMOBJ_NAME
Definition: main.c:32
void * tStartStopMotor(void *arg)
Controls the motor depending on swing flag value.
Definition: main.c:196
#define streamPrio
Definition: main.c:38
_Bool streamFlag
Definition: main.c:47
#define updateDatabasePrio
Definition: main.c:40
#define sensorPrio
Definition: main.c:41
void * tReadSensor(void *arg)
Reads from temperature and humidity sensor and stores values.
Definition: main.c:119
pthread_mutex_t motorFlag_mutex
Definition: main.c:50
pthread_mutex_t sensorFlag_mutex
Definition: main.c:52
pid_t daemonPID
Definition: main.c:57
void checkErrors(int status)
Check for errors upon creating threads.
Definition: main.c:472
#define MSGQOBJ_NAME
Definition: main.c:33
void initMotor()
Load the motor driver device driver.
Definition: motor.c:22
int stopMotor()
Stop the motor.
Definition: motor.c:55
void remMotor()
Remove the motor driver device driver.
Definition: motor.c:27
int startMotor()
Start the motor.
Definition: motor.c:31
_Bool getMotorStatus()
Get the Motor Status object.
Definition: motor.c:79
DHT11 Data structure CompleteSample: receives all the data from the sensor.
Definition: dht.h:31