Stima V4 Slave RAIN  4.2
canard_class_rain.cpp
Go to the documentation of this file.
1 
31 #include "canard_class_rain.hpp"
32 #include "canard_config.hpp"
33 #include "bxcan.h"
34 
35 // Callback per ISR Routine HAL STM32
38 extern "C" void CAN1_RX0_IRQHandler(void) {
39  #if (ENABLE_CAN)
40  HAL_CAN_IRQHandler(&hcan1);
41  #endif
42 }
43 
44 // ***************** ISR READ RX CAN_BUS, BUFFER RX SETUP ISR, CALLBACK *****************
45 // Gestita come coda FIFO (In sostituzione interrupt bxCAN non funzionante correttamente)
46 extern "C" void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan)
47 {
48  uint8_t testElement = __CAN1_RX0_IRQHandler_PTR->wr_ptr + 1;
49  if(testElement >= CAN_RX_QUEUE_CAPACITY) testElement = 0;
50  // Leggo il messaggio già pronto per libreria CANARD (Frame) e Inserisco in Buffer RX
51  if (bxCANPop(IFACE_CAN_IDX,
52  &__CAN1_RX0_IRQHandler_PTR->msg[testElement].frame.extended_can_id,
53  &__CAN1_RX0_IRQHandler_PTR->msg[testElement].frame.payload_size,
54  __CAN1_RX0_IRQHandler_PTR->msg[testElement].buf)) {
55  if(testElement != __CAN1_RX0_IRQHandler_PTR->rd_ptr) {
56  // Non posso registrare il dato (MAX_QUEUE) se (testElement == _canard_rx_queue.rd_ptr)
57  // raggiunto MAX Buffer. E' più importante non perdere il primo FIFO payload
58  // Quindi non aggiungo il dato ma leggo per svuotare il Buffer FIFO
59  // altrimenti rientro sempre in Interrupt RX e mando in stallo la CPU senza RX...
60  // READ DATA BUFFER MSG ->
61  // Get payload from Buffer (possibilie inizializzazione statica fissa)
62  // Il Buffer non cambia indirizzo quindi basterebbe un'init statico di frame[x].payload
63  __CAN1_RX0_IRQHandler_PTR->msg[testElement].frame.payload =
64  __CAN1_RX0_IRQHandler_PTR->msg[testElement].buf;
65  // Push data in queue (Next_WR, Data in testElement + 1 Element from RX)
66  __CAN1_RX0_IRQHandler_PTR->wr_ptr = testElement;
67  }
68  }
69 }
70 
71 // ********************************************************************************
72 // Contructor Init Class Canard, O1Heap Mem Ptr ISR
73 // ********************************************************************************
74 
77 
78  // CallBack RX Messaggi
80  _attach_rx_callback = false;
81  _attach_param_PTR = NULL;
82 
83  // Sottoscrizioni
85 
86  // Reset master ID all'avvio
87  _master_id = UINT16_MAX;
88 
89  // Init Timing
90  _lastMicros = micros();
93 
94  // Init O1Heap arena base access ram Canard
95  _heap = o1heapInit(_heap_arena, sizeof(_heap_arena));
96  LOCAL_ASSERT(NULL != _heap);
97 
98  // Setup CanardIstance, SET Memory function Allocate, Free and set Canard Mem reference
99  _canard = canardInit(_memAllocate, _memFree);
100  _canard.user_reference = this;
101  _canard.node_id = CANARD_NODE_ID_UNSET;
102 
103  // Interrupt vector CB to Class PTR
104  memset(&_canard_rx_queue, 0, sizeof(_canard_rx_queue));
106 
107  // Init memory (0) per le sotto strutture dati che necessitano un INIT_MEM_RESET
108  memset(&master, 0, sizeof(master));
109  memset(&next_transfer_id, 0, sizeof(next_transfer_id));
110  memset(&flag, 0, sizeof(flag));
111 
112  // Inizializzazioni di sicurezza
114 
115  // Inizializzazioni locali da module_config.h
116  port_id.publisher_module_rain = UINT16_MAX;
117  port_id.service_module_rain = UINT16_MAX;
118 
121 
122  // Configura il trasporto dal registro standard uavcan. Capacità e CANARD_MTU_MAX
123  // I parametri sono fissi e configurabili dal file di configurazione
124  for (uint8_t ifidx = 0; ifidx < CAN_REDUNDANCY_FACTOR; ifidx++) {
125  _canard_tx_queues[ifidx] = canardTxInit(CAN_TX_QUEUE_CAPACITY, CANARD_MTU_MAX);
126  }
127 }
128 
129 // ***************************************************************
130 // Funzioni Timing sincronizzazione e gestione Canard
131 // ***************************************************************
132 
135 CanardMicrosecond canardClass::getMicros() {
136  // Start Syncro o real_time
137  uint32_t ts = micros();
138  if(ts > _lastMicros) {
139  // Standard micosecond successivo
140  _currMicros += (ts - _lastMicros);
141  } else if(ts < _lastMicros) {
142  // Overflow registro microsecond
143  _currMicros += (0xFFFFFFFFul - _lastMicros + 1 + ts);
144  }
145  // Backup current register micro
146  _lastMicros = ts;
147  return _currMicros;
148 }
149 
153 CanardMicrosecond canardClass::getMicros(GetMonotonicTime_Type syncro_type) {
154  // Time sincronizzato o da sincrtonizzare
155  if(syncro_type == start_syncronization) _syncMicros = getMicros();
156  return _syncMicros;
157 }
158 
163  return (uint32_t)(_currMicros / MEGA);
164 }
165 
166 // ***************************************************************************
167 // Gestione Coda messaggi in trasmissione (ciclo di svuotamento messaggi)
168 // ***************************************************************************
169 
175 void canardClass::send(const CanardMicrosecond tx_deadline_usec,
176  const CanardTransferMetadata* const metadata,
177  const size_t payload_size,
178  const void* const payload) {
179  for (uint8_t ifidx = 0; ifidx < CAN_REDUNDANCY_FACTOR; ifidx++) {
180  (void)canardTxPush(&_canard_tx_queues[ifidx],
181  &_canard,
182  _syncMicros + tx_deadline_usec,
183  metadata,
184  payload_size,
185  payload);
186  }
187 }
188 
194 void canardClass::sendResponse(const CanardMicrosecond tx_deadline_usec,
195  const CanardTransferMetadata* const request_metadata,
196  const size_t payload_size,
197  const void* const payload) {
198  CanardTransferMetadata meta = *request_metadata;
199  meta.transfer_kind = CanardTransferKindResponse;
200  send(tx_deadline_usec, &meta, payload_size, payload);
201 }
202 
206  // Transmit pending frames from the prioritized TX queues managed by libcanard.
207  for (uint8_t ifidx = 0; ifidx < CAN_REDUNDANCY_FACTOR; ifidx++)
208  {
209  CanardTxQueue* const que = &_canard_tx_queues[ifidx];
210  const CanardTxQueueItem* tqi = canardTxPeek(que); // Find the highest-priority frame.
211  if(tqi != NULL) return true;
212  }
213  return false;
214 }
215 
219  // Transmit pending frames from the prioritized TX queues managed by libcanard.
220  for (uint8_t ifidx = 0; ifidx < CAN_REDUNDANCY_FACTOR; ifidx++)
221  {
222  CanardTxQueue* const que = &_canard_tx_queues[ifidx];
223  const CanardTxQueueItem* tqi = canardTxPeek(que); // Find the highest-priority frame.
224  while (tqi != NULL)
225  {
226  // Delay Microsecond di sicurezza in Send (Migliora sicurezza RX Pacchetti)
227  // Da utilizzare con CPU poco performanti in RX o con controllo Polling gestito Canard
228  // N.B. Funziona perfettamente con i Nodi ma utilizzando Yakut è comunque necessario un USB/CAN
229  // che utilizzi un'interrupt o molto performanete, altrimenti vengono persi pacchetti in TX
230  // e questo comporta uina perdità dei messaggi RX in ricezione dal nodo (master/slave corrente)
231  #if (CAN_DELAY_US_SEND > 0)
232  delayMicroseconds(CAN_DELAY_US_SEND);
233  #endif
234  // Attempt transmission only if the frame is not yet timed out while waiting in the TX queue.
235  // Otherwise just drop it and move on to the next one.
236  if ((tqi->tx_deadline_usec == 0) || (tqi->tx_deadline_usec > _syncMicros)) {
237  // Non-blocking write attempt.
238  if (bxCANPush(0,
239  _syncMicros,
240  tqi->tx_deadline_usec,
241  tqi->frame.extended_can_id,
242  tqi->frame.payload_size,
243  tqi->frame.payload)) {
244  // Push CAN data
245  _canard.memory_free(&_canard, canardTxPop(que, tqi));
246  tqi = canardTxPeek(que);
247  } else {
248  // Empty Queue
249  break;
250  }
251  } else {
252  // loop continuo per mancato aggiornamento monotonic_time su TIME_OUT
253  // grandi quantità di dati trasmesse e raggiunto il TIMEOUT Subscription...
254  // Remove frame per blocco in timeout BUG trasmission security !!!
255  _canard.memory_free(&_canard, canardTxPop(que, tqi));
256  // Test prossimo pacchetto
257  tqi = canardTxPeek(que);
258  }
259  }
260  }
261 }
262 
263 // ***************************************************************
264 // Gestione Buffer memorizzazione RX BxCAN per Canard metodo FIFO
265 // ***************************************************************
266 
270 }
271 
276 }
277 
283  } else {
285  }
286 }
287 
291 uint8_t canardClass::receiveQueueNextElement(uint8_t currElement) {
292  if(currElement + 1 < CAN_RX_QUEUE_CAPACITY) return currElement + 1;
293  return 0;
294 }
295 
300  // Leggo l'elemento disponibile in coda BUFFER RX FiFo CanardFrame + Buffer
301  uint8_t getElement = receiveQueueNextElement(_canard_rx_queue.rd_ptr);
302  _canard_rx_queue.rd_ptr = getElement;
303  // Passaggio CanardFrame Buffered alla RxAccept CANARD
304  // DeadLine a partire dal realTime assoluto
305  const CanardMicrosecond timestamp_usec = getMicros();
306  CanardRxTransfer transfer;
307  const int8_t canard_result = canardRxAccept(&_canard, timestamp_usec, &_canard_rx_queue.msg[getElement].frame, IFACE_CAN_IDX, &transfer, NULL);
308  if (canard_result > 0) {
309  _attach_rx_callback_PTR(*this, &transfer, _attach_param_PTR);
310  _canard.memory_free(&_canard, (void*) transfer.payload);
311  } else if ((canard_result == 0) || (canard_result == -CANARD_ERROR_OUT_OF_MEMORY)) {
312  (void) 0; // The frame did not complete a transfer so there is nothing to do.
313  // OOM should never occur if the heap is sized correctly. You can track OOM errors via heap API.
314  } else {
315  LOCAL_ASSERT(false); // No other error can possibly occur at runtime.
316  }
317 }
318 
324 void canardClass::receiveQueue(char *logMessage) {
325  // Leggo l'elemento disponibile in coda BUFFER RX FiFo CanardFrame + Buffer
326  uint8_t getElement = receiveQueueNextElement(_canard_rx_queue.rd_ptr);
327  _canard_rx_queue.rd_ptr = getElement;
328  // *****************************************************************************
329  logMessage = itoa(_canard_rx_queue.msg[getElement].frame.payload_size, logMessage, 10);
330  logMessage += 1;
331  strcpy(logMessage, ",Val:");
332  logMessage += 5;
333  for(int iIdxPl=0; iIdxPl<_canard_rx_queue.msg[getElement].frame.payload_size; iIdxPl++) {
334  strcpy(logMessage, " 0x");
335  logMessage += 3;
336  if(_canard_rx_queue.msg[getElement].buf[iIdxPl] < 16) {
337  strcpy(logMessage, "0");
338  logMessage++;
339  strcpy(logMessage, itoa(_canard_rx_queue.msg[getElement].buf[iIdxPl], logMessage, HEX));
340  logMessage++;
341  } else {
342  strcpy(logMessage, itoa(_canard_rx_queue.msg[getElement].buf[iIdxPl], logMessage, HEX));
343  logMessage+=2;
344  }
345  }
346  *logMessage = 0;
347  // *****************************************************************************
348  // Passaggio CanardFrame Buffered alla RxAccept CANARD
349  // DeadLine a partire dal realTime assoluto
350  const CanardMicrosecond timestamp_usec = getMicros();
351  CanardRxTransfer transfer;
352  const int8_t canard_result = canardRxAccept(&_canard, timestamp_usec, &_canard_rx_queue.msg[getElement].frame, IFACE_CAN_IDX, &transfer, NULL);
353  if (canard_result > 0) {
354  _attach_rx_callback_PTR(*this, &transfer, _attach_param_PTR);
355  _canard.memory_free(&_canard, (void*) transfer.payload);
356  } else if ((canard_result == 0) || (canard_result == -CANARD_ERROR_OUT_OF_MEMORY)) {
357  (void) 0; // The frame did not complete a transfer so there is nothing to do.
358  // OOM should never occur if the heap is sized correctly. You can track OOM errors via heap API.
359  } else {
360  LOCAL_ASSERT(false); // No other error can possibly occur at runtime.
361  }
362 }
363 
368 void canardClass::setReceiveMessage_CB(void (*ptrFunction) (canardClass&, const CanardRxTransfer*, void *param), void *param) {
369  _attach_rx_callback_PTR = ptrFunction;
370  _attach_rx_callback = true;
371  _attach_param_PTR = param;
372 }
373 
376  _attach_rx_callback = true;
377 }
378 
381  _attach_rx_callback = false;
382 }
383 
384 // ***************************************************************************
385 // Gestione sottoscrizioni messaggi Canard
386 // ***************************************************************************
387 
395  const CanardTransferKind transfer_kind,
396  const CanardPortID port_id,
397  const size_t extent,
398  const CanardMicrosecond transfer_id_timeout_usec) {
399  // Controllo limiti di sottoscrizioni
400  if(_rxSubscriptionIdx >= MAX_SUBSCRIPTION) return false;
401  // Aggiunge rxSubscription con spazio RAM interna alla classe
402  const int8_t res = canardRxSubscribe(&_canard,
403  transfer_kind,
404  port_id,
405  extent,
406  transfer_id_timeout_usec,
408  return (res>=0);
409 }
410 
415 }
416 
421  const CanardTransferKind transfer_kind,
422  const CanardPortID port_id) {
423  (void)canardRxUnsubscribe(&_canard, transfer_kind, port_id);
424 }
425 
426 // *************************************************************************************
427 // GESTIONE TIME OUT E SERVIZI RETRY ED ALTRE UTILITY FUNZIONI DI CLASSE MASTER REMOTA
428 // *************************************************************************************
429 
434 {
435  // Accedo alla sezione master con il controllo pending locale
436  master.file.start_pending(timeout_us);
437  // Invio la richiesta standard
440 }
441 
447 bool canardClass::send_file_read_block(CanardNodeID server_id, char * fileName, uint64_t remoteOffset)
448 {
449  // FileRead V1.1 Handle Message
450  // ***** Ricezione di file generico dalla rete UAVCAN dal nodo chiamante *****
451  // Richiamo in continuazione rapida la funzione fino al riempimento del file
452  // Alla fine processo il firmware Upload (eventuale) vero e proprio con i relativi check
453  uavcan_file_Read_Request_1_1 remotefile = {0};
454  remotefile.path.path.count = strlen(fileName);
455  memcpy(remotefile.path.path.elements, fileName, remotefile.path.path.count);
456  remotefile.offset = remoteOffset;
457 
458  uint8_t serialized[uavcan_file_Read_Request_1_1_SERIALIZATION_BUFFER_SIZE_BYTES_] = {0};
459  size_t serialized_size = sizeof(serialized);
460  const int8_t err = uavcan_file_Read_Request_1_1_serialize_(&remotefile, &serialized[0], &serialized_size);
461  LOCAL_ASSERT(err >= 0);
462  if (err >= 0)
463  {
464  const CanardTransferMetadata meta = {
465  .priority = CanardPriorityHigh,
466  .transfer_kind = CanardTransferKindRequest,
467  .port_id = uavcan_file_Read_1_1_FIXED_PORT_ID_,
468  .remote_node_id = server_id,
469  .transfer_id = (CanardTransferID) (next_transfer_id.uavcan_file_read_data()),
470  };
471  // Messaggio standard ad un secondo dal timeStamp Sincronizzato
472  send(MEGA, &meta, serialized_size, &serialized[0]);
473  return true;
474  }
475  return false;
476 }
477 
478 // *******************************************************************************
479 // GESTIONE TIME OUT E SERVIZI RETRY ED ALTRE UTILITY FUNZIONI DI CLASSE MASTER
480 // *******************************************************************************
481 
482 // ******************************** HEART BEAT ***********************************
483 
484 // ******************************** HEART BEAT ***********************************
485 
489 bool canardClass::master::heartbeat::is_online(bool is_heart_syncronized) {
490  // ? Out of TIME Max (Sempre false)
491  if (_syncMicros < _timeout_us) {
492  // Richiedo Internal HeartBeat Area check ? (Possibile syncro HeartBeat Locale...)
493  // Altrimenti la richiesta ha già esito positivo
494  if(is_heart_syncronized) {
495  // ? Siamo all'interno del tempo di HeartBeat Max (x1.5)
496  if ((_syncMicros - _mastMicros) < MEGA * (TIME_PUBLISH_HEARTBEAT * 1.5)) {
497  // Reset (Wait Next Syncro Master...)
499  return true;
500  }
501  else return false;
502  }
503  else return true;
504  }
505  else return false;
506 }
507 
510 void canardClass::master::heartbeat::set_online(uint32_t dead_line_us) {
511  _timeout_us = _syncMicros + dead_line_us;
513 }
514 
517  return _mastMicros;
518 }
519 
520 // ******************************** TIME STAMP ***********************************
521 
527  CanardMicrosecond previous_tx_timestamp_us) {
528  // Controllo coerenza messaggio per consentire l'aggiornamento timestamp
529  // 1) Sequenza di transfer_id con previous
530  // 2) differenza di tempo tra due timestamp remoti inferiore al massimo timeOut impostato di controllo
531  if((++_previous_transfer_id == current_transfer_id) &&
532  ((previous_tx_timestamp_us - _previous_msg_monotonic_us) < MASTER_MAXSYNCRO_VALID_US))
533  // Riferimento locale
534  return true;
535  // Risincronizzo il transferID Corretto per sicurezza
536  _previous_transfer_id = current_transfer_id;
537  return false;
538 }
539 
544 CanardMicrosecond canardClass::master::timestamp::get_timestamp_syncronized(CanardMicrosecond current_rx_timestamp_us,
545  CanardMicrosecond previous_tx_timestamp_us) {
546  // Save timestamp variabili per SET e controllo Time nella successiva chiamata time_syncronization
547  // Local RealTime RX timestamp monotonic locale al tempo reale di rx_message (transfer->timestamp_usec)
548  _syncronized_timestamp_us = previous_tx_timestamp_us + current_rx_timestamp_us - _previous_local_timestamp_us;
549  // Aggiusto e sommo la differenza tra il timestamp reale del messaggio ricevuto con il monotonic reale attuale (al tempo di esecuzione syncro real)
550  _previous_syncronized_timestamp_us = getMicros();
551  _syncronized_timestamp_us += (_previous_syncronized_timestamp_us - current_rx_timestamp_us);
552  return _syncronized_timestamp_us;
553 }
554 
560  CanardMicrosecond realtime_us = getMicros();
561  CanardMicrosecond diff_synconized_us = realtime_us - _previous_syncronized_timestamp_us;
562  _previous_syncronized_timestamp_us = realtime_us;
563  _syncronized_timestamp_us += diff_synconized_us;
564  return _syncronized_timestamp_us;
565 }
566 
571 CanardMicrosecond canardClass::master::timestamp::update_timestamp_message(CanardMicrosecond current_rx_timestamp_us,
572  CanardMicrosecond previous_tx_timestamp_us) {
573  // Differenza tra due messaggi in microsecondi
574  CanardMicrosecond difference_timestamp_us = previous_tx_timestamp_us - _previous_msg_monotonic_us;
575  // Save timestamp variabili per SET e controllo Time nella successiva chiamata time_syncronization
576  // Local RealTime RX timestamp monotonic locale al tempo reale di rx_message (transfer->timestamp_usec)
577  _previous_local_timestamp_us = current_rx_timestamp_us;
578  // RealTime callBack message RX (TX RTC uSec(Canard type) Master Remoto al tempo di send)
579  _previous_msg_monotonic_us = previous_tx_timestamp_us;
580  return difference_timestamp_us;
581 }
582 
583 // ******************************** FILE CLIENT ***********************************
584 
590 void canardClass::master::file::start_request(uint8_t remote_node, uint8_t *param_request_name,
591  uint8_t param_request_len, bool is_firmware) {
592  _node_id = remote_node;
593  // Copio la stringa nel name file firmware disponibile su state generale (per download successivo)
594  memcpy(_filename, param_request_name, param_request_len);
595  _filename[param_request_len] = '\0';
596  // Init varaiabili di download
597  _is_firmware = is_firmware;
598  _updating = true;
599  _updating_eof = false;
600  // Start Offset File
601  _offset = 0;
602  _updating_retry = 0;
603  // Set first pending
604  _timeout_us = _syncMicros + NODE_GETFILE_TIMEOUT_US;
605 }
606 
610  return _filename;
611 }
612 
616  return _node_id;
617 }
618 
622  return _updating;
623 }
624 
629  return _updating_eof;
630 }
631 
635  _updating = false;
636  _node_id = CANARD_NODE_ID_UNSET;
637 }
638 
642 {
643  // Riferimento locale
644  return _is_firmware;
645 }
646 
650  return _offset;
651 }
652 
655 void canardClass::master::file::set_offset_rx(uint64_t remote_file_offset) {
656  _offset = remote_file_offset;
657 }
658 
662  return _offset == 0;
663 }
664 
669  if (++_updating_retry > NODE_GETFILE_MAX_RETRY) _updating_retry = NODE_GETFILE_MAX_RETRY;
670  // Reset pending state
671  _is_pending = false;
672  return _updating_retry < NODE_GETFILE_MAX_RETRY;
673 }
674 
679 bool canardClass::master::file::next_retry(uint8_t *avaiable_retry) {
680  if (++_updating_retry > NODE_GETFILE_MAX_RETRY) _updating_retry = NODE_GETFILE_MAX_RETRY;
681  *avaiable_retry = NODE_GETFILE_MAX_RETRY - _updating_retry;
682  // Reset pending state
683  _is_pending = false;
684  return _updating_retry < NODE_GETFILE_MAX_RETRY;
685 }
686 
690 {
691  // Riferimento locale
692  _is_pending = true;
693  _timeout_us = _syncMicros + timeout_us;
694 }
695 
698 {
699  _is_pending = false;
700  // Azzero contestualmente le retry di controllo x gestione MAX_RETRY -> ABORT
701  _updating_retry = 0;
702 }
703 
707 {
708  _is_pending = false;
709  // Azzero contestualmente le retry di controllo x gestione MAX_RETRY -> ABORT
710  _updating_retry = 0;
711  // Gestisco internamente l'offset di RX File
712  _offset += message_len;
713  // Overload per controllo EOF (se lunghezza messaggio != MAX_ARRAY_UAVCAN ... 2\6 Bytes)
714  _updating_eof = (message_len != uavcan_primitive_Unstructured_1_0_value_ARRAY_CAPACITY_);
715 }
716 
720 {
721  if(_is_pending) return _syncMicros > _timeout_us;
722  return false;
723 }
724 
728 {
729  return _is_pending;
730 }
731 
732 // ***********************************************************************************
733 // GESTIONE TIME OUT E SERVIZI RETRY ED ALTRE UTILITY FUNZIONI DI CLASSE LOCALE SLAVE
734 // ***********************************************************************************
735 
739 {
740  // ***** Trasmette alla rete UAVCAN lo stato haeartbeat del modulo *****
741  // Heartbeat Fisso anche per modulo Master (Visibile a yakut o altri tools/script gestionali)
742  uavcan_node_Heartbeat_1_0 heartbeat = {0};
743  heartbeat.uptime = getUpTimeSecond();
744  const O1HeapDiagnostics heap_diag = _memGetDiagnostics();
745  if (heap_diag.oom_count > 0) {
746  heartbeat.health.value = uavcan_node_Health_1_0_CAUTION;
747  } else {
748  heartbeat.health.value = uavcan_node_Health_1_0_NOMINAL;
749  }
750  // Stato di heartbeat gestito dalla classe
751  heartbeat.vendor_specific_status_code = flag.get_local_value_heartbeat_VSC();
752  heartbeat.mode.value = flag.get_local_node_mode();
753  // Trasmetto il pacchetto
754  uint8_t serialized[uavcan_node_Heartbeat_1_0_SERIALIZATION_BUFFER_SIZE_BYTES_] = {0};
755  size_t serialized_size = sizeof(serialized);
756  const int8_t err = uavcan_node_Heartbeat_1_0_serialize_(&heartbeat, &serialized[0], &serialized_size);
757  LOCAL_ASSERT(err >= 0);
758  if (err >= 0) {
759  const CanardTransferMetadata meta = {
760  .priority = CanardPriorityNominal,
761  .transfer_kind = CanardTransferKindMessage,
762  .port_id = uavcan_node_Heartbeat_1_0_FIXED_PORT_ID_,
763  .remote_node_id = CANARD_NODE_ID_UNSET,
764  .transfer_id = (CanardTransferID)(next_transfer_id.uavcan_node_heartbeat()),
765  };
766  // Messaggio standard ad un secondo dal timeStamp Sincronizzato
767  send(MEGA, &meta, serialized_size, &serialized[0]);
768  return true;
769  }
770  return false;
771 }
772 
775 bool canardClass::slave_pnp_send_request(uint64_t serial_number) {
776  // PnP over Classic CAN, use message v1.0.
777  uavcan_pnp_NodeIDAllocationData_1_0 msg = {0};
778  // truncated uint48 unique_id_hash
779  // msg.allocated_node_id.(count/element) => Solo in response non in request;
780  msg.unique_id_hash = serial_number >> HASH_EXCLUDING_BIT;
781  msg.unique_id_hash &= HASH_SERNUMB_MASK;
782  msg.unique_id_hash |= MODULE_TYPE;
783  uint8_t serialized[uavcan_pnp_NodeIDAllocationData_1_0_SERIALIZATION_BUFFER_SIZE_BYTES_] = {0};
784  size_t serialized_size = sizeof(serialized);
785  const int8_t err = uavcan_pnp_NodeIDAllocationData_1_0_serialize_(&msg, &serialized[0], &serialized_size);
786  LOCAL_ASSERT(err >= 0);
787  if (err >= 0) {
788  const CanardTransferMetadata meta = {
789  .priority = CanardPrioritySlow,
790  .transfer_kind = CanardTransferKindMessage,
791  .port_id = uavcan_pnp_NodeIDAllocationData_1_0_FIXED_PORT_ID_,
792  .remote_node_id = CANARD_NODE_ID_UNSET,
793  .transfer_id = (CanardTransferID) (next_transfer_id.uavcan_pnp_allocation()),
794  };
795  // Messaggio standard ad un secondo dal timeStamp Sincronizzato
796  send(MEGA, &meta, serialized_size, &serialized[0]);
797  return true;
798  }
799  return false;
800 }
801 
805 void canardClass::_fillSubscriptions(const CanardTreeNode* const tree, uavcan_node_port_SubjectIDList_0_1* const obj)
806 {
807  if (NULL != tree) {
808  _fillSubscriptions(tree->lr[0], obj);
809  const CanardRxSubscription* crs = (const CanardRxSubscription*)tree;
810  if (crs->port_id <= CANARD_SUBJECT_ID_MAX) {
811  LOCAL_ASSERT(obj->sparse_list.count < uavcan_node_port_SubjectIDList_0_1_sparse_list_ARRAY_CAPACITY_);
812  obj->sparse_list.elements[obj->sparse_list.count++].value = crs->port_id;
813  _fillSubscriptions(tree->lr[1], obj);
814  }
815  }
816 }
817 
821 void canardClass::_fillServers(const CanardTreeNode* const tree, uavcan_node_port_ServiceIDList_0_1* const obj)
822 {
823  if (NULL != tree) {
824  _fillServers(tree->lr[0], obj);
825  const CanardRxSubscription* crs = (const CanardRxSubscription*)tree;
826  if (crs->port_id <= CANARD_SERVICE_ID_MAX) {
827  (void)nunavutSetBit(&obj->mask_bitpacked_[0], sizeof(obj->mask_bitpacked_), crs->port_id, true);
828  _fillServers(tree->lr[1], obj);
829  }
830  }
831 }
832 
836 {
837  // Publish the recommended (not required) port introspection message. No point publishing it if we're anonymous.
838  // The message is a bit heavy on the stack (about 2 KiB) but this is not a problem for a modern MCU.
839  // L'abilitazione del comando è facoltativa, può essere attivata/disattivata da un comando UAVCAN
841  (_canard.node_id <= CANARD_NODE_ID_MAX))
842  {
843  uavcan_node_port_List_0_1 m = {0};
844  uavcan_node_port_List_0_1_initialize_(&m);
845  uavcan_node_port_SubjectIDList_0_1_select_sparse_list_(&m.publishers);
846  uavcan_node_port_SubjectIDList_0_1_select_sparse_list_(&m.subscribers);
847 
848  // Indicate which subjects we publish to. Don't forget to keep this updated if you add new publications!
849  {
850  size_t* const cnt = &m.publishers.sparse_list.count;
851  m.publishers.sparse_list.elements[(*cnt)++].value = uavcan_node_Heartbeat_1_0_FIXED_PORT_ID_;
852  m.publishers.sparse_list.elements[(*cnt)++].value = uavcan_node_port_List_0_1_FIXED_PORT_ID_;
853  // Aggiungo i publisher interni validi privati (quando abilitati)
854  if ((port_id.publisher_module_rain <= CANARD_SUBJECT_ID_MAX)&&
856  {
857  m.publishers.sparse_list.elements[(*cnt)++].value = port_id.publisher_module_rain;
858  }
859  }
860 
861  // Indicate which servers and subscribers we implement.
862  // We could construct the list manually but it's easier and more robust to just query libcanard for that.
863  _fillSubscriptions(_canard.rx_subscriptions[CanardTransferKindMessage], &m.subscribers);
864  _fillServers(_canard.rx_subscriptions[CanardTransferKindRequest], &m.servers);
865  _fillServers(_canard.rx_subscriptions[CanardTransferKindResponse], &m.clients); // For regularity.
866 
867  // Serialize and publish the message. Use a small buffer because we know that our message is always small.
868  // Verificato massimo utilizzo a 156 bytes. Limitiamo il buffer a 256 Bytes (Come esempio UAVCAN)
869  uint8_t serialized[256] = {0};
870  size_t serialized_size = uavcan_node_port_List_0_1_SERIALIZATION_BUFFER_SIZE_BYTES_;
871  if (uavcan_node_port_List_0_1_serialize_(&m, &serialized[0], &serialized_size) >= 0)
872  {
873  const CanardTransferMetadata meta = {
874  .priority = CanardPriorityOptional, // Mind the priority.
875  .transfer_kind = CanardTransferKindMessage,
876  .port_id = uavcan_node_port_List_0_1_FIXED_PORT_ID_,
877  .remote_node_id = CANARD_NODE_ID_UNSET,
878  .transfer_id = (CanardTransferID) (next_transfer_id.uavcan_node_port_list()),
879  };
880  // Send a 2 secondi
881  send(MEGA * 2, &meta, serialized_size, &serialized[0]);
882  return true;
883  }
884  }
885  return false;
886 }
887 
888 // ***************************************************************
889 // ID di Trasferimento UAVCAN Canard
890 // ***************************************************************
891 
896 }
897 
902 }
903 
908 }
909 
914 }
915 
920 }
921 
922 // ***************************************************************
923 // Funzioni ed Utility Canard su Local Flag
924 // ***************************************************************
925 
926 // ******** COMMAND REMOTI E Stati gestionali ********
927 
930  _restart_required = true;
931 }
932 
936  return _restart_required;
937 }
938 
941  // Con inibizione, non permetto lo sleep del modulo
942  if(_inibith_sleep) return;
943  // Eseguo la procedura di messa in sleep del modulo
944  // Variabili, HW CAN ecc... alla fine setto la var di entrata in sleep
945  _enter_sleep = true;
946 }
947 
951  return _enter_sleep;
952 }
953 
956  _inibith_sleep = true;
957 }
958 
961  _inibith_sleep = false;
962 }
963 
964 // ******** HEARTBEAT Vendor Status Code ********
965 // Set VendorStatusCode per Heratbeat in RX/TX al modulo Master/Slave
966 
971  _heartLocalVSC.powerMode = powerMode;
972 }
973 
977  _heartLocalVSC.fwUploading = fwUploading;
978 }
979 
983  _heartLocalVSC.dataReady = dataReady;
984 }
985 
989  _heartLocalVSC.moduleReady = moduleReady;
990 }
991 
995  _heartLocalVSC.moduleError = moduleError;
996 }
997 
1001  return _heartLocalVSC.powerMode;
1002 }
1003 
1007  return _heartLocalVSC.fwUploading;
1008 }
1009 
1013  return _heartLocalVSC.dataReady;
1014 }
1015 
1019  return _heartLocalVSC.moduleReady;
1020 }
1021 
1025  return _heartLocalVSC.moduleError;
1026 }
1027 
1031  return _heartLocalVSC.uint8_val;
1032 }
1033 
1034 // Funzioni Locali per gestione interna NODE MODE x HeartBeat standard UAVCAN
1035 
1038 void canardClass::flag::set_local_node_mode(uint8_t heartLocalMODE) {
1039  _heartLocalMODE = heartLocalMODE;
1040 }
1041 
1045  return _heartLocalMODE;
1046 }
1047 
1048 // ***************************************************************
1049 // Funzioni ed Utility di Classe Generali
1050 // ***************************************************************
1051 
1054 void canardClass::set_canard_node_id(CanardNodeID local_id) {
1055  // Istanza del modulo canard
1056  _canard.node_id = local_id;
1057 }
1058 
1062  // Istanza del modulo canard
1063  return _canard.node_id;
1064 }
1065 
1069  // Istanza del modulo canard
1070  return _canard.node_id > CANARD_NODE_ID_MAX;
1071 }
1072 
1075 void canardClass::set_canard_master_id(CanardNodeID remote_id) {
1076  // Istanza del modulo canard
1077  _master_id = remote_id;
1078 }
1079 
1083  // Istanza del modulo canard
1084  return _master_id;
1085 }
1086 
1087 // ***************************************************************
1088 // Wrapper C++ O1Heap memory Access & Function CB Private
1089 // ***************************************************************
1090 
1095 void* canardClass::_memAllocate(CanardInstance* const ins, const size_t amount) {
1096  O1HeapInstance* const heap = ((canardClass*)ins->user_reference)->_heap;
1097  LOCAL_ASSERT(o1heapDoInvariantsHold(heap));
1098  return o1heapAllocate(heap, amount);
1099 }
1100 
1104 void canardClass::_memFree(CanardInstance* const ins, void* const pointer) {
1105  O1HeapInstance* const heap = ((canardClass*)ins->user_reference)->_heap;
1106  o1heapFree(heap, pointer);
1107 }
1108 
1111 O1HeapDiagnostics canardClass::_memGetDiagnostics(void) {
1112  return o1heapGetDiagnostics(_heap);
1113 }
canardClass::CanardRxQueue * __CAN1_RX0_IRQHandler_PTR
ISR di sistema CAN1_RX0_IRQHandler HAL_CAN_IRQHandler STM32.
void CAN1_RX0_IRQHandler(void)
void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan)
Uavcan Canard Class LibCanard, bxCan, o1Heap.
Uavcan Canard Configuration file.
#define IFACE_CAN_IDX
#define NODE_GETFILE_MAX_RETRY
#define TIME_PUBLISH_HEARTBEAT
#define NODE_GETFILE_TIMEOUT_US
#define MASTER_MAXSYNCRO_VALID_US
#define MEGA
#define DEFAULT_PUBLISH_PORT_LIST
#define HASH_SERNUMB_MASK
#define CAN_RX_QUEUE_CAPACITY
#define CAN_DELAY_US_SEND
#define CAN_TX_QUEUE_CAPACITY
#define LOCAL_ASSERT
#define HASH_EXCLUDING_BIT
#define MAX_SUBSCRIPTION
#define DEFAULT_PUBLISH_MODULE_DATA
#define CAN_REDUNDANCY_FACTOR
bool get_local_data_ready(void)
Proprietà GET per il valore VendorStatusCode di Heartbeat e per gli utilizzi locali.
void set_local_power_mode(Power_Mode powerMode)
Proprietà SET per il valore VendorStatusCode di Heartbeat e per gli utilizzi locali La proprietà è im...
void set_local_fw_uploading(bool fwUploading)
Proprietà SET per il valore VendorStatusCode di Heartbeat e per gli utilizzi locali.
Power_Mode get_local_power_mode(void)
Proprietà GET per il valore VendorStatusCode di Heartbeat e per gli utilizzi locali.
void set_local_data_ready(bool dataReady)
Proprietà SET per il valore VendorStatusCode di Heartbeat e per gli utilizzi locali.
void disable_sleep(void)
Permetto l'attivazione sleep, funzioni ed hardware, del modulo.
uint8_t get_local_node_mode(void)
Ritorna la modalità node mode locale standard UAVCAN per la gestione heartbeat.
void set_local_node_mode(uint8_t heartLocalMODE)
Imposta la modalità nodo standard UAVCAN, gestita nelle funzioni heartbeat.
bool get_local_module_error(void)
Proprietà GET per il valore VendorStatusCode di Heartbeat e per gli utilizzi locali.
bool is_requested_system_restart(void)
Verifica una richiesta di riavvio del sistema standard UAVCAN.
void set_local_module_ready(bool moduleReady)
Proprietà SET per il valore VendorStatusCode di Heartbeat e per gli utilizzi locali.
void set_local_module_error(bool moduleError)
Proprietà SET per il valore VendorStatusCode di Heartbeat e per gli utilizzi locali.
uint8_t get_local_value_heartbeat_VSC(void)
Proprietà GET per il valore VendorStatusCode di Heartbeat e per gli utilizzi locali.
void enable_sleep(void)
Inibisce l'attivazione sleep, funzioni ed hardware, del modulo.
bool get_local_fw_uploading(void)
Proprietà GET per il valore VendorStatusCode di Heartbeat e per gli utilizzi locali.
bool is_module_sleep(void)
Verifica se attiva la funzione dello sleep del modulo Canard e hardware relativo.
bool get_local_module_ready(void)
Proprietà GET per il valore VendorStatusCode di Heartbeat e per gli utilizzi locali.
void request_sleep(void)
Avvia la richiesta di sleep del modulo. Da chiamare prima di attivare il basso consumo generale.
void request_system_restart(void)
Avvia una richiesta standard UAVCAN per il riavvio del sistema.
CanardNodeID get_server_node(void)
Legge il nodo master file server che richiede il caricamento del file.
uint64_t get_offset_rx(void)
Legge l'offset corrente.
bool download_request(void)
Gestione file, verifica richiesta di download da un nodo remoto.
char * get_name(void)
Nome del file in download.
bool event_timeout(void)
Gestione timeout pending file. Controlla il raggiungimento del timeout.
bool is_pending(void)
Verifica se un comando per il relativo modulo è in attesa. Diventerà false o verrà attivato il timeou...
bool is_first_data_block(void)
Verifica se è il primo blocco di un file. Da utilizzare per rewrite file o init E2Prom Space.
void set_offset_rx(uint64_t remote_file_offset)
Imposta l'offset RX per la lettura di un blocco specifico del file in donload remoto.
void start_pending(uint32_t timeout_us)
Avvia un comando per il metodo corrente con timeOut di validità
void download_end(void)
Gestione file, abbandona o termina richiesta di download da un nodo remoto. Il nodo non risponde più ...
bool is_firmware(void)
Controlla se il file è di tipo firmware o altra tipologia.
void reset_pending(void)
Resetta lo stato dei flag pending per il metodo corrente.
bool next_retry(void)
Gestione automatica totale retry del comando file all'interno della classe MAX retry è gestito nel fi...
bool is_download_complete(void)
Gestione file, fine con successo del download file da un nodo remoto. Il nodo non risponde più alle r...
void start_request(uint8_t remote_node, uint8_t *param_request_name, uint8_t param_request_len, bool is_firmware)
Avvia una richiesta remota di download file ed inizializza le risorse nella classe.
void set_online(uint32_t dead_line_us)
Imposta il nodo OnLine, richiamato in heartbeat o altre comunicazioni client.
CanardMicrosecond last_online(void)
Imposta il nodo OnLine, richiamato in heartbeat o altre comunicazioni client.
bool is_online(bool is_heart_syncronized)
Controlla se il modulo master è online.
bool check_valid_syncronization(uint8_t current_transfer_id, CanardMicrosecond previous_tx_timestamp_us)
Controlla se messaggio valido (coerenza sequenza e validità di time_stamp)
CanardMicrosecond update_timestamp_message(CanardMicrosecond current_rx_timestamp_us, CanardMicrosecond previous_tx_timestamp_us)
Aggiorna i time stamp della classe sul messaggio standard UAVCAN per le successive sincronizzazioni.
CanardMicrosecond get_timestamp_syncronized()
Legge il tempo sincronizzato dal master, in Overload, regolato sui microsecondi locali a partire dall...
class canardClass::master::file file
class canardClass::master::heartbeat heartbeat
uint8_t uavcan_node_heartbeat(void)
Gestione transfer ID UAVCAN per la classe relativa.
uint8_t uavcan_pnp_allocation(void)
Gestione transfer ID UAVCAN per la classe relativa.
uint8_t uavcan_file_read_data(void)
Gestione transfer ID UAVCAN per la classe relativa.
uint8_t module_rain(void)
Gestione transfer ID UAVCAN per la classe relativa.
uint8_t uavcan_node_port_list(void)
Gestione transfer ID UAVCAN per la classe relativa.
CanardPortID publisher_module_rain
CanardPortID service_module_rain
static uint32_t _lastMicros
canardClass()
Contruttore della classe Canard.
void rxUnSubscribe(const CanardTransferKind transfer_kind, const CanardPortID port_id)
Rimozione di una sottoscrizione di una funzione Canard.
bool master_file_read_block_pending(uint32_t timeout_us)
Avvia la richiesta di un blocco file contiguo al file_server tramite classe e controllo Master.
void(* _attach_rx_callback_PTR)(canardClass &, const CanardRxTransfer *, void *)
CanardNodeID get_canard_node_id(void)
Legge l'ID Nodo locale per l'istanza Canard privata della classe Canard.
static CanardMicrosecond getMicros()
Get MonotonicTime Interno realTime.
void send(CanardMicrosecond tx_deadline_usec, const CanardTransferMetadata *const metadata, const size_t payload_size, const void *const payload)
Send messaggio Canard con daeadline del tempo sincronizzato.
bool slave_heartbeat_send_message(void)
Invia il messaggio di HeartBeat ai nodi remoti.
static uint64_t _mastMicros
void set_canard_node_id(CanardNodeID local_id)
Imposta l'ID Nodo locale per l'istanza Canard privata della classe Canard.
void _fillSubscriptions(const CanardTreeNode *const tree, uavcan_node_port_SubjectIDList_0_1 *const obj)
Prepara la lista delle sottoscrizioni Canard (privata)
CanardNodeID _master_id
CanardInstance _canard
void receiveQueue(void)
Gestione metodo ricezione coda messaggi dal buffer FIFO preparato di BxCAN Il buffer gestito nella IS...
CanardTxQueue _canard_tx_queues[CAN_REDUNDANCY_FACTOR]
static uint64_t _syncMicros
void _fillServers(const CanardTreeNode *const tree, uavcan_node_port_ServiceIDList_0_1 *const obj)
Prepara la lista dei servizi Canard (privata)
void setReceiveMessage_CB(void(*ptrFunction)(canardClass &, const CanardRxTransfer *, void *), void *param)
Setta il CallBack Function per il processo esterno di interprete su messaggio ricevuto e conforme a C...
uint8_t receiveQueueNextElement(uint8_t currElement)
Ritorna il prossimo elemento del buffer.
void transmitQueue(void)
Trasmette la coda con timeStamp sincronizzato. Per inviare con real_time va aggiornata la sincronizza...
void receiveQueueEmpty(void)
Azzera il buffer di ricezione dati collegato a BxCAN e ISR Interrupt.
uint8_t receiveQueueElement(void)
Ritorna l'elemento corrente del buffer di BxCAN, pronto ad essere gestito con Canard.
CanardRxSubscription _rxSubscription[MAX_SUBSCRIPTION]
bool slave_servicelist_send_message(void)
Invia il messaggio dei servizi attivi ai nodi remoti.
bool is_canard_node_anonymous(void)
Controlla se il nodo è anonimo (senza ID Impostato)
void sendResponse(const CanardMicrosecond tx_deadline_usec, const CanardTransferMetadata *const request_metadata, const size_t payload_size, const void *const payload)
Send risposta al messaggio Canard con daeadline del tempo sincronizzato.
static void * _memAllocate(CanardInstance *const ins, const size_t amount)
Gestione O1Heap Memory Canard Allocate.
bool slave_pnp_send_request(uint64_t serial_number)
Invia il messaggio di PNP request (richiesta di node_id valido) al nodo server PNP (master)
CanardRxQueue _canard_rx_queue
CanardNodeID get_canard_master_id(void)
Get master node id for local set and flag operation automatic (sleep, power...)
bool send_file_read_block(CanardNodeID server_id, char *fileName, uint64_t remoteOffset)
Avvia la richiesta di un blocco file contiguo al file_server con ID Fisico.
void set_canard_master_id(CanardNodeID remote_id)
Set node master ID (slave respond to RMAP command and flag with master ID)
void disableReceiveMessage_CB(void)
Disabilita il CallBack Function Canard RX Message CanardRxAccept.
static uint32_t getUpTimeSecond(void)
Ritorna i secondi dall'avvio Canard per UpTime in (in formato 64 BIT necessario per UAVCAN) Non perme...
bool transmitQueueDataPresent(void)
Test coda presenza dati in trasmissione di Canard.
O1HeapDiagnostics _memGetDiagnostics(void)
Diagnostica Heap Data per Heartbeat e/o azioni interne.
bool rxSubscribe(const CanardTransferKind transfer_kind, const CanardPortID port_id, const size_t extent, const CanardMicrosecond transfer_id_timeout_usec)
Sottoscrizione di una funzione Canard.
uint8_t rxSubscriptionAvaiable(void)
Ritorna il numero di sottoscrizioni ancora disponibili.
O1HeapInstance * _heap
void enableReceiveMessage_CB(void)
Abilita il CallBack Function Canard RX Message CanardRxAccept.
uint8_t _rxSubscriptionIdx
bool receiveQueueDataPresent(void)
Ritorna true se ci sono dati utili da gestire dal buffer di RX per BxCAN.
static void _memFree(CanardInstance *const ins, void *const pointer)
Gestione O1Heap Memory Canard Free.
static uint64_t _currMicros
#define MODULE_TYPE
Type of module. It is defined in registers.h.
Definition: config.h:55
Power_Mode
Power mode (Canard and general Node)
Definition: local_typedef.h:31
Interface STM32 hardware_hal STIMAV4 Header config.
CAN_HandleTypeDef hcan1
struct canardClass::CanardRxQueue::msg msg[CAN_RX_QUEUE_CAPACITY]