Stima V4 Slave RAIN  4.2
register_class.cpp
Go to the documentation of this file.
1 
30 #include "register_class.hpp"
31 #include "canard_config.hpp"
32 
33 #include "config.h"
34 #include "stima_utility.h"
35 
36 #include <stdbool.h>
37 #include <stdio.h>
38 #include <stdlib.h>
39 
40 #define PASTE3_IMPL(x, y, z) x##y##z
41 #define PASTE3(x, y, z) PASTE3_IMPL(x, y, z)
42 
43 // ***************************************************************************************
44 // E2PROM STIMAV4 STM32 ARDUINO REGISTER CLASS ACCESS
45 // ***************************************************************************************
46 
49 {
50 }
55 EERegister::EERegister(TwoWire *wire, BinarySemaphore *wireLock, uint8_t i2c_address)
56 {
57  // Memory controller for ClassRegister
58  _Eprom = EEprom(wire, wireLock);
59 }
60 
65 void EERegister::_memory_write_block(uint16_t address, uint8_t *data, uint8_t len) {
66  _Eprom.Write(address, data, len);
67 }
68 
73 void EERegister::_memory_read_block(uint16_t address, uint8_t *data, uint8_t len) {
74  _Eprom.Read(address, data, len);
75 }
76 
80 void EERegister::_memory_write_byte(uint16_t address, uint8_t data) {
81  _Eprom.Write(address, data);
82 }
83 
87 void EERegister::_memory_read_byte(uint16_t address, uint8_t *data) {
88  _Eprom.Read(address, data);
89 }
90 
93  uint8_t register_index[MEM_UAVCAN_MAX_REG];
94  // Scrivo in un unica tornata
95  memset(register_index, MEM_UAVCAN_REG_UNDEF, MEM_UAVCAN_MAX_REG);
97 }
98 
101 void EERegister::_eeprom_register_clear(uint8_t reg_numb) {
102  // Controllo area register
103  if(reg_numb<MEM_UAVCAN_MAX_REG)
105 }
106 
113 size_t EERegister::_eeprom_register_get_fast(uint8_t reg_numb, uint8_t *reg_name, uint8_t *reg_value) {
114  uint8_t read_block[MEM_UAVCAN_LEN_REG];
115  uint8_t reg_valid = MEM_UAVCAN_REG_UNDEF;
116  uint8_t data_len;
117  uint8_t name_len;
118  // Leggo il blocco in un unica read
120  // Ritorno i campi name e value corretti
121  name_len = read_block[MEM_UAVCAN_POS_LEN_NAME];
122  data_len = read_block[MEM_UAVCAN_POS_LEN_DATA];
123  memcpy(reg_name, &read_block[MEM_UAVCAN_POS_STR_NAME], name_len);
124  memcpy(reg_value, &read_block[MEM_UAVCAN_POS_VALUE_DATA], data_len);
125  return (size_t)data_len;
126 }
127 
133  uint8_t name_len;
134  // Registro eeprom valido, ritorno i campi name e value
135  _memory_read_byte(MEM_UAVCAN_GET_ADDR_NAME_LEN(reg_numb), &name_len);
136  return (size_t)name_len;
137 }
138 
144 void EERegister::_eeprom_register_get_intest_fast(uint8_t reg_numb, uint8_t *reg_name, uint8_t name_len) {
145  // Registro eeprom valido, ritorno i campi name e value
146  _memory_read_block(MEM_UAVCAN_GET_ADDR_NAME(reg_numb), reg_name, name_len);
147 }
148 
153 bool EERegister::_eeprom_register_get_name_from_index(uint8_t reg_numb, uint8_t *reg_name) {
154  uint8_t reg_valid = MEM_UAVCAN_REG_UNDEF;
155  uint8_t len_name;
156  // Controllo area register
157  if(reg_numb>=MEM_UAVCAN_MAX_REG) return false;
158  // Leggo l'indice se impostato (registro valido)
159  _memory_read_byte(MEM_UAVCAN_GET_ADDR_FLAG_REG(reg_numb), &reg_valid);
160  if(reg_valid == reg_numb) {
161  // Registro eeprom valido, ritorno i campi name e value
162  _memory_read_byte(MEM_UAVCAN_GET_ADDR_NAME_LEN(reg_numb), &len_name);
163  _memory_read_block(MEM_UAVCAN_GET_ADDR_NAME(reg_numb), reg_name, len_name);
164  return true;
165  }
166  // Registro non impostato correttamente
167  return false;
168 }
169 
175 size_t EERegister::_eeprom_register_get_from_name(uint8_t const *reg_name, uint8_t *reg_numb, uint8_t *data) {
176  uint8_t _reg_name[MEM_UAVCAN_LEN_NAME_REG];
177  uint8_t _reg_data[MEM_UAVCAN_LEN_VALUE_REG];
178  uint8_t _len_name = strlen((char*)reg_name);
179  size_t _len_data = 0;
180  uint8_t register_index[MEM_UAVCAN_MAX_REG];
181  // Leggo l'intero status register per velocizzare l'indice di ricerca
182  // Controllo preventivo dell'array di validità dei registri indicizzata
184  // Controllo area register (Search for name)
185  for(uint8_t reg_index = 0; reg_index<MEM_UAVCAN_MAX_REG; reg_index++) {
186  // Test Data (Register Valid && Len Intest == for Rapid Check)
187  if(register_index[reg_index]!=MEM_UAVCAN_REG_UNDEF) {
188  // eeprom_register_get_len_intest_fast -> Rapido senza controllo validità REG
189  // La sua chiamata prevede un controllo preventivo della validità del REG
190  if (_eeprom_register_get_len_intest_fast(reg_index) == _len_name) {
191  // Retrieve all info register value
192  _len_data = _eeprom_register_get_fast(reg_index, _reg_name, _reg_data);
193  // Compare value name
194  if(memcmp(reg_name, _reg_name, _len_name) == 0) {
195  // Data is found
196  memcpy(data, _reg_data, _len_data);
197  *reg_numb = reg_index;
198  return _len_data;
199  }
200  }
201  }
202  }
203  // End Of Size ROM (Register Not Found)
204  return 0;
205 }
206 
211  uint8_t _reg_name[MEM_UAVCAN_LEN_NAME_REG];
212  uint8_t _reg_data[MEM_UAVCAN_LEN_VALUE_REG];
213  uint8_t _len_name = strlen((char*)reg_name);
214  uint8_t register_index[MEM_UAVCAN_MAX_REG];
215  // Leggo l'intero status register per velocizzare l'indice di ricerca
216  // Controllo preventivo dell'array di validità dei registri indicizzata
218  // Controllo area register (Search for name)
219  for(uint8_t reg_index = 0; reg_index<MEM_UAVCAN_MAX_REG; reg_index++) {
220  // Test Data (Register Valid && Len Intest == for Rapid Check)
221  if(register_index[reg_index]!=MEM_UAVCAN_REG_UNDEF) {
222  // eeprom_register_get_len_intest_fast -> Rapido senza controllo validità REG
223  // La sua chiamata prevede un controllo preventivo della validità del REG
224  if (_eeprom_register_get_len_intest_fast(reg_index) == _len_name) {
225  // Test Data (Register Valid)
226  _eeprom_register_get_intest_fast(reg_index, _reg_name, _len_name);
227  // Compare value name
228  if(memcmp(reg_name, _reg_name, _len_name) == 0) {
229  // Data is found
230  return reg_index;
231  }
232  }
233  }
234  }
235  // End Of Size ROM (Register Not Found)
236  return MEM_UAVCAN_REG_UNDEF;
237 }
238 
244 void EERegister::_eeprom_register_set(uint8_t reg_numb, uint8_t *reg_name, uint8_t *data, size_t len_data) {
245  uint8_t reg_valid;
246  uint8_t name_len = strlen((char*)reg_name);
247  uint8_t write_block[MEM_UAVCAN_LEN_REG] = {0};
248  // Controllo area register
249  if(reg_numb>=MEM_UAVCAN_MAX_REG) return;
250  // Leggo l'indice se impostato (registro valido)
251  _memory_read_byte(MEM_UAVCAN_GET_ADDR_FLAG_REG(reg_numb), &reg_valid);
252  if(reg_valid != reg_numb) {
253  // Imposto il Numero sul BYTE relativo (Registro inizializzato)
255  }
256  // Registro eeprom valido, imposto i campi name e value
257  write_block[MEM_UAVCAN_POS_LEN_NAME] = name_len;
258  write_block[MEM_UAVCAN_POS_LEN_DATA] = len_data;
259  memcpy(write_block + MEM_UAVCAN_POS_STR_NAME, reg_name, name_len);
260  memcpy(write_block + MEM_UAVCAN_POS_VALUE_DATA, data, len_data);
261  // Perform in unica scrittura
263 }
264 
267 void EERegister::_eeprom_register_get_next_id(uint8_t *current_register) {
268  uint8_t register_index[MEM_UAVCAN_MAX_REG];
269  // Controllo se richiesto avvio dall'inizio della coda... get_next(MAX)...
270  bool is_first = (*current_register==MEM_UAVCAN_REG_UNDEF);
271  // Continuo alla ricerca del prossimo register se esiste
273  while((*current_register<MEM_UAVCAN_MAX_REG) || (is_first))
274  {
275  // Starting attempt
276  if(is_first)
277  *current_register = 0;
278  else
279  (*current_register)++;
280  is_first = false;
281  if(register_index[*current_register] == *current_register) {
282  // Found... exit
283  break;
284  }
285  }
286 }
287 
293 uint8_t EERegister::_eeprom_register_add(uint8_t *reg_name, uint8_t *data, size_t data_len) {
294  uint8_t register_index[MEM_UAVCAN_MAX_REG];
295  // Vado alla ricerca del prossimo register se esiste (parto dal primo...)
297  for(uint8_t register_ptr=0; register_ptr<MEM_UAVCAN_MAX_REG; register_ptr++) {
298  if(register_index[register_ptr] == MEM_UAVCAN_REG_UNDEF) {
299  _eeprom_register_set(register_ptr, reg_name, data, data_len);
300  return register_ptr;
301  }
302  }
303  return MEM_UAVCAN_REG_UNDEF;
304 }
305 
308 {
309  // Init AREA E2PROM
311 
312  // Open Register in Write se non inizializzati correttamente...
313  // Populate INIT Default Value
314  static uavcan_register_Value_1_0 val = {0};
315  uavcan_register_Value_1_0_select_natural16_(&val);
316  val.natural16.value.count = 1;
317  val.natural16.value.elements[0] = CAN_MTU_BASE; // CAN_CLASSIC MTU 8
318  write(REGISTER_UAVCAN_MTU, &val);
319 
320  // We also need the bitrate configuration register. In this demo we can't really use it but an embedded application
321  // should define "uavcan.can.bitrate" of type natural32[2]; the second value is 0/ignored if CAN FD not supported.
322  uavcan_register_Value_1_0_select_natural32_(&val);
323  val.natural32.value.count = 2;
324  val.natural32.value.elements[0] = CAN_BIT_RATE;
325  val.natural32.value.elements[1] = 0ul; // Ignored for CANARD_MTU_CAN_CLASSIC
327 
328  // N.B. Inserire quà la personalizzazione dei registri in SETUP Fisso o di compilazione di modulo
329 
330  // Node ID
331  #ifndef USE_NODE_SLAVE_ID_FIXED
332  uavcan_register_Value_1_0_select_natural16_(&val);
333  val.natural16.value.count = 1;
334  val.natural16.value.elements[0] = NODE_VALUE_UNSET; // This means undefined (anonymous), per Specification/libcanard.
335  write(REGISTER_UAVCAN_NODE_ID, &val); // The names of the standard registers are regulated by the Specification.
336  #endif
337 
338  // Master ID
339  #ifdef NODE_MASTER_ID
340  uavcan_register_Value_1_0_select_natural16_(&val);
341  val.natural16.value.count = 1;
342  val.natural16.value.elements[0] = NODE_MASTER_ID; // This means undefined (anonymous), per Specification/libcanard.
343  write(REGISTER_RMAP_MASTER_ID, &val); // The names of the standard registers are regulated by the Specification.
344  #endif
345 
346  // Service RMAP
347  #ifdef PORT_SERVICE_RMAP
348  uavcan_register_Value_1_0_select_natural16_(&val);
349  val.natural16.value.count = 1;
350  val.natural16.value.elements[0] = PORT_SERVICE_RMAP;
352  #endif
353 
354  // Publish RMAP
355  #ifdef SUBJECTID_PUBLISH_RMAP
356  uavcan_register_Value_1_0_select_natural16_(&val);
357  val.natural16.value.count = 1;
358  val.natural16.value.elements[0] = SUBJECTID_PUBLISH_RMAP;
360  #endif
361 
362  // The description register is optional but recommended because it helps constructing/maintaining large networks.
363  // It simply keeps a human-readable description of the node that should be empty by default.
364  char stima_description[STIMA_MODULE_DESCRIPTION_LENGTH] = {0};
365  getStimaDescriptionByType(stima_description, MODULE_TYPE);
366  uavcan_register_Value_1_0_select_string_(&val);
367  val._string.value.count = strlen(stima_description);
368  memcpy(val._string.value.elements, stima_description, val._string.value.count);
369  write(REGISTER_UAVCAN_NODE_DESCR, &val); // We don't need the value, we just need to ensure it exists.
370 }
371 
376 void EERegister::read(const char* const register_name, uavcan_register_Value_1_0* const inout_value) {
377  LOCAL_ASSERT(inout_value != NULL);
378 
379  uint8_t register_number;
380  bool init_required = !uavcan_register_Value_1_0_is_empty_(inout_value);
381  uint8_t serialized[uavcan_register_Value_1_0_EXTENT_BYTES_] = {0};
382  size_t sr_size = _eeprom_register_get_from_name((const uint8_t*)register_name, &register_number, serialized);
383 
384  static uavcan_register_Value_1_0 out = {0};
385  const int8_t err = uavcan_register_Value_1_0_deserialize_(&out, serialized, &sr_size);
386  if (err >= 0) init_required = !assign(inout_value, &out);
387  if (init_required) write(register_name, inout_value);
388 }
389 
393 void EERegister::write(const char* const register_name, const uavcan_register_Value_1_0* const value) {
394  uint8_t serialized[uavcan_register_Value_1_0_EXTENT_BYTES_] = {0};
395  size_t sr_size = uavcan_register_Value_1_0_EXTENT_BYTES_;
396  const int8_t err = uavcan_register_Value_1_0_serialize_(value, serialized, &sr_size);
397  uint8_t register_index = _eeprom_register_get_index_from_name((uint8_t*) register_name);
398  if(register_index == MEM_UAVCAN_REG_UNDEF) {
399  printf("Init register: %s\n", register_name);
400  _eeprom_register_add((uint8_t*) register_name, serialized, sr_size);
401  } else {
402  _eeprom_register_set(register_index, (uint8_t*) register_name, serialized, sr_size);
403  }
404 }
405 
412 uavcan_register_Name_1_0 EERegister::getNameByIndex(const uint16_t index) {
413  uavcan_register_Name_1_0 out = {0};
414  uavcan_register_Name_1_0_initialize_(&out);
415  // N.B. Get starting list from first data Next of MEM_UAVCAN_REG_UNDEF -> = 0
416  // Get First...
417  if(index > MEM_UAVCAN_LEN_NAME_REG)
418  return out;
419  uint8_t reg_current = MEM_UAVCAN_REG_UNDEF;
420  _eeprom_register_get_next_id(&reg_current);
421  uint8_t reg_index = 0;
422  while(reg_current<=MEM_UAVCAN_MAX_REG) {
423  // Index Exact
424  if(reg_index==index) {
425  uint8_t _reg_name[MEM_UAVCAN_LEN_NAME_REG] = {0};
426  _eeprom_register_get_name_from_index(reg_current, _reg_name);
427  out.name.count = nunavutChooseMin(strlen((char*)_reg_name), uavcan_register_Name_1_0_name_ARRAY_CAPACITY_);
428  memcpy(out.name.elements, _reg_name, out.name.count);
429  break;
430  }
431  // Get Next register E2prom
432  _eeprom_register_get_next_id(&reg_current);
433  // Set next Id register list contiguos UAVCAN
434  reg_index++;
435  }
436  return out;
437 }
438 
441  setup();
442 }
443 
448 bool EERegister::assign(uavcan_register_Value_1_0* const dst, const uavcan_register_Value_1_0* const src) {
449  if (uavcan_register_Value_1_0_is_empty_(dst)) {
450  *dst = *src;
451  return true;
452  }
453  if ((uavcan_register_Value_1_0_is_string_(dst) && uavcan_register_Value_1_0_is_string_(src)) ||
454  (uavcan_register_Value_1_0_is_unstructured_(dst) && uavcan_register_Value_1_0_is_unstructured_(src))) {
455  *dst = *src;
456  return true;
457  }
458  if (uavcan_register_Value_1_0_is_bit_(dst) && uavcan_register_Value_1_0_is_bit_(src)) {
459  nunavutCopyBits(dst->bit.value.bitpacked,
460  0,
461  nunavutChooseMin(dst->bit.value.count, src->bit.value.count),
462  src->bit.value.bitpacked,
463  0);
464  return true;
465  }
466  // This is a violation of MISRA/AUTOSAR but it is believed to be less error-prone than manually copy-pasted code.
467  #define REGISTER_CASE_SAME_TYPE(TYPE) \
468  if (PASTE3(uavcan_register_Value_1_0_is_, TYPE, _)(dst) && PASTE3(uavcan_register_Value_1_0_is_, TYPE, _)(src)) { \
469  for (size_t i = 0; i < nunavutChooseMin(dst->TYPE.value.count, src->TYPE.value.count); ++i) { \
470  dst->TYPE.value.elements[i] = src->TYPE.value.elements[i]; \
471  } \
472  return true; \
473  }
474  REGISTER_CASE_SAME_TYPE(integer64)
475  REGISTER_CASE_SAME_TYPE(integer32)
476  REGISTER_CASE_SAME_TYPE(integer16)
477  REGISTER_CASE_SAME_TYPE(integer8)
478  REGISTER_CASE_SAME_TYPE(natural64)
479  REGISTER_CASE_SAME_TYPE(natural32)
480  REGISTER_CASE_SAME_TYPE(natural16)
481  REGISTER_CASE_SAME_TYPE(natural8)
485  return false;
486 }
Uavcan Canard Configuration file.
#define CAN_BIT_RATE
#define NODE_VALUE_UNSET
#define SUBJECTID_PUBLISH_RMAP
#define NODE_MASTER_ID
#define LOCAL_ASSERT
#define CAN_MTU_BASE
#define PORT_SERVICE_RMAP
void _eeprom_register_get_intest_fast(uint8_t reg_numb, uint8_t *reg_name, uint8_t name_len)
Legge un registro CYPAL/STIMAV4 dalla memoria (per indice) (fast=senza controlli validità) la procedu...
size_t _eeprom_register_get_fast(uint8_t reg_numb, uint8_t *reg_name, uint8_t *reg_value)
Legge un registro CYPAL/STIMAV4 dalla memoria (per indice) (fast=senza controlli validità) la procedu...
bool _eeprom_register_get_name_from_index(uint8_t reg_numb, uint8_t *reg_name)
Legge un registro CYPAL/STIMAV4 dalla EEprom (per indice)
void _memory_write_block(uint16_t address, uint8_t *data, uint8_t len)
Wrapper memory_write_block.
void setup(void)
Check if exist or create space register with init default value.
void _eeprom_register_clear(uint8_t reg_numb)
Inizializza/Elimina un registro CYPAL/STIMAV4 dalla memoria.
uavcan_register_Name_1_0 getNameByIndex(const uint16_t index)
Scroll degli indici dal primo all'ultimo e return ID UavCAN Nel passaggio di un eventuale INDICE vuot...
void _eeprom_register_set(uint8_t reg_numb, uint8_t *reg_name, uint8_t *data, size_t len_data)
Scrive/edita un registro CYPAL/STIMAV4 sulla memoria.
bool assign(uavcan_register_Value_1_0 *const dst, const uavcan_register_Value_1_0 *const src)
Register type Assign UAVCAN.
void doFactoryReset(void)
Erase all registers such that the defaults are used at the next launch.
void _memory_write_byte(uint16_t address, uint8_t data)
Wrapper memory_write_byte.
void read(const char *const register_name, uavcan_register_Value_1_0 *const inout_value)
Legge un registro Cypal/Uavcan wrapper UAVCAN (Imposta Default su Set inout_value su value se non esi...
EERegister()
Constructor Class.
uint8_t _eeprom_register_add(uint8_t *reg_name, uint8_t *data, size_t data_len)
Aggiunge un registro alla configurazione CYPAL/STIMAV4.
void _memory_read_block(uint16_t address, uint8_t *data, uint8_t len)
Wrapper memory_read_block.
size_t _eeprom_register_get_from_name(uint8_t const *reg_name, uint8_t *reg_numb, uint8_t *data)
Legge un registro CYPAL/STIMAV4 dalla memoria (per Nome)
void _memory_read_byte(uint16_t address, uint8_t *data)
Wrapper memory_read_byte.
void write(const char *const register_name, const uavcan_register_Value_1_0 *const value)
Store the given register value into the persistent storage.
size_t _eeprom_register_get_len_intest_fast(uint8_t reg_numb)
Legge un registro CYPAL/STIMAV4 dalla memoria (per indice) (fast=senza controlli validità) la procedu...
uint8_t _eeprom_register_get_index_from_name(uint8_t *reg_name)
Legge un indiced di registro CYPAL/STIMAV4 dalla memoria (per Nome)
void _eeprom_register_get_next_id(uint8_t *current_register)
Ritorna il prossimo indice (se esiste) valido nella sezione memoria Cypal dedicata.
void _eeprom_register_factory(void)
Inizializza l'area memory (indice) dedicata a REGISTER.
Definition: eeprom.h:49
bool Read(uint16_t address, uint8_t *buffer, uint16_t length)
Read a number of data byte from EEPROM.
Definition: eeprom.cpp:167
bool Write(uint16_t address, uint8_t *buffer, uint16_t length)
Write a number of data byte into EEPROM.
Definition: eeprom.cpp:86
#define MODULE_TYPE
Type of module. It is defined in registers.h.
Definition: config.h:55
#define REGISTER_CASE_SAME_TYPE(TYPE)
Register class (Uavcan/Other) header file.
#define MEM_UAVCAN_LEN_REG
#define MEM_UAVCAN_MAX_REG
#define REGISTER_RMAP_MASTER_ID
#define MEM_UAVCAN_POS_LEN_DATA
#define MEM_UAVCAN_POS_VALUE_DATA
#define REGISTER_UAVCAN_NODE_DESCR
#define MEM_UAVCAN_POS_LEN_NAME
#define REGISTER_UAVCAN_BITRATE
#define REGISTER_UAVCAN_NODE_ID
#define MEM_UAVCAN_LEN_VALUE_REG
#define MEM_UAVCAN_POS_STR_NAME
#define REGISTER_UAVCAN_DATA_PUBLISH
#define MEM_UAVCAN_GET_ADDR_NAME(X)
#define MEM_UAVCAN_LEN_NAME_REG
#define REGISTER_UAVCAN_DATA_SERVICE
#define MEM_UAVCAN_REG_UNDEF
#define MEM_UAVCAN_GET_ADDR_FLAG_REG(X)
#define MEM_UAVCAN_GET_ADDR_NAME_LEN(X)
#define REGISTER_UAVCAN_MTU
#define MEM_UAVCAN_GET_ADDR_BASE_REG(X)
#define MEM_UAVCAN_GET_ADDR_FLAG()