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