root/RF_BT_Tail/Terminal.c

Revision 244, 9.2 kB (checked in by phil, 4 years ago)

added initial Tail Source Package

Line 
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
Note: See TracBrowser for help on using the browser.