1 |
// File: Terminal.c |
---|
2 |
//------------------------------------------------------------------------------ |
---|
3 |
// Author: Giovanni de Sanctis |
---|
4 |
// Email: info@lateral-technologies.com |
---|
5 |
//------------------------------------------------------------------------------ |
---|
6 |
// Date: Dec 2018 |
---|
7 |
// Implements the serial interface |
---|
8 |
//------------------------------------------------------------------------------ |
---|
9 |
|
---|
10 |
#include "mcc_generated_files/device_config.h" //For __delay_ms |
---|
11 |
#include "Terminal.h" |
---|
12 |
#include "Definitions.h" |
---|
13 |
#include "Power.h" |
---|
14 |
#include "Servos.h" |
---|
15 |
#include "LEDs.h" |
---|
16 |
|
---|
17 |
#include "JDY08.h" |
---|
18 |
|
---|
19 |
#include <string.h> |
---|
20 |
|
---|
21 |
enum { |
---|
22 |
ST_IDLE, |
---|
23 |
ST_USER_MOVE_INIT, |
---|
24 |
ST_USER_LEDS_INIT, |
---|
25 |
ST_USER_MOVE, |
---|
26 |
ST_USER_LEDS, |
---|
27 |
ST_AUTO |
---|
28 |
} st; |
---|
29 |
|
---|
30 |
#define MAX_USER_PRESETS 4u |
---|
31 |
#define MAX_AUTO_G 3u //We need 3 groups max for automode |
---|
32 |
#define LEN_AUTO_T 3u //We need 3 timing parameters for automode |
---|
33 |
#define MIN_AUTO_T 15u //Min time that can be specified (seconds) |
---|
34 |
#define MAX_AUTO_T 240u //Max time that can be specified (seconds) |
---|
35 |
|
---|
36 |
#define ERR_NOERR 0u |
---|
37 |
#define ERR_OUTOFRANGE 1u |
---|
38 |
#define ERR_UNKNOWNTYPE 2u |
---|
39 |
#define ERR_UNEXPECTED 3u |
---|
40 |
#define ERR_MISSINGTOKEN 4u |
---|
41 |
|
---|
42 |
//Error messages |
---|
43 |
#define ERR_OUTOFRANGE_STR "OUT OF RANGE" |
---|
44 |
#define ERR_UNKNOWN_TYPE_STR "UNKNOWN TYPE" |
---|
45 |
#define ERR_UNEXPECTED_TOKEN_STR "UNEXPECTED TOKEN" |
---|
46 |
#define ERR_MISSING_TOKEN_STR "MISSING PARAMETER" |
---|
47 |
#define ERR_ERROR_STR "ERROR" |
---|
48 |
|
---|
49 |
#define MAX_PFX_LEN 6u |
---|
50 |
#define MSG_BEGIN "BEGIN " |
---|
51 |
#define MSG_END "END " |
---|
52 |
|
---|
53 |
//Commands |
---|
54 |
char const * const CMD_SHUTDN = "SHUTDOWN"; |
---|
55 |
char const * const CMD_PING = "PING"; |
---|
56 |
char const * const CMD_BATT = "BATT"; |
---|
57 |
char const * const CMD_VER = "VER"; |
---|
58 |
char const * const CMD_ULEDS = "USERLEDS"; |
---|
59 |
char const * const CMD_UMOVE = "USERMOVE"; |
---|
60 |
char const * const CMD_AUTO = "AUTOMODE"; |
---|
61 |
char const * const CMD_ABORT = "STOPAUTO"; |
---|
62 |
|
---|
63 |
//Responses |
---|
64 |
char const * const RES_OK ="OK"; |
---|
65 |
char const * const RES_ERR="ERR"; |
---|
66 |
|
---|
67 |
uint8_t parCycles; //Number of cycles in the parsed move or leds pattern |
---|
68 |
uint8_t parUserMem; //User mem preset to host the specified move |
---|
69 |
uint8_t parNum; //Number of positions to expect |
---|
70 |
uint8_t parPtrA; //Pointer to the servo1 positions (<parNum) |
---|
71 |
uint8_t parPtrB; //Pointer to the servo2 positions (<parNum) |
---|
72 |
uint8_t parPtrG; //Counter for the number of groups specified in a cmd line |
---|
73 |
uint8_t parPtrS; //Pointer to the step values (<parNum) |
---|
74 |
uint8_t parPtrT; //Pointer to the timing values (<LEN_AUTO_T) |
---|
75 |
int8_t error; |
---|
76 |
|
---|
77 |
union ParPos //Buffers to contain the parsed move/led pattern positions |
---|
78 |
{ |
---|
79 |
struct Leds |
---|
80 |
{ |
---|
81 |
int8_t pos[MAX_PATTERNS]; |
---|
82 |
}leds; |
---|
83 |
struct Move |
---|
84 |
{ |
---|
85 |
int8_t pos1[MAX_MOVES]; |
---|
86 |
int8_t pos2[MAX_MOVES]; |
---|
87 |
}move; |
---|
88 |
struct AutM |
---|
89 |
{ |
---|
90 |
uint8_t t[LEN_AUTO_T]; |
---|
91 |
uint8_t grps; |
---|
92 |
}autm; |
---|
93 |
}parPos; |
---|
94 |
|
---|
95 |
char currMoveStr[MAX_CMD_LEN+1]=""; |
---|
96 |
char currLedsStr[MAX_CMD_LEN+1]=""; |
---|
97 |
|
---|
98 |
#if (MAX_MOVES>MAX_PATTERNS) |
---|
99 |
int8_t parStep[MAX_MOVES]; |
---|
100 |
#else |
---|
101 |
int8_t parStep[MAX_PATTERNS]; |
---|
102 |
#endif |
---|
103 |
|
---|
104 |
//Send a concatenation of 2 strings to the BT module |
---|
105 |
//This is used to send a BEGIN/END+CmdName message |
---|
106 |
void sendCompMex(const char* str1, char* str2) |
---|
107 |
{ |
---|
108 |
char str[MAX_PFX_LEN+MAX_CMD_LEN+1]; |
---|
109 |
uint8_t pd,ps; |
---|
110 |
pd=0; |
---|
111 |
for (ps=0; ps<=MAX_PFX_LEN && str1[ps]; ps++) |
---|
112 |
str[pd++]=str1[ps]; |
---|
113 |
for (ps=0; ps<MAX_CMD_LEN && str2[ps]; ps++) |
---|
114 |
str[pd++]=str2[ps]; |
---|
115 |
str[pd]='\0'; |
---|
116 |
btSendStr(str,0); |
---|
117 |
} |
---|
118 |
|
---|
119 |
void terminal(AckEnum ack) |
---|
120 |
{ |
---|
121 |
//Check for new BT messages |
---|
122 |
char* res=btReadStr(); |
---|
123 |
uint8_t i; |
---|
124 |
|
---|
125 |
if (res) |
---|
126 |
|
---|
127 |
{ |
---|
128 |
for (i=0; i<MAX_MOVE_CMDS; i++) |
---|
129 |
{ |
---|
130 |
if (btRxStrContains(MOVE_CMDS[i].cmdStr)) |
---|
131 |
{ |
---|
132 |
//If a move is still running (currMoveStr not empty) then send |
---|
133 |
// end move message |
---|
134 |
if (currMoveStr[0]) |
---|
135 |
{ |
---|
136 |
sendCompMex(MSG_END,currMoveStr); |
---|
137 |
//__delay_ms(1000); |
---|
138 |
} |
---|
139 |
memcpy(currMoveStr,MOVE_CMDS[i].cmdStr,MAX_CMD_LEN+1); |
---|
140 |
sendCompMex(MSG_BEGIN,currMoveStr); |
---|
141 |
setMove((MoveType*)MOVE_CMDS[i].cmd); |
---|
142 |
return; |
---|
143 |
} |
---|
144 |
} |
---|
145 |
|
---|
146 |
for (i=0; i<MAX_LEDS_CMDS; i++) |
---|
147 |
{ |
---|
148 |
if (btRxStrContains(LEDS_CMDS[i].cmdStr)) |
---|
149 |
{ |
---|
150 |
//If leds are still running (currLedsStr not empty) then send |
---|
151 |
// end leds message |
---|
152 |
if (currLedsStr[0]) sendCompMex(MSG_END,currLedsStr); |
---|
153 |
memcpy(currLedsStr,LEDS_CMDS[i].cmdStr,MAX_CMD_LEN+1); |
---|
154 |
sendCompMex(MSG_BEGIN,currLedsStr); |
---|
155 |
setLEDs(LEDS_CMDS[i].cmd); |
---|
156 |
return; |
---|
157 |
} |
---|
158 |
} |
---|
159 |
|
---|
160 |
if (btRxStrContains(CMD_SHUTDN)) |
---|
161 |
{ |
---|
162 |
shutDown(); |
---|
163 |
return; |
---|
164 |
} |
---|
165 |
|
---|
166 |
if (btRxStrContains(CMD_PING)) |
---|
167 |
{ |
---|
168 |
btSendStr(RES_OK,0); |
---|
169 |
return; |
---|
170 |
} |
---|
171 |
|
---|
172 |
if (btRxStrContains(CMD_VER)) |
---|
173 |
{ |
---|
174 |
btSendStr(STR_VER,0); |
---|
175 |
return; |
---|
176 |
} |
---|
177 |
|
---|
178 |
if (btRxStrContains(CMD_ABORT)) |
---|
179 |
{ |
---|
180 |
abortAuto(); |
---|
181 |
btSendStr(RES_OK,0); |
---|
182 |
return; |
---|
183 |
} |
---|
184 |
|
---|
185 |
if (btRxStrContains(CMD_BATT)) |
---|
186 |
{ |
---|
187 |
char buff[5]; |
---|
188 |
buff[0]='B'; |
---|
189 |
buff[1]='A'; |
---|
190 |
buff[2]='T'; |
---|
191 |
buff[3]='0'+getBattBars(); |
---|
192 |
buff[4]='\0'; |
---|
193 |
btSendStr(buff,0); |
---|
194 |
return; |
---|
195 |
} |
---|
196 |
|
---|
197 |
if (btRxStrContains(CMD_UMOVE)) st=ST_USER_MOVE; |
---|
198 |
else if (btRxStrContains(CMD_ULEDS)) st=ST_USER_LEDS; |
---|
199 |
else if (btRxStrContains(CMD_AUTO)) |
---|
200 |
{ |
---|
201 |
st=ST_AUTO; |
---|
202 |
} |
---|
203 |
|
---|
204 |
if (st==ST_USER_MOVE || st==ST_USER_LEDS || st==ST_AUTO) |
---|
205 |
{ |
---|
206 |
char type='\0'; |
---|
207 |
uint16_t val; |
---|
208 |
|
---|
209 |
//Clear the temp buffers and pointers before parsing new move/pattern |
---|
210 |
memset(&parPos,0,sizeof(parPos)); |
---|
211 |
memset(parStep,0,sizeof(parStep)); |
---|
212 |
parUserMem=0; |
---|
213 |
parNum=0; |
---|
214 |
parCycles=0; |
---|
215 |
parPtrA=0; //Pointer for servo1/leds positions |
---|
216 |
parPtrB=0; //Pointer for servo2 positions |
---|
217 |
parPtrG=0; //Pointer for groups (auto) |
---|
218 |
parPtrS=0; //Pointer for step values |
---|
219 |
parPtrT=0; //Pointer for timing values (auto) |
---|
220 |
error = 0; //No errors so far |
---|
221 |
|
---|
222 |
while (btRxValue(&val,&type,9999)==0 && error==0) |
---|
223 |
{ |
---|
224 |
switch(type) |
---|
225 |
{ |
---|
226 |
case 'U': //User preset number |
---|
227 |
if (parUserMem==0) |
---|
228 |
{ |
---|
229 |
if (val<MAX_USER_PRESETS) parUserMem=(uint8_t)val; |
---|
230 |
else error = ERR_OUTOFRANGE; |
---|
231 |
} |
---|
232 |
break; |
---|
233 |
case 'P': //Positions |
---|
234 |
if (parNum==0) |
---|
235 |
{ |
---|
236 |
if ((st==ST_USER_MOVE && val<MAX_MOVES)||(st==ST_USER_LEDS && val<MAX_PATTERNS)) |
---|
237 |
parNum=(uint8_t)val; |
---|
238 |
else error = ERR_OUTOFRANGE; |
---|
239 |
} |
---|
240 |
break; |
---|
241 |
case 'N': //Number of cycles |
---|
242 |
if (parCycles==0) |
---|
243 |
{ |
---|
244 |
if (val<MAX_CYCLES) parCycles=(uint8_t)val; |
---|
245 |
else error = ERR_OUTOFRANGE; |
---|
246 |
} |
---|
247 |
break; |
---|
248 |
case 'A': //Servo 1/LEDs position |
---|
249 |
if (parPtrA<parNum) |
---|
250 |
if (st==ST_USER_MOVE) |
---|
251 |
if (val<MAX_MOVE_POS) parPos.move.pos1[parPtrA++]=(int8_t)val; |
---|
252 |
else error = ERR_OUTOFRANGE; |
---|
253 |
else |
---|
254 |
if (val<MAX_LEDS_POS) parPos.leds.pos[parPtrA++]=(int8_t)val; |
---|
255 |
else error = ERR_OUTOFRANGE; |
---|
256 |
else error = ERR_UNEXPECTED; |
---|
257 |
break; |
---|
258 |
|
---|
259 |
case 'B': //Servo 2 position |
---|
260 |
if (st==ST_USER_MOVE && parPtrB<parNum) |
---|
261 |
if (val<MAX_MOVE_POS) parPos.move.pos2[parPtrB++]=(int8_t)val; |
---|
262 |
else error = ERR_OUTOFRANGE; |
---|
263 |
else error = ERR_UNEXPECTED; |
---|
264 |
break; |
---|
265 |
|
---|
266 |
case 'G': //Move Group parameter |
---|
267 |
if (st==ST_AUTO) |
---|
268 |
if (val && val<=MAX_AUTO_G) parPos.autm.grps |= 1u<<(uint8_t)(val-1); |
---|
269 |
else error = ERR_OUTOFRANGE; |
---|
270 |
else error = ERR_UNEXPECTED; |
---|
271 |
break; |
---|
272 |
|
---|
273 |
case 'L': //Step parameter with linear variation |
---|
274 |
if (parPtrS<parNum) |
---|
275 |
if (val<=MAX_STEP_VAL) |
---|
276 |
parStep[parPtrS++]=(int8_t)val; |
---|
277 |
else error = ERR_OUTOFRANGE; |
---|
278 |
else error = ERR_UNEXPECTED; |
---|
279 |
break; |
---|
280 |
|
---|
281 |
case 'S': //Step parameter with step variation (val is negative) |
---|
282 |
if (parPtrS<parNum) |
---|
283 |
if (val<=MAX_STEP_VAL) |
---|
284 |
parStep[parPtrS++]=(int8_t)-val; |
---|
285 |
else error = ERR_OUTOFRANGE; |
---|
286 |
else error = ERR_UNEXPECTED; |
---|
287 |
break; |
---|
288 |
|
---|
289 |
case 'T': //Timing parameter |
---|
290 |
if (st==ST_AUTO && parPtrT<LEN_AUTO_T) |
---|
291 |
if (val>=MIN_AUTO_T && val<=MAX_AUTO_T) parPos.autm.t[parPtrT++]=(uint8_t)val; |
---|
292 |
else error = ERR_OUTOFRANGE; |
---|
293 |
else error = ERR_UNEXPECTED; |
---|
294 |
break; |
---|
295 |
|
---|
296 |
default: |
---|
297 |
error = ERR_UNKNOWNTYPE; |
---|
298 |
break; |
---|
299 |
} |
---|
300 |
} |
---|
301 |
if (error==0) |
---|
302 |
{ |
---|
303 |
if (st==ST_USER_MOVE) |
---|
304 |
{ |
---|
305 |
setUserMove(parUserMem-1u,parNum,parCycles,parPos.move.pos1,parPos.move.pos2,parStep); |
---|
306 |
} |
---|
307 |
else if (st==ST_USER_LEDS) |
---|
308 |
{ |
---|
309 |
setUserLeds(parUserMem-1u,parNum,parCycles,parPos.leds.pos,parStep); |
---|
310 |
} |
---|
311 |
else |
---|
312 |
{ |
---|
313 |
setAuto(parPos.autm.t[0],parPos.autm.t[1],parPos.autm.t[2],parPos.autm.grps); |
---|
314 |
} |
---|
315 |
} |
---|
316 |
//Check that all the positions and step timings have been received |
---|
317 |
if (error==0 && st!=ST_AUTO) |
---|
318 |
{ |
---|
319 |
if (parNum>parPtrA || parNum>parPtrS) error=ERR_MISSINGTOKEN; |
---|
320 |
//If defining a move then check the pointer for the Servo2 as well |
---|
321 |
if (st==ST_USER_MOVE && parNum>parPtrS) error=ERR_MISSINGTOKEN; |
---|
322 |
} |
---|
323 |
switch (error) |
---|
324 |
{ |
---|
325 |
case ERR_NOERR: btSendStr(RES_OK,0); break; |
---|
326 |
case ERR_OUTOFRANGE: btSendStr(ERR_OUTOFRANGE_STR,0); break; |
---|
327 |
case ERR_UNKNOWNTYPE: btSendStr(ERR_UNKNOWN_TYPE_STR,0); break; |
---|
328 |
case ERR_UNEXPECTED: btSendStr(ERR_UNEXPECTED_TOKEN_STR,0); break; |
---|
329 |
case ERR_MISSINGTOKEN:btSendStr(ERR_MISSING_TOKEN_STR,0); break; |
---|
330 |
default: btSendStr(ERR_ERROR_STR,0); break; |
---|
331 |
} |
---|
332 |
} |
---|
333 |
} |
---|
334 |
|
---|
335 |
//If ack for move end then send out END MOVE message |
---|
336 |
// and clear current move string |
---|
337 |
if (ack==ACK_END_MOVE) |
---|
338 |
{ |
---|
339 |
sendCompMex(MSG_END,currMoveStr); |
---|
340 |
currMoveStr[0]=0; |
---|
341 |
} |
---|
342 |
|
---|
343 |
//If ack for leds end then send out END LEDS message |
---|
344 |
// and clear current leds string |
---|
345 |
if (ack==ACK_END_LEDS) |
---|
346 |
{ |
---|
347 |
sendCompMex(MSG_END,currLedsStr); |
---|
348 |
currLedsStr[0]=0; |
---|
349 |
} |
---|
350 |
} |
---|
351 |
|
---|
352 |
|
---|
353 |
|
---|