SmartCradle v1
Baby smart cradle
daemon.c
Go to the documentation of this file.
1
10#include <sys/syslog.h>
11#include <stdio.h>
12#include <sys/socket.h>
13#include <mqueue.h>
14#include <sys/types.h>
15#include <resolv.h>
16#include <netdb.h>
17#include <stdlib.h>
18#include <string.h>
19#include <pthread.h>
20#include <signal.h>
21#include <sys/time.h>
22#include <unistd.h>
23#include <sys/stat.h>
24#include <errno.h>
25#include <fcntl.h>
26#include <sys/mman.h>
27#include <sys/shm.h>
28#include "../inc/microphone.h"
29
30#define detectCryingPrio 3
31#define watchFlagPrio 2
33#define MSGQOBJ_NAME "/mqLocalDaemon"
34#define SHMEMOBJ_NAME "/shLocalDaemon"
36mqd_t msgq_id;
38_Bool isStreamActive = 0;
47void initThread(int priority, pthread_attr_t *pthread_attr, struct sched_param *pthread_param);
48
54void checkErrors(int status);
55
61static void signalHandler(int signo)
62{
63 switch (signo)
64 {
65 case (SIGTERM):
66 syslog(LOG_INFO, "SIGTERM received. Closing daemon...\n");
67 exit(1);
68 }
69}
70
76void *tDetectCrying(void *local_pid)
77{
78 int ret = 0;
79 while (1)
80 {
81 if (!isStreamActive) //If streaming is not active
82 {
83 double loudness;
84
85 syslog(LOG_INFO, "Recording will start.\n");
86 ret = startRecording();
87 sleep(2);
88 if(!ret)
89 {
90 syslog(LOG_INFO, "Recording ended.\n");
91 ret = processAudio(&loudness);
92 switch(ret)
93 {
94 case 1: //Loudness exceeds the limit
95 syslog(LOG_INFO, "Signaling local system at PID: %d\n", local_pid);
96 kill(local_pid, SIGUSR1);
97 case 0: //Loudness does not exceed the limit
98 syslog(LOG_INFO, "Audio process returned: %d | loudness : %.3f\n", ret, loudness);
99 break;
100 case ERR_OPEN: //Error in processAudio()
101 syslog(LOG_ERR, "Error when opening file audiorecord.wav.\n" );
102 break;
103 case ERR_READ: //Error in processAudio()
104 syslog(LOG_ERR, "Error when reading from file audiorecord.wav.\n" );
105 break;
106 default: //Error in processAudio()
107 syslog(LOG_ERR, "In processAudio()\n" );
108 break;
109 }
110 }
111 else
112 syslog(LOG_ERR, "In startRecording().\n");
113 }
114
115 /* Sleep for 2 seconds */
116 sleep(2);
117 }
118}
119
123void *tWatchStreamFlag(void *arg)
124{
125 struct mq_attr msgq_attr;
126 char *msg;
127 const char msg_type[4] = "LV-"; //Command structure
128 unsigned int ret;
129
130 while (1)
131 {
132 mq_getattr(msgq_id, &msgq_attr);
133 if (msgq_attr.mq_curmsgs) //If there are messages on the message queue
134 {
135 msg = malloc(6);
136 ret = mq_receive(msgq_id, msg, 6, NULL); //Receive the message
137 if (ret > 0)
138 {
139 syslog(LOG_INFO, "Command received: %s\n", msg);
140 if (!strncmp(msg, msg_type, strlen(msg_type))) //Checks if the command is valid
141 {
142 syslog(LOG_INFO, "Command valid.\n");
143 isStreamActive = msg[3]-'0'; //Update variable with the current streamFlag value
144 syslog(LOG_INFO, "Streaming is now %d.\n", isStreamActive);
145 }
146 else
147 syslog(LOG_ERR, "Command not valid.\n");
148 }
149 else
150 {
151 errno = ret;
152 syslog(LOG_ERR, "Error (%d) when receiving message.\n",errno);
153 }
154 free(msg);
155 }
156
157 /* Sleep for 3 seconds */
158 sleep(3);
159 }
160}
161
162int main(int argc, char *args[])
163{
164 pid_t localPID = 0;
165 int ret;
166
167 msgq_id = mq_open(MSGQOBJ_NAME, O_RDONLY | O_NONBLOCK);
168 if (msgq_id == (mqd_t)-1) {
169 syslog(LOG_ERR, "mq_open() got error %d\n",msgq_id);
170 exit(1);
171 }
172
173 /*
174 * Define the signal handler to received SIGTERM from
175 * the main process
176 */
177 signal(SIGTERM, signalHandler);
178
179 /*
180 * Fork, create new session, change root dir,
181 * umask and close file descriptors
182 */
183 pid_t pid, sid;
184
185 pid = fork(); // create a new process
186 if (pid < 0)
187 { // on error exit
188 syslog(LOG_ERR, "%s\n", "fork");
189 exit(EXIT_FAILURE);
190 }
191
192 if (pid > 0)
193 {
194 printf("Deamon PID: %d\n", pid);
195
196 // parent process (exit)
197 exit(EXIT_SUCCESS);
198 }
199 sid = setsid(); // create a new session
200 if (sid < 0)
201 { // on error exit
202 syslog(LOG_ERR, "%s\n", "setsid");
203 exit(EXIT_FAILURE);
204 }
205
206 // make '/' the root directory
207 if (chdir("/") < 0)
208 { // on error exit
209 syslog(LOG_ERR, "%s\n", "chdir");
210 exit(EXIT_FAILURE);
211 }
212 umask(0);
213
214 close(STDIN_FILENO); // close standard input file descriptor
215 close(STDOUT_FILENO); // close standard output file descriptor
216 close(STDERR_FILENO); // close standard error file descriptor
217
218 /*
219 * Opens shared memory to read local's PID
220 * and send Daemon's PID
221 */
222 int fd;
223 fd = shm_open(SHMEMOBJ_NAME, O_RDWR, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);
224 void *ptr;
225 ptr = mmap(0, sizeof(pid_t), PROT_WRITE | PROT_READ, MAP_SHARED, fd, 0);
226 if(ptr == (void *)-1)
227 {
228 shm_unlink(SHMEMOBJ_NAME);
229 syslog(LOG_ERR, "Error %s in mmap()\n",errno);
230 exit(1);
231 }
232 localPID = atoi((char *)ptr);
233 sprintf(ptr, "%d", getpid());
234 ret = munmap(0, sizeof(pid_t));
235 if(ret < 0)
236 {
237 shm_unlink(SHMEMOBJ_NAME);
238 syslog(LOG_ERR, "Error %s in munmap()\n",errno);
239 exit(1);
240 }
241 syslog(LOG_INFO, "Received local PID: %d\n",localPID);
242
243 /*
244 * Threads initialization with predefined priorities:
245 *
246 * @ tDetectCrying with priority detectCryingPrio
247 * @ tWatchStreamFlag with priority watchFlagPrio
248 *
249 * Create threads and detach them
250 */
251 int anyError = 0;
252 pthread_attr_t thread_attr;
253 struct sched_param thread_param;
254
255 pthread_t detectCryingID, watchStreamFlagID;
256
257 pthread_attr_init(&thread_attr);
258 pthread_attr_getschedparam(&thread_attr, &thread_param);
259
260 initThread(watchFlagPrio, &thread_attr, &thread_param);
261 anyError = pthread_create(&watchStreamFlagID, &thread_attr, tWatchStreamFlag, NULL);
262 checkErrors(anyError); //Check for errors when creating thread
263
264 initThread(detectCryingPrio, &thread_attr, &thread_param);
265 anyError = pthread_create(&detectCryingID, &thread_attr, tDetectCrying, (void *)localPID);
266 checkErrors(anyError); //Check for errors when creating thread
267
268 pthread_detach(watchStreamFlagID);
269 pthread_detach(detectCryingID);
270
271 while (1){}
272}
273
274void initThread(int priority, pthread_attr_t *pthread_attr, struct sched_param *pthread_param)
275{
276 int min = sched_get_priority_min (SCHED_RR);
277 int max = sched_get_priority_max (SCHED_RR);
278
279 if(priority < min || priority > max) //If priority exceeds the limits
280 {
281 fprintf(stderr,"Thread priorities not valid.\n");
282 perror("initThread()");
283 exit(1);
284 }
285 pthread_param->sched_priority = priority;
286 pthread_attr_setschedparam(&pthread_attr, &pthread_param); //Set the thread's priority
287}
288
289void checkErrors(int status)
290{
291 if(status)
292 {
293 fprintf(stderr,"pthread_create() got error %d\n",status);
294 errno=status;
295 perror("pthread_create()");
296 exit(1);
297 }
298}
void initThread(int priority, pthread_attr_t *pthread_attr, struct sched_param *pthread_param)
Initializes the thread parameters with defined priority.
Definition: daemon.c:274
mqd_t msgq_id
Definition: daemon.c:36
void * tDetectCrying(void *local_pid)
Detects crying from microphone.
Definition: daemon.c:76
static void signalHandler(int signo)
Process signal handler.
Definition: daemon.c:61
#define SHMEMOBJ_NAME
Definition: daemon.c:34
#define detectCryingPrio
Definition: daemon.c:30
#define watchFlagPrio
Definition: daemon.c:31
_Bool isStreamActive
Definition: daemon.c:38
void * tWatchStreamFlag(void *arg)
Watches message queue for any changes in livestream flag.
Definition: daemon.c:123
void checkErrors(int status)
Check for errors upon creating threads.
Definition: daemon.c:289
#define MSGQOBJ_NAME
Definition: daemon.c:33
struct mq_attr msgq_attr
Definition: main.c:36
int processAudio(double *loudness)
Processes the audio to check whether the baby is crying.
Definition: microphone.c:73
#define ERR_OPEN
Definition: microphone.h:13
#define ERR_READ
Definition: microphone.h:14
int startRecording()
Records a 2 second .wav audio from microphone.
Definition: microphone.c:18