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