1 // *********************************************************************
    2 //   Sketch to cooperate with CustomDpaHandler-Bridge-UART.c           *
    3 // *********************************************************************
    4 // Copyright (c) IQRF Tech s.r.o.
    5 //
    6 // File:    $RCSfile: CustomDpaHandler-Bridge-UART.ino,v $
    7 // Version: $Revision: 1.7 $
    8 // Date:    $Date: 2021/02/22 17:55:18 $
    9 //
   10 // Revision history:
   11 //   2019/03/01  Release for DPA 4.01
   12 //   2018/10/25  Release for DPA 3.03
   13 //
   14 // *********************************************************************
   15 
   16 // Please see CustomDpaHandler-Bridge-UART.c for implementation details.
   17 
   18 // This Sketch implements one standard IQRF sensor
   19 // Type of the sensor is Binary7
   20 
   21 // Include IQRF DPA headers
   22 #include "DPA.h"
   23 #include "IQRFstandard.h"
   24 #include "IQRF_HWPID.h"
   25 
   26 //############################################################################################
   27 void setup()
   28 //############################################################################################
   29 {
   30   // Setup UART to connect to IQRF TR module
   31   Serial.begin( 115200 );
   32 }
   33 
   34 //############################################################################################
   35 // Returns sensor value
   36 byte GetSensor0Value()
   37 //############################################################################################
   38 {
   39   // Remap values from Alcohol Gas Sensor MQ-3 connected to the analog input 0
   40   return map( analogRead( 0 ), 500, 1023, 0, 127 );
   41 }
   42 
   43 //############################################################################################
   44 
   45 // HDLC byte stuffing bytes
   46 // Flag Sequence
   47 #define   HDLC_FRM_FLAG_SEQUENCE    0x7e
   48 // Asynchronous Control Escape
   49 #define   HDLC_FRM_CONTROL_ESCAPE   0x7d
   50 // Asynchronous transparency modifier
   51 #define   HDLC_FRM_ESCAPE_BIT       0x20
   52 
   53 // Flag to DpaEvent_DpaRequest event value to indicate return TRUE not FALSE
   54 #define EVENT_RETURN_TRUE           0x80
   55 // Flag to DpaEvent_DpaRequest event value to report error, error value is the 1st data byte
   56 #define EVENT_RESPONSE_ERROR        0x40
   57 
   58 // Received data from IQRF
   59 byte RxBuffer[2 * sizeof( byte ) + sizeof( TDpaIFaceHeader ) + sizeof( TDpaMessage )];
   60 
   61 // Data from IQRF length limits
   62 #define MIN_RX_PACKET_DATA_LENGTH  2
   63 #define MAX_RX_PACKET_DATA_LENGTH  sizeof( RxBuffer )
   64 
   65 //############################################################################################
   66 // Sends one byte to IQRF
   67 void TxByte( byte data )
   68 //############################################################################################
   69 {
   70   Serial.write( data );
   71 }
   72 
   73 //############################################################################################
   74 // Sends one HDLC byte to IQRF
   75 void TxHdlcByte( byte data )
   76 //############################################################################################
   77 {
   78   switch ( data )
   79   {
   80     default:
   81       TxByte( data );
   82       return;
   83 
   84     case HDLC_FRM_FLAG_SEQUENCE:
   85     case HDLC_FRM_CONTROL_ESCAPE:
   86     {
   87       TxByte( HDLC_FRM_CONTROL_ESCAPE );
   88       TxByte( data ^ HDLC_FRM_ESCAPE_BIT );
   89       return;
   90     }
   91   }
   92 }
   93 
   94 //############################################################################################
   95 // Returns FRC value back to IQRF
   96 void ResponseFRCvalue( unsigned long frcValue )
   97 //############################################################################################
   98 {
   99   // Start packet
  100   TxByte( HDLC_FRM_FLAG_SEQUENCE );
  101   // Send event value
  102   TxHdlcByte( DpaEvent_FrcValue );
  103   // Send FRC value up to 4 bytes
  104   TxHdlcByte( frcValue & 0xFF );
  105   TxHdlcByte( ( frcValue >> 8 ) & 0xFF );
  106   TxHdlcByte( ( frcValue >> 16 ) & 0xFF );
  107   TxHdlcByte( ( frcValue >> 24 ) & 0xFF );
  108   // Stop packet
  109   TxByte( HDLC_FRM_FLAG_SEQUENCE );
  110 }
  111 
  112 //############################################################################################
  113 // Return DPA response back to IQRF
  114 void ResponseCommand( byte returnFlags, byte _DpaDataLength, byte dataLength, byte *pData )
  115 //############################################################################################
  116 {
  117   // Start packet
  118   TxByte( HDLC_FRM_FLAG_SEQUENCE );
  119   // Send event value
  120   TxHdlcByte( DpaEvent_DpaRequest | returnFlags );
  121   // Send DPA variable data length (must not equal to the actual data length sent)
  122   TxHdlcByte( _DpaDataLength );
  123   // Send DPA response data
  124   for ( ; dataLength != 0; dataLength-- )
  125     TxHdlcByte( *pData++ );
  126   // Stop packet
  127   TxByte( HDLC_FRM_FLAG_SEQUENCE );
  128 }
  129 
  130 //############################################################################################
  131 // Packet from Custom DPA Handler was received
  132 void CustomDpaHandler( byte dataLength )
  133 //############################################################################################
  134 {
  135   // Which Custom DPA Handler event to handle?
  136   switch ( RxBuffer[0] )
  137   {
  138     // Prepare DPA response to DPA request
  139     case DpaEvent_DpaRequest:
  140       if ( dataLength >= ( 2 * sizeof( byte ) + sizeof( TDpaIFaceHeader ) ) )
  141       {
  142         // Fake important DPA variables for the DPA Request/Response so the Custom DPA handler code will can be written almost same way on both platforms
  143 #define _DpaDataLength  (RxBuffer[1])
  144 #define _NADR           (RxBuffer[2])
  145 #define _NADRhigh       (RxBuffer[3])
  146 #define _PNUM           (RxBuffer[4])
  147 #define _PCMD           (RxBuffer[5])
  148 #define _HWPIDlow       (RxBuffer[6])
  149 #define _HWPIDhigh      (RxBuffer[7])
  150 #define _DpaMessage     (*((TDpaMessage*)(RxBuffer+8)))
  151 
  152       // Fake Custom DPA Handler macro to return DPA error (this macro does not do return the same way the DPA original macro)
  153 #define DpaApiReturnPeripheralError(error) do { \
  154   _DpaMessage.ErrorAnswer.ErrN = error; \
  155   returnDataLength = _DpaDataLength = sizeof( _DpaMessage.ErrorAnswer.ErrN ); \
  156   returnFlags = EVENT_RESPONSE_ERROR | EVENT_RETURN_TRUE; \
  157   } while( 0 )
  158 
  159         // Value or error flag to return from Custom DPA handler
  160         byte returnFlags = 0;
  161         // Length data to return (may not equal to _DpaDataLength)
  162         byte returnDataLength = 0;
  163         // Device enumeration?
  164         if ( IsDpaEnumPeripheralsRequest() )
  165         {
  166           // We implement 1 user peripheral
  167           _DpaMessage.EnumPeripheralsAnswer.UserPerNr = 1;
  168           FlagUserPer( _DpaMessage.EnumPeripheralsAnswer.UserPer, PNUM_STD_SENSORS );
  169           _DpaMessage.EnumPeripheralsAnswer.HWPID = 0x123F;
  170           _DpaMessage.EnumPeripheralsAnswer.HWPIDver = 0xABCD;
  171 
  172           // Return the enumeration structure but do not modify _DpaDataLength
  173           returnDataLength = sizeof( _DpaMessage.EnumPeripheralsAnswer );
  174           // Return TRUE
  175           returnFlags = EVENT_RETURN_TRUE;
  176         }
  177         // Get information about peripherals?
  178         else if ( IsDpaPeripheralInfoRequest() )
  179         {
  180           if ( _PNUM == PNUM_STD_SENSORS )
  181           {
  182             _DpaMessage.PeripheralInfoAnswer.PerT = PERIPHERAL_TYPE_STD_SENSORS;
  183             _DpaMessage.PeripheralInfoAnswer.PerTE = PERIPHERAL_TYPE_EXTENDED_READ_WRITE;
  184             // Set standard version
  185             _DpaMessage.PeripheralInfoAnswer.Par1 = STD_SENSORS_VERSION;
  186 
  187             // Return the information structure but do not modify _DpaDataLength
  188             returnDataLength = sizeof( _DpaMessage.PeripheralInfoAnswer );
  189             // Return TRUE
  190             returnFlags = EVENT_RETURN_TRUE;
  191           }
  192         }
  193         else
  194         {
  195           // Handle peripheral command
  196 
  197           // Supported peripheral number?
  198           if ( _PNUM == PNUM_STD_SENSORS )
  199           {
  200             // Supported commands?
  201             switch ( _PCMD )
  202             {
  203               // Invalid command
  204               default:
  205                 // Return error
  206                 DpaApiReturnPeripheralError( ERROR_PCMD );
  207                 break;
  208 
  209                 // Sensor enumeration
  210               case PCMD_STD_ENUMERATE:
  211                 // Check data request length
  212                 if ( _DpaDataLength != 0 )
  213                 {
  214                   DpaApiReturnPeripheralError( ERROR_DATA_LEN );
  215                   break;
  216                 }
  217 
  218                 // 1st byte is sensor type
  219                 _DpaMessage.Response.PData[0] = STD_SENSOR_TYPE_BINARYDATA7;
  220 
  221                 // Return just one sensor type
  222                 returnDataLength = _DpaDataLength = sizeof( _DpaMessage.Response.PData[0] );
  223                 // Return TRUE
  224                 returnFlags = EVENT_RETURN_TRUE;
  225                 break;
  226 
  227                 // Supported commands. They are handled almost the same way
  228               case PCMD_STD_SENSORS_READ_VALUES:
  229               case PCMD_STD_SENSORS_READ_TYPES_AND_VALUES:
  230               {
  231                 // No sensor bitmap specified?
  232                 if ( _DpaDataLength == 0 )
  233                 {
  234                   // Bitmap is 32 bits long = 4
  235                   _DpaDataLength = 4;
  236                   // Simulate 1st sensor in the bitmap (states of the other unimplemented sensors do not care)
  237                   _DpaMessage.Request.PData[0] |= 0x01; // Note: must not modify W
  238                 }
  239                 // Valid bitmap length?
  240                 else if ( _DpaDataLength != 4 )
  241                 {
  242                   // Return error
  243                   DpaApiReturnPeripheralError( ERROR_DATA_LEN );
  244                   break;
  245                 }
  246 
  247                 // Pointer to the response data
  248                 byte *pResponseData = _DpaMessage.Response.PData;
  249                 // Is my only sensor selected?
  250                 if ( ( _DpaMessage.Request.PData[0] & 0x01 ) != 0 )
  251                 {
  252                   // Return also sensor type?
  253                   if ( _PCMD == PCMD_STD_SENSORS_READ_TYPES_AND_VALUES )
  254                     *pResponseData++ = STD_SENSOR_TYPE_BINARYDATA7;
  255 
  256                   // Return sensor data
  257                   *pResponseData++ = GetSensor0Value();
  258                 }
  259 
  260                 // Returned data length
  261                 returnDataLength = _DpaDataLength = ( pResponseData - _DpaMessage.Response.PData );
  262                 // Return TRUE
  263                 returnFlags = EVENT_RETURN_TRUE;
  264                 break;
  265               }
  266             }
  267           }
  268         }
  269 
  270         // Return DPA response
  271         ResponseCommand( returnFlags, _DpaDataLength, returnDataLength, (byte*)&_DpaMessage );
  272       }
  273       break;
  274 
  275       // Return FRC Value
  276     case DpaEvent_FrcValue:
  277       // Check for the minimum length (FRC command and at least 2 bytes of data)
  278       if ( dataLength >= ( 2 + 1 + 2 ) )
  279       {
  280         // Fake important DPA variables for the DPA FRC handling
  281 #define FrcCommand               (RxBuffer[1])
  282 #define DataOutBeforeResponseFRC ((byte*)( &RxBuffer[2] ))
  283 
  284       // Check the correct FRC request
  285         if ( DataOutBeforeResponseFRC[0] == PNUM_STD_SENSORS &&
  286           ( DataOutBeforeResponseFRC[1] == 0x00 || DataOutBeforeResponseFRC[1] == STD_SENSOR_TYPE_BINARYDATA7 ) &&
  287              ( DataOutBeforeResponseFRC[2] & 0x1f ) == 0 )
  288         {
  289           // Which FRC command to handle?
  290           switch ( FrcCommand )
  291           {
  292             case FRC_STD_SENSORS_1B:
  293               ResponseFRCvalue( GetSensor0Value() + 4 );
  294               break;
  295 
  296             case FRC_STD_SENSORS_BIT:
  297               ResponseFRCvalue( ( GetSensor0Value() & ( 0x01 << ( DataOutBeforeResponseFRC[2] >> 5 ) ) ) != 0 ? 0x03 : 0x01 );
  298               break;
  299           }
  300         }
  301       }
  302       break;
  303   }
  304 }
  305 
  306 //############################################################################################
  307 void loop()
  308 //############################################################################################
  309 {
  310   // Byte received from the IQRF?
  311   while ( Serial.available() )
  312   {
  313     // HDLC machine states
  314     typedef enum { RXstateWaitHead, RXstatePacket, RXstateEscape } TState;
  315 
  316     // HDLC state
  317     static byte state = RXstateWaitHead;
  318     // Length of the already received data
  319     static byte rxLength;
  320     // Pointer to the received data
  321     static byte *pRxBuffer;
  322 
  323     // Read the byte from IQRF
  324     byte oneByte = Serial.read();
  325     switch ( state )
  326     {
  327       // Waiting for the HDLC header
  328       case RXstateWaitHead:
  329       {
  330         if ( oneByte == HDLC_FRM_FLAG_SEQUENCE )
  331         {
  332 _SetRXstatePacket:
  333           rxLength = 0;
  334           pRxBuffer = RxBuffer;
  335           state = RXstatePacket;
  336         }
  337         break;
  338       }
  339 
  340       // Handling packet data byte
  341       case RXstatePacket:
  342       {
  343         switch ( oneByte )
  344         {
  345           case HDLC_FRM_CONTROL_ESCAPE:
  346             // RXstateEscape
  347             state++;
  348             goto _ExitMachine;
  349 
  350           case HDLC_FRM_FLAG_SEQUENCE:
  351           {
  352             if ( rxLength >= MIN_RX_PACKET_DATA_LENGTH )
  353               // Packet received, handle it
  354               CustomDpaHandler( rxLength );
  355 
  356             goto _SetRXstatePacket;
  357           }
  358         }
  359 
  360 _StoreByte:
  361         if ( rxLength == ( MAX_RX_PACKET_DATA_LENGTH + 2 ) )
  362           goto _SetRXstateWaitHead;
  363 
  364         *pRxBuffer++ = oneByte;
  365         rxLength++;
  366 
  367 _ExitMachine:
  368         break;
  369       }
  370 
  371       // Handle escaped byte
  372       case RXstateEscape:
  373       {
  374         switch ( oneByte )
  375         {
  376           case HDLC_FRM_FLAG_SEQUENCE:
  377             goto _SetRXstatePacket;
  378 
  379           case HDLC_FRM_CONTROL_ESCAPE:
  380 _SetRXstateWaitHead:
  381             state = RXstateWaitHead;
  382             break;
  383 
  384           default:
  385             // RXstatePacket
  386             state--;
  387             oneByte ^= HDLC_FRM_ESCAPE_BIT;
  388             goto _StoreByte;
  389         }
  390         break;
  391       }
  392     }
  393   }
  394 }
  395 
  396 //############################################################################################