Added periodic thread (reloads item config, checks coke slots)
[tpg/opendispense2.git] / src / server / main.c
1 /*
2  * OpenDispense 2 
3  * UCC (University [of WA] Computer Club) Electronic Accounting System
4  *
5  * main.c - Initialisation Code
6  *
7  * This file is licenced under the 3-clause BSD Licence. See the file
8  * COPYING for full details.
9  */
10 #include <stdlib.h>
11 #include <stdio.h>
12 #include <string.h>
13 #include <signal.h>
14 #include "common.h"
15 #include <termios.h>
16 #include <unistd.h>
17 #include <sys/stat.h>
18 #include <fcntl.h>
19 #include <stdarg.h>
20 #include <syslog.h>
21 #include <pthread.h>
22 #include "../cokebank.h"
23
24 // === IMPORTS ===
25 extern void     Init_Handlers(void);
26 extern void     Load_Itemlist(void);
27 extern void     Server_Start(void);
28 extern int      giServer_Port;
29 extern char     *gsItemListFile;
30 extern char     *gsCoke_SerialPort;
31 extern char     *gsSnack_SerialPort;
32 extern char     *gsDoor_Password;
33
34 // === PROTOTYPES ===
35 void    *Periodic_Thread(void *Unused);
36
37 // === GLOBALS ===
38  int    giDebugLevel = 0;
39 char    *gsCokebankPath = "cokebank.db";
40 // - Functions called every 20s (or so)
41 #define ciMaxPeriodics  10
42 struct sPeriodicCall {
43         void    (*Function)(void);
44 }       gaPeriodicCalls[ciMaxPeriodics];
45
46 // === CODE ===
47 void sigint_handler()
48 {
49         exit(0);
50 }
51
52 int main(int argc, char *argv[])
53 {
54          int    i;
55         pthread_t       timer_thread;
56         
57         // Parse Arguments
58         for( i = 1; i < argc; i++ )
59         {
60                 char    *arg = argv[i];
61                 if( arg[0] == '-' && arg[1] != '-')
62                 {
63                         switch(arg[1])
64                         {
65                         case 'p':
66                                 if( i + 1 >= argc )     return -1;
67                                 giServer_Port = atoi(argv[++i]);
68                                 break;
69                         case 'd':
70                                 if( i + 1 >= argc )     return -1;
71                                 giDebugLevel = atoi(argv[++i]);
72                                 break;
73                         default:
74                                 // Usage Error?
75                                 break;
76                         }
77                 }
78                 else if( arg[0] == '-' && arg[1] == '-' ) {
79                         if( strcmp(arg, "--itemsfile") == 0 ) {
80                                 if( i + 1 >= argc )     return -1;
81                                 gsItemListFile = argv[++i];
82                         }
83                         else if( strcmp(arg, "--cokeport") == 0 ) {
84                                 if( i + 1 >= argc )     return -1;
85                                 gsCoke_SerialPort = argv[++i];
86                         }
87                         else if( strcmp(arg, "--snackport") == 0 ) {
88                                 if( i + 1 >= argc )     return -1;
89                                 gsSnack_SerialPort = argv[++i];
90                         }
91                         else if( strcmp(arg, "--doorpass") == 0 ) {
92                                 if( i + 1 >= argc )     return -1;
93                                 gsDoor_Password = argv[++i];
94                         }
95                         else {
96                                 // Usage error?
97                         }
98                 }
99                 else {
100                         // Usage Error?
101                 }
102         }
103         
104         signal(SIGINT, sigint_handler);
105         
106         openlog("odispense2", 0, LOG_LOCAL4);
107         
108         if( Bank_Initialise(gsCokebankPath) )
109                 return -1;
110
111         Init_Handlers();
112
113         Load_Itemlist();
114         
115         pthread_create( &timer_thread, NULL, Periodic_Thread, NULL );
116         
117         Server_Start();
118         
119         pthread_kill(timer_thread, SIGKILL);
120
121         return 0;
122 }
123
124 void *Periodic_Thread(void *Unused)
125 {
126          int    i;
127         Unused = NULL;  // quiet, gcc
128         
129         for( ;; )
130         {
131                 sleep(10);      // Sleep for a while
132                 printf("Periodic firing\n");
133                 for( i = 0; i < ciMaxPeriodics; i ++ )
134                 {
135                         if( gaPeriodicCalls[i].Function )
136                                 gaPeriodicCalls[i].Function();
137                 }
138         }
139         return NULL;
140 }
141
142 void AddPeriodicFunction(void (*Fcn)(void))
143 {
144         int i;
145         for( i = 0; i < ciMaxPeriodics; i ++ )
146         {
147                 if( gaPeriodicCalls[i].Function )       continue;
148                 gaPeriodicCalls[i].Function = Fcn;
149                 return ;
150         }
151         
152         fprintf(stderr, "Error: No space for %p in periodic list\n", Fcn);
153 }
154
155 int RunRegex(regex_t *regex, const char *string, int nMatches, regmatch_t *matches, const char *errorMessage)
156 {
157          int    ret;
158         
159         ret = regexec(regex, string, nMatches, matches, 0);
160         if( ret == REG_NOMATCH ) {
161                 return -1;
162         }
163         if( ret ) {
164                 size_t  len = regerror(ret, regex, NULL, 0);
165                 char    errorStr[len];
166                 regerror(ret, regex, errorStr, len);
167                 printf("string = '%s'\n", string);
168                 fprintf(stderr, "%s\n%s", errorMessage, errorStr);
169                 exit(-1);
170         }
171         
172         return ret;
173 }
174
175 void CompileRegex(regex_t *regex, const char *pattern, int flags)
176 {
177          int    ret = regcomp(regex, pattern, flags);
178         if( ret ) {
179                 size_t  len = regerror(ret, regex, NULL, 0);
180                 char    errorStr[len];
181                 regerror(ret, regex, errorStr, len);
182                 fprintf(stderr, "Regex compilation failed - %s\n", errorStr);
183                 exit(-1);
184         }
185 }
186
187 // Serial helper
188 int InitSerial(const char *File, int BaudRate)
189 {
190         struct termios  info;
191          int    baud;
192          int    fd;
193         
194         fd = open(File, O_RDWR | O_NOCTTY | O_NONBLOCK);
195         if( fd == -1 )  return -1;
196         
197         switch(BaudRate)
198         {
199         case 9600:      baud = B9600;   break;
200         default:        close(fd);      return -1;
201         }
202         
203         info.c_lflag = 0;       // Non-Canoical, No Echo
204         info.c_cflag = baud | CS8 | CLOCAL | CREAD;     // baud, 8N1
205         cfsetspeed(&info, baud);
206         info.c_cc[VTIME] = 0;   // No time limit
207         info.c_cc[VMIN] = 1;    // Block until 1 char
208         
209         tcflush(fd, TCIFLUSH);
210         tcsetattr(fd, TCSANOW, &info);
211         
212         return fd;
213 }
214
215
216 /**
217  * \brief Create a formatted heap string
218  */
219 char *mkstr(const char *Format, ...)
220 {
221         va_list args;
222          int    len;
223         char    *ret;
224
225         va_start(args, Format);
226         len = vsnprintf(NULL, 0, Format, args);
227         va_end(args);
228
229         ret = malloc( len + 1 );
230         if(!ret)        return NULL;
231
232         va_start(args, Format);
233         vsprintf(ret, Format, args);
234         va_end(args);
235         
236         return ret;
237 }
238

UCC git Repository :: git.ucc.asn.au