1 // ********************************************************************************** 2 // Custom DPA Handler code example - Simple reflex game controlled by coordinator * 3 // ********************************************************************************** 4 // Copyright (c) MICRORISC s.r.o. 5 // 6 // File: $RCSfile: CustomDpaHandler-Coordinator-ReflexGame.c,v $ 7 // Version: $Revision: 1.39 $ 8 // Date: $Date: 2021/04/26 15:13:50 $ 9 // 10 // Revision history: 11 // 2019/01/10 Release for DPA 4.00 12 // 2018/10/25 Release for DPA 3.03 13 // 2017/03/13 Release for DPA 3.00 14 // 2015/08/05 Release for DPA 2.20 15 // 2014/10/31 Release for DPA 2.10 16 // 2014/04/30 Release for DPA 2.00 17 // 18 // ********************************************************************************** 19 20 // Online DPA documentation https://doc.iqrf.org/DpaTechGuide/ 21 22 // Default IQRF include (modify the path according to your setup) 23 #include "IQRF.h" 24 25 // Implement Custom DPA Handler for Coordinator 26 #define COORDINATOR_CUSTOM_HANDLER 27 28 // Default DPA header (modify the path according to your setup) 29 #include "DPA.h" 30 // Default Custom DPA Handler header (modify the path according to your setup) 31 #include "DPAcustomHandler.h" 32 33 // Application randomly chooses one of the gaming nodes to test the player's reaction 34 // It tests whether the button (use e.g. at DK-EVAL-04) of the node is not pressed in advance 35 // If so it tries to find another node with the button not being pressed 36 // After a random time it pulses node's LEDR 37 // If the player presses button within a certain time then LEDG at coordinator goes ON 38 // If the player does not press the button then LEDR at coordinator goes ON 39 // The game repeats again 40 // This example works only at STD mode, not at LP mode 41 42 // Max. number of gaming nodes 43 // The application uses nodes with VRN=1,2, ... ,NODES to play with 44 #define NODES 4 45 46 // Machine states 47 typedef enum 48 { 49 // Send button off test 50 state_TestOff, 51 // Receive button off test 52 state_TestOffResponse, 53 // Pulse LED 54 state_Pulse, 55 // Send button on test 56 state_Test, 57 // Receive button on test 58 state_TestResponse, 59 } TState; 60 61 // Must be the 1st defined function in the source code in order to be placed at the correct FLASH location! 62 //############################################################################################ 63 bit CustomDpaHandler() 64 //############################################################################################ 65 { 66 // Handler presence mark 67 clrwdt(); 68 69 // Addresses indexed by VRNs 70 static uns8 nodes[NODES]; 71 // Number of VRNs found 72 static uns8 nodesCnt; 73 // Random value 74 static uns8 rand; 75 // Machine state 76 static uns8 state; 77 // Tested node VRN 78 static uns8 nodeVrn; 79 // Tested node address 80 static uns8 nodeAddr; 81 82 // Detect DPA event to handle 83 switch ( GetDpaEvent() ) 84 { 85 // ------------------------------------------------- 86 case DpaEvent_Init: 87 // Do a one time initialization before main loop starts 88 89 // Find nodes with VRN starting 1 up to NODES, break if node not found 90 for ( nodesCnt = 0; nodesCnt < NODES; nodesCnt++ ) 91 { 92 // Try to find VRN among all nodes 93 for ( RX = 0; RX <= MAX_ADDRESS; RX++ ) 94 { 95 // Node is bonded and discovered 96 if ( isBondedNode( RX ) && isDiscoveredNode( RX ) ) 97 { 98 optimizeHops( 0xFF ); 99 // if VRN matches 100 if ( RTHOPS - 1 == nodesCnt ) 101 { 102 // Store its address 103 writeToRAM( nodes + nodesCnt, RX ); 104 // and try to find next VRN 105 goto nextVrn; 106 } 107 } 108 } 109 110 // Node with requested VRN not found 111 break; 112 113 nextVrn: 114 } 115 116 // Initialize random seed 117 rand = lastRSSI ^ TMR1L; 118 if ( rand == 0 ) 119 rand.0 = 1; 120 121 // Set starting state 122 state = state_TestOff; 123 124 // Set starting delay 2s 125 GIE = FALSE; 126 DpaTicks = 100L * 2; 127 GIE = TRUE; 128 129 break; 130 131 // ------------------------------------------------- 132 case DpaEvent_Idle: 133 // Do a quick background work when RF packet is not received 134 135 // Game runs only if interface master is not connected 136 if ( IFaceMasterNotConnected ) 137 { 138 // In the meantime generate new and new random values 139 rand = lsr( rand ); 140 W = 0b10111000; 141 if ( Carry ) 142 rand ^= W; 143 144 // We run state machine within Idle event handler 145 switch ( state ) 146 { 147 case state_TestOff: 148 // Timer is over? 149 if ( DpaTicks.15 == 0 ) 150 break; 151 152 // If no nodes found, then restart pulsing LEDR every 1s 153 if ( nodesCnt == 0 ) 154 { 155 pulsingLEDR(); 156 GIE = FALSE; 157 DpaTicks = 1L * 100; 158 GIE = TRUE; 159 break; 160 } 161 162 // Generate random VRN to test 163 nodeVrn = rand % nodesCnt; 164 nodeVrn++; 165 // Get its address 166 FSR0 = &nodes[nodeVrn - 1]; 167 nodeAddr = *FSR0; 168 // fall through! 169 170 case state_Test: 171 // Wait for the testing DPA request 172 if ( DpaTicks.15 == 0 ) 173 break; 174 175 // DPA request to test the button pin 176 _NADR = nodeAddr; 177 _NADRhigh = 0; 178 // Use IO peripheral 179 _PNUM = PNUM_IO; 180 // Read GPIOs 181 _PCMD = CMD_IO_GET; 182 // Any HWPID 183 _HWPID = HWPID_DoNotCheck; 184 // This DPA request has no data 185 _DpaDataLength = 0; 186 // Send the DPA request 187 DpaApiRfTxDpaPacketCoordinator(); 188 // Setup safe 1s timeout to recover from not receiving the DPA response at state state_Response 189 GIE = FALSE; 190 DpaTicks = 1 * 100L; 191 GIE = TRUE; 192 // Next state 193 state++; 194 break; 195 196 case state_Pulse: 197 // DPA request to pulse LEDR in the tested node by batch (this is done synchronously in the precise time) 198 _NADR = nodeAddr; 199 _NADRhigh = 0; 200 // Use IO peripheral to work with LEDs even if LED peripherals are not present 201 _PNUM = PNUM_IO; 202 // Make a LEDR pulse 203 _PCMD = CMD_IO_SET; 204 // Any HWPID 205 _HWPID = HWPID_DoNotCheck; 206 207 // LEDR=1 => Set PORTA.2 to 1 208 _DpaMessage.PerIoDirectionAndSet_Request.Triplets[0].Port = PNUM_IO_PORTA; // PORTA 209 _DpaMessage.PerIoDirectionAndSet_Request.Triplets[0].Mask = 0b0000.0100; // bit 2 210 _DpaMessage.PerIoDirectionAndSet_Request.Triplets[0].Value = 0b0000.0100; // bit 2 = 1 211 212 // 64 ms pulse 213 _DpaMessage.PerIoDirectionAndSet_Request.Delays[1].Header = PNUM_IO_DELAY; // delay 214 _DpaMessage.PerIoDirectionAndSet_Request.Delays[1].Delay = 64; // 64 215 216 // LEDR=0 => Set PORTA.2 to 0 217 _DpaMessage.PerIoDirectionAndSet_Request.Triplets[2].Port = PNUM_IO_PORTA; // PORTA 218 _DpaMessage.PerIoDirectionAndSet_Request.Triplets[2].Mask = 0b0000.0100; // bit 2 219 _DpaMessage.PerIoDirectionAndSet_Request.Triplets[2].Value = 0b0000.0000; // bit 2 = 0 220 221 // Setup the correct length of data 222 _DpaDataLength = 3 * sizeof( _DpaMessage.PerIoDirectionAndSet_Request.Triplets[0] ); 223 224 // Send the DPA request 225 DpaApiRfTxDpaPacketCoordinator(); 226 227 // Set timeout in the way that the testing of the button will be at the same time as possible independently on the node VRN 228 GIE = FALSE; 229 DpaTicks = 35L + nodeVrn * MIN_STD_TIMESLOT - 2 * MIN_STD_TIMESLOT; 230 GIE = TRUE; 231 // Next state 232 state++; 233 break; 234 235 case state_TestOffResponse: 236 case state_TestResponse: 237 // Did we get DPA response within timeout? 238 if ( DpaTicks.15 ) 239 // No, go to the 1st state 240 state = state_TestOff; 241 242 break; 243 } 244 } 245 246 break; 247 248 // ------------------------------------------------- 249 case DpaEvent_ReceiveDpaResponse: 250 // Called after DPA response was received at coordinator 251 252 // Did we get the testing response? 253 if ( _NADR == nodeAddr && _PNUM == PNUM_IO && _PCMD == ( CMD_IO_GET | RESPONSE_FLAG ) ) 254 { 255 if ( state == state_TestResponse ) 256 { 257 // Long pulse 258 setOnPulsingLED( 30 ); 259 // and the color depends on the state of the button PIN @ PORTA.5 260 if ( _DpaMessage.Response.PData[0].5 ) 261 pulseLEDR(); 262 else 263 pulseLEDG(); 264 265 startMachine: 266 // Set the starting state 267 state = state_TestOff; 268 // With random time to start new test 269 GIE = FALSE; 270 DpaTicks = ( 2 * 100L ) + rand / 2; 271 GIE = TRUE; 272 273 // By returning true consume the DPA request 274 DpaHandleReturnTRUE: 275 return TRUE; 276 } 277 278 if ( state == state_TestOffResponse ) 279 { 280 // Button @ PORTA.5 must be off 281 if ( !_DpaMessage.Response.PData[0].5 ) 282 goto startMachine; 283 284 state = state_Pulse; 285 286 // By returning true consume the DPA request 287 goto DpaHandleReturnTRUE; 288 } 289 } 290 291 break; 292 } 293 294 return FALSE; 295 } 296 297 //############################################################################################ 298 // Default Custom DPA Handler header; 2nd include to implement Code bumper to detect too long code of the Custom DPA Handler (modify the path according to your setup) 299 #include "DPAcustomHandler.h" 300 //############################################################################################