├── .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 |
--------------------------------------------------------------------------------