UartBus source documentation
ub_bootloader.c
1 
2 #include "ubh.h"
3 
4 #pragma message "Compiling UARTBus host application with clock speed: " SX(F_CPU)
5 
6 /******************************* GLOBAL variables *****************************/
7 
8 volatile bool app_run;
9 volatile uint8_t reset_flag;
10 
11 void (*app_int_handler)(void*);
12 
13 void ubh_provide_dispatch_interrupt(void* from)
14 {
15  if(NULL != app_int_handler)
16  {
17  app_int_handler(from);
18  }
19 }
20 
21 /******************* On board software upgrade functionalities ***************/
22 
23 //enter into upgrade mode (is in upgrade mode)
24 
25 //get constants, required by the compiler whos send the code
26 
27 //erase app
28 
29 //supply code segment
30 
31 //flush
32 
33 //read programspace: addr len
34 //commit -> back to app mode
35 //bool send_packet(int16_t to, uint8_t* data, uint16_t size);
36 uint8_t crc8(uint8_t* data, uint8_t length);
37 bool send_packet_priv(int16_t to, uint8_t ns, uint8_t* data, uint8_t size);
38 
39 int16_t rpc_response(struct rpc_request* req, uint8_t args, struct response_part** parts)
40 {
41  int neg = req->procPtr;
42 
43  int size = rpc_append_size(args, parts);
44  if(size < 0)
45  {
46  return size;
47  }
48 
49  uint8_t* d = (uint8_t*) alloca(size+neg);
50 
51  for(uint8_t i=0;i<neg;++i)
52  {
53  d[i] = req->payload[i];
54  }
55 
56  rpc_append_arr(d+neg, size, args, parts);
57 
58  return send_packet_priv(req->from, 0, d, size+neg);
59 }
60 
61 /************************** RPC functions - Basic *****************************/
62 
63 //1:0
64 void rpc_basic_ping(struct rpc_request* req)
65 {
66  il_reply(req, 0);
67 }
68 
69 //1:1
70 void rpc_basic_replay(struct rpc_request* req)
71 {
72  il_reply_arr(req, req->payload+req->procPtr, req->size - req->procPtr);
73 }
74 
75 //1:2:x
76 void rpc_basic_user_led(struct rpc_request* req)
77 {
78  if(0 != (req->size - req->procPtr))
79  {
80  il_reply(req, 1, ubh_impl_set_user_led(req->payload[req->procPtr]));
81  }
82 }
83 
84 
85 //https://www.avrfreaks.net/forum/extracting-bytes-long
87 {
88  int16_t int16;
89  uint16_t uint16;
90  int32_t int32;
91  uint32_t uint32;
92 
93  struct {
94  uint8_t b0;
95  uint8_t b1;
96  uint8_t b2;
97  uint8_t b3;
98  } bytes;
99 
100  struct {
101  uint16_t w0;
102  uint16_t w1;
103  } words;
104 };
105 
106 //1:3
107 void rpc_basic_get_time(struct rpc_request* req)
108 {
109  union LONG_BYTES t;
110  t.uint32 = micros();
111 
112  il_reply
113  (
114  req, 4,
115 
116  t.bytes.b3,
117  t.bytes.b2,
118  t.bytes.b1,
119  t.bytes.b0
120  );
121 }
122 
123 //1:4
124 void rpc_basic_random(struct rpc_request* req)
125 {
126  il_reply(req, 1, rando());
127 }
128 
129 void* RPC_FUNCTIONS_BASIC[] =
130 {
131  (void*) 5,
132  (void*) rpc_basic_ping,
133  (void*) rpc_basic_replay,
134  (void*) rpc_basic_user_led,
135  (void*) rpc_basic_get_time,
136  (void*) rpc_basic_random
137 };
138 
139 /****************************** RPC bootloader ********************************/
140 //2:0:x
141 void rpc_bootloader_power_function(struct rpc_request* req)
142 {
143  if(0 == (req->size - req->procPtr))
144  {
145  il_reply(req, 1, EINVAL);
146  return;
147  }
148 
149  switch(req->payload[req->procPtr])
150  {
151  case 0: ubh_impl_wdt_start(false);while(1){}
152  case 1: asm ("jmp 0x00");
153  default: break;
154  }
155 }
156 
157 //2:1:x
158 void rpc_bootloader_get_var(struct rpc_request* req)
159 {
160  if(0 == (req->size - req->procPtr))
161  {
162  il_reply(req, 1, EINVAL);
163  return;
164  }
165 
166  uint8_t res;
167  switch(req->payload[req->procPtr])
168  {
169  case 0: res = app_run; break;
170 // case 1: res = sos_signal; break;
171  case 2: res = reset_flag; break;
172  case 3: res = ubh_impl_has_app(); break;
173  default: res = 0;break;
174  }
175  il_reply(req, 1, res);
176 }
177 
178 //2:2:x
179 void rpc_bootloader_set_var(struct rpc_request* req)
180 {
181  if((req->size - req->procPtr) < 2)
182  {
183  il_reply(req, 1, EINVAL);
184  return;
185  }
186 
187  uint8_t val = req->payload[req->procPtr+1];
188  switch(req->payload[req->procPtr])
189  {
190  case 0: app_run = (bool) val; break;
191 // case 1: sos_signal = (bool) val; break;
192  case 2: reset_flag = (uint8_t) val; break;
193  default: break;
194  }
195  il_reply(req, 1, 0);
196 }
197 
198 
199 
200 //2:3:x
201 void rpc_bootloader_read_code(struct rpc_request* req)
202 {
203  uint8_t* data = req->payload+ req->procPtr;
204  uint16_t base = data[0] << 8 | data[1];
205  uint8_t s = (uint8_t) data[2];
206  if(s > 32)
207  {
208  s = 32;
209  }
210 
211  uint8_t* rec = (uint8_t*) alloca(s+2);
212 
213  rec[0] = data[0];
214  rec[1] = data[1];
215 
216  uint8_t read = ubh_impl_read_code(base, s, &rec[2]);
217 
218  il_reply_arr(req, rec, s+2);
219 }
220 
221 /***************************** Flashing functions *****************************/
222 
223 uint8_t flash_stage = 0;
224 
225 //when it's initailized, always must point to the start of a page boundry.
226 uint16_t flash_crnt_address = 0;
227 uint8_t* flash_tmp = NULL;
228 
229 //2:4:0
230 void blf_get_flash_stage(struct rpc_request* req)
231 {
232  il_reply(req, 2, 0, flash_stage);
233 }
234 
235 //2:4:1
236 void blf_start_flash(struct rpc_request* req)
237 {
238  if(1 == flash_stage)
239  {
240  il_reply(req, 1, EALREADY);
241  }
242 
243  flash_tmp = (uint8_t*) ubh_impl_go_upload_and_allocate_program_tmp_storage();
244  if(NULL == flash_tmp)
245  {
246  il_reply(req, 1, ENOMEM);
247  return;
248  }
249 
250  app_run = false;
251 // sos_signal = false;
252  flash_crnt_address = (uint16_t) APP_START_ADDRESS;
253  flash_stage = 1;
254 
255  il_reply(req, 1, 0);
256 }
257 
258 //2:4:2
259 void blf_get_next_addr(struct rpc_request* req)
260 {
261  il_reply(req, 2, ((flash_crnt_address >> 8) & 0xff), flash_crnt_address & 0xff);
262 }
263 
264 
265 void fill_flash(uint8_t *buf, uint16_t size)
266 {
267  uint8_t page_size = ubh_impl_get_program_page_size();
268  for(uint16_t i = 0;i<size;++i)
269  {
270  //filling flash temporary write storage from the given buffer.
271  flash_tmp[flash_crnt_address % page_size] = buf[i];
272  ++flash_crnt_address;
273 
274  //if page fullfilled => flush it.
275  if(0 == flash_crnt_address % page_size)
276  {
277  ubh_impl_write_program_page
278  (
279  (flash_crnt_address-1) & ~(page_size-1),
280  flash_tmp,
281  page_size
282  );
283  }
284  }
285 }
286 
287 //2:4:3
288 void blf_push_code(struct rpc_request* req)
289 {
290  uint8_t* data = req->payload + req->procPtr;
291  uint8_t size = req->size - req->procPtr;
292  if(0 == flash_stage)
293  {
294  il_reply(req, 1, ENOTCONN);
295  return;
296  }
297 
298  if(size < 3)
299  {
300  il_reply(req, 1, EBADMSG);
301  return;
302  }
303 
304  if(flash_crnt_address < 0x1f00)
305  {
306  il_reply(req, 1, EFAULT);
307  return;
308  }
309 
310  if(data[0] != ((flash_crnt_address >> 8) & 0xff) || data[1] != (flash_crnt_address & 0xff))
311  {
312  il_reply(req, 1, ENXIO);
313  return;
314  }
315 
316  fill_flash(data+2, size-2);
317 
318  il_reply(req, 3, 0, (flash_crnt_address >> 8) & 0xff, flash_crnt_address & 0xff);
319 }
320 
321 //2:4:4
322 void commit_flash(struct rpc_request* req)
323 {
324  if(0 == flash_stage)
325  {
326  il_reply(req, 1, EBADFD);
327  return;
328  }
329 
330  if(flash_crnt_address < 0x1f00)
331  {
332  il_reply(req, 1, EFAULT);
333  return;
334  }
335 
336  uint8_t page_size = ubh_impl_get_program_page_size();
337 
338  //something filled into the write buffer => writing page
339  if(0 != flash_crnt_address % page_size)
340  {
341  ubh_impl_write_program_page
342  (
343  flash_crnt_address & ~(page_size-1),
344  flash_tmp,
345  (flash_crnt_address & (page_size-1))
346  );
347  }
348 
349  flash_stage = 0;
350 
351  il_reply(req, 1, 0);
352 }
353 
354 //2:4:x
355 void* BOOTLOADER_FLASH_FUNCTIONS[] =
356 {
357  (void*) 5,
358  (void*) blf_get_flash_stage,
359  (void*) blf_start_flash,
360  (void*) blf_get_next_addr,
361  (void*) blf_push_code,
362  (void*) commit_flash
363 };
364 
365 //2:4:x
366 void rpc_bootloader_flash(struct rpc_request* req)
367 {
368  dispatch_function_chain(BOOTLOADER_FLASH_FUNCTIONS, req);
369 }
370 
371 //2:
372 void* RPC_FUNCTIONS_BOOTLOADER[] =
373 {
374  (void*) 5,
375  (void*) rpc_bootloader_power_function,
376  (void*) rpc_bootloader_get_var,
377  (void*) rpc_bootloader_set_var,
378  (void*) rpc_bootloader_read_code,
379  (void*) rpc_bootloader_flash,
380 };
381 
382 /************************ On board debug functionalities **********************/
383 
384 void* RPC_FUNCTIONS_DEBUG[] =
385 {
386  (void*) 0,
387  //get sram value
388  //set sram value
389  //free (available) mem
390 };
391 
392 /********************* On board transaction functionalities *******************/
393 
394 void* RPC_FUNCTIONS_TRANSACTION[] =
395 {
396  (void*) 0,
397 };
398 
399 
400 /************************* RPC namespace dispatch ****************************/
401 
402 void* RPC_NS_FUNCTIONS[] =
403 {
404  (void*) 5,
405  NULL,
406  RPC_FUNCTIONS_BASIC,
407  RPC_FUNCTIONS_BOOTLOADER,
408  RPC_FUNCTIONS_DEBUG,
409  RPC_FUNCTIONS_TRANSACTION,//transaction management
410 };
411 
412 void dispatch_root(struct rpc_request* req)
413 {
414  dispatch_descriptor_chain(RPC_NS_FUNCTIONS, req);
415 }
416 
417 /************************ UARTBus application code ****************************/
418 
419 
420 int received_ep;
421 uint8_t received_data[MAX_PACKET_SIZE];
422 
423 uint8_t send_size;
424 uint8_t send_data[MAX_PACKET_SIZE];
425 
426 void (*app_dispatch)(struct rpc_request* req) = NULL;
427 
428 /*void predict_transmission()
429 {
430  if((PORTD & _BV(PD0)))//if RX is low
431  {
432  ub_predict_transmission_start(&bus);
433  }
434 }*/
435 
436 
437 #ifndef EXTERNAL_SEND_PACKET_PRIV
438 
439 bool send_packet_priv(int16_t to, uint8_t NS, uint8_t* data, uint8_t size)
440 {
441  //1 from 1 to 1 NS 1 CRC
442  if(0 != send_size || size >= MAX_PACKET_SIZE-4)
443  {
444  return false;
445  }
446 
447  uint8_t ep = 0;
448  int8_t add;
449 
450  if((add = ub_pack_16_value(to, send_data, MAX_PACKET_SIZE)) < 1)
451  {
452  return false;
453  }
454 
455  ep += add;
456 
457  if((add = ub_pack_16_value(BUS_ADDRESS, send_data+ep, MAX_PACKET_SIZE-ep)) < 1)
458  {
459  return false;
460  }
461 
462  ep += add;
463 
464  send_data[ep] = NS;
465  ++ep;
466 
467  for(int i=0;i<size;++i)
468  {
469  send_data[ep+i] = data[i];
470  }
471  send_data[ep+size] = crc8(send_data, ep+size);
472  send_size = size+ep+1;
473 
474 #ifdef UBH_CALLBACK_ENQUEUE_PACKET
475  ubh_callback_enqueue_packet();
476 #endif
477 
478  return true;
479 }
480 
481 #endif
482 
483 void dispatch(struct rpc_request* req)
484 {
485  if(0 == req->size)
486  {
487  return;
488  }
489 
490  uint8_t ns = req->payload[req->procPtr];
491 
492  if(req->from >= 0 && 0 < ns && ns < 32)
493  {
494  dispatch_root(req);
495  }
496  else if(NULL != app_dispatch && (32 <= ns || 0 == ns))
497  {
498  app_dispatch(req);
499  }
500 }
501 
502 volatile bool received = false;
503 
504 void try_dispatch_received_packet()
505 {
506  if(!received)
507  {
508  return;
509  }
510 
511  received = false;
512 
513  //is the packet flawless?
514  if(crc8(received_data, received_ep-1) == received_data[received_ep-1])
515  {
516  //is size is acceptable?
517  if(received_ep > 3)
518  {
519  uint8_t ep = 0;
520  int8_t add = 0;
521 
522  struct rpc_request req;
523  req.reply = rpc_response;
524  if((add = ub_unpack_16_value(&req.to, received_data, received_ep-1)) < 1)
525  {
526  return;
527  }
528 
529  ep += add;
530 
531  if((add = ub_unpack_16_value(&req.from, received_data+ep, received_ep-1-ep)) < 1)
532  {
533  return;
534  }
535 
536  ep += add;
537 
538  req.size = received_ep-ep-1;
539 
540  req.payload = (uint8_t*) alloca(req.size);// = received_data+ep;
541  for(int i=0;i<req.size;++i)
542  {
543  req.payload[i] = received_data[ep+i];
544  }
545  req.procPtr = 0;
546 
547  //early release of receive buffer
548  received_ep = 0;
549 
550  //is we are the target, or group/broadcast?
551  if(req.to < 1 || BUS_ADDRESS == req.to)
552  {
553  dispatch(&req);
554  }
555  }
556  }
557 
558 #ifdef UBH_DEBUG_BROADCAST_PACKET_WITH_BAD_CRC
559  else
560  {
561  received_data[received_ep] = crc8(received_data, received_ep-1);
562  send_packet_priv(-10, 0, received_data, received_ep+1);
563  }
564 #endif
565 
566  received_ep = 0;
567 }
568 
569 /*bool send_packet(int16_t to, uint8_t* data, uint16_t size)
570 {
571  return send_packet_priv(to, 16, data, size);
572 }*/
573 
574 bool may_send_packet()
575 {
576  return 0 == send_size;
577 }
578 
579 uint8_t get_max_packet_size()
580 {
581  return MAX_PACKET_SIZE;
582 }
583 
584 void register_packet_dispatch(void (*addr)(struct rpc_request* req))
585 {
586  app_dispatch = addr;
587 }
588 
589 /*************************** Host software utilities **************************/
590 
591 int init_board(void)
592 {
593  ubh_impl_init();
594  init_bus();
595 }
596 
597 bool manage_bus()
598 {
599  ubh_impl_wdt_checkpoint();
600  ubh_manage_bus();
601  ubh_impl_wdt_checkpoint();
602 }
603 
604 /********************************** Host tables *******************************/
605 
606 //constants, function pointers
607 
608 //bus address
609 //app start address [default] = 4096
610 
611 void* HOST_TABLE[] =
612 {
613  (void*) register_packet_dispatch,
614  (void*) may_send_packet,
615  (void*) send_packet_priv,
616  (void*) get_max_packet_size,
617  (void*) micros,
618  (void*) manage_bus
619 };
620 
621 
622 
623 __attribute__((section(".host_table"))) void** getHostTable()
624 {
625  return HOST_TABLE;
626 }
627 
628 /********************************** Host Main *********************************/
629 
630 bool afterMicro(uint32_t* last_time, uint32_t timeMicro)
631 {
632  if(*last_time + timeMicro < micros())
633  {
634  *last_time = micros();
635  return true;
636  }
637  return false;
638 }
639 
640 //uint32_t last_panic_signal_time = 0;
641 
642 void busSignalOnline(uint8_t powerOnMode, uint8_t softMode)
643 {
644  uint8_t p[2];
645  p[0] = powerOnMode;
646  p[1] = softMode;
647  send_packet_priv(-1, 0, (uint8_t*) p, sizeof(p));
648 }
649 
650 //boolean bit
651 #define bb(x, y) x?(0x1 <<y):0
652 
653 int main()
654 {
655  reset_flag = ubh_impl_get_power_state();
656  //watchdog reset and not external or power-on
657 
658  app_run = reset_flag != 8;
659 
660  init_board();
661 
662  busSignalOnline
663  (
664  reset_flag,
665 // bb(sos_signal, 2)
666 // |
667  (app_run?2:0)
668  |
669  (ubh_impl_has_app()?1:0)
670  );
671  //srand(micros());
672 
673  #ifdef DEBUG_TIME_AT_BOOT
674 
675  {
676  ubh_impl_set_user_led(1);
677  uint32_t t = micros();
678  while(!afterMicro(&t, 1000000));
679  ubh_impl_set_user_led(0);
680  }
681  #endif
682  //wait a little bit, we might get some instruction from the bus before
683  //entering application mode
684  {
685  uint32_t t = micros();
686  while(!afterMicro(&t, 500000))
687  {
688  ubh_impl_wdt_checkpoint();
689  ubh_manage_bus();
690  }
691  }
692 
693 
694 
695  ubh_impl_wdt_start(true);
696  bool first = true;
697  while(1)
698  {
699  manage_bus();
700 
701  if(app_run && ubh_impl_has_app())
702  {
703  ubh_impl_call_app(first);
704  first = false;
705  }
706  }
707 
708  abort();
709 }
710 
711