dataXferImpl.c

Go to the documentation of this file.
00001 #include "dataXferImpl.h"
00002 #include <string.h>
00003 
00008 
00009 
00010 
00012 static CMD_STATE cmdState;
00013 
00015 static CMD_OUTPUT cmdOutput;
00016 
00019 void resetCommandFindMachine()
00020 {
00021         cmdState = STATE_CMD_START;
00022         cmdOutput = OUTPUT_CMD_NONE;
00023 }
00024 
00062 CMD_OUTPUT stepCommandFindMachine(char c_inChar, char* c_outChar)
00063 {
00064         switch (cmdState)
00065         {
00066         case STATE_CMD_START :
00067                 if (c_inChar != CMD_TOKEN) {
00068                         // This is just a character, not a command.
00069                         *c_outChar = c_inChar;
00070                         cmdOutput = OUTPUT_CMD_CHAR;
00071                 } else {
00072                         cmdState = STATE_CMD_WAIT1;
00073                         cmdOutput = OUTPUT_CMD_NONE;
00074                 }
00075                 break;
00076 
00077         // We're waiting for a command or an escaped command.
00078         case STATE_CMD_WAIT1 :
00079                 switch (c_inChar) {
00080             case CMD_TOKEN :
00081                         // The sequence CMD_TOKEN CMD_TOKEN.
00082                         cmdState = STATE_CMD_WAIT2;
00083                         break;
00084 
00085             case ESCAPED_CMD :
00086                         // This was an escaped CMD_TOKEN char.
00087                         *c_outChar = CMD_TOKEN;
00088                         cmdOutput = OUTPUT_CMD_CHAR;
00089                         cmdState = STATE_CMD_START;
00090                         break;
00091 
00092                 default :
00093                         // This is a command
00094                         *c_outChar = c_inChar;
00095                         cmdOutput = OUTPUT_CMD_CMD;
00096                         cmdState = STATE_CMD_START;
00097                         break;
00098                 }
00099                 break;
00100 
00101         case STATE_CMD_WAIT2 :
00102                 switch (c_inChar) {
00103             case ESCAPED_CMD :
00104                     // The sequence CMD_TOKEN CMD_TOKEN ESCAPED_CMD, which
00105                     // is the command CMD_TOKEN
00106                         cmdOutput = OUTPUT_CMD_CMD;
00107                         cmdState = STATE_CMD_START;
00108                         *c_outChar = CMD_TOKEN;
00109                         break;
00110 
00111                 case CMD_TOKEN :
00112                         // The sequence CMD_TOKEN CMD_TOKEN CMD_TOKEN, which
00113                         // is a repeated command (the first CMD_TOKEN) followed
00114                         // by CMD_TOKEN CMD_TOKEN (so remain in this state to
00115                         // decode it based on the next incoming char).
00116                         cmdOutput = OUTPUT_CMD_REPEATED_WAIT;
00117                         break;
00118 
00119                 default :
00120                         // The sequence CMD_TOKEN CMD_TOKEN c,
00121                         // which is a repeated command c.
00122                         *c_outChar = c_inChar;
00123                         cmdOutput = OUTPUT_CMD_REPEATED_CMD;
00124                         cmdState = STATE_CMD_START;
00125                         break;
00126 
00127                 }
00128                 break;
00129 
00130         default:
00131                 // Shouldn't happen
00132                 ASSERT(FALSE);
00133                 break;
00134         }
00135         
00136         return cmdOutput;
00137 }
00139 
00140 
00141 
00142 XFER_VAR xferVar[NUM_XFER_VARS];
00143 uint8 au8_xferVarWriteable[NUM_XFER_VARS/8 + ((NUM_XFER_VARS % 8) > 0)];
00144 
00145 
00146 
00147 
00149 
00150 
00152 static RECEIVE_STATE receiveState;
00153 
00156 static char c_outChar;
00157 
00161 static uint u_index;
00162 
00165 static RECEIVE_ERROR receiveError;
00166 
00167 #ifndef __PIC__
00170 static BOOL b_isSpec;
00171 #define B_IS_SPEC b_isSpec
00172 #else
00173 // For the PIC, we never have a spec.
00174 #define B_IS_SPEC 0
00175 #endif
00176 
00179 RECEIVE_STATE getReceiveMachineState()
00180 {
00181         return receiveState;
00182 }
00183 
00186 char getReceiveMachineOutChar()
00187 {
00188         return c_outChar;
00189 }
00190 
00193 uint getReceiveMachineIndex()
00194 {
00195         return u_index;
00196 }
00197 
00198 
00202 RECEIVE_ERROR getReceiveMachineError()
00203 {
00204         RECEIVE_ERROR re = receiveError;
00205         receiveError = ERR_NONE;
00206         return re;
00207 }
00208 
00209 
00210 #if !defined(__PIC__) || defined(__DOXYGEN__)
00214 BOOL getReceiveMachineIsSpec()
00215 {
00216         return b_isSpec;
00217 }
00218 #endif
00219 
00220 
00224 void resetReceiveMachine()
00225 {
00226         receiveState = STATE_RECV_START;
00227         receiveError = ERR_NONE;
00228         // Since this state machine depends on the command-finding machine
00229         // reset it also.
00230         resetCommandFindMachine();
00231 }
00232 
00233 
00236 void clearReceiveMachineError() {
00237         receiveError = ERR_NONE;
00238 }
00239 
00240 
00243 void clearReceiveStruct() {
00244         memset(xferVar, 0, sizeof(xferVar));
00245         memset(au8_xferVarWriteable, 0, sizeof(au8_xferVarWriteable));
00246 }
00247 
00255 BOOL isReceiveMachineChar(char* c_receivedChar)
00256 {
00257         *c_receivedChar = c_outChar;
00258         return ( (receiveState == STATE_RECV_START) && (receiveError == ERR_NONE) &&
00259              (u_index == CHAR_RECEIVED_INDEX) );
00260 }
00261 
00262 
00270 BOOL isReceiveMachineData(uint* u_receivedIndex)
00271 {
00272         *u_receivedIndex = u_index;
00273         return ( (receiveState == STATE_RECV_START) && (receiveError == ERR_NONE) &&
00274              (u_index != CHAR_RECEIVED_INDEX) && !B_IS_SPEC);
00275 }
00276 
00277 
00278 #if !defined(__PIC__) || defined(__DOXYGEN__)
00279 
00286 BOOL isReceiveMachineSpec(uint* u_receivedIndex)
00287 {
00288         *u_receivedIndex = u_index;
00289         return ( (receiveState == STATE_RECV_START) && (receiveError == ERR_NONE) &&
00290              (u_index != CHAR_RECEIVED_INDEX) && B_IS_SPEC);
00291 }
00292 #endif
00293 
00294 
00299 uint getVarIndex(char c_cmd)
00300 {
00301         return ((unsigned char) c_cmd) >> VAR_SIZE_BITS;
00302 }
00303 
00308 uint getVarLength(char c_cmd)
00309 {
00310         return (c_cmd & VAR_SIZE_MASK) + 1;
00311 }
00312 
00319 static uint8* validateIndex() {
00320         uint8* pu8_data = NULL;
00321 
00322         // Check that the index exists
00323         if (u_index >= NUM_XFER_VARS) {
00324                 receiveError = ERR_INDEX_TOO_HIGH;
00325                 receiveState = STATE_RECV_START;
00326                 return NULL;
00327         }
00328 
00329         // Set up to read length bytes in during
00330         // subsequent calls.
00331         pu8_data = xferVar[u_index].pu8_data;
00332         // If this index isn't configured, issue an error and abort
00333         if (pu8_data == NULL) {
00334                 receiveError = ERR_UNSPECIFIED_INDEX;
00335                 receiveState = STATE_RECV_START;
00336                 return NULL;
00337         }
00338 
00339         // If this variable is read-only, issue an error and abort
00340 #ifdef __PIC__
00341         if (!isVarWriteable(u_index)) {
00342                 receiveError = ERR_READ_ONLY_VAR;
00343                 receiveState = STATE_RECV_START;
00344                 return NULL;
00345         }
00346 #endif
00347 
00348         // Indicate success by returning a pointer to the data
00349         return pu8_data;
00350 }
00351 
00356 void assignBit(uint u_index, BOOL b_bitVal) {
00357         // Determine which byte this bit lives in
00358         uint u_byteIndex = u_index / 8;
00359         // Create a bit mask for this bit
00360         uint8 u8_mask = 1 << (u_index % 8);
00361         // Set or clear it
00362         if (b_bitVal)
00363                 au8_xferVarWriteable[u_byteIndex] |= u8_mask;
00364         else
00365                 au8_xferVarWriteable[u_byteIndex] &= ~u8_mask;
00366 }
00367 
00375 BOOL isVarWriteable(uint u_index) {
00376         // Determine which byte this bit lives in
00377         uint u_byteIndex = u_index / 8;
00378         // Create a bit mask for this bit
00379         uint8 u8_mask = 1 << (u_index % 8);
00380         // Read it
00381         return (au8_xferVarWriteable[u_byteIndex] & u8_mask) != 0;
00382 }
00383 
00390 static BOOL validateLength(uint u_varLength) {
00391         if (xferVar[u_index].u8_size != (u_varLength - 1)) {
00392                 receiveError = ERR_VAR_SIZE_MISMATCH;
00393                 receiveState = STATE_RECV_START;
00394                 return FALSE;
00395         } else {
00396                 return TRUE;
00397         }
00398 }
00399 
00400 #ifndef __PIC__
00403 static uint8 au8_varSpecData[256 + 3];
00404 
00406 static uint u_specLength;
00407 
00411 static void parseVarSpec() {
00412         uint u_size;
00413         size_t st_len;
00414         XFER_VAR* pXferVar = xferVar + u_index;
00415         char* psz_s;
00416 
00417         // Free old memory associated with this variable
00418         if (pXferVar->pu8_data != NULL) {
00419                 free(pXferVar->pu8_data);
00420                 free(pXferVar->psz_format);
00421                 free(pXferVar->psz_name);
00422                 free(pXferVar->psz_desc);
00423         }
00424 
00425         // Determine the size of this variable then allocate it. Note that
00426         // the size stored is the actual size minus one!
00427         u_size = pXferVar->u8_size = au8_varSpecData[0];
00428         u_size++;
00429         pXferVar->pu8_data = (uint8*) malloc(sizeof(uint8)*u_size);
00430 
00431         // Force all three strings to be null-terminated.
00432         ASSERT(u_specLength + 2 < sizeof(au8_varSpecData));
00433         au8_varSpecData[u_specLength + 0] = 0;
00434         au8_varSpecData[u_specLength + 1] = 0;
00435         au8_varSpecData[u_specLength + 2] = 0;
00436 
00437         // Copy the format string of the variable
00438         psz_s = (char*) au8_varSpecData + 1;
00439         st_len = strlen(psz_s) + 1;
00440         pXferVar->psz_format = (char*) malloc(sizeof(char)*st_len);
00441         strcpy(pXferVar->psz_format, psz_s);
00442         psz_s += st_len;
00443         ASSERT(((uint8*) psz_s) < au8_varSpecData + sizeof(au8_varSpecData));
00444 
00445         // Copy the name string of the variable
00446         st_len = strlen(psz_s) + 1;
00447         pXferVar->psz_name = (char*) malloc(sizeof(char)*st_len);
00448         strcpy(pXferVar->psz_name, psz_s);
00449         psz_s += st_len;
00450         ASSERT(((uint8*) psz_s) < au8_varSpecData + sizeof(au8_varSpecData));
00451 
00452         // Copy the description string of the variable
00453         st_len = strlen(psz_s) + 1;
00454         pXferVar->psz_desc = (char*) malloc(sizeof(char)*st_len);
00455         strcpy(pXferVar->psz_desc, psz_s);
00456         psz_s += st_len;
00457         ASSERT(((uint8*) psz_s) < au8_varSpecData + sizeof(au8_varSpecData));
00458 }
00459 #endif
00460 
00475 RECEIVE_ERROR stepReceiveMachine(char c_inChar, BOOL b_isTimeout)
00476 {
00477         // Output of the command-finding state machine
00478         CMD_OUTPUT cmdOutput;
00479         // Bytes of a variable that still need to be read
00480         static uint u_varLength;
00481         // A pointer which variable data is read into
00482         static uint8* pu8_data = NULL;
00483 #ifndef __PIC__
00484         // The last command received
00485         static char c_lastCommand;
00486 #endif
00487 
00488         // Global state transition: a timeout.
00489         // Look for a timeout; they only occur during reception, not
00490         // in the start state.
00491         if ((receiveState != STATE_RECV_START) && b_isTimeout) {
00492                 // Reset the machine, then signal the error (since errors
00493                 // are cleared during reset).
00494                 resetReceiveMachine();
00495                 receiveError = ERR_TIMEOUT;
00496         }
00497 
00498         // Global state transition: waiting for a char or command
00499         // Run a char through the command state machine
00500     cmdOutput = stepCommandFindMachine(c_inChar, &c_outChar);
00501         // If we're waiting for another char, do that here instead of
00502         // adding a wait case to every receive state below.
00503         // If this is the start state (which signals data out is valid),
00504         // move out of that start state.
00505         switch (cmdOutput) {
00506                 case OUTPUT_CMD_NONE :
00507                         if (receiveState == STATE_RECV_START) {
00508                             receiveState = STATE_RECV_CMD_WAIT;
00509                         }
00510                     return receiveError;
00511 
00512                 case OUTPUT_CMD_REPEATED_CMD :
00513                         // Report the repeated command, then begin processing
00514                         // the second command as a (usual) command.
00515                         receiveError = ERR_REPEATED_CMD;
00516                         cmdOutput = OUTPUT_CMD_CMD;
00517                         break;
00518 
00519                 case OUTPUT_CMD_REPEATED_WAIT :
00520                         // Report the repeated command, then wait
00521                         // for another character.
00522                         receiveError = ERR_REPEATED_CMD;
00523                         return receiveError;
00524 
00525                 case OUTPUT_CMD_CMD :
00526                         // If we're not expecting a command, then signal an
00527                         // interrupted command then move the state machine to
00528                         // accept the command.
00529                         if (receiveState != STATE_RECV_CMD_WAIT) {
00530                                 receiveError = ERR_INTERRUPTED_CMD;
00531                                 receiveState = STATE_RECV_CMD_WAIT;
00532                         }
00533                         break;
00534 
00535                 case OUTPUT_CMD_CHAR :
00536                         // These will be processed by the state machine below.
00537                         break;
00538 
00539                 default :
00540                         ASSERT(FALSE);
00541                         break;
00542         }
00543 
00544         // Process a command or a character using the remainer of the
00545         // receive state machine.
00546         switch (receiveState)
00547         {
00548         case STATE_RECV_START:
00549                 switch (cmdOutput)
00550                 {
00551             case OUTPUT_CMD_CHAR :
00552                         // c_outChar is already assigned. Stay in this state.
00553                         // Reset the error on a valid received character, unless this
00554                         // this character caused a timeout.
00555                         if (receiveError != ERR_TIMEOUT)
00556                                 receiveError = ERR_NONE;
00557                         u_index = CHAR_RECEIVED_INDEX;
00558                         break;
00559 
00560                 default :
00561                         // Commands and wait shouldn't be possible; any other
00562                         // state is invalid.
00563                         ASSERT(FALSE);
00564                         break;
00565                 }
00566                 break;
00567 
00568         case STATE_RECV_CMD_WAIT :
00569                 switch (cmdOutput)
00570                 {
00571             case OUTPUT_CMD_CHAR :
00572                         // c_outChar is already assigned.
00573                         // Signal a character (the command token escaped) was received.
00574                         ASSERT(c_outChar == CMD_TOKEN);
00575                         receiveState = STATE_RECV_START;
00576                         receiveError = ERR_NONE;
00577                         u_index = CHAR_RECEIVED_INDEX;
00578                         break;
00579 
00580             case OUTPUT_CMD_CMD :
00581                         // Decode this command
00582                         switch (c_outChar)
00583                         {
00584                         case CMD_LONG_VAR : 
00585                                 receiveState = STATE_RECV_LONG_INDEX;
00586                                 break;
00587 
00588                         case CMD_SEND_ONLY : 
00589                         case CMD_SEND_RECEIVE_VAR :
00590 #ifdef __PIC__
00591                                 // The PIC should never receive a variable spec
00592                                 receiveState = STATE_RECV_START;
00593                                 receiveError = ERR_PIC_VAR_SPEC;
00594                                 break;
00595 #else
00596                                 // Record this command, for use in the next state.
00597                                 c_lastCommand = c_outChar;
00598                                 receiveState = STATE_RECV_SPEC_INDEX;
00599                                 break;
00600 #endif
00601 
00602                         case ESCAPED_CMD :
00603                                 // Should never reach this state.
00604                                 ASSERT(FALSE); 
00605                                 break;
00606 
00607                         default :
00608                                 // It's not one of the special codes, so determine
00609                                 // the variable number and length.
00610                                 u_index = getVarIndex(c_outChar);
00611                                 u_varLength = getVarLength(c_outChar);
00612 #ifndef __PIC__
00613                                 b_isSpec = FALSE;
00614 #endif
00615                                 // Validate the index, getting a pointer to the data
00616                                 pu8_data = validateIndex();
00617                                 // If the index is invalid, go no further.
00618                                 if (pu8_data == NULL)
00619                                         break;
00620                                 // Check that the variable length matches
00621                                 if (!validateLength(u_varLength))
00622                                         break;
00623                                 // All checks passed; move to the receive state to
00624                                 // receive bytes.
00625                                 receiveState = STATE_RECV_READ_BYTES;
00626                                 break;
00627                         }
00628                         break;
00629 
00630                 default :
00631                         ASSERT(FALSE);
00632                         break;
00633                 }
00634                 break;
00635 
00636         case STATE_RECV_READ_BYTES :
00637                 // Save data to variable
00638                 *pu8_data++ = c_outChar;
00639                 // When all data is saved, indicate that
00640                 // output is available
00641                 if (--u_varLength == 0)
00642                 {
00643                         receiveError = ERR_NONE;
00644                         receiveState = STATE_RECV_START;
00645 #ifndef __PIC__
00646                         if (b_isSpec)
00647                                 parseVarSpec();
00648 #endif
00649                 }
00650                 break;
00651 
00652         case STATE_RECV_LONG_INDEX :
00653                 // Save the index of this variable
00654                 u_index = c_outChar;
00655 #ifndef __PIC__
00656                 b_isSpec = FALSE;
00657 #endif
00658                 // Validate the index, getting a pointer to the data
00659                 pu8_data = validateIndex();
00660                 // If the index is invalid, go no further.
00661                 if (pu8_data == NULL)
00662                         break;
00663                 // Read the variable's length next
00664                 receiveState = STATE_RECV_LONG_LENGTH;
00665                 break;
00666 
00667 #ifndef __PIC__
00668         case STATE_RECV_SPEC_INDEX :
00669                 // Save the index of this variable
00670                 u_index = c_outChar;
00671                 b_isSpec = TRUE;
00672                 // Point to the var spec temp buffer
00673                 pu8_data = au8_varSpecData;
00674                 // Record the type of this variable: send/receive or just send
00675                 ASSERT( (c_lastCommand == CMD_SEND_ONLY) || 
00676                         (c_lastCommand == CMD_SEND_RECEIVE_VAR) );
00677                 assignBit(u_index, c_lastCommand == CMD_SEND_RECEIVE_VAR);
00678                 // Read the variable's length next
00679                 receiveState = STATE_RECV_LONG_LENGTH;
00680                 break;
00681 #endif
00682 
00683         case STATE_RECV_LONG_LENGTH :
00684                 // Receive and record the length.
00685                 // Subtle bug: the statement
00686                 //  u_varLength = ((uint) c_outChar) + 1;
00687                 // doesn't work:  C first converts c_outChar to a int, then from that to
00688                 // a uint. Therefore, if c_outChar < 0, sign extension occurs, which is
00689                 // incorrect. The syntax below first converts to a uint8 then grows that
00690                 // to a uint to guarantee zero extension rather than sign extension.
00691                 u_varLength = ((uint) ((uint8) c_outChar)) + 1;
00692                 // Validate it only if this isn't a variable spec
00693                 if (!B_IS_SPEC && !validateLength(u_varLength))
00694                         break;
00695 #ifndef __PIC__
00696                 else
00697                         // Otherwise, record the number of bytes in the spec for later processing
00698                         // in parseVarSpec.
00699                         u_specLength = u_varLength;
00700 #endif
00701                 // Read the data
00702                 receiveState = STATE_RECV_READ_BYTES;
00703                 break;
00704 
00705         default:
00706                 ASSERT(FALSE);
00707                 break;
00708         }
00709 
00710         return receiveError;
00711 }
00713 
00714 
00717 static const char* apsz_errorDesc[NUM_ERROR_CODES] = {
00718         "no error",
00719         "repeated command",
00720         "timeout",
00721         "interrupted command",
00722         "unspecified index",
00723         "index too high",
00724         "variable size mismatch",
00725         "read only variable",
00726         "illegal variable specification",
00727 };
00728 
00730 const char* getReceiveErrorString() {
00731         ASSERT( (receiveError > 0) && (receiveError < NUM_ERROR_CODES) );
00732         return apsz_errorDesc[receiveError];
00733 }

Generated on Mon Oct 18 07:40:46 2010 for Python-on-a-chip by  doxygen 1.5.9