1 // ********************************************************************* 2 // Custom DPA Handler code example - Auto network example * 3 // ********************************************************************* 4 // Copyright (c) IQRF Tech s.r.o. 5 // 6 // File: $RCSfile: CustomDpaHandler-AutoNetwork.c,v $ 7 // Version: $Revision: 1.74 $ 8 // Date: $Date: 2018/10/25 09:51:28 $ 9 // 10 // Revision history: 11 // 2018/10/25 Release for DPA 3.03 12 // 2017/11/16 Release for DPA 3.02 13 // 2017/03/13 Release for DPA 3.00 14 // 2016/09/12 Release for DPA 2.28 15 // 2016/02/10 Release for DPA 2.26 16 // 2015/09/03 Release for DPA 2.21 17 // 2015/08/05 Release for DPA 2.20 18 // 19 // ********************************************************************* 20 21 //############################################################################################ 22 // Description 23 24 // ! IMPORTANT - Please note the Autonetwork process is complex. Before using it in your production environment please understand 25 // the process in detail and do thorough test in the lab. 26 // Please also read on-line DPA documentation http://www.iqrf.org/DpaTechGuide/ (chapter "8.6.2 AutoNetwork & Coordinator-AutoNetwork-Embedded"). 27 28 // This example implements automatic network construction and optional switching between autonetwork and user handler. 29 // Define SWAP_HANDLERS to use automatic handler switching. 30 // It allows to use the benefits of automatic network construction and save the program memory for user specific functions. 31 // It works with corresponding AutoNetwork application build with IQRF SDK or CustomDpaHandler-Coordinator-AutoNetwork-Embedded.c. 32 // The same code is for [N] devices and [C] (use COORDINATOR_CUSTOM_HANDLER symbol to allow conditional compilation for [C] device). 33 // The handler for [C] devices is used in case the autonetwork is controlled by external device connected to the [C]. 34 // Another example CustomDpaHandler-Coordinator-AutoNetwork-Embedded.c demonstrates self-containing [C] handler that controls the whole Autonetwork process. 35 36 // For all type of devices the code implements custom peripheral (PNUM=0x20, PCMD=0x00) with PDATA containing TStartBonding. 37 // The command is executed at [N] only when it is broadcast and the device does not have a temporary address. 38 // The command actually sends the peer2peer packet to all not yet bonded nodes to let them know that the bonding interval starts. 39 // The packet is send from all nodes at isolated slots. The slots are identified by nodes' VRNs. 40 41 // [N] device implements also custom bonding routine done inside Reset event. 42 // First the node tries to receive 1st TStartBonding packet. Then it tries to receive more TStartBonding packets from other Nodes or Coordinator. 43 // Node remembers senders of TStartBonding packets. Later Node will try to pre-bond to these senders only. 44 // After all TStartBonding packets were sent then the Node uses LBT (listen before talk) to find the RF gap to request bonding. If node is then bonded, 45 // it goes into main DPA loop. If node is not bonded it waits for double plus some random time and it tries bonding again. 46 47 // Node LED Indication 48 // * no LED => Node is bonded 49 // * RED : before a bonding phase 50 // * RED => trying to receive 1st TStartBonding packet 51 // * RED + pulsing GREEN => receiving next TStartBonding packets, then bonding phase starts 52 // * GREEN : bonding phase 53 // * GREEN + pulsing RED => ListenBeforeTalk (LBT) before trying to bond 54 // * GREEN => bonding and if not bonded random time delay before next LBT 55 56 // When SWAP_HANDLERS is defined (applies only to the Node version, of course): 57 // * If the Node is bonded and assigned with real address, user handler is loaded. 58 // * If the Node is unbonded, autonetwork handler is loaded. 59 // Some part (code and variables) of autonetwork handler must be implemented at user handler too. 60 // All parts of user handler which are not used for autonetwork handler must be compiled conditionally. 61 // Example - User handler requires DpaEvent_Init event implementation. 62 // The DpaEvent_Init is compiled for user handler only, it is not used for autonetwork handler: 63 // #ifdef USER_HANDLER 64 // case DpaEvent_Init: 65 // Do a one time initialization work before main loop starts 66 // User handler code 67 // break; 68 // #endif // #ifndef USER_HANDLER 69 // Use find function to quick find following marks: 70 // [User Handler] - Implement your code here. 71 // [Mandatory part] - Must be implemented at the user handler and/or the autonetwork handler in order to support handler swapping. 72 // [Customizable part] - The part could be customized (for example an error indication). 73 // The example expects that both autonetwork and user handler of the example are preloaded at the external EEPROM in the way they can be loaded by CMD_OS_LOAD_CODE command. 74 // Also, the example expects that there are parameters for CMD_OS_LOAD_CODE for loading the handlers stored at the external EEPROM too. 75 // Parameters for the "autonetwork" handler must be stored at address 0 and for the "user" handler at the address 6 respectively. 76 // Each set of parameters takes 6 bytes. Parameters have the following format (see https://www.iqrf.org/DpaTechGuide/#3.4.13%20LoadCode for details): 77 // offset name value 78 // 0 addrLow lower byte of the corresponding driver .hex image in the external EEPROM 79 // 1 addrHigh same as above but higher byte 80 // 2 lengthLow lower byte of the corresponding driver .hex image length in the external EEPROM 81 // 3 lengthHigh same as above but higher byte 82 // 4 checksumLow lower byte of the corresponding driver .hex image checksum in the external EEPROM 83 // 5 checksumHigh same as above but higher byte 84 // IQRF IDE Tools / IQRF Network Manager / Control / Upload can be used to upload both .hex images into the external EEPROM. 85 // Then Terminal in DPA mode is used to write LoadCode parameters into external EEPROM too. 86 87 //############################################################################################ 88 // Global Autonetwork declarations and definitions 89 90 // Start bonding packet, it is sent both to the Peripheral and then as peer2peer to not yet bonded nodes 91 // In real application the packet might store more useful information and it also should be somehow protected against potential misuse 92 typedef struct 93 { 94 // Header, equals TStartBondingHeader 95 uns8 Header; 96 // Remaining invitation time, 10 ms units 97 uns16 RemainingInvitationTime; 98 // Total bonding interval time, 10 ms units 99 uns16 BondingTime; 100 // Temporary address timeout in 100 ms units 101 uns16 TemporaryAddressTimeout; 102 // Network channel 103 uns8 Channel; 104 // Sender address 105 uns8 Sender; 106 } TStartBonding; 107 108 // TStartBondingHeader packet header 109 #define TStartBondingHeader 'B' 110 111 // Length of the start bonding packet TStartBonding equals the slot length (10 ms unit) 112 #define SLOT_LENGTH MIN_STD_TIMESLOT 113 114 //############################################################################################ 115 // Not used just as a header file? 116 #ifndef CustomDpaHandler_AutoNetwork_HEADER 117 118 #warning "This Autonetwork is obsolete. Use CustomDpaHandler-Coordinator-AutoNetworkV2-Embedded.c at Coordinator instead and no Custom DPA Handler at Nodes." 119 120 //############################################################################################ 121 // Headers 122 123 // Default IQRF include (modify the path according to your setup) 124 #include "IQRF.h" 125 // Default DPA header (modify the path according to your setup) 126 #include "DPA.h" 127 // Default Custom DPA Handler header (modify the path according to your setup) 128 #include "DPAcustomHandler.h" 129 130 //############################################################################################ 131 // Conditionals 132 133 // Define the next symbol to let the [N] variant work at LP mode. 134 // Then TMR6 is not used for timing during bonding and when node has temporary address but less precise captureTicks() IQRF OS function. 135 // The reason is the WDT sleeps during RF communication. 136 //#define DPA_LP 137 #ifdef DPA_LP 138 #message "CustomDpaHandler-AutoNetwork.c" compiled for LP mode 139 #else 140 #message "CustomDpaHandler-AutoNetwork.c" compiled for STD mode 141 #endif 142 143 // If compiled for coordinator, then no handler swapping is possible 144 #ifndef COORDINATOR_CUSTOM_HANDLER 145 146 // Define SWAP_HANDLERS to allow autonetwork and user handler switching 147 //#define SWAP_HANDLERS 148 149 #ifdef SWAP_HANDLERS 150 151 // Define USER_HANDLER to compile swappable user handler. Otherwise swappable autonetwork handler is compiled. 152 //#define USER_HANDLER 153 154 #ifdef USER_HANDLER 155 #message "Swap version - User handler for Node" 156 #else 157 #message "Swap version - AutoNetwork handler for Node" 158 #endif 159 160 #else // #ifdef SWAP_HANDLERS 161 #message "AutoNetwork handler" 162 #endif // #ifdef SWAP_HANDLERS 163 164 #endif // #ifndef COORDINATOR_CUSTOM_HANDLER 165 166 // Define to enable example authorization of pre-bondig. See code for details. 167 //#define AUTHORIZE_PRE_BONDING 168 169 //############################################################################################ 170 // Declarations, Definitions 171 172 // Packet at DPA memory 173 TStartBonding StartBondingDpa @ _DpaMessage.Request.PData; 174 // Packet at bufferRF (BTW same as above] 175 TStartBonding StartBondingRF @ bufferRF; 176 177 #ifndef COORDINATOR_CUSTOM_HANDLER 178 // Copy of start binding DPA packet later used to be sent as peer2peer 179 TStartBonding StartBondingBackup @ PeripheralRam; 180 // Bitmap of the inviting Nodes + Coordinator 181 uns8 InvitingNodes[( MAX_ADDRESS + 1 + 7 ) / 8] @ PeripheralRam[sizeof( TStartBonding )]; 182 #endif // #ifndef COORDINATOR_CUSTOM_HANDLER 183 184 #if !defined( USER_HANDLER ) && !defined( COORDINATOR_CUSTOM_HANDLER ) 185 // Random value 186 static uns8 rand; 187 // Generates next random value and does clrwdt() 188 uns8 Rand(); 189 #endif // #if !defined( USER_HANDLER ) && !defined( COORDINATOR_CUSTOM_HANDLER ) 190 191 // Sets RF mode for scanning channels 192 void SetScanRfMode(); 193 // Disables used interrupts 194 void DisableInterrupts(); 195 // Loads DPA handler from ext. EEPROM to Flash 196 uns8 LoadHandler( uns16 address @ param3 ); 197 // Makes copy of bonding packet 198 void BackupBondingPacket(); 199 // Compute FSR0 and bitmapBitMask at InvitingNodes 200 void BitmapNode( uns8 address ); 201 // Runs local command at OS peripheral 202 void DpaApiLocalRequest_OS( uns8 cmd @ W ); 203 204 // Macros to atomically access Timeout variable 205 #define GIEoff() GIE = FALSE 206 #define GIEon() GIE = TRUE 207 208 #ifdef SWAP_HANDLERS 209 // External EEPROM address of both swappable autonetwork versions description records (address, length, checksum), see structure TPerOSLoadCode_Request without Flags field 210 #define EEE_ADDR_USER_HANDLER 0 211 // 2nd record is adjacent to the 1st one 212 #define EEE_ADDR_AUTONETWORK_HANDLER ( EEE_ADDR_USER_HANDLER + sizeof( DpaRfMessage.PerOSLoadCode_Request ) - sizeof( DpaRfMessage.PerOSLoadCode_Request.Flags ) ) 213 #endif // #ifdef SWAP_HANDLERS 214 215 #ifdef DPA_LP 216 // Ticks summed after call captureTicks() 217 uns16 SumTicks; 218 219 #ifdef __CC5XFREE__ 220 // Same as var1 -= var2 but even at free CC5X compiler version it is compiled nice way and sets the Carry correctly 221 #define Minus16vars(var1,var2) \ 222 var1.low8 -= (uns8)( var2 & 0xFF ); \ 223 W = (uns8)( var2 >> 8 ); \ 224 var1.high8 = subWFB( var1.high8 ); 225 #else // #ifdef __CC5XFREE__ 226 #define Minus16vars(var1,var2) var1 -= var2 227 #endif // #ifdef __CC5XFREE__ 228 229 #endif // #ifdef DPA_LP 230 231 #if defined( AUTHORIZE_PRE_BONDING ) && !defined( COORDINATOR_CUSTOM_HANDLER ) 232 // Initialize PIN for pre-bonding authorization example 233 #pragma cdata[ __EESTART + PERIPHERAL_EEPROM_START ] = 0x78, 0x56, 0x34, 0x12 234 #endif 235 236 // Must be the 1st defined function in the source code in order to be placed at the correct FLASH location! 237 //############################################################################################ 238 bit CustomDpaHandler() 239 //############################################################################################ 240 { 241 // Handler presence mark 242 clrwdt(); 243 244 #ifndef COORDINATOR_CUSTOM_HANDLER 245 #ifndef USER_HANDLER 246 // To access use GIE=0, because it can be changed by ISR (valid for STD mode only) 247 // General timeout variable controlled by TMR6 interrupt, PreScallerInit variable used to count in 10 ms (1) or 100 ms (10) 248 static uns16 Timeout; 249 // Prescaler variables used to count Timeout variable in 10 ms (PreScallerInit value is 1) or in 100 ms (PreScallerInit value is 10) 250 static uns8 PreScaller; 251 static uns8 PreScallerInit; 252 #ifdef DPA_LP 253 // TMR6 is used at LP mode to measure time when TStartBonding packets are send by existing network Nodes and the Coordinator 254 static bit UseTMRinLP; 255 #endif // #ifdef DPA_LP 256 #endif // #ifndef USER_HANDLER 257 258 #if !defined( SWAP_HANDLERS ) || defined( USER_HANDLER ) 259 // TRUE when an invitation to start bonding will be send later by already bonded Node 260 static bit SendInvitation; 261 #endif // !defined( SWAP_HANDLERS ) || defined( USER_HANDLER ) 262 #endif // #ifndef COORDINATOR_CUSTOM_HANDLER 263 264 #ifdef SWAP_HANDLERS 265 // [Mandatory part] - the variable HandlerNotPresent must be defined at both handlers if SWAP_HANDLERS is defined 266 static bit HandlerNotPresent; 267 #endif // #ifdef SWAP_HANDLERS 268 269 // Detect DPA event to handle (unused event handlers can be commented out or even deleted) 270 switch ( GetDpaEvent() ) 271 { 272 #ifndef COORDINATOR_CUSTOM_HANDLER 273 // ------------------------------------------------- 274 case DpaEvent_Interrupt: 275 // Do an extra quick background interrupt work 276 // ! The time spent handling this event is critical.If there is no interrupt to handle return immediately otherwise keep the code as fast as possible. 277 // ! Make sure the event is the 1st case in the main switch statement at the handler routine.This ensures that the event is handled as the 1st one. 278 // ! It is desirable that this event is handled with immediate return even if it is not used by the custom handler because the Interrupt event is raised on every MCU interrupt and the “empty” return handler ensures the shortest possible interrupt routine response time. 279 // ! Only global variables or local ones marked by static keyword can be used to allow reentrancy. 280 // ! Make sure race condition does not occur when accessing those variables at other places. 281 // ! Make sure( inspect.lst file generated by C compiler ) compiler does not create any hidden temporary local variable( occurs when using division, multiplication or bit shifts ) at the event handler code.The name of such variable is usually Cnumbercnt. 282 // ! Do not call any OS functions except setINDFx(). 283 // ! Do not use any OS variables especially for writing access. 284 // ! All above rules apply also to any other function being called from the event handler code, although calling any function from Interrupt event is not recommended because of additional MCU stack usage. 285 286 #ifndef USER_HANDLER 287 // Autonetwork handler code 288 // If 10 ms TMR6 interrupt occurred 289 if ( TMR6IF ) 290 { 291 // Unmask interrupt 292 TMR6IF = 0; 293 294 // Prescaler is over? 295 if ( --PreScaller == 0 ) 296 { 297 // Yes, initialize it (PreScallerInit is 1 or 10) 298 PreScaller = PreScallerInit; 299 // Timeout is over? 300 if ( Timeout != 0 ) 301 #ifdef DPA_LP 302 if ( UseTMRinLP ) 303 #endif // #ifdef DPA_LP 304 // No, decrement timeout counter (10 or 100 ms unit) 305 Timeout--; 306 } 307 } 308 #else // #ifndef USER_HANDLER 309 // [User Handler] - User handler DpaEvent_Interrupt implementation 310 311 #endif // #ifndef USER_HANDLER 312 return Carry; 313 314 // ------------------------------------------------- 315 case DpaEvent_Idle: 316 // Do a quick background work when RF packet is not received 317 #ifndef USER_HANDLER 318 // Node did not get the real address (i.e. was not authorized) for the long time? 319 if ( ntwADDR == TEMPORARY_ADDRESS ) 320 { 321 #ifndef DPA_LP 322 GIEoff(); 323 if ( Timeout == 0 ) 324 #else // #ifndef DPA_LP 325 captureTicks(); 326 // Decrease the timeout 327 // To save the code we divide by 8 not by 10, so the time will go a little bit faster, but in this case it is not so important because sleeping inside RFRX is inaccurate anyway 328 param4 += 4; // Rounding for /8 329 param4 /= 8; 330 Minus16vars( Timeout, param4 ); 331 // Overflow? Time is over! 332 if ( !Carry ) 333 #endif // #ifndef DPA_LP 334 { 335 // Disable user interrupts 336 DisableInterrupts(); 337 // Unbond Node by IQRF OS call 338 removeBond(); 339 // And restart device to bond node again 340 _DpaDataLength = 0; 341 DpaApiLocalRequest_OS( CMD_OS_RESTART ); 342 } 343 #ifndef DPA_LP 344 GIEon(); 345 #endif // #ifndef DPA_LP 346 } 347 // [Mandatory part] - must be implemented at autonetwork handler if SWAP_HANDLERS is defined 348 #ifdef SWAP_HANDLERS 349 else 350 { 351 // Node is bonded and assigned with real address, switch to user handler, reset device 352 if ( !HandlerNotPresent ) 353 { 354 // Try to load user handler 355 HandlerNotPresent = TRUE; 356 // Try to load User handler (reset if OK) 357 LoadHandler( EEE_ADDR_USER_HANDLER ); 358 } 359 else 360 { 361 // [Customizable part] 362 // Error - User handler not preloaded at external EEPROM 363 // LEDR is still on at STD mode, flashing at LP mode 364 setLEDR(); 365 #ifdef DPA_LP 366 waitMS( 20 ); 367 #endif // #ifndef DPA_LP 368 } 369 } 370 #endif // #ifdef SWAP_HANDLERS 371 #else // #ifndef USER_HANDLER 372 // [User Handler] - User handler DpaEvent_Idle implementation 373 { 374 #ifndef DPA_LP 375 // User handler STD mode example - LEDG is flashing 376 static uns16 tmr; 377 tmr++; 378 if ( tmr.9 ) 379 { 380 tmr.9 = 0; 381 _LEDG ^= 1; 382 } 383 #else // #ifndef DPA_LP 384 // User handler LP mode example - LEDG is flashing 385 setLEDG(); 386 waitMS( 20 ); 387 #endif // #ifndef DPA_LP 388 } 389 #endif // #ifndef USER_HANDLER 390 break; 391 392 // [User Handler] - User handler DpaEvent_Init implementation 393 #if !defined ( SWAP_HANDLERS ) || defined( USER_HANDLER ) 394 // ------------------------------------------------- 395 case DpaEvent_Init: 396 // Do a one time initialization work before main loop starts 397 398 break; 399 #endif // #if !defined ( SWAP_HANDLERS ) || defined( USER_HANDLER ) 400 401 // ------------------------------------------------- 402 case DpaEvent_Reset: 403 // Called after module is reset to allow (un)bonding 404 // When run fist time, do some global initializations 405 static bit wasFirstReset; 406 if ( !wasFirstReset ) 407 { 408 // Already called once 409 wasFirstReset = TRUE; 410 // [Mandatory part] - must be implemented at both handlers if SWAP_HANDLERS is defined 411 #ifdef SWAP_HANDLERS 412 HandlerNotPresent = FALSE; 413 #endif // #ifdef SWAP_HANDLERS 414 415 #ifndef USER_HANDLER 416 // Set Timeout prescaler to 10 ms unit 417 PreScaller = PreScallerInit = 1; 418 419 // Setup TMR6 to ISR get ticks on the background (ticks every 10 ms) 420 #if F_OSC == 16000000 421 PR6 = 250 - 1; 422 T6CON = 0b0.1001.1.10; // Prescaler 16, Postscaler 10, 16 * 10 * 250 = 40000 = 4MHz * 10ms 423 #else // #if F_OSC == 16000000 424 #error Unsupported oscillator frequency 425 #endif // #if F_OSC == 16000000 426 // Enable TMR6 ISR 427 TMR6IE = TRUE; 428 #endif // #ifndef USER_HANDLER 429 } 430 431 #ifndef USER_HANDLER 432 // Optional: Allow LED indication e.g. during discovery 433 _systemLEDindication = TRUE; 434 435 // Is node already bonded? 436 if ( amIBonded() ) 437 { 438 #ifdef DPA_LP 439 // Force unbonding if temporary address was assigned 440 startCapture(); 441 #endif // #ifdef DPA_LP 442 // Do DPA default unbonding 443 goto DpaHandleReturnFALSE; 444 } 445 else 446 { 447 // Take care of custom bonding 448 449 // Generate non-zero random number (seed) based on MID 450 moduleInfo(); 451 // Seed is the lowest MID byte (pseudo random seed must not be zero) 452 rand = bufferINFO[0] | 0x10; 453 454 // Remember current DPA RF mode 455 uns8 saveRFmode = RFmodeByte; 456 457 // Loop until not bonded 458 for ( ;; ) 459 { 460 // Reset inviting network items bitmap 461 clearBufferINFO(); 462 // setFSR0( _FSR_INFO ); // Already done by clearBufferINFO 463 copyMemoryBlock( FSR0, InvitingNodes, sizeof( InvitingNodes ) ); 464 465 // Set RF mode 466 SetScanRfMode(); 467 // Work until invitation is received 468 bit invitationRecevied = FALSE; 469 for ( ;;) 470 { 471 Rand(); 472 setLEDR(); 473 474 // Check RFIC 475 if ( wasRFICrestarted() ) 476 DpaApiSetRfDefaults(); 477 478 // Set the best bonding channel 479 if ( !invitationRecevied ) 480 setServiceChannel( 0 ); 481 else 482 { 483 GIEoff(); 484 if ( Timeout == 0 ) 485 break; 486 GIEon(); 487 } 488 489 toutRF = 100; 490 if ( RFRXpacket() && DLEN == sizeof( StartBondingRF ) && StartBondingRF.Header == TStartBondingHeader ) 491 { 492 BitmapNode( StartBondingRF.Sender ); 493 setINDF0( INDF0 | bitmapBitMask ); 494 495 if ( !invitationRecevied ) 496 { 497 invitationRecevied = TRUE; 498 #ifdef DPA_LP 499 UseTMRinLP = TRUE; 500 #endif // #ifdef DPA_LP 501 // Copy the packet 502 BackupBondingPacket(); 503 504 pulsingLEDG(); 505 506 GIEoff(); 507 Timeout = StartBondingBackup.RemainingInvitationTime; 508 GIEon(); 509 } 510 } 511 } 512 513 // Start bonding packet(s) was received 514 // Set timeout to the length of the bonding invitation 515 #ifdef DPA_LP 516 UseTMRinLP = FALSE; 517 startCapture(); 518 SumTicks = 0; 519 #endif // #ifdef DPA_LP 520 Timeout = StartBondingBackup.BondingTime; 521 GIEon(); 522 523 // And now wait some random time so nodes will not be synchronized when doing LBT 524 waitDelay( Rand() / 2 ); 525 526 // Start with the shortest gap between bonding attempts 527 uns8 BondingGapLength = 1; 528 529 // Set network working channel 530 setRFchannel( StartBondingBackup.Channel ); 531 // Indicate bonding phase 532 stopLEDG(); 533 // Loop till the bonding interval is valid 534 for ( ;; ) 535 { 536 // Set bonding counter to a random already bonded node (or coordinator) address 537 for ( ;; ) 538 { 539 // Get (including zero) random address 540 bondingCounter = Rand() - 1; 541 if ( bondingCounter <= MAX_ADDRESS ) 542 { 543 BitmapNode( bondingCounter ); 544 if ( ( *FSR0 & bitmapBitMask ) != 0 ) 545 { 546 // Adjust address for later bondRequestAdvanced() that pre-increments bondingCounter 547 bondingCounter--; 548 break; 549 } 550 } 551 } 552 553 // Indicate 554 setLEDG(); 555 pulsingLEDR(); 556 // Do LBT (listen before talk) for 400 x ( 1ms + checkRF ) 557 uns16 loop = 400; 558 do 559 { 560 Rand(); 561 waitMS( 1 ); 562 563 // Bonding interval is over? 564 #ifndef DPA_LP 565 GIEoff(); 566 if ( Timeout == 0 ) 567 { 568 GIEon(); 569 goto ExitBondingLoop; 570 } 571 GIEon(); 572 #else // #ifndef DPA_LP 573 captureTicks(); 574 SumTicks += param4; 575 // Decrease the timeout 576 Minus16vars( Timeout, SumTicks ); 577 // Overflow? Time is over! 578 if ( !Carry ) 579 goto ExitBondingLoop; 580 581 SumTicks = 0; 582 #endif // #ifndef DPA_LP 583 } while ( !checkRF( DpaApiReadConfigByte( CFGIND_RXFILTER ) ) && --loop != 0 ); 584 585 // Indicate 586 stopLEDR(); 587 588 // RF was quiet? 589 if ( loop == 0 ) 590 { 591 // Set original RF settings 592 setRFmode( saveRFmode ); 593 594 // Set node mode and network filtering 595 setNetworkFilteringOn(); 596 setNodeMode(); 597 598 #if defined( AUTHORIZE_PRE_BONDING ) 599 // In this example first 4 bytes of EEPROM peripheral must be pre-filled with 32bit PIN code 600 // The PIN code will be checked at the node or coordinator that provides pre-bonding 601 eeReadData( PERIPHERAL_EEPROM_START, sizeof( nodeUserDataToSend ) ); 602 setFSR0( _FSR_INFO ); 603 copyMemoryBlock( FSR0, nodeUserDataToSend, sizeof( nodeUserDataToSend ) ); 604 #endif // #if defined( AUTHORIZE_PRE_BONDING ) 605 606 // Execute bonding 607 #ifdef DPA_LP 608 // To keep captureTicks() the most precise as possible 609 waitNewTick(); 610 #endif // #ifdef DPA_LP 611 // Are we bonded? 612 if ( bondRequestAdvanced() ) 613 { 614 stopLEDG(); 615 // Bonded! 616 // Set DPA API variable 617 NodeWasBonded = TRUE; 618 #ifndef DPA_LP 619 // Now timeout will measure at 100 ms 620 PreScallerInit = 10; 621 GIEoff(); 622 #else // #ifndef DPA_LP 623 startCapture(); 624 #endif // #ifndef DPA_LP 625 // Time to wait for getting real address 626 Timeout = StartBondingBackup.TemporaryAddressTimeout; 627 #ifndef DPA_LP 628 GIEon(); 629 #endif // #ifndef DPA_LP 630 631 // Write working channel to the configuration 632 _DpaMessage.PerOSWriteCfgByte_Request.Triplets[0].Value = RFchannel; 633 _DpaMessage.PerOSWriteCfgByte_Request.Triplets[0].Address = CFGIND_CHANNEL_A; 634 _DpaMessage.PerOSWriteCfgByte_Request.Triplets[0].Mask = 0xFF; 635 _DpaDataLength = sizeof( TPerOSWriteCfgByteTriplet ); 636 DpaApiLocalRequest_OS( CMD_OS_WRITE_CFG_BYTE ); 637 638 // Go to the DPA main loop 639 DpaApiSetRfDefaults(); 640 goto DpaHandleReturnTRUE; 641 } 642 643 // Setup RF 644 SetScanRfMode(); 645 } 646 647 // Delay for a random time proportional to the gap 648 // Fixed part 649 startLongDelay( (uns16)BondingGapLength * 2 ); 650 do 651 { 652 Rand(); 653 } while ( isDelay() ); 654 655 // Random part 656 waitDelay( ( Rand() & BondingGapLength ) | 0b11.1111 ); 657 658 // Next gap size will be doubled (2^n-1) 659 Carry = TRUE; 660 BondingGapLength = rl( BondingGapLength ); 661 } 662 663 ExitBondingLoop: 664 stopLEDR(); 665 stopLEDG(); 666 } 667 } 668 #else // #ifndef USER_HANDLER 669 // [Mandatory part] - must be implemented at user handler is defined 670 // Check the node is bonded 671 if ( !amIBonded() ) 672 { 673 // No, switch to Autonetwork handler, reset device 674 if ( !HandlerNotPresent ) 675 { 676 // Try to load autonetwork handler (reset if OK) 677 HandlerNotPresent = TRUE; 678 LoadHandler( EEE_ADDR_AUTONETWORK_HANDLER ); 679 } 680 else 681 { 682 // [Customizable part] - If the Autonetwork handler not preloaded at external EEPROM, implement your error indication. 683 // In this example standard DPA bonding is used when Autonetwork handler not preloaded. 684 } 685 } 686 // [User Handler] - User handler DpaEvent_Reset implementation 687 688 break; 689 #endif // #ifndef USER_HANDLER 690 691 // ------------------------------------------------- 692 #if !defined( SWAP_HANDLERS ) || defined( USER_HANDLER ) 693 case DpaEvent_AfterRouting: 694 // Called after Notification and after routing of the DPA response was finished 695 // Request to send peer2peer start bonding packet? 696 if ( SendInvitation ) 697 { 698 SendInvitation = FALSE; 699 // Wait number of slots equal the VRN 700 uns8 loop @ userReg0; 701 loop = ntwVRN; 702 do 703 { 704 clrwdt(); 705 // Decrease number of remaining invitation time 706 StartBondingBackup.RemainingInvitationTime -= SLOT_LENGTH; 707 waitDelay( SLOT_LENGTH ); 708 } while ( --userReg0 != 0 ); 709 710 // Now send peer2peer packet 711 SetScanRfMode(); 712 713 // Prepare packet to bufferRF 714 setFSR1( _FSR_RF ); 715 copyMemoryBlock( &StartBondingBackup, FSR1, DLEN = sizeof( StartBondingBackup ) ); 716 StartBondingRF.Sender = ntwADDR; 717 StartBondingRF.Channel = RFchannel; 718 719 // Send the packet at all 3 service channels 720 uns8 channelIndex = SERVICE_CHANNELS_COUNT; 721 do 722 { 723 setServiceChannel( channelIndex ); 724 // Send the packet 725 PIN = 0; 726 RFTXpacket(); 727 waitMS( 5 ); 728 } while ( --channelIndex != 0 ); 729 730 // Restore RF mode 731 DpaApiSetRfDefaults(); 732 // and filtering 733 setNetworkFilteringOn(); 734 // and node mode 735 setNodeMode(); 736 } 737 738 break; 739 #endif // #if !defined( SWAP_HANDLERS ) || defined( USER_HANDLER ) 740 741 // ------------------------------------------------- 742 case DpaEvent_AfterSleep: 743 // Called after woken up after sleep 744 #ifndef USER_HANDLER 745 // Use TMR6 again 746 TMR6IE = TRUE; 747 TMR6ON = TRUE; 748 #else // #ifndef USER_HANDLER 749 // [User Handler] - User handler DpaEvent_AfterSleep implementation 750 751 #endif // #ifndef USER_HANDLER 752 break; 753 754 // ------------------------------------------------- 755 case DpaEvent_BeforeSleep: 756 // Called before going to sleep 757 #ifndef USER_HANDLER 758 // Fall through! 759 #else // #ifndef USER_HANDLER 760 // [User Handler] - User handler DpaEvent_BeforeSleep implementation 761 762 break; 763 #endif // #ifndef USER_HANDLER 764 765 // ------------------------------------------------- 766 case DpaEvent_DisableInterrupts: 767 // Called when device needs all hardware interrupts to be disabled (before Reset, Restart and RFPGM) 768 #ifndef USER_HANDLER 769 // Do not need to use TMR6 any more 770 DisableInterrupts(); 771 #else // #ifndef USER_HANDLER 772 // [User Handler] - User handler DpaEvent_DisableInterrupts implementation 773 774 #endif // #ifndef USER_HANDLER 775 break; 776 777 #endif // #ifndef COORDINATOR_CUSTOM_HANDLER 778 779 #if defined( AUTHORIZE_PRE_BONDING ) && ( !defined( SWAP_HANDLERS ) || defined( USER_HANDLER ) ) 780 // ------------------------------------------------- 781 case DpaEvent_AuthorizePreBonding: 782 // Called when remote bonding is enabled and a node requests pre-bonding 783 784 // 32 bit PIN that has to be matched is stored at last 4 bytes of peripheral RAM 785 // PIN must be same as the PIN sent from the requesting NODE. Requesting node PIN is stored at its EEPROM peripheral. 786 if ( nodeUserDataReceived[0] != PeripheralRam[PERIPHERAL_RAM_LENGTH - 4] || 787 PeripheralRam[PERIPHERAL_RAM_LENGTH - 3] != nodeUserDataReceived[1] || 788 nodeUserDataReceived[2] != PeripheralRam[PERIPHERAL_RAM_LENGTH - 2] || 789 PeripheralRam[PERIPHERAL_RAM_LENGTH - 1] != nodeUserDataReceived[3] ) 790 // If PINs do not match, reject the pre-bonding request 791 goto DpaHandleReturnTRUE; 792 793 break; 794 #endif // #if defined( AUTHORIZE_PRE_BONDING ) && ( !defined( SWAP_HANDLERS ) || defined( USER_HANDLER ) ) 795 796 // ------------------------------------------------- 797 case DpaEvent_DpaRequest: 798 // Called to interpret DPA request for peripherals 799 // ------------------------------------------------- 800 // Peripheral enumeration 801 IfDpaEnumPeripherals_Else_PeripheralInfo_Else_PeripheralRequest() 802 { 803 #if defined( COORDINATOR_CUSTOM_HANDLER ) || !defined( SWAP_HANDLERS ) || defined( USER_HANDLER ) 804 // Autonetwork handler implements user peripheral PNUM_USER + 0 805 _DpaMessage.EnumPeripheralsAnswer.UserPerNr++; // = 1; 806 FlagUserPer( _DpaMessage.EnumPeripheralsAnswer.UserPer, PNUM_USER + 0 ); 807 #endif // #if defined( COORDINATOR_CUSTOM_HANDLER ) || !defined( SWAP_HANDLERS ) || defined( USER_HANDLER ) 808 // [User Handler] - implement user Peripheral enumeration 809 810 // We implement a HW Profile 811 #ifndef USER_HANDLER 812 _DpaMessage.EnumPeripheralsAnswer.HWPID = 0x000F; 813 #else // #ifndef USER_HANDLER 814 // [User Handler] - define user HW Profile 815 _DpaMessage.EnumPeripheralsAnswer.HWPID = 0x000F; 816 #endif // #ifndef USER_HANDLER 817 818 DpaHandleReturnTRUE: 819 return TRUE; 820 } 821 // ------------------------------------------------- 822 // Get information about peripheral 823 else 824 { 825 #if defined( COORDINATOR_CUSTOM_HANDLER ) || !defined( SWAP_HANDLERS ) || defined( USER_HANDLER ) 826 // User peripheral PNUM_USER + 0 is reserved for autonetwork 827 if ( _PNUM == PNUM_USER + 0 ) 828 { 829 // It is user type peripheral 830 _DpaMessage.PeripheralInfoAnswer.PerT = PERIPHERAL_TYPE_USER_AREA; 831 // And write only style 832 _DpaMessage.PeripheralInfoAnswer.PerTE = PERIPHERAL_TYPE_EXTENDED_WRITE; 833 goto DpaHandleReturnTRUE; 834 } 835 #endif // #if defined( COORDINATOR_CUSTOM_HANDLER ) || !defined( SWAP_HANDLERS ) || defined( USER_HANDLER ) 836 837 // [User Handler] - implement user peripheral information 838 839 break; 840 } 841 // ------------------------------------------------- 842 { 843 #if defined( COORDINATOR_CUSTOM_HANDLER ) || !defined( SWAP_HANDLERS ) || defined( USER_HANDLER ) 844 // Handle broadcast only peripheral command 845 if ( 846 // My peripheral 847 _PNUM == PNUM_USER + 0 && 848 // My command 849 _PCMD == 0 && 850 // Correct data length 851 _DpaDataLength == sizeof( StartBondingDpa ) 852 #ifndef COORDINATOR_CUSTOM_HANDLER 853 // Broadcast 854 && _NADR == BROADCAST_ADDRESS && 855 // And I do not have temporary address (i.e. no VRN) 856 ntwADDR != TEMPORARY_ADDRESS 857 #endif // #ifndef COORDINATOR_CUSTOM_HANDLER 858 ) 859 { 860 #ifndef COORDINATOR_CUSTOM_HANDLER 861 // [N] version 862 863 #if !defined( SWAP_HANDLERS ) || defined( USER_HANDLER ) 864 // Store peer2peer start bonding packet values 865 BackupBondingPacket(); 866 // Send invitation later 867 SendInvitation = TRUE; 868 #endif // !defined( SWAP_HANDLERS ) || defined( USER_HANDLER ) ) 869 870 #else // #ifndef COORDINATOR_CUSTOM_HANDLER 871 // [C] version 872 873 // Now send peer2peer packet 874 // Set RF to peer2peer packet 875 SetScanRfMode(); 876 // Prepare packet to bufferRF 877 // ! StartBondingRF == StartBondingDpa ! 878 StartBondingRF.Channel = RFchannel; 879 880 // Send the packet at all 3 service channels 881 uns8 channelIndex = SERVICE_CHANNELS_COUNT; 882 do 883 { 884 setServiceChannel( channelIndex ); 885 // Send the packet 886 DLEN = sizeof( StartBondingRF ); 887 PIN = 0; 888 RFTXpacket(); 889 waitMS( 5 ); 890 } while ( --channelIndex != 0 ); 891 892 // Restore RF mode 893 DpaApiSetRfDefaults(); 894 // and filtering 895 setNetworkFilteringOn(); 896 // and coordinator mode 897 setCoordinatorMode(); 898 #endif // #ifndef COORDINATOR_CUSTOM_HANDLER 899 900 goto DpaHandleReturnTRUE; 901 } 902 else 903 { 904 // [User Handler] - implement user peripheral request 905 906 DpaApiReturnPeripheralError( ERROR_FAIL ); 907 } 908 #endif // #if defined( COORDINATOR_CUSTOM_HANDLER ) || !defined( SWAP_HANDLERS ) || defined( USER_HANDLER ) 909 } 910 } 911 912 DpaHandleReturnFALSE: 913 return FALSE; 914 } 915 916 //############################################################################################ 917 918 #ifndef COORDINATOR_CUSTOM_HANDLER 919 #ifndef USER_HANDLER 920 921 //############################################################################################ 922 uns8 Rand() 923 //############################################################################################ 924 { 925 clrwdt(); 926 rand = lsr( rand ); 927 #pragma updateBank 0 /* OFF */ // Optimization (avoid duplicate bank setting for RandomValue access) 928 W = 0b10111000; // x^8 + x^6 + x^5 + x^4 + 1 929 if ( Carry ) 930 rand ^= W; 931 932 return rand; 933 #pragma updateBank 1 /* ON */ 934 } 935 936 //############################################################################################ 937 void BitmapNode( uns8 address ) 938 //############################################################################################ 939 { 940 addressBitmap( address ); 941 FSR0 = InvitingNodes; 942 FSR0L += bitmapByteIndex; // Note: FSR0H will not overflow 943 } 944 945 //############################################################################################ 946 void DisableInterrupts() 947 //############################################################################################ 948 { 949 TMR6ON = FALSE; 950 TMR6IE = FALSE; 951 } 952 953 #endif // #ifndef COORDINATOR_CUSTOM_HANDLER 954 955 //############################################################################################ 956 void BackupBondingPacket() 957 //############################################################################################ 958 { 959 setFSR0( _FSR_RF ); 960 copyMemoryBlock( FSR0, &StartBondingBackup, sizeof( StartBondingBackup ) ); 961 } 962 963 #endif // #ifndef USER_HANDLER 964 965 //############################################################################################ 966 // [Mandatory part] - SetScanRfMode function must be implemented at both handlers 967 void SetScanRfMode() 968 //############################################################################################ 969 { 970 setNonetMode(); 971 setNetworkFilteringOff(); 972 setRFmode( _WPE | _RX_STD | _TX_STD ); 973 } 974 975 //############################################################################################ 976 void DpaApiLocalRequest_OS( uns8 cmd @ W ) 977 //############################################################################################ 978 { 979 _PCMD = cmd; 980 _PNUM = PNUM_OS; 981 DpaApiLocalRequest(); 982 } 983 984 #ifdef SWAP_HANDLERS 985 //############################################################################################ 986 // [Mandatory part] - must be implemented at both handlers 987 uns8 LoadHandler( uns16 address @ param3 ) 988 //############################################################################################ 989 { 990 // Read CMD_OS_LOAD_CODE parameters (address, length, checksum) into bufferINFO for loading the other driver 991 eeeReadData( address ); 992 // Copy CMD_OS_LOAD_CODE parameters to the correct offset at the DPA request 993 memoryOffsetTo = offsetof( TPerOSLoadCode_Request, Address ); 994 // Copy loaded parameters from bufferINFO into bufferRF where actually _DpaMessage is 995 copyBufferINFO2RF(); 996 // We load custom DPA handler stored at .hex format and want to really load it 997 _DpaMessage.PerOSLoadCode_Request.Flags = 0x01; 998 // Length of the DPA request 999 _DpaDataLength = sizeof( _DpaMessage.PerOSLoadCode_Request ); 1000 // Perform LoadCode, if it succeeds the device resets 1001 DpaApiLocalRequest_OS( CMD_OS_LOAD_CODE ); 1002 // If the LoadCode failed (reason: .hex not loaded at the external EEPROM memory or the LoadCode parameters stored at external EEPROM are incorrect) ... 1003 return _DpaMessage.Response.PData[0]; 1004 } 1005 #endif // #ifdef SWAP_HANDLERS 1006 1007 //############################################################################################ 1008 // 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) 1009 #include "DPAcustomHandler.h" 1010 //############################################################################################ 1011 #endif // #ifndef CustomDpaHandler_AutoNetwork_HEADER 1012 //############################################################################################