title: Handling protocol inside ISR to avoid atomicity
body: <p>I have to handle simple serial protocol. The protocol format is Start byte, Length, Data bytes and Check sum.
  I am using UART for data communication. I want to know what is the best way to handle protocol.
  In first method, I planned to handle reception inside ISR itself. Checksum validation will not be handled inside ISR. My ISR may look something like below code (Considering generic micro controller). But ISR is little lengthy (Though code is lengthy, there are many if statements and ultimately it may not be too lengthy)</p>
  
  <p>In second method, ISR will just dump the data into a receive buffer and main program will take care of handling the protocol. Though ISR is short, I may have to disable/enable ISR frequently while accessing the Receive buffer from main to avoid atomicity problem. This may lead to performance issues and frequent ISR disable may cause data loss!!</p>
  
  <p>Which is the best method? Any example protocol implementations like this?
  Note: The below code is just an outline and not yet tested. There could be few logical errors.</p>
  
  <pre><code>#ifndef TRUE
  #define TRUE 1
  #endif // TRUE
  
  #ifndef FALSE
  #define FALSE 0
  #endif // TRUE
  
  #define NUM_START_BYTES 1
  #define LENGTH_BYTE_POSITION (NUM_START_BYTES)
  #define START_BYTE1 0xAA
  #define START_BYTE2 0x55
  #define END_BYTE 0x0A
  
  
  
  #ifdef CHECKSUM_DISABLED
  #define CHECKSUM_BYTES 0
  #elif defined SIMPLE_CHECKSUM
  #define  CHECKSUM_BYTES 1
  #else
  #define CHECKSUM_BYTES 2
  #endif // CHECKSUM_DISABLED
  
  
  #define NUM_START_BYTES 1
  #define LENGTH_BYTE_POSITION (NUM_START_BYTES)
  #define START_BYTE1 0xAA
  #define START_BYTE2 0x55
  #define END_BYTE 0x0A
  
  #define UDR0 0   // Only temporarily declared it as 0. It is actually a register in processor.
  
  enum FRAME_RECEIVE_STATUS
  {
      FRAME_SUCCESS=0,
      START_BYTE_RECVD=1,
      RECV_PROGRESS=2,
      FRAME_RECEIVED=3,
      CHECKSUM_ERROR=4,
      FRAME_NOT_RECEIVED=5,
  };
  
  volatile enum FRAME_RECEIVE_STATUS frameStatus=FRAME_NOT_RECEIVED;
  
  #define RX_MAX_SIZE 32 // size for received data buffer.
  
  volatile uint8_t RxData[RX_MAX_SIZE];
  volatile uint8_t RxHead=0;              // Initialize the RxHead to 0
  volatile uint8_t frameLength=0;         // Overall length of the received data
  
  
  /**RX Complete interrupt service routine
  // Receive the data and write to  buffer if buffer is not full
  Initially frameStatus=FRAME_NOT_RECEIVED;
  This protocol supports, 0, 1 or 2 start bytes and indicated by NUM_START_BYTES
  
  As soon as first START_BYTE is verified, frameStatus changes to START_BYTE_RECVD.
  As soon as second start byte is received, frameStatus changes to RECV_PROGRESS.
  That means as soon as START Bytes are verified (It could be 0 1 or 2), frameStatus changes to RECV_PROGRESS
  
  Packet Format:
  Start Byte1 (optional), Start byte2 (optional), Length=n, data bytes = n-check sum bytes, one or two check sum bytes
  
  Length includes data bytes and check sum
  Checksum may be 0, 1 or 2 bytes and indicated by CHECKSUM_BYTES field
  */
  
  void myRxISR()
  {
  
      // If buffer is full, we cannot transfer data. We probably want to discard the data if buffer is full.
      // Yet to decide on this
      if(RxHead&lt;RX_MAX_SIZE)
      {
          RxData[RxHead++]=UDR0;
          frameLength++;
          if(frameStatus==RECV_PROGRESS) //Packet reception is already started
          {
              // We need to check if all bytes including checksum is received
              //First verify the length field. Length field is immediately after START_BYTE fields
              if(frameLength==CHECKSUM_BYTES+1)
              {
                  //Minimum 1 byte must be there in any command excluding check sum
                  // In case the data length is less than 1+checksum bytes,
                  //we need to completely discard the transaction.
                  // Length is available in RxData[NUM_START_BYTES]
                  if(RxData[NUM_START_BYTES]&lt;CHECKSUM_BYTES+1)
                  {
                      frameStatus=FRAME_NOT_RECEIVED;  // Discard the data
                      RxHead=0;  // Clear the received data buffer
                  }
              }
              else   // Length is already received and verified. Receive other data bytes and CS
              {
  
                  // Once the length is received, we need to count as many bytes as length
                  //and receive the complete the frame.
  
                  if(frameLength &gt;= RxData[NUM_START_BYTES]+NUM_START_BYTES+1)   //1 for length field itself
                  {
                      // Finished receiving the complete frame
                      //At the end, frameRecived flag must be set.
                      frameStatus=FRAME_RECEIVED;
                  }
                  else
                  {
                      //Nothing needs to be done. Just data bytes are being received
                  }
              }
          }
          else
          {
              // Check if START_BYTE is present in this protocol or not.
              // This code supports 0, 1 or 2 start bytes.
              if(NUM_START_BYTES)
              {
                  //First wait for the first START_BYTE. If first START_BYTE is received,
                  // check if second start byte is present and verify the second start byte.
                  // As soon as first start byte is received, status changes to START_BYTE_RECVD
  
                  if((frameStatus==START_BYTE_RECVD))
                  {
                      // first byte is received already. This is the second byte
                      // Need to verify the second Byte in case there are two bytes
                      // In case there is only one start byte, control will not come here anyway
  
                      if(RxData[RxHead-1]==START_BYTE2)
                      {
                          frameStatus=RECV_PROGRESS;
                      }
                      else
                      {
                          //Discard data
                          RxHead=0;
                          frameStatus=FRAME_NOT_RECEIVED;
                      }
                  }
                  else  // Just First start Byte is received
                  {
                      if(RxData[RxHead-1]==START_BYTE1)
                      {
                          if(NUM_START_BYTES&gt;1)  // 2 start bytes only possible in this protocol
                          {
                              // We need to wait for start byte2 next
                              frameStatus=START_BYTE_RECVD;
                          }
                          else
                          {
                              // Only one start byte. So start byte reception is successful
                              frameStatus=RECV_PROGRESS;
                          }
                      }
                      else
                      {
                          //Discard data
                          RxHead=0;
                          //frameStatus already FRAME_NOT_RECEIVED
                          //frameStatus=FRAME_NOT_RECEIVED;
                      }
                  }
              }
              else  // NUM_START_BYTES=0. Means we directly start reception without any start bytes
              {
                  frameStatus=RECV_PROGRESS;
              }
          }
  
      }
      else
      {
          //In case buffer is full, we need to see what to do.
          // May be discard the data received.
          frameStatus=FRAME_NOT_RECEIVED;  // Discard the data
          RxHead=0;  // Clear the received data buffer
      }
  }
  </code></pre>