Fixes to the coke handler
[tpg/opendispense2.git] / src / server / handler_coke.c
1 /*
2  * OpenDispense 2 
3  * UCC (University [of WA] Computer Club) Electronic Accounting System
4  *
5  * handler_coke.c - Coke controller code
6  *
7  * This file is licenced under the 3-clause BSD Licence. See the file
8  * COPYING for full details.
9  */
10 #include "common.h"
11 #include <stdio.h>
12 #include <string.h>
13 #include <unistd.h>
14 #include <sys/stat.h>
15 #include <fcntl.h>
16 #include <regex.h>
17
18 // === IMPORTS ===
19
20 // === PROTOTYPES ===
21  int    Coke_InitHandler();
22  int    Coke_CanDispense(int User, int Item);
23  int    Coke_DoDispense(int User, int Item);
24  int    WaitForColon();
25  int    ReadLine(int len, char *output);
26
27 // === GLOBALS ===
28 tHandler        gCoke_Handler = {
29         "coke",
30         Coke_InitHandler,
31         Coke_CanDispense,
32         Coke_DoDispense
33 };
34 char    *gsCoke_SerialPort = "/dev/ttyS0";
35  int    giCoke_SerialFD;
36 regex_t gCoke_StatusRegex;
37
38 // == CODE ===
39 int Coke_InitHandler()
40 {
41         printf("connecting to coke machine...\n");
42         
43         giCoke_SerialFD = InitSerial(gsCoke_SerialPort, 9600);
44         if( giCoke_SerialFD == -1 ) {
45                 fprintf(stderr, "ERROR: Unable to open coke serial port ('%s')\n", gsCoke_SerialPort);
46         }
47         
48         CompileRegex(&gCoke_StatusRegex, "^slot\\s+(\\d)\\s+([^:]+):([a-zA-Z]+)\\s*", REG_EXTENDED);
49         return 0;
50 }
51
52 int Coke_CanDispense(int User, int Item)
53 {
54         char    tmp[32], *status;
55         regmatch_t      matches[4];
56          int    ret;
57
58         // Sanity please
59         if( Item < 0 || Item > 6 )      return -1;      // -EYOURBAD
60         
61         ret = 0;
62         do {
63                 write(giCoke_SerialFD, "d7\r\n", 4);
64         } while( WaitForColon() && ret++ < 3 );
65
66         if( ret == 3 ) {
67                 fprintf(stderr, "Coke machine timed out\n");
68                 return -2;      // -EMYBAD
69         }
70
71         // TODO: Handle "not ok" response to D7
72         
73         // Ask the coke machine
74         sprintf(tmp, "s%i\r\n", Item);
75         write(giCoke_SerialFD, tmp, 4);
76
77         ret = ReadLine(sizeof(tmp)-1, tmp);
78         printf("ret = %i, tmp = '%s'\n", ret, tmp);
79 //      if( !ret )
80 //              ret = ReadLine(sizeof(tmp)-1, tmp);
81         printf("ret = %i, tmp = '%s'\n", ret, tmp);
82
83         // Catch an error       
84         if( ret <= 0 ) {
85                 fprintf(stderr, "Coke machine is not being chatty (read = %i)\n", ret);
86                 if( ret == -1 ) {
87                         perror("Coke Machine");
88                 }
89                 return -1;
90         }
91
92         // Parse status response
93         ret = RunRegex(&gCoke_StatusRegex, tmp, sizeof(matches)/sizeof(matches[0]), matches, "Bad Response");
94         if( ret ) {
95                 return -1;
96         }
97
98         // Get slot status
99         tmp[ matches[3].rm_eo ] = '\0';
100         status = &tmp[ matches[3].rm_so ];
101
102         printf("Machine responded slot status '%s'\n", status);
103
104         if( strcmp(status, "full") == 0 )
105                 return 0;
106
107         return 1;
108 }
109
110 /**
111  * \brief Actually do a dispense from the coke machine
112  */
113 int Coke_DoDispense(int User, int Item)
114 {
115         char    tmp[32], *status;
116         regmatch_t      matches[4];
117
118         // Sanity please
119         if( Item < 0 || Item > 6 )      return -1;
120
121         WaitForColon();
122
123         // Dispense
124         sprintf(tmp, "d%i\r\n", Item);
125         write(giCoke_SerialFD, tmp, 4);
126         
127         WaitForColon();
128
129         // Get status
130         ReadLine(sizeof(tmp)-1, tmp);
131         
132         tmp[ matches[3].rm_eo ] = '\0';
133         status = &tmp[ matches[3].rm_so ];
134
135         printf("Machine responded slot status '%s'\n", status);
136
137         return 0;
138 }
139
140 char ReadChar()
141 {
142         fd_set  readfs;
143         char    ch = 0;
144          int    ret;
145         struct timeval  timeout;
146         
147         timeout.tv_sec = 5;     // 5 second timeout
148         timeout.tv_usec = 0;
149         
150         FD_ZERO(&readfs);
151         FD_SET(giCoke_SerialFD, &readfs);
152         
153         ret = select(giCoke_SerialFD+1, &readfs, NULL, NULL, &timeout);
154         if( ret == 0 )  return 0;       // Timeout
155         if( ret != 1 ) {
156                 printf("readchar return %i\n", ret);
157                 return 0;
158         }
159         
160         ret = read(giCoke_SerialFD, &ch, 1);
161         if( ret != 1 ) {
162                 printf("ret = %i\n", ret);
163                 return 0;
164         }
165         
166         return ch;
167 }
168
169 int WaitForColon()
170 {
171         fd_set  readfs;
172         char    ch = 0;
173         
174         FD_SET(giCoke_SerialFD, &readfs);
175         
176         while( (ch = ReadChar()) != ':' && ch != 0);
177         
178         if( ch == 0 )   return -1;      // Timeout
179         
180         return 0;
181 }
182
183 int ReadLine(int len, char *output)
184 {
185         char    ch;
186          int    i = 0;
187          int    ret = 0;
188         
189         for(;;)
190         {
191                 ch = ReadChar();
192                         
193                 if( i < len )
194                         output[i++] = ch;
195                 
196                 if( ch == '\0' ) {
197                         break;
198                 }
199                 if( ch == '\n' || ch == '\r' ) {
200                         if( i < len )
201                                 output[--i] = '\0';
202                         break;
203                 }
204         }
205
206         //printf("ReadLine: output=%s\n", output);
207
208         if( !ch )       return -1;
209         return i;
210 }
211
212

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