Server - Add error message if a bad baud rate is chosen
[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      gbServer_RunInBackground;
29 extern int      giServer_Port;
30 extern const char       *gsItemListFile;
31 extern const char       *gsCoke_ModbusAddress;
32 extern const char       *gsDoor_SerialPort;
33
34 // === PROTOTYPES ===
35 void    *Periodic_Thread(void *Unused);
36
37 // === GLOBALS ===
38  int    giDebugLevel = 0;
39  int    gbNoCostMode = 0;
40 const char      *gsCokebankPath = "cokebank.db";
41 // - Functions called every 20s (or so)
42 #define ciMaxPeriodics  10
43 struct sPeriodicCall {
44         void    (*Function)(void);
45 }       gaPeriodicCalls[ciMaxPeriodics];
46 pthread_t       gTimerThread;
47
48 // === CODE ===
49 void sigint_handler()
50 {
51         exit(0);
52 }
53
54 void PrintUsage(const char *progname)
55 {
56         fprintf(stderr, "Usage: %s\n", progname);
57         fprintf(stderr, "  -f,--configfile\n");
58         fprintf(stderr, "        Set the config file path (default `dispsrv.conf')\n");
59         fprintf(stderr, "  -d    Set debug level (0 - 2, default 0)\n");
60         fprintf(stderr, "  --[dont-]daemonise\n");
61         fprintf(stderr, "        Run (or explicitly don't run) the server disconnected from the terminal\n");
62 }
63
64 int main(int argc, char *argv[])
65 {
66          int    i;
67         const char      *config_file = "dispsrv.conf";
68
69         // Parse Arguments
70         for( i = 1; i < argc; i++ )
71         {
72                 char    *arg = argv[i];
73                 if( arg[0] == '-' && arg[1] != '-')
74                 {
75                         switch(arg[1])
76                         {
77                         case 'f':
78                                 if( i + 1 >= argc )     return -1;
79                                 config_file = argv[++i];
80                                 break;
81                         case 'd':
82                                 if( i + 1 >= argc )     return -1;
83                                 Config_AddValue("debug_level", argv[++i]);
84                                 giDebugLevel = atoi(argv[i]);
85                                 break;
86                         default:
87                                 // Usage Error
88                                 fprintf(stderr, "Unknown option '-%c'\n", arg[1]);
89                                 PrintUsage(argv[0]);
90                                 return -1;
91                         }
92                 }
93                 else if( arg[0] == '-' && arg[1] == '-' )
94                 {
95                         if( strcmp(arg, "--configfile") == 0 ) {
96                                 if( i + 1 >= argc )     return -1;
97                                 config_file = argv[++i];
98                         }
99                         else if( strcmp(arg, "--daemonise") == 0 ) {
100                                 Config_AddValue("daemonise", "true");
101                         }
102                         else if( strcmp(arg, "--dont-daemonise") == 0 ) {
103                                 Config_AddValue("daemonise", "false");
104                         }
105                         else {
106                                 // Usage error
107                                 fprintf(stderr, "Unknown option '%s'\n", arg);
108                                 PrintUsage(argv[0]);
109                                 return -1;
110                         }
111                 }
112                 else
113                 {
114                         // Usage Error
115                         PrintUsage(argv[0]);
116                         return -1;
117                 }
118         }
119
120         Config_ParseFile( config_file );
121
122         // Parse config values
123         gbServer_RunInBackground = Config_GetValue_Bool("daemonise", 0);
124         gsCokebankPath       = Config_GetValue("cokebank_database", 0);
125         gsDoor_SerialPort    = Config_GetValue("door_serial_port", 0);
126         gsCoke_ModbusAddress = Config_GetValue("coke_modbus_address", 0);
127         giServer_Port        = Config_GetValue_Int("server_port", 0);
128         gsItemListFile       = Config_GetValue("items_file", 0);
129
130         gbNoCostMode         = (Config_GetValue_Bool("test_mode", 0) == 1);
131
132         signal(SIGINT, sigint_handler);
133         signal(SIGTERM, sigint_handler);
134         
135         openlog("odispense2", 0, LOG_LOCAL4);
136         
137         if( Bank_Initialise(gsCokebankPath) )
138                 return -1;
139
140         Init_Handlers();
141
142         Load_Itemlist();
143         
144         Server_Start();
145         
146         if(gTimerThread)
147                 pthread_kill(gTimerThread, SIGKILL);
148
149         return 0;
150 }
151
152 void *Periodic_Thread(void *Unused __attribute__((unused)))
153 {
154          int    i;
155         
156         for( ;; )
157         {
158                 sleep(10);      // Sleep for a while
159 //              printf("Periodic firing\n");
160                 for( i = 0; i < ciMaxPeriodics; i ++ )
161                 {
162                         if( gaPeriodicCalls[i].Function )
163                                 gaPeriodicCalls[i].Function();
164                 }
165         }
166         return NULL;
167 }
168
169 void StartPeriodicThread(void)
170 {
171         pthread_create( &gTimerThread, NULL, Periodic_Thread, NULL );
172 }
173
174 void AddPeriodicFunction(void (*Fcn)(void))
175 {
176         int i;
177         for( i = 0; i < ciMaxPeriodics; i ++ )
178         {
179                 if( gaPeriodicCalls[i].Function )       continue;
180                 gaPeriodicCalls[i].Function = Fcn;
181                 return ;
182         }
183         
184         fprintf(stderr, "Error: No space for %p in periodic list\n", Fcn);
185 }
186
187 int RunRegex(regex_t *regex, const char *string, int nMatches, regmatch_t *matches, const char *errorMessage)
188 {
189          int    ret;
190         
191         ret = regexec(regex, string, nMatches, matches, 0);
192         if( ret == REG_NOMATCH ) {
193                 return -1;
194         }
195         if( ret ) {
196                 size_t  len = regerror(ret, regex, NULL, 0);
197                 char    errorStr[len];
198                 regerror(ret, regex, errorStr, len);
199                 printf("string = '%s'\n", string);
200                 fprintf(stderr, "%s\n%s", errorMessage, errorStr);
201                 exit(-1);
202         }
203         
204         return ret;
205 }
206
207 void CompileRegex(regex_t *regex, const char *pattern, int flags)
208 {
209          int    ret = regcomp(regex, pattern, flags);
210         if( ret ) {
211                 size_t  len = regerror(ret, regex, NULL, 0);
212                 char    errorStr[len];
213                 regerror(ret, regex, errorStr, len);
214                 fprintf(stderr, "Regex compilation failed - %s\n%s\n", errorStr, pattern);
215                 exit(-1);
216         }
217 }
218
219 // Serial helper
220 int InitSerial(const char *File, int BaudRate)
221 {
222         struct termios  info;
223          int    baud;
224          int    fd;
225         
226         fd = open(File, O_RDWR | O_NOCTTY | O_NONBLOCK);
227         if( fd == -1 )  return -1;
228         
229         switch(BaudRate)
230         {
231         case 1200:      baud = B1200;   break;
232         case 9600:      baud = B9600;   break;
233         case 115200:    baud = B115200; break;
234         default:
235                 fprintf(stderr, "ERROR: Invalid baud rate to InitSerial (%i)\n", BaudRate);
236                 exit(1);
237         }
238         
239         info.c_lflag = 0;       // Non-Canoical, No Echo
240         info.c_cflag = baud | CS8 | CLOCAL | CREAD;     // baud, 8N1
241         info.c_iflag = IGNCR;   // Ignore \r
242         info.c_oflag = 0;       // ???
243         cfsetspeed(&info, baud);
244         info.c_cc[VTIME] = 0;   // No time limit
245         info.c_cc[VMIN] = 1;    // Block until 1 char
246         
247         tcflush(fd, TCIFLUSH);
248         tcsetattr(fd, TCSANOW, &info);
249         
250         return fd;
251 }
252
253
254 /**
255  * \brief Create a formatted heap string
256  */
257 char *mkstr(const char *Format, ...)
258 {
259         va_list args;
260          int    len;
261         char    *ret;
262
263         va_start(args, Format);
264         len = vsnprintf(NULL, 0, Format, args);
265         va_end(args);
266
267         ret = malloc( len + 1 );
268         if(!ret)        return NULL;
269
270         va_start(args, Format);
271         vsprintf(ret, Format, args);
272         va_end(args);
273         
274         return ret;
275 }
276

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