Door - Move thread init to after fork()
[tpg/opendispense2.git] / src / server / handler_door.c
1 /*
2  * OpenDispense 2 
3  * UCC (University [of WA] Computer Club) Electronic Accounting System
4  *
5  * handler_door.c - Door Relay code
6  *
7  * This file is licenced under the 3-clause BSD Licence. See the file
8  * COPYING for full details.
9  */
10 #define DEBUG   1
11
12 #include "common.h"
13 #include <stdio.h>
14 #include <string.h>
15 #include <unistd.h>
16 #include <sys/stat.h>
17 #include <fcntl.h>
18 #include <signal.h>
19 #include <unistd.h>
20 #include <pty.h>
21 #include <pthread.h>
22 #include <semaphore.h>
23 #include <errno.h>
24 #include <stdbool.h>
25
26 #define DOOR_UNLOCKED_DELAY     10      // Time in seconds before the door re-locks
27
28 // === IMPORTS ===
29
30 // === PROTOTYPES ===
31 void*   Door_Lock(void* Unused);
32  int    Door_InitHandler();
33  int    Door_CanDispense(int User, int Item);
34  int    Door_DoDispense(int User, int Item);
35
36 // === GLOBALS ===
37 tHandler        gDoor_Handler = {
38         "door",
39         Door_InitHandler,
40         Door_CanDispense,
41         Door_DoDispense
42 };
43 char    *gsDoor_SerialPort;     // Set from config in main.c
44 sem_t   gDoor_UnlockSemaphore;
45 pthread_t       gDoor_LockThread;
46 bool    gbDoor_LockThreadStarted;
47
48 // === CODE ===
49 void* Door_Lock(void* Unused __attribute__((unused)))
50 {
51         while(1)
52         {
53                 sem_wait(&gDoor_UnlockSemaphore);
54
55                 int door_serial_handle = InitSerial(gsDoor_SerialPort, 9600);
56                 if(door_serial_handle < 0)
57                 {
58                         fprintf(stderr, "Unable to open door serial '%s'\n", gsDoor_SerialPort);
59                         perror("Opening door port");
60                 }
61
62                 // Disable local echo
63                 {
64                         struct termios  info;
65                         tcgetattr(door_serial_handle, &info);
66                         info.c_cflag &= ~CLOCAL;
67                         tcsetattr(door_serial_handle, TCSANOW, &info);
68                 }
69
70                 if(write(door_serial_handle, "\xff\x01\x01", 3) != 3)   // Relay ON
71                 {
72                         fprintf(stderr, "Failed to write Relay ON (unlock) command, errstr: %s", strerror(errno));
73                 }
74
75                 sleep(DOOR_UNLOCKED_DELAY);
76
77                 if(write(door_serial_handle, "\xff\x01\x00", 3) != 3)   // Relay OFF
78                 {
79                         fprintf(stderr, "Failed to write Relay OFF (lock) command, errstr: %s", strerror(errno));
80                 }
81
82                 close(door_serial_handle);
83         }
84 }
85
86 int Door_InitHandler(void)
87 {
88         // Thread started later
89
90         return 0;
91 }
92
93 /**
94  */
95 int Door_CanDispense(int User, int Item)
96 {
97         #if DEBUG
98         printf("Door_CanDispense: (User=%i,Item=%i)\n", User, Item);
99         #endif
100         // Sanity please
101         if( Item != 0 ) return -1;
102         
103         if( !(Bank_GetFlags(User) & USER_FLAG_DOORGROUP) )
104         {
105                 #if DEBUG
106                 printf("Door_CanDispense: User %i not in door\n", User);
107                 #endif
108                 return 1;
109         }
110         
111         #if DEBUG
112         printf("Door_CanDispense: User %i can open the door\n", User);
113         #endif
114         
115         return 0;
116 }
117
118 /**
119  * \brief Actually do a dispense from the coke machine
120  */
121 int Door_DoDispense(int User, int Item)
122 {       
123         #if DEBUG
124         printf("Door_DoDispense: (User=%i,Item=%i)\n", User, Item);
125         #endif
126
127         // Sanity please
128         if( Item != 0 ) return -1;
129         
130         // Check if user is in door
131         if( !(Bank_GetFlags(User) & USER_FLAG_DOORGROUP) )
132         {
133                 #if DEBUG
134                 printf("Door_CanDispense: User %i not in door\n", User);
135                 #endif
136                 return 1;
137         }
138         
139         // Door thread spun up here because program is forked after thread created
140         if( !gbDoor_LockThreadStarted )
141         {
142                 // Initialize semaphore, triggers door lock release if semaphore is greater than 0
143                 sem_init(&gDoor_UnlockSemaphore, 0, 0); 
144
145                 pthread_create(&gDoor_LockThread, NULL, &Door_Lock, NULL);
146         }
147
148         if(sem_post(&gDoor_UnlockSemaphore))
149         {
150                 perror("Failed to post \"Unlock Door\" semaphore, sem_post returned");
151                 return -1;
152         }
153
154         #if DEBUG
155         printf("Door_DoDispense: User %i opened door\n", User);
156         #endif
157
158         return 0;
159 }

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