1 // ********************************************************************************** 2 // Custom DPA Handler code example - Simple reflex game controlled by coordinator * 3 // ********************************************************************************** 4 // Copyright (c) IQRF Tech s.r.o. 5 // 6 // File: $RCSfile: CustomDpaHandler-Coordinator-ReflexGame.c,v $ 7 // Version: $Revision: 1.27 $ 8 // Date: $Date: 2017/08/31 08:32:32 $ 9 // 10 // Revision history: 11 // 2017/03/13 Release for DPA 3.00 12 // 2015/08/05 Release for DPA 2.20 13 // 2014/10/31 Release for DPA 2.10 14 // 2014/04/30 Release for DPA 2.00 15 // 16 // ********************************************************************************** 17 18 // Online DPA documentation http://www.iqrf.org/DpaTechGuide/ 19 20 // Default IQRF include (modify the path according to your setup) 21 #include "IQRF.h" 22 23 // Implement Custom DPA Handler for Coordinator 24 #define COORDINATOR_CUSTOM_HANDLER 25 26 // Default DPA header (modify the path according to your setup) 27 #include "DPA.h" 28 // Default Custom DPA Handler header (modify the path according to your setup) 29 #include "DPAcustomHandler.h" 30 31 // Application randomly chooses one of the gaming nodes to test the player's reaction 32 // It tests whether the button (use e.g. at DK-EVAL-04) of the node is not pressed in advance 33 // If so it tries to find another node with the button not being pressed 34 // After a random time it pulses node's LEDR 35 // If the player presses button within a certain time then LEDG at coordinator goes ON 36 // If the player does not press the button then LEDR at coordinator goes ON 37 // The game repeats again 38 // This example works only at STD mode, not at LP mode 39 40 // The example will not work at demo DPA version because demo DPA does not support the following Custom DPA Handler events: DpaEvent_Interrupt, DpaEvent_BeforeSleep, DpaEvent_AfterSleep, DpaEvent_Reset, DpaEvent_DisableInterrupts, DpaEvent_ReceiveDpaResponse, DpaEvent_IFaceReceive, DpaEvent_ReceiveDpaRequest, DpaEvent_BeforeSendingDpaResponse 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 work 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 nodeAddr = readFromRAM( nodes + nodeVrn - 1 ); 167 // fall through! 168 169 case state_Test: 170 // Wait for the testing DPA request 171 if ( DpaTicks.15 == 0 ) 172 break; 173 174 // DPA request to test the button pin 175 _NADR = nodeAddr; 176 _NADRhigh = 0; 177 // Use IO peripheral 178 _PNUM = PNUM_IO; 179 // Read GPIOs 180 _PCMD = CMD_IO_GET; 181 // Any HWPID 182 _HWPID = HWPID_DoNotCheck; 183 // This DPA request has no data 184 _DpaDataLength = 0; 185 // Send the DPA request 186 DpaApiRfTxDpaPacketCoordinator(); 187 // Setup safe 1s timeout to recover from not receiving the DPA response at state state_Response 188 GIE = FALSE; 189 DpaTicks = 1 * 100L; 190 GIE = TRUE; 191 // Next state 192 state++; 193 break; 194 195 case state_Pulse: 196 // DPA request to pulse LEDR in the tested node by batch (this is done synchronously in the precise time) 197 _NADR = nodeAddr; 198 _NADRhigh = 0; 199 // Use IO peripheral to work with LEDs even if LED peripherals are not present 200 _PNUM = PNUM_IO; 201 // Make a LEDR pulse 202 _PCMD = CMD_IO_SET; 203 // Any HWPID 204 _HWPID = HWPID_DoNotCheck; 205 206 // LEDR=1 => Set PORTA.2 to 1 207 _DpaMessage.PerIoDirectionAndSet_Request.Triplets[0].Port = PNUM_IO_PORTA; // PORTA 208 _DpaMessage.PerIoDirectionAndSet_Request.Triplets[0].Mask = 0b0000.0100; // bit 2 209 _DpaMessage.PerIoDirectionAndSet_Request.Triplets[0].Value = 0b0000.0100; // bit 2 = 1 210 211 // 64 ms pulse 212 _DpaMessage.PerIoDirectionAndSet_Request.Delays[1].Header = PNUM_IO_DELAY; // delay 213 _DpaMessage.PerIoDirectionAndSet_Request.Delays[1].Delay = 64; // 64 214 215 // LEDR=0 => Set PORTA.2 to 0 216 _DpaMessage.PerIoDirectionAndSet_Request.Triplets[2].Port = PNUM_IO_PORTA; // PORTA 217 _DpaMessage.PerIoDirectionAndSet_Request.Triplets[2].Mask = 0b0000.0100; // bit 2 218 _DpaMessage.PerIoDirectionAndSet_Request.Triplets[2].Value = 0b0000.0000; // bit 2 = 0 219 220 // Setup the correct length of data 221 _DpaDataLength = 3 * sizeof( _DpaMessage.PerIoDirectionAndSet_Request.Triplets[0] ); 222 223 // Send the DPA request 224 DpaApiRfTxDpaPacketCoordinator(); 225 226 // Set timeout in the way that the testing of the button will be at the same time as possible independently on the node VRN 227 GIE = FALSE; 228 DpaTicks = 35L + nodeVrn * MIN_TIMESLOT - 2 * MIN_TIMESLOT; 229 GIE = TRUE; 230 // Next state 231 state++; 232 break; 233 234 case state_TestOffResponse: 235 case state_TestResponse: 236 // Did we get DPA response within timeout? 237 if ( DpaTicks.15 ) 238 // No, go to the 1st state 239 state = state_TestOff; 240 241 break; 242 } 243 } 244 245 break; 246 247 // ------------------------------------------------- 248 case DpaEvent_ReceiveDpaResponse: 249 // Called after DPA response was received at coordinator 250 251 // Did we get the testing response? 252 if ( _NADR == nodeAddr && _PNUM == PNUM_IO && _PCMD == ( CMD_IO_GET | RESPONSE_FLAG ) ) 253 { 254 if ( state == state_TestResponse ) 255 { 256 // Long pulse 257 setOnPulsingLED( 30 ); 258 // and the color depends on the state of the button PIN @ PORTA.5 259 if ( _DpaMessage.Response.PData[0].5 ) 260 pulseLEDR(); 261 else 262 pulseLEDG(); 263 264 startMachine: 265 // Set the starting state 266 state = state_TestOff; 267 // With random time to start new test 268 GIE = FALSE; 269 DpaTicks = ( 2 * 100L ) + rand / 2; 270 GIE = TRUE; 271 272 // By returning true consume the DPA request 273 DpaHandleReturnTRUE: 274 return TRUE; 275 } 276 277 if ( state == state_TestOffResponse ) 278 { 279 // Button @ PORTA.5 must be off 280 if ( !_DpaMessage.Response.PData[0].5 ) 281 goto startMachine; 282 283 state = state_Pulse; 284 285 // By returning true consume the DPA request 286 goto DpaHandleReturnTRUE; 287 } 288 } 289 290 break; 291 } 292 293 return FALSE; 294 } 295 296 //############################################################################################ 297 // 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) 298 #include "DPAcustomHandler.h" 299 //############################################################################################