├── .gitignore ├── LICENSE ├── README.md ├── arm ├── nrf51-ble-loader.uvopt └── nrf51-ble-loader.uvproj ├── ble_bls.c ├── ble_bls.h ├── bootloader_startup_nrf51.s ├── main.c └── pure-gcc └── Makefile /.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | *.swp 3 | all_tests 4 | _build/ 5 | build/ 6 | *.hex 7 | *.jlink 8 | .gdbinit 9 | *.log 10 | *.d 11 | *.lnk 12 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013, Ole Morten Haaland 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 5 | Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 6 | Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 7 | 8 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 9 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | nrf51-ble-bootloader 2 | ==================== 3 | 4 | A proof-of-concept bootloader application for the nRF51822/S110 softdevice 5 | 6 | This application is to be written in the bottom of code region 1 on an nRF51822, with the S110 present. It allows you to 7 | update an application residing in the rest of code region 1. It is set up to use the space from 0x14000 to 0x20000, but 8 | doesn't actually need all this space. 9 | 10 | If an application has been written, and button 0 is not pressed when starting, the application will be started. If 11 | button 0 is held, the bootloader will be run instead. 12 | 13 | The application was developed with GCC and on the Evaluation Kit, PCA10001. The quality should be considered to be a 14 | proof of concept, nothing more. 15 | 16 | Steps to use 17 | ------------ 18 | 1. Enable notifications on the response characteristic. 19 | 2. Write the Erase app command to the command characteristic. The device will disconnect, then do the erase, and start 20 | advertising again. 21 | 3. Do 1 again. 22 | 4. Write the hex file, line by line, split in 20 byte chuncks to the data characteristic. Each line will be acked with a 23 | response notification. 24 | 5. When all lines have been written and acked, write the Reset and run command. The bootloader will reset and start the 25 | application. 26 | 27 | Architecture 28 | ------------ 29 | The bootloader runs in the bottom of code region 1, on top of the S110, and implements assembly wrappers for all 30 | interrupts. If the bootloader is not currently running, any interrupts will be forwarded to the application, so that 31 | they can be handled. This gives some extra latency. 32 | 33 | Known issues 34 | ------------ 35 | - The writing is quite slow. It hasn't been checked in detail why this is, but transmitting a hex file is not an 36 | efficient solution. It was chosen for the simplicity of the PC-side implementation. 37 | - The application has not been tested very thoroughly, and might very well have issues. 38 | - As stated above, this has been developed with GCC, and has not been tested or verified at all with Keil. 39 | 40 | Dependencies 41 | ------------ 42 | This uses my libhexwriter for parsing hex files. See http://github.com/hlnd/libhexwriter/ 43 | -------------------------------------------------------------------------------- /arm/nrf51-ble-loader.uvopt: -------------------------------------------------------------------------------- 1 | 2 | 3 | 1.0 4 |
### uVision Project, (C) Keil Software
5 | 6 | nrf51822_xxaa_s110 (256K) 7 | 0x4 8 | ARM-ADS 9 | 10 | 11 | 1 12 | 13 | 14 | Segger\JL2CM3.dll 15 | 16 | 17 | 18 | 0 19 | JL2CM3 20 | -O78 -S1 -A0 -C0 -JU1 -JI127.0.0.1 -JP0 -RST0 -N00("ARM CoreSight SW-DP") -D00(0BB11477) -L00(0) -TO18 -TC10000000 -TP21 -TDS8007 -TDT0 -TDC1F -TIEFFFFFFFF -TIP8 -TB1 -TFE0 -FO15 -FD20000000 -FC2000 -FN1 -FF0nRF51xxx -FS00 -FL0200000 21 | 22 | 23 | 24 | 25 | 26 | 27 | nrf51822_xxab_s110 (128K) 28 | 0x4 29 | ARM-ADS 30 | 31 | 32 | Segger\JL2CM3.dll 33 | 34 | 35 | 36 | 0 37 | JL2CM3 38 | -O78 -S1 -A0 -C0 -JU1 -JI127.0.0.1 -JP0 -RST0 -N00("ARM CoreSight SW-DP") -D00(0BB11477) -L00(0) -TO18 -TC10000000 -TP21 -TDS8007 -TDT0 -TDC1F -TIEFFFFFFFF -TIP8 -TB1 -TFE0 -FO15 -FD20000000 -FC2000 -FN1 -FF0nRF51xxx -FS00 -FL0200000 39 | 40 | 41 | 42 | 43 |
44 | -------------------------------------------------------------------------------- /arm/nrf51-ble-loader.uvproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 1.1 5 | 6 |
### uVision Project, (C) Keil Software
7 | 8 | 9 | 10 | nrf51822_xxaa_s110 (256K) 11 | 0x4 12 | ARM-ADS 13 | 14 | 15 | nRF51822_xxAA 16 | Nordic 17 | IRAM(0x20000000-0x20003FFF) IROM(0-0x3FFFF) CLOCK(16000000) CPUTYPE("Cortex-M0") ESEL ELITTLE 18 | 19 | "Device\Nordic\nRF51822\Source\templates\arm\arm_startup_nrf51.s"("Nordic Semiconductor nRF51822 Startup Code") 20 | UL2CM3(-UM0364FCE -O78 -S0 -C0 -TO18 -TC16000000 -TP21 -TDS800D -TDT0 -TDC1F -TIEFFFFFFFF -TIP8 -FO15 -FD20000000 -FC2000 -FN1 -FF0nRF51xxx -FS00 -FL0200000) 21 | 0 22 | nrf.h 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | SFD\Nordic\nRF51\nrf51822.sfr 33 | 0 34 | 35 | 36 | 37 | ..\Device\Nordic\nRF51822\Include\ 38 | ..\Device\Nordic\nRF51822\Include\ 39 | 40 | 0 41 | 0 42 | 0 43 | 0 44 | 1 45 | 46 | .\_build\ 47 | nrf51-ble-loader 48 | 1 49 | 0 50 | 1 51 | 1 52 | 1 53 | .\_build\ 54 | 1 55 | 0 56 | 0 57 | 58 | 0 59 | 0 60 | 61 | 62 | 0 63 | 0 64 | 0 65 | 0 66 | 67 | 68 | 0 69 | 0 70 | 71 | 72 | 0 73 | 0 74 | 75 | 76 | 0 77 | 0 78 | 79 | 80 | 0 81 | 0 82 | 83 | 0 84 | 85 | 86 | 87 | 0 88 | 0 89 | 0 90 | 0 91 | 0 92 | 1 93 | 0 94 | 0 95 | 0 96 | 0 97 | 3 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | SARMCM3.DLL 107 | 108 | TARMCM1.DLL 109 | -pCM0 110 | 111 | 112 | 113 | 1 114 | 0 115 | 0 116 | 0 117 | 16 118 | 119 | 120 | 0 121 | 1 122 | 1 123 | 1 124 | 1 125 | 1 126 | 1 127 | 1 128 | 0 129 | 130 | 131 | 1 132 | 1 133 | 0 134 | 1 135 | 1 136 | 1 137 | 0 138 | 1 139 | 0 140 | 141 | 0 142 | 7 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | Segger\JL2CM3.dll 157 | 158 | 159 | 160 | 161 | 1 162 | 0 163 | 0 164 | 1 165 | 1 166 | 4099 167 | 168 | Segger\JL2CM3.dll 169 | 170 | 171 | 172 | 173 | 174 | 0 175 | 1 176 | 1 177 | 1 178 | 1 179 | 1 180 | 1 181 | 1 182 | 0 183 | 1 184 | 1 185 | 0 186 | 1 187 | 1 188 | 0 189 | 0 190 | 1 191 | 1 192 | 1 193 | 1 194 | 1 195 | 1 196 | 1 197 | 1 198 | 1 199 | 0 200 | 0 201 | "Cortex-M0" 202 | 203 | 0 204 | 0 205 | 0 206 | 1 207 | 1 208 | 0 209 | 0 210 | 0 211 | 0 212 | 0 213 | 8 214 | 0 215 | 1 216 | 0 217 | 3 218 | 3 219 | 0 220 | 0 221 | 0 222 | 0 223 | 0 224 | 0 225 | 0 226 | 0 227 | 0 228 | 0 229 | 1 230 | 0 231 | 0 232 | 0 233 | 0 234 | 1 235 | 0 236 | 237 | 238 | 0 239 | 0x0 240 | 0x0 241 | 242 | 243 | 0 244 | 0x0 245 | 0x0 246 | 247 | 248 | 0 249 | 0x0 250 | 0x0 251 | 252 | 253 | 0 254 | 0x0 255 | 0x0 256 | 257 | 258 | 0 259 | 0x0 260 | 0x0 261 | 262 | 263 | 0 264 | 0x0 265 | 0x0 266 | 267 | 268 | 0 269 | 0x20000000 270 | 0x4000 271 | 272 | 273 | 1 274 | 0x0 275 | 0x40000 276 | 277 | 278 | 0 279 | 0x0 280 | 0x0 281 | 282 | 283 | 1 284 | 0x0 285 | 0x0 286 | 287 | 288 | 1 289 | 0x0 290 | 0x0 291 | 292 | 293 | 1 294 | 0x0 295 | 0x0 296 | 297 | 298 | 1 299 | 0x00014000 300 | 0x0002B000 301 | 302 | 303 | 1 304 | 0x0 305 | 0x0 306 | 307 | 308 | 0 309 | 0x0 310 | 0x0 311 | 312 | 313 | 0 314 | 0x0 315 | 0x0 316 | 317 | 318 | 0 319 | 0x0 320 | 0x0 321 | 322 | 323 | 0 324 | 0x20002000 325 | 0x00002000 326 | 327 | 328 | 0 329 | 0x0 330 | 0x0 331 | 332 | 333 | 334 | 335 | 336 | 1 337 | 1 338 | 0 339 | 0 340 | 0 341 | 0 342 | 1 343 | 0 344 | 0 345 | 0 346 | 2 347 | 0 348 | 0 349 | 350 | --c99 351 | NRF51,DEBUG_NRF_USER 352 | 353 | ..;..\..\..\..\..\Include;..\..\..\..\..\Include\app_common;..\..\..\..\..\Include\ble;..\..\..\..\..\Include\ble\ble_services;..\..\..\..\..\Include\ble\softdevice 354 | 355 | 356 | 357 | 1 358 | 0 359 | 0 360 | 0 361 | 0 362 | 0 363 | 0 364 | 0 365 | 366 | 367 | 368 | 369 | 370 | 371 | 372 | 373 | 1 374 | 0 375 | 0 376 | 0 377 | 1 378 | 0 379 | 0x00000000 380 | 0x20000000 381 | ..\scatter.sct 382 | 383 | 384 | 385 | 386 | 387 | 388 | 389 | 390 | 391 | 392 | Startup Code 393 | 394 | 395 | arm_startup_nrf51.s 396 | 2 397 | .\..\..\..\..\..\Source\templates\arm\arm_startup_nrf51.s 398 | 399 | 400 | system_nrf51.c 401 | 1 402 | .\..\..\..\..\..\Source\templates\system_nrf51.c 403 | 404 | 405 | 406 | 407 | Source Code 408 | 409 | 410 | main.c 411 | 1 412 | .\..\main.c 413 | 414 | 415 | 416 | 417 | Services 418 | 419 | 420 | ble_srv_common.c 421 | 1 422 | ..\..\..\..\..\Source\ble\ble_services\ble_srv_common.c 423 | 424 | 425 | 426 | 427 | Libraries 428 | 429 | 430 | ble_error_log.c 431 | 1 432 | ..\..\..\..\..\Source\ble\ble_error_log.c 433 | 434 | 435 | ble_flash.c 436 | 1 437 | ..\..\..\..\..\Source\ble\ble_flash.c 438 | 439 | 440 | ble_advdata.c 441 | 1 442 | ..\..\..\..\..\Source\ble\ble_advdata.c 443 | 444 | 445 | app_timer.c 446 | 1 447 | ..\..\..\..\..\Source\app_common\app_timer.c 448 | 449 | 450 | ble_conn_params.c 451 | 1 452 | ..\..\..\..\..\Source\ble\ble_conn_params.c 453 | 454 | 455 | ble_stack_handler.c 456 | 1 457 | ..\..\..\..\..\Source\ble\ble_stack_handler.c 458 | 459 | 460 | ble_debug_assert_handler.c 461 | 1 462 | ..\..\..\..\..\Source\ble\ble_debug_assert_handler.c 463 | 464 | 465 | 466 | 467 | 468 | 469 | 470 | nrf51822_xxab_s110 (128K) 471 | 0x4 472 | ARM-ADS 473 | 474 | 475 | nRF51822_xxAB 476 | Nordic 477 | IRAM(0x20000000-0x20003FFF) IROM(0-0x3FFFF) CLOCK(16000000) CPUTYPE("Cortex-M0") ESEL ELITTLE 478 | 479 | "Device\Nordic\nRF51822\Source\templates\arm\arm_startup_nrf51.s"("Nordic Semiconductor nRF51822 Startup Code") 480 | UL2CM3(-UM0364FCE -O78 -S0 -C0 -TO18 -TC16000000 -TP21 -TDS800D -TDT0 -TDC1F -TIEFFFFFFFF -TIP8 -FO15 -FD20000000 -FC2000 -FN1 -FF0nRF51xxx -FS00 -FL0200000) 481 | 0 482 | nrf.h 483 | 484 | 485 | 486 | 487 | 488 | 489 | 490 | 491 | 492 | SFD\Nordic\nRF51\nrf51822.sfr 493 | 0 494 | 495 | 496 | 497 | ..\Device\Nordic\nRF51822\Include\ 498 | ..\Device\Nordic\nRF51822\Include\ 499 | 500 | 0 501 | 0 502 | 0 503 | 0 504 | 1 505 | 506 | .\_build\ 507 | nrf51-ble-loader 508 | 1 509 | 0 510 | 1 511 | 1 512 | 1 513 | .\_build\ 514 | 1 515 | 0 516 | 0 517 | 518 | 0 519 | 0 520 | 521 | 522 | 0 523 | 0 524 | 0 525 | 0 526 | 527 | 528 | 0 529 | 0 530 | 531 | 532 | 0 533 | 0 534 | 535 | 536 | 0 537 | 0 538 | 539 | 540 | 0 541 | 0 542 | 543 | 0 544 | 545 | 546 | 547 | 0 548 | 0 549 | 0 550 | 0 551 | 0 552 | 1 553 | 0 554 | 0 555 | 0 556 | 0 557 | 3 558 | 559 | 560 | 561 | 562 | 563 | 564 | 565 | 566 | SARMCM3.DLL 567 | 568 | TARMCM1.DLL 569 | -pCM0 570 | 571 | 572 | 573 | 1 574 | 0 575 | 0 576 | 0 577 | 16 578 | 579 | 580 | 0 581 | 1 582 | 1 583 | 1 584 | 1 585 | 1 586 | 1 587 | 1 588 | 0 589 | 590 | 591 | 1 592 | 1 593 | 0 594 | 1 595 | 1 596 | 1 597 | 0 598 | 1 599 | 0 600 | 601 | 0 602 | 7 603 | 604 | 605 | 606 | 607 | 608 | 609 | 610 | 611 | 612 | 613 | 614 | 615 | 616 | Segger\JL2CM3.dll 617 | 618 | 619 | 620 | 621 | 1 622 | 0 623 | 0 624 | 1 625 | 1 626 | 4099 627 | 628 | Segger\JL2CM3.dll 629 | 630 | 631 | 632 | 633 | 634 | 0 635 | 1 636 | 1 637 | 1 638 | 1 639 | 1 640 | 1 641 | 1 642 | 0 643 | 1 644 | 1 645 | 0 646 | 1 647 | 1 648 | 0 649 | 0 650 | 1 651 | 1 652 | 1 653 | 1 654 | 1 655 | 1 656 | 1 657 | 1 658 | 1 659 | 0 660 | 0 661 | "Cortex-M0" 662 | 663 | 0 664 | 0 665 | 0 666 | 1 667 | 1 668 | 0 669 | 0 670 | 0 671 | 0 672 | 0 673 | 8 674 | 0 675 | 1 676 | 0 677 | 3 678 | 3 679 | 0 680 | 0 681 | 0 682 | 0 683 | 0 684 | 0 685 | 0 686 | 0 687 | 0 688 | 0 689 | 1 690 | 0 691 | 0 692 | 0 693 | 0 694 | 1 695 | 0 696 | 697 | 698 | 0 699 | 0x0 700 | 0x0 701 | 702 | 703 | 0 704 | 0x0 705 | 0x0 706 | 707 | 708 | 0 709 | 0x0 710 | 0x0 711 | 712 | 713 | 0 714 | 0x0 715 | 0x0 716 | 717 | 718 | 0 719 | 0x0 720 | 0x0 721 | 722 | 723 | 0 724 | 0x0 725 | 0x0 726 | 727 | 728 | 0 729 | 0x20000000 730 | 0x4000 731 | 732 | 733 | 1 734 | 0x0 735 | 0x40000 736 | 737 | 738 | 0 739 | 0x0 740 | 0x0 741 | 742 | 743 | 1 744 | 0x0 745 | 0x0 746 | 747 | 748 | 1 749 | 0x0 750 | 0x0 751 | 752 | 753 | 1 754 | 0x0 755 | 0x0 756 | 757 | 758 | 1 759 | 0x00014000 760 | 0x0000B000 761 | 762 | 763 | 1 764 | 0x0 765 | 0x0 766 | 767 | 768 | 0 769 | 0x0 770 | 0x0 771 | 772 | 773 | 0 774 | 0x0 775 | 0x0 776 | 777 | 778 | 0 779 | 0x0 780 | 0x0 781 | 782 | 783 | 0 784 | 0x20002000 785 | 0x00002000 786 | 787 | 788 | 0 789 | 0x0 790 | 0x0 791 | 792 | 793 | 794 | 795 | 796 | 1 797 | 1 798 | 0 799 | 0 800 | 0 801 | 0 802 | 1 803 | 0 804 | 0 805 | 0 806 | 2 807 | 0 808 | 0 809 | 810 | --c99 811 | NRF51,DEBUG_NRF_USER 812 | 813 | ..;..\..\..\..\..\Include;..\..\..\..\..\Include\app_common;..\..\..\..\..\Include\ble;..\..\..\..\..\Include\ble\ble_services;..\..\..\..\..\Include\ble\softdevice 814 | 815 | 816 | 817 | 1 818 | 0 819 | 0 820 | 0 821 | 0 822 | 0 823 | 0 824 | 0 825 | 826 | 827 | 828 | 829 | 830 | 831 | 832 | 833 | 1 834 | 0 835 | 0 836 | 0 837 | 1 838 | 0 839 | 0x00000000 840 | 0x20000000 841 | ..\scatter.sct 842 | 843 | 844 | 845 | 846 | 847 | 848 | 849 | 850 | 851 | 852 | Startup Code 853 | 854 | 855 | arm_startup_nrf51.s 856 | 2 857 | .\..\..\..\..\..\Source\templates\arm\arm_startup_nrf51.s 858 | 859 | 860 | system_nrf51.c 861 | 1 862 | .\..\..\..\..\..\Source\templates\system_nrf51.c 863 | 864 | 865 | 866 | 867 | Source Code 868 | 869 | 870 | main.c 871 | 1 872 | .\..\main.c 873 | 874 | 875 | 876 | 877 | Services 878 | 879 | 880 | ble_srv_common.c 881 | 1 882 | ..\..\..\..\..\Source\ble\ble_services\ble_srv_common.c 883 | 884 | 885 | 886 | 887 | Libraries 888 | 889 | 890 | ble_error_log.c 891 | 1 892 | ..\..\..\..\..\Source\ble\ble_error_log.c 893 | 894 | 895 | ble_flash.c 896 | 1 897 | ..\..\..\..\..\Source\ble\ble_flash.c 898 | 899 | 900 | ble_advdata.c 901 | 1 902 | ..\..\..\..\..\Source\ble\ble_advdata.c 903 | 904 | 905 | app_timer.c 906 | 1 907 | ..\..\..\..\..\Source\app_common\app_timer.c 908 | 909 | 910 | ble_conn_params.c 911 | 1 912 | ..\..\..\..\..\Source\ble\ble_conn_params.c 913 | 914 | 915 | ble_stack_handler.c 916 | 1 917 | ..\..\..\..\..\Source\ble\ble_stack_handler.c 918 | 919 | 920 | ble_debug_assert_handler.c 921 | 1 922 | ..\..\..\..\..\Source\ble\ble_debug_assert_handler.c 923 | 924 | 925 | 926 | 927 | 928 | 929 | 930 |
931 | -------------------------------------------------------------------------------- /ble_bls.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "ble.h" 4 | 5 | #include "ble_bls.h" 6 | 7 | static uint32_t cmd_char_add(ble_bls_t * p_bls, ble_bls_init_t * p_bls_init) 8 | { 9 | ble_gatts_char_md_t char_md; 10 | ble_gatts_attr_md_t attr_md; 11 | ble_gatts_attr_t attr; 12 | ble_uuid_t uuid; 13 | 14 | uuid.type = p_bls->uuid_type; 15 | uuid.uuid = BLS_UUID_CMD; 16 | 17 | memset(&attr_md, 0, sizeof(attr_md)); 18 | BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_md.write_perm); 19 | attr_md.vloc = BLE_GATTS_VLOC_STACK; 20 | 21 | memset(&char_md, 0, sizeof(char_md)); 22 | char_md.char_props.write = 1; 23 | 24 | memset(&attr, 0, sizeof(attr)); 25 | attr.p_uuid = &uuid; 26 | attr.p_attr_md = &attr_md; 27 | attr.init_len = sizeof(ble_bls_cmd_t); 28 | attr.max_len = sizeof(ble_bls_cmd_t); 29 | 30 | return sd_ble_gatts_characteristic_add(p_bls->service_handle, &char_md, &attr, &p_bls->cmd_char_handles); 31 | } 32 | 33 | static uint32_t response_char_add(ble_bls_t * p_bls, ble_bls_init_t * p_bls_init) 34 | { 35 | ble_gatts_char_md_t char_md; 36 | ble_gatts_attr_md_t attr_md; 37 | ble_gatts_attr_md_t cccd_md; 38 | ble_gatts_attr_t attr; 39 | ble_uuid_t uuid; 40 | 41 | uuid.type = p_bls->uuid_type; 42 | uuid.uuid = BLS_UUID_RESPONSE; 43 | 44 | memset(&attr_md, 0, sizeof(attr_md)); 45 | BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_md.write_perm); 46 | attr_md.vloc = BLE_GATTS_VLOC_STACK; 47 | 48 | 49 | memset(&cccd_md, 0, sizeof(cccd_md)); 50 | BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.write_perm); 51 | BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.read_perm); 52 | cccd_md.vloc = BLE_GATTS_VLOC_STACK; 53 | 54 | memset(&char_md, 0, sizeof(char_md)); 55 | char_md.char_props.notify = 1; 56 | char_md.p_cccd_md = &cccd_md; 57 | 58 | memset(&attr, 0, sizeof(attr)); 59 | attr.p_uuid = &uuid; 60 | attr.p_attr_md = &attr_md; 61 | attr.init_len = sizeof(ble_bls_response_t); 62 | attr.max_len = sizeof(ble_bls_response_t); 63 | 64 | return sd_ble_gatts_characteristic_add(p_bls->service_handle, &char_md, &attr, &p_bls->response_char_handles); 65 | } 66 | 67 | static uint32_t data_char_add(ble_bls_t * p_bls, ble_bls_init_t * p_bls_init) 68 | { 69 | ble_gatts_char_md_t char_md; 70 | ble_gatts_attr_md_t attr_md; 71 | ble_gatts_attr_t attr; 72 | ble_uuid_t uuid; 73 | 74 | uuid.type = p_bls->uuid_type; 75 | uuid.uuid = BLS_UUID_DATA; 76 | 77 | memset(&attr_md, 0, sizeof(attr_md)); 78 | BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_md.write_perm); 79 | attr_md.vloc = BLE_GATTS_VLOC_STACK; 80 | attr_md.vlen = 1; 81 | 82 | memset(&char_md, 0, sizeof(char_md)); 83 | char_md.char_props.write_wo_resp = 1; 84 | 85 | memset(&attr, 0, sizeof(attr)); 86 | attr.p_uuid = &uuid; 87 | attr.p_attr_md = &attr_md; 88 | attr.init_len = 0; 89 | attr.max_len = 20; 90 | 91 | return sd_ble_gatts_characteristic_add(p_bls->service_handle, &char_md, &attr, &p_bls->data_char_handles); 92 | } 93 | 94 | static void on_write(ble_bls_t * p_bls, ble_evt_t * p_ble_evt) 95 | { 96 | ble_gatts_evt_write_t * write_evt = &p_ble_evt->evt.gatts_evt.params.write; 97 | ble_bls_evt_t bls_evt; 98 | if (write_evt->handle == p_bls->cmd_char_handles.value_handle) 99 | { 100 | bls_evt.cmd = write_evt->data[0]; 101 | 102 | p_bls->evt_handler(p_bls, &bls_evt); 103 | } 104 | else if (write_evt->handle == p_bls->data_char_handles.value_handle) 105 | { 106 | bls_evt.cmd = BLE_BLS_CMD_WRITE_LINE; 107 | 108 | for (uint8_t i = 0; i < write_evt->len; i++) 109 | { 110 | p_bls->buffer[p_bls->buffer_index++] = write_evt->data[i]; 111 | } 112 | 113 | if (p_bls->buffer[p_bls->buffer_index-1] == '\n' || p_bls->buffer_index >= BLE_BLS_MAX_LINE_LEN) 114 | { 115 | bls_evt.data = (uint8_t *) p_bls->buffer; 116 | bls_evt.len = p_bls->buffer_index; 117 | p_bls->evt_handler(p_bls, &bls_evt); 118 | p_bls->buffer_index = 0; 119 | } 120 | } 121 | 122 | } 123 | 124 | void ble_bls_on_ble_evt(ble_bls_t * p_bls, ble_evt_t * p_ble_evt) 125 | { 126 | switch (p_ble_evt->header.evt_id) 127 | { 128 | case BLE_GAP_EVT_CONNECTED: 129 | p_bls->conn_handle = p_ble_evt->evt.gap_evt.conn_handle; 130 | break; 131 | 132 | case BLE_GAP_EVT_DISCONNECTED: 133 | p_bls->conn_handle = BLE_CONN_HANDLE_INVALID; 134 | break; 135 | 136 | case BLE_GATTS_EVT_WRITE: 137 | on_write(p_bls, p_ble_evt); 138 | break; 139 | 140 | default: 141 | break; 142 | } 143 | } 144 | 145 | uint32_t ble_bls_init(ble_bls_t * p_bls, ble_bls_init_t * p_bls_init) 146 | { 147 | uint32_t err_code; 148 | ble_uuid128_t base_uuid = {BLS_UUID_BASE}; 149 | ble_uuid_t service_uuid; 150 | 151 | if (p_bls_init->evt_handler == NULL) 152 | { 153 | return NRF_ERROR_INVALID_PARAM; 154 | } 155 | p_bls->evt_handler = p_bls_init->evt_handler; 156 | 157 | err_code = sd_ble_uuid_vs_add(&base_uuid, &p_bls->uuid_type); 158 | if (err_code != NRF_SUCCESS) 159 | { 160 | return err_code; 161 | } 162 | 163 | service_uuid.type = p_bls->uuid_type; 164 | service_uuid.uuid = BLS_UUID_SERVICE; 165 | 166 | err_code = sd_ble_gatts_service_add(BLE_GATTS_SRVC_TYPE_PRIMARY, &service_uuid, &p_bls->service_handle); 167 | if (err_code != NRF_SUCCESS) 168 | { 169 | return err_code; 170 | } 171 | 172 | err_code = cmd_char_add(p_bls, p_bls_init); 173 | if (err_code != NRF_SUCCESS) 174 | { 175 | return err_code; 176 | } 177 | 178 | err_code = response_char_add(p_bls, p_bls_init); 179 | if (err_code != NRF_SUCCESS) 180 | { 181 | return err_code; 182 | } 183 | 184 | err_code = data_char_add(p_bls, p_bls_init); 185 | if (err_code != NRF_SUCCESS) 186 | { 187 | return err_code; 188 | } 189 | return NRF_SUCCESS; 190 | } 191 | 192 | uint32_t ble_bls_response_send(ble_bls_t * p_bls, ble_bls_response_t response) 193 | { 194 | ble_gatts_hvx_params_t params; 195 | uint16_t len = sizeof(response); 196 | 197 | params.handle = p_bls->response_char_handles.value_handle; 198 | params.type = BLE_GATT_HVX_NOTIFICATION; 199 | params.offset = 0; 200 | params.p_data = &response; 201 | params.p_len = &len; 202 | 203 | return sd_ble_gatts_hvx(p_bls->conn_handle, ¶ms); 204 | } 205 | -------------------------------------------------------------------------------- /ble_bls.h: -------------------------------------------------------------------------------- 1 | #ifndef __BLE_BLS_H_ 2 | #define __BLE_BLS_H_ 3 | 4 | #include 5 | 6 | #define BLS_UUID_BASE {0x44, 0x98, 0xBC, 0xEA, 0x5F, 0x78, 0x23, 0x15, 0xDE, 0xEF, 0x12, 0x12, 0x00, 0x00, 0x00, 0x00} 7 | #define BLS_UUID_SERVICE 0x1000 8 | #define BLS_UUID_CMD 0x2000 9 | #define BLS_UUID_RESPONSE 0x2001 10 | #define BLS_UUID_DATA 0x2002 11 | 12 | #define BLE_BLS_MAX_LINE_LEN 48 13 | 14 | typedef enum 15 | { 16 | BLE_BLS_CMD_NOP, 17 | BLE_BLS_CMD_ERASE_APP, 18 | BLE_BLS_CMD_WRITE_LINE, 19 | BLE_BLS_CMD_RESET_AND_RUN, 20 | } ble_bls_cmd_t; 21 | 22 | typedef enum 23 | { 24 | BLE_BLS_RESPONSE_SUCCESS = 0, 25 | BLE_BLS_RESPONSE_ILLEGAL_RECORD = 1, 26 | BLE_BLS_RESPONSE_ILLEGAL_ADDRESS = 2 27 | } ble_bls_response_t; 28 | 29 | typedef struct 30 | { 31 | ble_bls_cmd_t cmd; 32 | uint8_t len; 33 | uint8_t * data; 34 | } ble_bls_evt_t; 35 | 36 | typedef struct ble_bls_s ble_bls_t; 37 | 38 | typedef void (*ble_bls_evt_handler_t)(ble_bls_t * p_bls, ble_bls_evt_t * p_evt); 39 | 40 | typedef struct 41 | { 42 | ble_bls_evt_handler_t evt_handler; 43 | } ble_bls_init_t; 44 | 45 | typedef struct ble_bls_s 46 | { 47 | uint16_t conn_handle; 48 | uint8_t uuid_type; 49 | uint16_t service_handle; 50 | ble_gatts_char_handles_t cmd_char_handles; 51 | ble_gatts_char_handles_t response_char_handles; 52 | ble_gatts_char_handles_t data_char_handles; 53 | ble_bls_evt_handler_t evt_handler; 54 | uint8_t buffer_index; 55 | uint8_t buffer[BLE_BLS_MAX_LINE_LEN]; 56 | } ble_bls_t; 57 | 58 | void ble_bls_on_ble_evt(ble_bls_t * p_bls, ble_evt_t * p_ble_evt); 59 | uint32_t ble_bls_init(ble_bls_t * p_bls, ble_bls_init_t * p_bls_init); 60 | uint32_t ble_bls_response_send(ble_bls_t * p_bls, ble_bls_response_t response); 61 | 62 | #endif 63 | -------------------------------------------------------------------------------- /bootloader_startup_nrf51.s: -------------------------------------------------------------------------------- 1 | /* File: startup_ARMCM0.S 2 | * Purpose: startup file for Cortex-M0 devices. Should use with 3 | * GCC for ARM Embedded Processors 4 | * Version: V1.2 5 | * Date: 15 Nov 2011 6 | * 7 | * Copyright (c) 2011, ARM Limited 8 | * All rights reserved. 9 | * 10 | * Redistribution and use in source and binary forms, with or without 11 | * modification, are permitted provided that the following conditions are met: 12 | * Redistributions of source code must retain the above copyright 13 | notice, this list of conditions and the following disclaimer. 14 | * Redistributions in binary form must reproduce the above copyright 15 | notice, this list of conditions and the following disclaimer in the 16 | documentation and/or other materials provided with the distribution. 17 | * Neither the name of the ARM Limited nor the 18 | names of its contributors may be used to endorse or promote products 19 | derived from this software without specific prior written permission. 20 | * 21 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 22 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 23 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 24 | * DISCLAIMED. IN NO EVENT SHALL ARM LIMITED BE LIABLE FOR ANY 25 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 26 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 27 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 28 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 30 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | */ 32 | .syntax unified 33 | .arch armv6-m 34 | 35 | .section .stack 36 | .align 3 37 | #ifdef __STACK_SIZE 38 | .equ Stack_Size, __STACK_SIZE 39 | #else 40 | .equ Stack_Size, 0xc00 41 | #endif 42 | .globl __StackTop 43 | .globl __StackLimit 44 | __StackLimit: 45 | .space Stack_Size 46 | .size __StackLimit, . - __StackLimit 47 | __StackTop: 48 | .size __StackTop, . - __StackTop 49 | 50 | .section .heap 51 | .align 3 52 | #ifdef __HEAP_SIZE 53 | .equ Heap_Size, __HEAP_SIZE 54 | #else 55 | .equ Heap_Size, 0x100 56 | #endif 57 | .globl __HeapBase 58 | .globl __HeapLimit 59 | __HeapBase: 60 | .space Heap_Size 61 | .size __HeapBase, . - __HeapBase 62 | __HeapLimit: 63 | .size __HeapLimit, . - __HeapLimit 64 | 65 | .macro vector_definition peripheral 66 | \peripheral\()Vector : 67 | .long \peripheral\()Wrapper 68 | .endm 69 | 70 | .section .isr_vector 71 | .align 2 72 | .globl __isr_vector 73 | __isr_vector: 74 | .long __StackTop /* Top of Stack */ 75 | .long Reset_Handler /* Reset Handler */ 76 | .long NMI_Handler /* NMI Handler */ 77 | vector_definition HardFault_/* Hard Fault Handler */ 78 | .long 0 /* Reserved */ 79 | .long 0 /* Reserved */ 80 | .long 0 /* Reserved */ 81 | .long 0 /* Reserved */ 82 | .long 0 /* Reserved */ 83 | .long 0 /* Reserved */ 84 | .long 0 /* Reserved */ 85 | vector_definition SVC_ /* SVCall Handler */ 86 | .long 0 /* Reserved */ 87 | .long 0 /* Reserved */ 88 | vector_definition PendSV_ /* PendSV Handler */ 89 | vector_definition SysTick_ /* SysTick Handler */ 90 | 91 | /* External interrupts */ 92 | vector_definition POWER_CLOCK_IRQ /*POWER_CLOCK */ 93 | vector_definition RADIO_IRQ /*RADIO */ 94 | vector_definition UART0_IRQ /*UART0 */ 95 | vector_definition SPI0_TWI0_IRQ /*SPI0_TWI0 */ 96 | vector_definition SPI1_TWI1_IRQ /*SPI1_TWI1 */ 97 | .long 0 /*Reserved */ 98 | vector_definition GPIOTE_IRQ /*GPIOTE */ 99 | vector_definition ADC_IRQ /*ADC */ 100 | vector_definition TIMER0_IRQ /*TIMER0 */ 101 | vector_definition TIMER1_IRQ /*TIMER1 */ 102 | vector_definition TIMER2_IRQ /*TIMER2 */ 103 | vector_definition RTC0_IRQ /*RTC0 */ 104 | vector_definition TEMP_IRQ /*TEMP */ 105 | vector_definition RNG_IRQ /*RNG */ 106 | vector_definition ECB_IRQ /*ECB */ 107 | vector_definition CCM_AAR_IRQ /*CCM_AAR */ 108 | vector_definition WDT_IRQ /*WDT */ 109 | vector_definition RTC1_IRQ /*RTC1 */ 110 | vector_definition QDEC_IRQ /*QDEC */ 111 | .long 0 /*Reserved */ 112 | vector_definition SWI0_IRQ /*SWI0 */ 113 | vector_definition SWI1_IRQ /*SWI1 */ 114 | vector_definition SWI2_IRQ /*SWI2 */ 115 | vector_definition SWI3_IRQ /*SWI3 */ 116 | vector_definition SWI4_IRQ /*SWI4 */ 117 | vector_definition SWI5_IRQ /*SWI5 */ 118 | .long 0 /*Reserved */ 119 | .long 0 /*Reserved */ 120 | .long 0 /*Reserved */ 121 | .long 0 /*Reserved */ 122 | .long 0 /*Reserved */ 123 | .long 0 /*Reserved */ 124 | 125 | .size __isr_vector, . - __isr_vector 126 | 127 | .text 128 | .thumb 129 | .thumb_func 130 | .align 2 131 | .globl Reset_Handler 132 | .type Reset_Handler, %function 133 | Reset_Handler: 134 | .equ NRF_POWER_RAMON_ADDRESS, 0x40000524 135 | .equ NRF_POWER_RAMON_RAM1ON_ONMODE_Msk, 0x3 136 | ldr r0, =NRF_POWER_RAMON_ADDRESS 137 | ldr r2, [r0] 138 | movs r1, #NRF_POWER_RAMON_RAM1ON_ONMODE_Msk 139 | orrs r2, r1 140 | str r2, [r0] 141 | 142 | /* Loop to copy data from read only memory to RAM. The ranges 143 | * of copy from/to are specified by following symbols evaluated in 144 | * linker script. 145 | * __etext: End of code section, i.e., begin of data sections to copy from. 146 | * __data_start__/__data_end__: RAM address range that data should be 147 | * copied to. Both must be aligned to 4 bytes boundary. */ 148 | ldr r1, =__etext 149 | ldr r2, =__data_start__ 150 | ldr r3, =__data_end__ 151 | 152 | subs r3, r2 153 | ble .flash_to_ram_loop_end 154 | 155 | movs r4, 0 156 | .flash_to_ram_loop: 157 | ldr r0, [r1,r4] 158 | str r0, [r2,r4] 159 | adds r4, 4 160 | cmp r4, r3 161 | blt .flash_to_ram_loop 162 | .flash_to_ram_loop_end: 163 | ldr r0, =SystemInit 164 | blx r0 165 | ldr r0, =_start 166 | bx r0 167 | .pool 168 | .size Reset_Handler, . - Reset_Handler 169 | 170 | .equ APPLICATION_BASE_ADDRESS_CONSTANT, 0x20000 171 | 172 | .macro def_wrapper peripheral 173 | .align 1 174 | .thumb_func 175 | .globl is_bootloader_running 176 | .type \peripheral\()Wrapper, %function 177 | \peripheral\()Wrapper: 178 | ldr r5, =is_bootloader_running 179 | ldr r4, [r5] 180 | cmp r4, #0 181 | beq .\peripheral\()_app_handler 182 | ldr r5, =\peripheral\()Handler 183 | bx r5 184 | .\peripheral\()_app_handler : 185 | ldr r5, =APPLICATION_BASE_ADDRESS_CONSTANT+\peripheral\()Vector 186 | bx r5 187 | .size \peripheral\()Wrapper, . - \peripheral\()Wrapper 188 | .endm 189 | 190 | /* Macro to define default handlers. Default handler 191 | * will be weak symbol and just dead loops. They can be 192 | * overwritten by other handlers */ 193 | .macro def_default_handler handler_name 194 | .align 1 195 | .thumb_func 196 | .weak \handler_name 197 | .type \handler_name, %function 198 | \handler_name : 199 | b . 200 | .size \handler_name, . - \handler_name 201 | .endm 202 | 203 | def_default_handler NMI_Handler 204 | def_wrapper HardFault_ 205 | def_default_handler HardFault_Handler 206 | def_wrapper SVC_ 207 | def_default_handler SVC_Handler 208 | def_wrapper PendSV_ 209 | def_default_handler PendSV_Handler 210 | def_wrapper SysTick_ 211 | def_default_handler SysTick_Handler 212 | def_default_handler Default_Handler 213 | def_wrapper POWER_CLOCK_IRQ 214 | def_default_handler POWER_CLOCK_IRQHandler 215 | def_wrapper RADIO_IRQ 216 | def_default_handler RADIO_IRQHandler 217 | def_wrapper UART0_IRQ 218 | def_default_handler UART0_IRQHandler 219 | def_wrapper SPI0_TWI0_IRQ 220 | def_default_handler SPI0_TWI0_IRQHandler 221 | def_wrapper SPI1_TWI1_IRQ 222 | def_default_handler SPI1_TWI1_IRQHandler 223 | def_wrapper GPIOTE_IRQ 224 | def_default_handler GPIOTE_IRQHandler 225 | def_wrapper ADC_IRQ 226 | def_default_handler ADC_IRQHandler 227 | def_wrapper TIMER0_IRQ 228 | def_default_handler TIMER0_IRQHandler 229 | def_wrapper TIMER1_IRQ 230 | def_default_handler TIMER1_IRQHandler 231 | def_wrapper TIMER2_IRQ 232 | def_default_handler TIMER2_IRQHandler 233 | def_wrapper RTC0_IRQ 234 | def_default_handler RTC0_IRQHandler 235 | def_wrapper TEMP_IRQ 236 | def_default_handler TEMP_IRQHandler 237 | def_wrapper RNG_IRQ 238 | def_default_handler RNG_IRQHandler 239 | def_wrapper ECB_IRQ 240 | def_default_handler ECB_IRQHandler 241 | def_wrapper CCM_AAR_IRQ 242 | def_default_handler CCM_AAR_IRQHandler 243 | def_wrapper WDT_IRQ 244 | def_default_handler WDT_IRQHandler 245 | def_wrapper RTC1_IRQ 246 | def_default_handler RTC1_IRQHandler 247 | def_wrapper QDEC_IRQ 248 | def_default_handler QDEC_IRQHandler 249 | def_wrapper SWI0_IRQ 250 | def_default_handler SWI0_IRQHandler 251 | def_wrapper SWI1_IRQ 252 | def_default_handler SWI1_IRQHandler 253 | def_wrapper SWI2_IRQ 254 | def_default_handler SWI2_IRQHandler 255 | def_wrapper SWI3_IRQ 256 | def_default_handler SWI3_IRQHandler 257 | def_wrapper SWI4_IRQ 258 | def_default_handler SWI4_IRQHandler 259 | def_wrapper SWI5_IRQ 260 | def_default_handler SWI5_IRQHandler 261 | 262 | .weak DEF_IRQHandler 263 | .set DEF_IRQHandler, Default_Handler 264 | 265 | .end 266 | -------------------------------------------------------------------------------- /main.c: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2012 Nordic Semiconductor. All Rights Reserved. 2 | * 3 | * The information contained herein is property of Nordic Semiconductor ASA. 4 | * Terms and conditions of usage are described in detail in NORDIC 5 | * SEMICONDUCTOR STANDARD SOFTWARE LICENSE AGREEMENT. 6 | * 7 | * Licensees are granted free, non-transferable use of the information. NO 8 | * WARRANTY of ANY KIND is provided. This heading must NOT be removed from 9 | * the file. 10 | * 11 | */ 12 | 13 | /** @file 14 | * 15 | * @defgroup ble_sdk_app_template_main main.c 16 | * @{ 17 | * @ingroup ble_sdk_app_template 18 | * @brief Template project main file. 19 | * 20 | * This file contains a template for creating a new application. It has the code necessary to wakeup from button, advertise, get a connection 21 | * restart advertising on disconnect and if no new connection created go back to system-off mode. 22 | * It can easily be used as a starting point for creating a new application, the comments identified with 'YOUR_JOB' indicates where 23 | * and how you can customize. 24 | */ 25 | 26 | #include 27 | #include 28 | #include "nordic_common.h" 29 | #include "nrf.h" 30 | #include "app_error.h" 31 | #include "nrf_gpio.h" 32 | #include "nrf51_bitfields.h" 33 | #include "ble.h" 34 | #include "ble_hci.h" 35 | #include "ble_srv_common.h" 36 | #include "ble_advdata.h" 37 | #include "ble_conn_params.h" 38 | #include "ble_eval_board_pins.h" 39 | #include "ble_stack_handler.h" 40 | #include "app_timer.h" 41 | #include "nrf_soc.h" 42 | 43 | #include "ble_bls.h" 44 | #include "hexparser.h" 45 | 46 | #include "nrf_delay.h" 47 | 48 | #define APPLICATION_BASE_ADDRESS 0x20000 49 | 50 | //#define WAKEUP_BUTTON_PIN NRF6310_BUTTON_0 /**< Button used to wake up the application. */ 51 | #define WAKEUP_BUTTON_PIN EVAL_BOARD_BUTTON_0 /**< Button used to wake up the application. */ 52 | // YOUR_JOB: Define any other buttons to be used by the applications: 53 | // #define MY_BUTTON_PIN NRF6310_BUTTON_1 54 | 55 | #define DEVICE_NAME "BLEloader" /**< Name of device. Will be included in the advertising data. */ 56 | 57 | #define APP_ADV_INTERVAL 64 /**< The advertising interval (in units of 0.625 ms. This value corresponds to 40 ms). */ 58 | #define APP_ADV_TIMEOUT_IN_SECONDS 180 /**< The advertising timeout (in units of seconds). */ 59 | 60 | #define APP_TIMER_PRESCALER 0 /**< Value of the RTC1 PRESCALER register. */ 61 | #define APP_TIMER_MAX_TIMERS 2 /**< Maximum number of simultaneously created timers. */ 62 | #define APP_TIMER_OP_QUEUE_SIZE 4 /**< Size of timer operation queues. */ 63 | 64 | #define MIN_CONN_INTERVAL 6 /**< Minimum acceptable connection interval (0.0075 seconds), Connection interval uses 1.25 ms units. */ 65 | #define MAX_CONN_INTERVAL 8 /**< Maximum acceptable connection interval (0.01 second), Connection interval uses 1.25 ms units. */ 66 | #define SLAVE_LATENCY 10 /**< Slave latency. */ 67 | #define CONN_SUP_TIMEOUT 100 /**< Connection supervisory timeout (0.1 seconds), Supervision Timeout uses 10 ms units. */ 68 | 69 | 70 | #define SEC_PARAM_TIMEOUT 30 /**< Timeout for Pairing Request or Security Request (in seconds). */ 71 | #define SEC_PARAM_BOND 1 /**< Perform bonding. */ 72 | #define SEC_PARAM_MITM 0 /**< Man In The Middle protection not required. */ 73 | #define SEC_PARAM_IO_CAPABILITIES BLE_GAP_IO_CAPS_NONE /**< No I/O capabilities. */ 74 | #define SEC_PARAM_OOB 0 /**< Out Of Band data not available. */ 75 | #define SEC_PARAM_MIN_KEY_SIZE 7 /**< Minimum encryption key size. */ 76 | #define SEC_PARAM_MAX_KEY_SIZE 16 /**< Maximum encryption key size. */ 77 | 78 | #define DEAD_BEEF 0xDEADBEEF /**< Value used as error code on stack dump, can be used to identify stack location on stack unwind. */ 79 | 80 | static ble_gap_sec_params_t m_sec_params; /**< Security requirements for this application. */ 81 | static uint16_t m_conn_handle = BLE_CONN_HANDLE_INVALID; /**< Handle of the current connection. */ 82 | static ble_bls_t m_bls; 83 | 84 | uint32_t is_bootloader_running = true; 85 | uint32_t application_base_address = 0x20000; 86 | 87 | typedef void (*application_main_t)(void); 88 | 89 | /**@brief Error handler function, which is called when an error has occurred. 90 | * 91 | * @warning This handler is an example only and does not fit a final product. You need to analyze 92 | * how your product is supposed to react in case of error. 93 | * 94 | * @param[in] error_code Error code supplied to the handler. 95 | * @param[in] line_num Line number where the handler is called. 96 | * @param[in] p_file_name Pointer to the file name. 97 | */ 98 | void app_error_handler(uint32_t error_code, uint32_t line_num, const uint8_t * p_file_name) 99 | { 100 | nrf_gpio_pin_set(CONNECTED_LED_PIN_NO); 101 | nrf_gpio_pin_set(ADVERTISING_LED_PIN_NO); 102 | 103 | while(1) 104 | { 105 | nrf_gpio_pin_toggle(CONNECTED_LED_PIN_NO); 106 | nrf_delay_us(100000); 107 | } 108 | } 109 | 110 | 111 | /**@brief Assert macro callback function. 112 | * 113 | * @details This function will be called in case of an assert in the SoftDevice. 114 | * 115 | * @warning This handler is an example only and does not fit a final product. You need to analyze 116 | * how your product is supposed to react in case of Assert. 117 | * @warning On assert from the SoftDevice, the system can only recover on reset. 118 | * 119 | * @param[in] line_num Line number of the failing ASSERT call. 120 | * @param[in] file_name File name of the failing ASSERT call. 121 | */ 122 | void assert_nrf_callback(uint16_t line_num, const uint8_t * p_file_name) 123 | { 124 | app_error_handler(DEAD_BEEF, line_num, p_file_name); 125 | } 126 | 127 | 128 | /**@brief Service error handler. 129 | * 130 | * @details A pointer to this function will be passed to each service which may need to inform the 131 | * application about an error. 132 | * 133 | * @param[in] nrf_error Error code containing information about what went wrong. 134 | */ 135 | /* 136 | // YOUR_JOB: Uncomment this function and make it handle error situations sent back to your 137 | // application by the services it uses. 138 | static void service_error_handler(uint32_t nrf_error) 139 | { 140 | APP_ERROR_HANDLER(nrf_error); 141 | } */ 142 | 143 | 144 | /**@brief LEDs initialization. 145 | * 146 | * @details Initializes all LEDs used by the application. 147 | */ 148 | static void leds_init(void) 149 | { 150 | GPIO_LED_CONFIG(ADVERTISING_LED_PIN_NO); 151 | GPIO_LED_CONFIG(CONNECTED_LED_PIN_NO); 152 | 153 | // YOUR_JOB: Add additional LED initialiazations if needed. 154 | } 155 | 156 | 157 | /**@brief Timer initialization. 158 | * 159 | * @details Initializes the timer module. 160 | */ 161 | static void timers_init(void) 162 | { 163 | // Initialize timer module, making it use the scheduler 164 | APP_TIMER_INIT(APP_TIMER_PRESCALER, APP_TIMER_MAX_TIMERS, APP_TIMER_OP_QUEUE_SIZE, false); 165 | 166 | /* YOUR_JOB: Create any timers to be used by the application. 167 | Below is an example of how to create a timer. 168 | err_code = app_timer_create(&m_app_timer_id, APP_TIMER_MODE_REPEATED, timer_timeout_handler); 169 | APP_ERROR_CHECK(err_code); */ 170 | } 171 | 172 | 173 | /**@brief GAP initialization. 174 | * 175 | * @details This function shall be used to setup all the necessary GAP (Generic Access Profile) 176 | * parameters of the device. It also sets the permissions and appearance. 177 | */ 178 | static void gap_params_init(void) 179 | { 180 | uint32_t err_code; 181 | ble_gap_conn_params_t gap_conn_params; 182 | ble_gap_conn_sec_mode_t sec_mode; 183 | 184 | BLE_GAP_CONN_SEC_MODE_SET_OPEN(&sec_mode); 185 | 186 | err_code = sd_ble_gap_device_name_set(&sec_mode, (const uint8_t *)DEVICE_NAME, strlen(DEVICE_NAME)); 187 | APP_ERROR_CHECK(err_code); 188 | 189 | /* YOUR_JOB: Use an appearance value matching the application's use case. 190 | err_code = sd_ble_gap_appearance_set(BLE_APPEARANCE_); 191 | APP_ERROR_CHECK(err_code); */ 192 | 193 | memset(&gap_conn_params, 0, sizeof(gap_conn_params)); 194 | 195 | gap_conn_params.min_conn_interval = MIN_CONN_INTERVAL; 196 | gap_conn_params.max_conn_interval = MAX_CONN_INTERVAL; 197 | gap_conn_params.slave_latency = SLAVE_LATENCY; 198 | gap_conn_params.conn_sup_timeout = CONN_SUP_TIMEOUT; 199 | 200 | err_code = sd_ble_gap_ppcp_set(&gap_conn_params); 201 | APP_ERROR_CHECK(err_code); 202 | } 203 | 204 | 205 | /**@brief Advertising functionality initialization. 206 | * 207 | * @details Encodes the required advertising data and passes it to the stack. 208 | * Also builds a structure to be passed to the stack when starting advertising. 209 | */ 210 | static void advertising_init(void) 211 | { 212 | uint32_t err_code; 213 | ble_advdata_t advdata; 214 | ble_advdata_t scanrsp; 215 | uint8_t flags = BLE_GAP_ADV_FLAGS_LE_ONLY_LIMITED_DISC_MODE; 216 | 217 | // YOUR_JOB: Use UUIDs for service(s) used in your application. 218 | ble_uuid_t adv_uuids[] = {{BLS_UUID_SERVICE, m_bls.uuid_type}}; 219 | 220 | // Build and set advertising data 221 | memset(&advdata, 0, sizeof(advdata)); 222 | advdata.name_type = BLE_ADVDATA_FULL_NAME; 223 | advdata.include_appearance = false; 224 | advdata.flags.size = sizeof(flags); 225 | advdata.flags.p_data = &flags; 226 | 227 | memset(&scanrsp, 0, sizeof(scanrsp)); 228 | scanrsp.uuids_complete.uuid_cnt = sizeof(adv_uuids) / sizeof(adv_uuids[0]); 229 | scanrsp.uuids_complete.p_uuids = adv_uuids; 230 | 231 | err_code = ble_advdata_set(&advdata, &scanrsp); 232 | APP_ERROR_CHECK(err_code); 233 | } 234 | 235 | void erase_app(void) 236 | { 237 | uint32_t last_page_address = NRF_FICR->CODEPAGESIZE * NRF_FICR->CODESIZE; 238 | 239 | NRF_NVMC->CONFIG = NVMC_CONFIG_WEN_Een << NVMC_CONFIG_WEN_Pos; 240 | 241 | for (uint32_t address = APPLICATION_BASE_ADDRESS; address < last_page_address; address += NRF_FICR->CODEPAGESIZE) 242 | { 243 | NRF_NVMC->ERASEPAGE = address; 244 | while (!NRF_NVMC->READY); 245 | } 246 | 247 | NRF_NVMC->CONFIG = 0x0; 248 | } 249 | 250 | ble_bls_response_t write_record(uint32_t base_address, hexparser_record * record) 251 | { 252 | if ((base_address + record->address) < APPLICATION_BASE_ADDRESS) 253 | return BLE_BLS_RESPONSE_ILLEGAL_ADDRESS; 254 | 255 | NRF_NVMC->CONFIG = NVMC_CONFIG_WEN_Wen << NVMC_CONFIG_WEN_Pos; 256 | 257 | for (uint32_t i = 0; i < record->byte_count / 4; i++) 258 | { 259 | *(uint32_t *) (base_address + (record->address + (4*i))) = record->data.words[i]; 260 | while (NRF_NVMC->READY & (NVMC_READY_READY_Busy << NVMC_READY_READY_Pos)) 261 | { 262 | } 263 | } 264 | 265 | NRF_NVMC->CONFIG = NVMC_CONFIG_WEN_Ren << NVMC_CONFIG_WEN_Pos; 266 | 267 | return BLE_BLS_RESPONSE_SUCCESS; 268 | } 269 | 270 | ble_bls_response_t write_line(ble_bls_evt_t * evt) 271 | { 272 | ble_bls_response_t response = BLE_BLS_RESPONSE_SUCCESS; 273 | static uint32_t base_address = 0; 274 | hexparser_record record; 275 | hexparser_parse_string((char * ) evt->data, evt->len, &record); 276 | 277 | if (!hexparser_is_record_valid(&record)) 278 | { 279 | response = BLE_BLS_RESPONSE_ILLEGAL_RECORD; 280 | return response; 281 | } 282 | 283 | switch (record.type) 284 | { 285 | case EXTENDED_LINEAR_ADDRESS_RECORD: 286 | base_address = record.data.words[0] << 16; 287 | break; 288 | 289 | case DATA_RECORD: 290 | response = write_record(base_address, &record); 291 | break; 292 | 293 | case EXTENDED_SEGMENT_ADDRESS_RECORD: 294 | base_address = record.data.words[0] << 4; 295 | break; 296 | 297 | default: 298 | break; 299 | } 300 | 301 | return response; 302 | } 303 | 304 | static void advertising_start(void); 305 | 306 | static void ble_bls_evt_handler(ble_bls_t * p_bls, ble_bls_evt_t * p_bls_evt) 307 | { 308 | uint32_t err_code; 309 | nrf_gpio_pin_toggle(ADVERTISING_LED_PIN_NO); 310 | 311 | ble_bls_response_t result; 312 | switch (p_bls_evt->cmd) 313 | { 314 | case BLE_BLS_CMD_NOP: 315 | nrf_gpio_pin_toggle(CONNECTED_LED_PIN_NO); 316 | ble_bls_response_send(p_bls, BLE_BLS_RESPONSE_SUCCESS); 317 | break; 318 | 319 | case BLE_BLS_CMD_ERASE_APP: 320 | sd_power_gpregret_set(0xAA); 321 | err_code = sd_ble_gap_disconnect(p_bls->conn_handle, BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION); 322 | APP_ERROR_CHECK(err_code); 323 | break; 324 | 325 | case BLE_BLS_CMD_WRITE_LINE: 326 | result = write_line(p_bls_evt); 327 | ble_bls_response_send(p_bls, result); 328 | break; 329 | 330 | case BLE_BLS_CMD_RESET_AND_RUN: 331 | ble_bls_response_send(p_bls, BLE_BLS_RESPONSE_SUCCESS); 332 | err_code = sd_ble_gap_disconnect(p_bls->conn_handle, BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION); 333 | APP_ERROR_CHECK(err_code); 334 | break; 335 | 336 | } 337 | } 338 | 339 | /**@brief Initialize services that will be used by the application. 340 | */ 341 | static void services_init(void) 342 | { 343 | // YOUR_JOB: Add code to initialize the services used by the application. 344 | uint32_t err_code; 345 | ble_bls_init_t init; 346 | 347 | memset(&init, 0, sizeof(init)); 348 | init.evt_handler = ble_bls_evt_handler; 349 | 350 | err_code = ble_bls_init(&m_bls, &init); 351 | APP_ERROR_CHECK(err_code); 352 | } 353 | 354 | 355 | /**@brief Initialize security parameters. 356 | */ 357 | static void sec_params_init(void) 358 | { 359 | m_sec_params.timeout = SEC_PARAM_TIMEOUT; 360 | m_sec_params.bond = SEC_PARAM_BOND; 361 | m_sec_params.mitm = SEC_PARAM_MITM; 362 | m_sec_params.io_caps = SEC_PARAM_IO_CAPABILITIES; 363 | m_sec_params.oob = SEC_PARAM_OOB; 364 | m_sec_params.min_key_size = SEC_PARAM_MIN_KEY_SIZE; 365 | m_sec_params.max_key_size = SEC_PARAM_MAX_KEY_SIZE; 366 | } 367 | 368 | 369 | 370 | /**@brief Start timers. 371 | */ 372 | static void timers_start(void) 373 | { 374 | /* YOUR_JOB: Start your timers. below is an example of how to start a timer. 375 | uint32_t err_code; 376 | 377 | err_code = app_timer_start(m_app_timer_id, TIMER_INTERVAL, NULL); 378 | APP_ERROR_CHECK(err_code); */ 379 | } 380 | 381 | 382 | /**@brief Start advertising. 383 | */ 384 | static void advertising_start(void) 385 | { 386 | uint32_t err_code; 387 | ble_gap_adv_params_t adv_params; 388 | 389 | // Start advertising 390 | memset(&adv_params, 0, sizeof(adv_params)); 391 | 392 | adv_params.type = BLE_GAP_ADV_TYPE_ADV_IND; 393 | adv_params.p_peer_addr = NULL; 394 | adv_params.fp = BLE_GAP_ADV_FP_ANY; 395 | adv_params.interval = APP_ADV_INTERVAL; 396 | adv_params.timeout = APP_ADV_TIMEOUT_IN_SECONDS; 397 | 398 | err_code = sd_ble_gap_adv_start(&adv_params); 399 | APP_ERROR_CHECK(err_code); 400 | nrf_gpio_pin_set(ADVERTISING_LED_PIN_NO); 401 | } 402 | 403 | 404 | /**@brief Application's BLE Stack event handler. 405 | * 406 | * @param[in] p_ble_evt Bluetooth stack event. 407 | */ 408 | static void on_ble_evt(ble_evt_t * p_ble_evt) 409 | { 410 | uint32_t err_code = NRF_SUCCESS; 411 | static ble_gap_evt_auth_status_t m_auth_status; 412 | ble_gap_enc_info_t * p_enc_info; 413 | 414 | switch (p_ble_evt->header.evt_id) 415 | { 416 | case BLE_GAP_EVT_CONNECTED: 417 | nrf_gpio_pin_set(CONNECTED_LED_PIN_NO); 418 | nrf_gpio_pin_clear(ADVERTISING_LED_PIN_NO); 419 | m_conn_handle = p_ble_evt->evt.gap_evt.conn_handle; 420 | 421 | break; 422 | 423 | case BLE_GAP_EVT_DISCONNECTED: 424 | nrf_gpio_pin_clear(CONNECTED_LED_PIN_NO); 425 | m_conn_handle = BLE_CONN_HANDLE_INVALID; 426 | 427 | sd_nvic_SystemReset(); 428 | break; 429 | 430 | case BLE_GAP_EVT_SEC_PARAMS_REQUEST: 431 | err_code = sd_ble_gap_sec_params_reply(m_conn_handle, 432 | BLE_GAP_SEC_STATUS_SUCCESS, 433 | &m_sec_params); 434 | break; 435 | 436 | case BLE_GATTS_EVT_SYS_ATTR_MISSING: 437 | err_code = sd_ble_gatts_sys_attr_set(m_conn_handle, NULL, 0); 438 | break; 439 | 440 | case BLE_GAP_EVT_AUTH_STATUS: 441 | m_auth_status = p_ble_evt->evt.gap_evt.params.auth_status; 442 | break; 443 | 444 | case BLE_GAP_EVT_SEC_INFO_REQUEST: 445 | p_enc_info = &m_auth_status.periph_keys.enc_info; 446 | if (p_enc_info->div == p_ble_evt->evt.gap_evt.params.sec_info_request.div) 447 | { 448 | err_code = sd_ble_gap_sec_info_reply(m_conn_handle, p_enc_info, NULL); 449 | } 450 | else 451 | { 452 | // No keys found for this device 453 | err_code = sd_ble_gap_sec_info_reply(m_conn_handle, NULL, NULL); 454 | } 455 | break; 456 | 457 | case BLE_GAP_EVT_TIMEOUT: 458 | if (p_ble_evt->evt.gap_evt.params.timeout.src == BLE_GAP_TIMEOUT_SRC_ADVERTISEMENT) 459 | { 460 | nrf_gpio_pin_clear(ADVERTISING_LED_PIN_NO); 461 | 462 | // Go to system-off mode (this function will not return; wakeup will cause a reset) 463 | GPIO_WAKEUP_BUTTON_CONFIG(WAKEUP_BUTTON_PIN); 464 | err_code = sd_power_system_off(); 465 | } 466 | break; 467 | 468 | default: 469 | break; 470 | } 471 | 472 | APP_ERROR_CHECK(err_code); 473 | } 474 | 475 | 476 | /**@brief Dispatches a BLE stack event to all modules with a BLE stack event handler. 477 | * 478 | * @details This function is called from the scheduler in the main loop after a BLE stack 479 | * event has been received. 480 | * 481 | * @param[in] p_ble_evt Bluetooth stack event. 482 | */ 483 | static void ble_evt_dispatch(ble_evt_t * p_ble_evt) 484 | { 485 | on_ble_evt(p_ble_evt); 486 | ble_conn_params_on_ble_evt(p_ble_evt); 487 | ble_bls_on_ble_evt(&m_bls, p_ble_evt); 488 | /* 489 | YOUR_JOB: Add service ble_evt handlers calls here, like, for example: 490 | ble_bas_on_ble_evt(&m_bas, p_ble_evt); 491 | */ 492 | } 493 | 494 | 495 | /**@brief BLE stack initialization. 496 | * 497 | * @details Initializes the SoftDevice and the BLE event interrupt. 498 | */ 499 | static void ble_stack_init(void) 500 | { 501 | // YOUR_JOB: If the MTU size is changed by the application, the MTU_SIZE parameter to 502 | // BLE_STACK_HANDLER_INIT() must be changed accordingly. 503 | BLE_STACK_HANDLER_INIT(NRF_CLOCK_LFCLKSRC_XTAL_20_PPM, 504 | BLE_L2CAP_MTU_DEF, 505 | ble_evt_dispatch, 506 | false); 507 | } 508 | 509 | 510 | 511 | 512 | 513 | /**@brief Initialize button handler module. 514 | */ 515 | static void buttons_init(void) 516 | { 517 | 518 | // Note: If the only use of buttons is to wake up, the app_button module can be omitted, and 519 | // the wakeup button can be configured by 520 | // GPIO_WAKEUP_BUTTON_CONFIG(WAKEUP_BUTTON_PIN); 521 | } 522 | 523 | 524 | /**@brief Power manager. 525 | */ 526 | static void power_manage(void) 527 | { 528 | uint32_t err_code = sd_app_event_wait(); 529 | APP_ERROR_CHECK(err_code); 530 | } 531 | 532 | 533 | /**@brief Application main function. 534 | */ 535 | int main(void) 536 | { 537 | is_bootloader_running = 1; 538 | if (NRF_POWER->GPREGRET == 0xAA) 539 | { 540 | erase_app(); 541 | NRF_POWER->GPREGRET = 0; 542 | } 543 | 544 | nrf_gpio_cfg_input(EVAL_BOARD_BUTTON_0, NRF_GPIO_PIN_PULLUP); 545 | 546 | application_main_t application_main = *(application_main_t *)(APPLICATION_BASE_ADDRESS+4); 547 | if ((application_main != (application_main_t) 0xFFFFFFFF) && 548 | (nrf_gpio_pin_read(EVAL_BOARD_BUTTON_0) != 0)) 549 | { 550 | is_bootloader_running = false; 551 | application_main(); 552 | } 553 | 554 | // Initialize 555 | leds_init(); 556 | timers_init(); 557 | buttons_init(); 558 | ble_stack_init(); 559 | gap_params_init(); 560 | services_init(); 561 | advertising_init(); 562 | sec_params_init(); 563 | 564 | // Start execution 565 | timers_start(); 566 | advertising_start(); 567 | 568 | // Enter main loop 569 | for (;;) 570 | { 571 | power_manage(); 572 | } 573 | } 574 | 575 | /** 576 | * @} 577 | */ 578 | -------------------------------------------------------------------------------- /pure-gcc/Makefile: -------------------------------------------------------------------------------- 1 | # List all source files the application uses. 2 | APPLICATION_SRCS = ../main.c 3 | APPLICATION_SRCS += ../ble_bls.c 4 | APPLICATION_SRCS += $(notdir $(wildcard ../../libhexwriter/src/*.c)) 5 | APPLICATION_SRCS += ble_advdata.c 6 | APPLICATION_SRCS += ble_srv_common.c 7 | APPLICATION_SRCS += app_timer.c 8 | APPLICATION_SRCS += ble_stack_handler.c 9 | APPLICATION_SRCS += ble_conn_params.c 10 | 11 | PROJECT_NAME = nrf51-ble-loader 12 | START_CODE = bootloader_startup_nrf51.s 13 | 14 | DEVICE = NRF51 15 | BOARD = BOARD_PCA10001 16 | USE_SOFTDEVICE = S110 17 | 18 | LIBRARY_PATHS += ../../libhexwriter/inc/ 19 | SOURCE_PATHS += ../../libhexwriter/src/ 20 | 21 | CFLAGS = -O0 -g 22 | 23 | SDK_PATH = ../../nrf51/nrf51822/ 24 | 25 | GDB_PORT_NUMBER = 2331 26 | 27 | include $(SDK_PATH)Source/templates/pure-gcc/Makefile 28 | --------------------------------------------------------------------------------