第一版代码,为了在EEPROM保存参数的时候走STM32的CRC,让Codex修改了一下,现在的效果是无法存储,codex表示原因是CRC方法不同,修改到一半今天的额度使用完了,有待后续解决CRC的bug
This commit is contained in:
113
Middleware/CANopenNode/storage/CO_eeprom.h
Normal file
113
Middleware/CANopenNode/storage/CO_eeprom.h
Normal file
@@ -0,0 +1,113 @@
|
||||
/**
|
||||
* Eeprom interface for use with CO_storageEeprom
|
||||
*
|
||||
* @file CO_eeprom.h
|
||||
* @ingroup CO_storage_eeprom
|
||||
* @author Janez Paternoster
|
||||
* @copyright 2021 Janez Paternoster
|
||||
*
|
||||
* This file is part of <https://github.com/CANopenNode/CANopenNode>, a CANopen Stack.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this
|
||||
* file except in compliance with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is
|
||||
* distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef CO_EEPROM_H
|
||||
#define CO_EEPROM_H
|
||||
|
||||
#include "301/CO_driver.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @addtogroup CO_storage_eeprom
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* Initialize eeprom device, target system specific function.
|
||||
*
|
||||
* @param storageModule Pointer to storage module.
|
||||
*
|
||||
* @return True on success
|
||||
*/
|
||||
bool_t CO_eeprom_init(void* storageModule);
|
||||
|
||||
/**
|
||||
* Get free address inside eeprom, target system specific function.
|
||||
*
|
||||
* Function is called several times for each storage block in the initialization phase after CO_eeprom_init().
|
||||
*
|
||||
* @param storageModule Pointer to storage module.
|
||||
* @param isAuto True, if variable is auto stored or false if protected
|
||||
* @param len Length of data, which will be stored to that location
|
||||
* @param [out] overflow set to true, if not enough eeprom memory
|
||||
*
|
||||
* @return Asigned eeprom address
|
||||
*/
|
||||
size_t CO_eeprom_getAddr(void* storageModule, bool_t isAuto, size_t len, bool_t* overflow);
|
||||
|
||||
/**
|
||||
* Read block of data from the eeprom, target system specific function.
|
||||
*
|
||||
* @param storageModule Pointer to storage module.
|
||||
* @param data Pointer to data buffer, where data will be stored.
|
||||
* @param eepromAddr Address in eeprom, from where data will be read.
|
||||
* @param len Length of the data block to be read.
|
||||
*/
|
||||
void CO_eeprom_readBlock(void* storageModule, uint8_t* data, size_t eepromAddr, size_t len);
|
||||
|
||||
/**
|
||||
* Write block of data to the eeprom, target system specific function.
|
||||
*
|
||||
* It is blocking function, so it waits, until all data is written.
|
||||
*
|
||||
* @param storageModule Pointer to storage module.
|
||||
* @param data Pointer to data buffer which will be written.
|
||||
* @param eepromAddr Address in eeprom, where data will be written. If data is stored across multiple pages, address
|
||||
* must be aligned with page.
|
||||
* @param len Length of the data block.
|
||||
*
|
||||
* @return true on success
|
||||
*/
|
||||
bool_t CO_eeprom_writeBlock(void* storageModule, uint8_t* data, size_t eepromAddr, size_t len);
|
||||
|
||||
/**
|
||||
* Get CRC checksum of the block of data stored in the eeprom, target system specific function.
|
||||
*
|
||||
* @param storageModule Pointer to storage module.
|
||||
* @param eepromAddr Address of data in eeprom.
|
||||
* @param len Length of the data.
|
||||
*
|
||||
* @return CRC checksum
|
||||
*/
|
||||
uint16_t CO_eeprom_getCrcBlock(void* storageModule, size_t eepromAddr, size_t len);
|
||||
|
||||
/**
|
||||
* Update one byte of data in the eeprom, target system specific function.
|
||||
*
|
||||
* Function is used by automatic storage. It updates byte in eeprom only if differs from data.
|
||||
*
|
||||
* @param storageModule Pointer to storage module.
|
||||
* @param data Data byte to be written
|
||||
* @param eepromAddr Address in eeprom, from where data will be updated.
|
||||
*
|
||||
* @return true if write was successful or false, if still waiting previous data to finish writing.
|
||||
*/
|
||||
bool_t CO_eeprom_updateByte(void* storageModule, uint8_t data, size_t eepromAddr);
|
||||
|
||||
/** @} */ /* CO_storage_eeprom */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif /* CO_EEPROM_H */
|
||||
165
Middleware/CANopenNode/storage/CO_storage.c
Normal file
165
Middleware/CANopenNode/storage/CO_storage.c
Normal file
@@ -0,0 +1,165 @@
|
||||
/*
|
||||
* CANopen data storage base object
|
||||
*
|
||||
* @file CO_storage.c
|
||||
* @author Janez Paternoster
|
||||
* @copyright 2021 Janez Paternoster
|
||||
*
|
||||
* This file is part of <https://github.com/CANopenNode/CANopenNode>, a CANopen Stack.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this
|
||||
* file except in compliance with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is
|
||||
* distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
#include "storage/CO_storage.h"
|
||||
|
||||
#if ((CO_CONFIG_STORAGE)&CO_CONFIG_STORAGE_ENABLE) != 0
|
||||
|
||||
/*
|
||||
* Custom function for writing OD object "Store parameters"
|
||||
*
|
||||
* For more information see file CO_ODinterface.h, OD_IO_t.
|
||||
*/
|
||||
static ODR_t
|
||||
OD_write_1010(OD_stream_t* stream, const void* buf, OD_size_t count, OD_size_t* countWritten) {
|
||||
/* verify arguments */
|
||||
if ((stream == NULL) || (stream->subIndex == 0U) || (buf == NULL) || (count != 4U) || (countWritten == NULL)) {
|
||||
return ODR_DEV_INCOMPAT;
|
||||
}
|
||||
|
||||
CO_storage_t* storage = stream->object;
|
||||
|
||||
if ((stream->subIndex == 0U) || (storage->store == NULL) || !storage->enabled) {
|
||||
return ODR_READONLY;
|
||||
}
|
||||
|
||||
uint32_t val = CO_getUint32(buf);
|
||||
if (val != 0x65766173U) {
|
||||
return ODR_DATA_TRANSF;
|
||||
}
|
||||
|
||||
/* loop through entries and store relevant */
|
||||
uint8_t found = 0;
|
||||
ODR_t returnCode = ODR_OK;
|
||||
|
||||
for (uint8_t i = 0; i < storage->entriesCount; i++) {
|
||||
CO_storage_entry_t* entry = &storage->entries[i];
|
||||
|
||||
if ((stream->subIndex == 1U) || (entry->subIndexOD == stream->subIndex)) {
|
||||
if (found == 0U) {
|
||||
found = 1;
|
||||
}
|
||||
if ((entry->attr & (uint8_t)CO_storage_cmd) != 0U) {
|
||||
ODR_t code = storage->store(entry, storage->CANmodule);
|
||||
if (code != ODR_OK) {
|
||||
returnCode = code;
|
||||
}
|
||||
found = 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (found != 2U) {
|
||||
returnCode = (found == 0U) ? ODR_SUB_NOT_EXIST : ODR_READONLY;
|
||||
}
|
||||
|
||||
if (returnCode == ODR_OK) {
|
||||
*countWritten = sizeof(uint32_t);
|
||||
}
|
||||
return returnCode;
|
||||
}
|
||||
|
||||
/*
|
||||
* Custom function for writing OD object "Restore default parameters"
|
||||
*
|
||||
* For more information see file CO_ODinterface.h, OD_IO_t.
|
||||
*/
|
||||
static ODR_t
|
||||
OD_write_1011(OD_stream_t* stream, const void* buf, OD_size_t count, OD_size_t* countWritten) {
|
||||
/* verify arguments */
|
||||
if ((stream == NULL) || (stream->subIndex == 0U) || (buf == NULL) || (count != 4U) || (countWritten == NULL)) {
|
||||
return ODR_DEV_INCOMPAT;
|
||||
}
|
||||
|
||||
CO_storage_t* storage = stream->object;
|
||||
|
||||
if ((stream->subIndex == 0U) || (storage->restore == NULL) || !storage->enabled) {
|
||||
return ODR_READONLY;
|
||||
}
|
||||
|
||||
uint32_t val = CO_getUint32(buf);
|
||||
if (val != 0x64616F6CU) {
|
||||
return ODR_DATA_TRANSF;
|
||||
}
|
||||
|
||||
/* loop through entries and store relevant */
|
||||
uint8_t found = 0;
|
||||
ODR_t returnCode = ODR_OK;
|
||||
|
||||
for (uint8_t i = 0; i < storage->entriesCount; i++) {
|
||||
CO_storage_entry_t* entry = &storage->entries[i];
|
||||
|
||||
if ((stream->subIndex == 1U) || (entry->subIndexOD == stream->subIndex)) {
|
||||
if (found == 0U) {
|
||||
found = 1;
|
||||
}
|
||||
if ((entry->attr & (uint8_t)CO_storage_restore) != 0U) {
|
||||
ODR_t code = storage->restore(entry, storage->CANmodule);
|
||||
if (code != ODR_OK) {
|
||||
returnCode = code;
|
||||
}
|
||||
found = 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (found != 2U) {
|
||||
returnCode = (found == 0U) ? ODR_SUB_NOT_EXIST : ODR_READONLY;
|
||||
}
|
||||
|
||||
if (returnCode == ODR_OK) {
|
||||
*countWritten = sizeof(uint32_t);
|
||||
}
|
||||
return returnCode;
|
||||
}
|
||||
|
||||
CO_ReturnError_t
|
||||
CO_storage_init(CO_storage_t* storage, CO_CANmodule_t* CANmodule, OD_entry_t* OD_1010_StoreParameters,
|
||||
OD_entry_t* OD_1011_RestoreDefaultParameters,
|
||||
ODR_t (*store)(CO_storage_entry_t* entry, CO_CANmodule_t* CANmodule),
|
||||
ODR_t (*restore)(CO_storage_entry_t* entry, CO_CANmodule_t* CANmodule), CO_storage_entry_t* entries,
|
||||
uint8_t entriesCount) {
|
||||
/* verify arguments */
|
||||
if ((storage == NULL) || (CANmodule == NULL) || (OD_1010_StoreParameters == NULL)
|
||||
|| (OD_1011_RestoreDefaultParameters == NULL) || (store == NULL) || (restore == NULL) || (entries == NULL)) {
|
||||
return CO_ERROR_ILLEGAL_ARGUMENT;
|
||||
}
|
||||
|
||||
/* Configure object variables */
|
||||
storage->CANmodule = CANmodule;
|
||||
storage->store = store;
|
||||
storage->restore = restore;
|
||||
storage->entries = entries;
|
||||
storage->entriesCount = entriesCount;
|
||||
|
||||
/* configure extensions */
|
||||
storage->OD_1010_extension.object = storage;
|
||||
storage->OD_1010_extension.read = OD_readOriginal;
|
||||
storage->OD_1010_extension.write = OD_write_1010;
|
||||
(void)OD_extension_init(OD_1010_StoreParameters, &storage->OD_1010_extension);
|
||||
|
||||
storage->OD_1011_extension.object = storage;
|
||||
storage->OD_1011_extension.read = OD_readOriginal;
|
||||
storage->OD_1011_extension.write = OD_write_1011;
|
||||
(void)OD_extension_init(OD_1011_RestoreDefaultParameters, &storage->OD_1011_extension);
|
||||
|
||||
return CO_ERROR_NO;
|
||||
}
|
||||
|
||||
#endif /* (CO_CONFIG_STORAGE) & CO_CONFIG_STORAGE_ENABLE */
|
||||
142
Middleware/CANopenNode/storage/CO_storage.h
Normal file
142
Middleware/CANopenNode/storage/CO_storage.h
Normal file
@@ -0,0 +1,142 @@
|
||||
/**
|
||||
* CANopen data storage base object
|
||||
*
|
||||
* @file CO_storage.h
|
||||
* @ingroup CO_storage
|
||||
* @author Janez Paternoster
|
||||
* @copyright 2021 Janez Paternoster
|
||||
*
|
||||
* This file is part of <https://github.com/CANopenNode/CANopenNode>, a CANopen Stack.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this
|
||||
* file except in compliance with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is
|
||||
* distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef CO_STORAGE_H
|
||||
#define CO_STORAGE_H
|
||||
|
||||
#include "301/CO_driver.h"
|
||||
#include "301/CO_ODinterface.h"
|
||||
|
||||
/* default configuration, see CO_config.h */
|
||||
#ifndef CO_CONFIG_STORAGE
|
||||
#define CO_CONFIG_STORAGE (CO_CONFIG_STORAGE_ENABLE)
|
||||
#endif
|
||||
|
||||
#if (((CO_CONFIG_STORAGE)&CO_CONFIG_STORAGE_ENABLE) != 0) || defined CO_DOXYGEN
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @defgroup CO_storage Data storage base
|
||||
* Base module for Data storage.
|
||||
*
|
||||
* @ingroup CO_CANopen_storage
|
||||
* @{
|
||||
*
|
||||
* CANopen provides OD objects 0x1010 and 0x1011 for control of storing and restoring data. Data source is usually a
|
||||
* group of variables inside object dictionary, but it is not limited to OD.
|
||||
*
|
||||
* When object dictionary is generated (OD.h and OD.c files), OD variables are grouped into structures according to
|
||||
* 'Storage group' parameter.
|
||||
*
|
||||
* Autonomous data storing must be implemented target specific, if in use.
|
||||
*
|
||||
* ### OD object 0x1010 - Store parameters:
|
||||
* - Sub index 0: Highest sub-index supported
|
||||
* - Sub index 1: Save all parameters, UNSIGNED32
|
||||
* - Sub index 2: Save communication parameters, UNSIGNED32
|
||||
* - Sub index 3: Save application parameters, UNSIGNED32
|
||||
* - Sub index 4 - 127: Manufacturer specific, UNSIGNED32
|
||||
*
|
||||
* Sub-indexes 1 and above:
|
||||
* - Reading provides information about its storage functionality:
|
||||
* - bit 0: If set, CANopen device saves parameters on command
|
||||
* - bit 1: If set, CANopen device saves parameters autonomously
|
||||
* - Writing value 0x65766173 ('s','a','v','e' from LSB to MSB) stores corresponding data.
|
||||
*
|
||||
* ### OD object 0x1011 - Restore default parameters
|
||||
* - Sub index 0: Highest sub-index supported
|
||||
* - Sub index 1: Restore all default parameters, UNSIGNED32
|
||||
* - Sub index 2: Restore communication default parameters, UNSIGNED32
|
||||
* - Sub index 3: Restore application default parameters, UNSIGNED32
|
||||
* - Sub index 4 - 127: Manufacturer specific, UNSIGNED32
|
||||
*
|
||||
* Sub-indexes 1 and above:
|
||||
* - Reading provides information about its restoring capability:
|
||||
* - bit 0: If set, CANopen device restores parameters
|
||||
* - Writing value 0x64616F6C ('l','o','a','d' from LSB to MSB) restores corresponding data.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Attributes (bit masks) for Data storage object.
|
||||
*/
|
||||
typedef enum {
|
||||
CO_storage_cmd = 0x01, /**< CANopen device saves parameters on OD 1010 command */
|
||||
CO_storage_auto = 0x02, /**< CANopen device saves parameters autonomously */
|
||||
CO_storage_restore = 0x04 /**< CANopen device restores parameters on OD 1011 command */
|
||||
} CO_storage_attributes_t;
|
||||
|
||||
/**
|
||||
* Data storage object.
|
||||
*
|
||||
* Object is used with CANopen OD objects at index 1010 and 1011.
|
||||
*/
|
||||
typedef struct {
|
||||
OD_extension_t OD_1010_extension; /**< Extension for OD object */
|
||||
OD_extension_t OD_1011_extension; /**< Extension for OD object */
|
||||
CO_CANmodule_t* CANmodule; /**< From CO_storage_init() */
|
||||
ODR_t (*store)(CO_storage_entry_t* entry, CO_CANmodule_t* CANmodule); /**< From CO_storage_init() */
|
||||
ODR_t (*restore)(CO_storage_entry_t* entry, CO_CANmodule_t* CANmodule); /**< From CO_storage_init() */
|
||||
CO_storage_entry_t* entries; /**< From CO_storage_init() */
|
||||
uint8_t entriesCount; /**< From CO_storage_init() */
|
||||
bool_t enabled; /**< true, if storage is enabled. Setting of this variable is implementation specific. */
|
||||
} CO_storage_t;
|
||||
|
||||
/**
|
||||
* Initialize data storage object
|
||||
*
|
||||
* This function should be called by application after the program startup, before @ref CO_CANopenInit(). This function
|
||||
* initializes storage object and OD extensions on objects 1010 and 1011. Function does not load stored data on startup,
|
||||
* because loading data is target specific.
|
||||
*
|
||||
* @param storage This object will be initialized. It must be defined by application and must exist permanently.
|
||||
* @param CANmodule CAN device, for optional usage.
|
||||
* @param OD_1010_StoreParameters OD entry for 0x1010 -"Store parameters". Entry is optional, may be NULL.
|
||||
* @param OD_1011_RestoreDefaultParameters OD entry for 0x1011 -"Restore default parameters". Entry is optional, may be
|
||||
* NULL.
|
||||
* @param store Pointer to externally defined function, which will store data specified by @ref CO_storage_entry_t.
|
||||
* Function will be called when OD variable 0x1010 will be written. Argument to function is entry, where
|
||||
* 'entry->subIndexOD' equals accessed subIndex. Function returns value from
|
||||
* @ref ODR_t : "ODR_OK" in case of success, "ODR_HW" in case of hardware error.
|
||||
* @param restore Same as 'store', but for restoring default data.
|
||||
* @param entries Pointer to array of storage entries. Array must be defined and initialized by application and must
|
||||
* exist permanently. Structure @ref CO_storage_entry_t is target specific and must be defined by CO_driver_target.h.
|
||||
* See CO_driver.h for required parameters.
|
||||
* @param entriesCount Count of storage entries
|
||||
*
|
||||
* @return CO_ERROR_NO or CO_ERROR_ILLEGAL_ARGUMENT.
|
||||
*/
|
||||
CO_ReturnError_t CO_storage_init(CO_storage_t* storage, CO_CANmodule_t* CANmodule, OD_entry_t* OD_1010_StoreParameters,
|
||||
OD_entry_t* OD_1011_RestoreDefaultParameters,
|
||||
ODR_t (*store)(CO_storage_entry_t* entry, CO_CANmodule_t* CANmodule),
|
||||
ODR_t (*restore)(CO_storage_entry_t* entry, CO_CANmodule_t* CANmodule),
|
||||
CO_storage_entry_t* entries, uint8_t entriesCount);
|
||||
|
||||
/** @} */ /* CO_storage */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif /* (CO_CONFIG_STORAGE) & CO_CONFIG_STORAGE_ENABLE */
|
||||
|
||||
#endif /* CO_STORAGE_H */
|
||||
222
Middleware/CANopenNode/storage/CO_storageEeprom.c
Normal file
222
Middleware/CANopenNode/storage/CO_storageEeprom.c
Normal file
@@ -0,0 +1,222 @@
|
||||
/*
|
||||
* CANopen data storage object for storing data into block device (eeprom)
|
||||
*
|
||||
* @file CO_storageEeprom.c
|
||||
* @author Janez Paternoster
|
||||
* @copyright 2021 Janez Paternoster
|
||||
*
|
||||
* This file is part of <https://github.com/CANopenNode/CANopenNode>, a CANopen Stack.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this
|
||||
* file except in compliance with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is
|
||||
* distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
#include "storage/CO_storageEeprom.h"
|
||||
#include "storage/CO_eeprom.h"
|
||||
#include "301/crc16-ccitt.h"
|
||||
|
||||
#if ((CO_CONFIG_STORAGE)&CO_CONFIG_STORAGE_ENABLE) != 0
|
||||
|
||||
/*
|
||||
* Function for writing data on "Store parameters" command - OD object 1010
|
||||
*
|
||||
* For more information see file CO_storage.h, CO_storage_entry_t.
|
||||
*/
|
||||
static ODR_t
|
||||
storeEeprom(CO_storage_entry_t* entry, CO_CANmodule_t* CANmodule) {
|
||||
(void)CANmodule;
|
||||
bool_t writeOk;
|
||||
|
||||
/* save data to the eeprom */
|
||||
writeOk = CO_eeprom_writeBlock(entry->storageModule, entry->addr, entry->eepromAddr, entry->len);
|
||||
entry->crc = crc16_ccitt(entry->addr, entry->len, 0);
|
||||
|
||||
/* Verify, if data in eeprom are equal */
|
||||
uint16_t crc_read = CO_eeprom_getCrcBlock(entry->storageModule, entry->eepromAddr, entry->len);
|
||||
if ((entry->crc != crc_read) || !writeOk) {
|
||||
return ODR_HW;
|
||||
}
|
||||
|
||||
/* Write signature (see CO_storageEeprom_init() for info) */
|
||||
uint16_t signatureOfEntry = (uint16_t)entry->len;
|
||||
uint32_t signature = (((uint32_t)entry->crc) << 16) | signatureOfEntry;
|
||||
writeOk = CO_eeprom_writeBlock(entry->storageModule, (uint8_t*)&signature, entry->eepromAddrSignature,
|
||||
sizeof(signature));
|
||||
|
||||
/* verify signature and write */
|
||||
uint32_t signatureRead;
|
||||
CO_eeprom_readBlock(entry->storageModule, (uint8_t*)&signatureRead, entry->eepromAddrSignature,
|
||||
sizeof(signatureRead));
|
||||
if ((signature != signatureRead) || !writeOk) {
|
||||
return ODR_HW;
|
||||
}
|
||||
|
||||
return ODR_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* Function for restoring data on "Restore default parameters" command - OD 1011
|
||||
*
|
||||
* For more information see file CO_storage.h, CO_storage_entry_t.
|
||||
*/
|
||||
static ODR_t
|
||||
restoreEeprom(CO_storage_entry_t* entry, CO_CANmodule_t* CANmodule) {
|
||||
(void)CANmodule;
|
||||
bool_t writeOk;
|
||||
|
||||
/* Write empty signature */
|
||||
uint32_t signature = 0xFFFFFFFFU;
|
||||
writeOk = CO_eeprom_writeBlock(entry->storageModule, (uint8_t*)&signature, entry->eepromAddrSignature,
|
||||
sizeof(signature));
|
||||
|
||||
/* verify signature and protection */
|
||||
uint32_t signatureRead;
|
||||
CO_eeprom_readBlock(entry->storageModule, (uint8_t*)&signatureRead, entry->eepromAddrSignature,
|
||||
sizeof(signatureRead));
|
||||
if ((signature != signatureRead) || !writeOk) {
|
||||
return ODR_HW;
|
||||
}
|
||||
|
||||
return ODR_OK;
|
||||
}
|
||||
|
||||
CO_ReturnError_t
|
||||
CO_storageEeprom_init(CO_storage_t* storage, CO_CANmodule_t* CANmodule, void* storageModule,
|
||||
OD_entry_t* OD_1010_StoreParameters, OD_entry_t* OD_1011_RestoreDefaultParam,
|
||||
CO_storage_entry_t* entries, uint8_t entriesCount, uint32_t* storageInitError) {
|
||||
CO_ReturnError_t ret;
|
||||
bool_t eepromOvf = false;
|
||||
|
||||
/* verify arguments */
|
||||
if ((storage == NULL) || (entries == NULL) || (entriesCount == 0U)
|
||||
|| (entriesCount > CO_CONFIG_STORAGE_MAX_ENTRIES_COUNT) || (storageInitError == NULL)) {
|
||||
return CO_ERROR_ILLEGAL_ARGUMENT;
|
||||
}
|
||||
|
||||
storage->enabled = false;
|
||||
|
||||
/* Initialize storage hardware */
|
||||
if (!CO_eeprom_init(storageModule)) {
|
||||
*storageInitError = 0xFFFFFFFFU;
|
||||
return CO_ERROR_DATA_CORRUPT;
|
||||
}
|
||||
|
||||
/* initialize storage and OD extensions */
|
||||
ret = CO_storage_init(storage, CANmodule, OD_1010_StoreParameters, OD_1011_RestoreDefaultParam, storeEeprom,
|
||||
restoreEeprom, entries, entriesCount);
|
||||
if (ret != CO_ERROR_NO) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Read entry signatures from the eeprom */
|
||||
uint32_t signatures[CO_CONFIG_STORAGE_MAX_ENTRIES_COUNT];
|
||||
size_t signaturesAddress = CO_eeprom_getAddr(storageModule, false, sizeof(signatures), &eepromOvf);
|
||||
CO_eeprom_readBlock(storageModule, (uint8_t*)signatures, signaturesAddress, sizeof(signatures));
|
||||
|
||||
/* initialize entries */
|
||||
*storageInitError = 0;
|
||||
for (uint8_t i = 0; i < entriesCount; i++) {
|
||||
CO_storage_entry_t* entry = &entries[i];
|
||||
bool_t isAuto = (entry->attr & (uint8_t)CO_storage_auto) != 0U;
|
||||
|
||||
/* verify arguments */
|
||||
if ((entry->addr == NULL) || (entry->len == 0U) || (entry->subIndexOD < 2U)) {
|
||||
*storageInitError = i;
|
||||
return CO_ERROR_ILLEGAL_ARGUMENT;
|
||||
}
|
||||
|
||||
/* calculate addresses inside eeprom */
|
||||
entry->eepromAddrSignature = signaturesAddress + (sizeof(uint32_t) * i);
|
||||
entry->eepromAddr = CO_eeprom_getAddr(storageModule, isAuto, entry->len, &eepromOvf);
|
||||
entry->offset = 0;
|
||||
|
||||
/* verify if eeprom is too small */
|
||||
if (eepromOvf) {
|
||||
*storageInitError = i;
|
||||
return CO_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
/* 32bit signature (which was stored in eeprom) is combined from
|
||||
* 16bit signature of the entry and 16bit CRC checksum of the data
|
||||
* block. 16bit signature of the entry is entry->len. */
|
||||
uint32_t signature = signatures[i];
|
||||
uint16_t signatureInEeprom = (uint16_t)signature;
|
||||
entry->crc = (uint16_t)(signature >> 16);
|
||||
uint16_t signatureOfEntry = (uint16_t)entry->len;
|
||||
|
||||
/* Verify two signatures */
|
||||
bool_t dataCorrupt = false;
|
||||
if (signatureInEeprom != signatureOfEntry) {
|
||||
dataCorrupt = true;
|
||||
} else {
|
||||
/* Read data into storage location */
|
||||
CO_eeprom_readBlock(entry->storageModule, entry->addr, entry->eepromAddr, entry->len);
|
||||
|
||||
/* Verify CRC, except for auto storage variables */
|
||||
if (!isAuto) {
|
||||
uint16_t crc = crc16_ccitt(entry->addr, entry->len, 0);
|
||||
if (crc != entry->crc) {
|
||||
dataCorrupt = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* additional info in case of error */
|
||||
if (dataCorrupt) {
|
||||
uint32_t errorBit = entry->subIndexOD;
|
||||
if (errorBit > 31U) {
|
||||
errorBit = 31;
|
||||
}
|
||||
*storageInitError |= ((uint32_t)1) << errorBit;
|
||||
ret = CO_ERROR_DATA_CORRUPT;
|
||||
}
|
||||
} /* for (entries) */
|
||||
|
||||
storage->enabled = true;
|
||||
return ret;
|
||||
}
|
||||
|
||||
void
|
||||
CO_storageEeprom_auto_process(CO_storage_t* storage, bool_t saveAll) {
|
||||
/* verify arguments */
|
||||
if ((storage == NULL) || !storage->enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* loop through entries */
|
||||
for (uint8_t n = 0; n < storage->entriesCount; n++) {
|
||||
CO_storage_entry_t* entry = &storage->entries[n];
|
||||
|
||||
if ((entry->attr & (uint8_t)CO_storage_auto) == 0U) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (saveAll) {
|
||||
/* update all bytes */
|
||||
for (size_t i = 0; i < entry->len;) {
|
||||
uint8_t dataByteToUpdate = ((uint8_t*)(entry->addr))[i];
|
||||
size_t eepromAddr = entry->eepromAddr + i;
|
||||
if (CO_eeprom_updateByte(entry->storageModule, dataByteToUpdate, eepromAddr)) {
|
||||
i++;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* update one data byte and if successful increment to next */
|
||||
uint8_t dataByteToUpdate = ((uint8_t*)(entry->addr))[entry->offset];
|
||||
size_t eepromAddr = entry->eepromAddr + entry->offset;
|
||||
if (CO_eeprom_updateByte(entry->storageModule, dataByteToUpdate, eepromAddr)) {
|
||||
if (++entry->offset >= entry->len) {
|
||||
entry->offset = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* (CO_CONFIG_STORAGE) & CO_CONFIG_STORAGE_ENABLE */
|
||||
109
Middleware/CANopenNode/storage/CO_storageEeprom.h
Normal file
109
Middleware/CANopenNode/storage/CO_storageEeprom.h
Normal file
@@ -0,0 +1,109 @@
|
||||
/**
|
||||
* CANopen data storage object for storing data into block device (eeprom)
|
||||
*
|
||||
* @file CO_storageEeprom.h
|
||||
* @ingroup CO_storage_eeprom
|
||||
* @author Janez Paternoster
|
||||
* @copyright 2021 Janez Paternoster
|
||||
*
|
||||
* This file is part of <https://github.com/CANopenNode/CANopenNode>, a CANopen Stack.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this
|
||||
* file except in compliance with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is
|
||||
* distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef CO_STORAGE_EEPROM_H
|
||||
#define CO_STORAGE_EEPROM_H
|
||||
|
||||
#include "storage/CO_storage.h"
|
||||
|
||||
#ifndef CO_CONFIG_STORAGE_MAX_ENTRIES_COUNT
|
||||
#define CO_CONFIG_STORAGE_MAX_ENTRIES_COUNT 5U
|
||||
#endif
|
||||
|
||||
#if (((CO_CONFIG_STORAGE)&CO_CONFIG_STORAGE_ENABLE) != 0) || defined CO_DOXYGEN
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @defgroup CO_storage_eeprom Data storage in eeprom
|
||||
* Eeprom specific data storage functions.
|
||||
*
|
||||
* @ingroup CO_CANopen_storage
|
||||
* @{
|
||||
* This is an interface into generic CANopenNode @ref CO_storage for usage with eeprom chip like 25LC256. Functions @ref
|
||||
* CO_storageEeprom_init() and @ref CO_storageEeprom_auto_process are target system independent. Functions specified by
|
||||
* @ref CO_eeprom.h file, must be defined by target system. For example implementation see CANopenPIC/PIC32.
|
||||
*
|
||||
* Storage principle:
|
||||
* This function first reads 'signatures' for all entries from the known address from the eeprom. If signature for each
|
||||
* entry is correct, then data is read from correct address from the eeprom into storage location. If signature is
|
||||
* wrong, then data for that entry is indicated as corrupt and CANopen emergency message is sent.
|
||||
*
|
||||
* Signature also includes 16-bit CRC checksum of the data stored in eeprom. If it differs from CRC checksum calculated
|
||||
* from the data actually loaded (on program startup), then entry is indicated as corrupt and CANopen emergency message
|
||||
* is sent.
|
||||
*
|
||||
* Signature is written to eeprom, when data block is stored via CANopen SDO write command to object 0x1010. Signature
|
||||
* is erased, with CANopen SDO write command to object 0x1011. If signature is not valid or is erased for any entry,
|
||||
* emergency message is sent. If eeprom is new, then all signatures are wrong, so it is best to store all parameters by
|
||||
* writing to 0x1010, sub 1.
|
||||
*
|
||||
* If entry attribute has CO_storage_auto set, then data block is stored autonomously, byte by byte, on change, during
|
||||
* program run. Those data blocks are stored into write unprotected location. For auto storage to work, its signature in
|
||||
* eeprom must be correct. CRC checksum for the data is not used.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Initialize data storage object (block device (eeprom) specific)
|
||||
*
|
||||
* This function should be called by application after the program startup, before @ref CO_CANopenInit(). This function
|
||||
* initializes storage object, OD extensions on objects 1010 and 1011, reads data from file, verifies them and writes
|
||||
* data to addresses specified inside entries. This function internally calls @ref CO_storage_init().
|
||||
*
|
||||
* @param storage This object will be initialized. It must be defined by application and must exist permanently.
|
||||
* @param CANmodule CAN device, for optional usage.
|
||||
* @param storageModule Pointer to storage module passed to CO_eeprom functions.
|
||||
* @param OD_1010_StoreParameters OD entry for 0x1010 -"Store parameters". Entry is optional, may be NULL.
|
||||
* @param OD_1011_RestoreDefaultParam OD entry for 0x1011 -"Restore default parameters". Entry is optional, may be NULL.
|
||||
* @param entries Pointer to array of storage entries, see @ref CO_storage_init.
|
||||
* @param entriesCount Count of storage entries, must not be larger than CO_CONFIG_STORAGE_MAX_ENTRIES_COUNT.
|
||||
* @param [out] storageInitError If function returns CO_ERROR_DATA_CORRUPT, then this variable contains a bit mask from
|
||||
* subIndexOD values, where data was not properly initialized. If other error, then this variable contains index or
|
||||
* erroneous entry. If there is hardware error like missing eeprom, then storageInitError is 0xFFFFFFFF and function
|
||||
* returns CO_ERROR_DATA_CORRUPT.
|
||||
*
|
||||
* @return CO_ERROR_NO, CO_ERROR_DATA_CORRUPT if data can not be initialized, CO_ERROR_ILLEGAL_ARGUMENT or
|
||||
* CO_ERROR_OUT_OF_MEMORY.
|
||||
*/
|
||||
CO_ReturnError_t CO_storageEeprom_init(CO_storage_t* storage, CO_CANmodule_t* CANmodule, void* storageModule,
|
||||
OD_entry_t* OD_1010_StoreParameters, OD_entry_t* OD_1011_RestoreDefaultParam,
|
||||
CO_storage_entry_t* entries, uint8_t entriesCount, uint32_t* storageInitError);
|
||||
|
||||
/**
|
||||
* Automatically update data if differs inside eeprom.
|
||||
*
|
||||
* Should be called cyclically by program. Each interval it updates one byte.
|
||||
*
|
||||
* @param storage This object
|
||||
* @param saveAll If true, all bytes are updated, useful on program end.
|
||||
*/
|
||||
void CO_storageEeprom_auto_process(CO_storage_t* storage, bool_t saveAll);
|
||||
|
||||
/** @} */ /* CO_storage_eeprom */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif /* (CO_CONFIG_STORAGE) & CO_CONFIG_STORAGE_ENABLE */
|
||||
|
||||
#endif /* CO_STORAGE_EEPROM_H */
|
||||
Reference in New Issue
Block a user