Create 'storage' directory, move CO_storage.h/c, add CO_storageEeeprom.h/c
This commit is contained in:
parent
67a1ed7512
commit
76b43c88ef
14 changed files with 589 additions and 29 deletions
|
|
@ -354,20 +354,39 @@ typedef struct {
|
|||
* Must be defined in the **CO_driver_target.h** file.
|
||||
*
|
||||
* For more information on Data storage see @ref CO_storage or **CO_storage.h**
|
||||
* file. Structure members documented here are required. Target system shall add
|
||||
* own additional, hardware specific variables.
|
||||
* file. Structure members documented here are always required or required with
|
||||
* @ref CO_storage_eeprom. Target system may add own additional, hardware
|
||||
* specific variables.
|
||||
*/
|
||||
typedef struct {
|
||||
/** Address of data to store */
|
||||
/** Address of data to store, always required. */
|
||||
void *addr;
|
||||
/** Length of data to store */
|
||||
/** Length of data to store, always required. */
|
||||
size_t len;
|
||||
/** Sub index in OD objects 1010 and 1011, from 2 to 127. Writing
|
||||
* 0x65766173 to 1010,subIndexOD will store data to non-volatile memory.
|
||||
* Writing 0x64616F6C to 1011,subIndexOD will restore default data. */
|
||||
* Writing 0x64616F6C to 1011,subIndexOD will restore default data, always
|
||||
* required. */
|
||||
uint8_t subIndexOD;
|
||||
/** Attribute from @ref CO_storage_attributes_t */
|
||||
/** Attribute from @ref CO_storage_attributes_t, always required. */
|
||||
uint8_t attr;
|
||||
/** Pointer to storage module, target system specific usage, required with
|
||||
* @ref CO_storage_eeprom. */
|
||||
void *storageModule;
|
||||
/** CRC checksum of the data stored in eeprom, set on store, required with
|
||||
* @ref CO_storage_eeprom. */
|
||||
uint16_t crc;
|
||||
/** Address of entry signature inside eeprom, set by init, required with
|
||||
* @ref CO_storage_eeprom. */
|
||||
size_t eepromAddrSignature;
|
||||
/** Address of data inside eeprom, set by init, required with
|
||||
* @ref CO_storage_eeprom. */
|
||||
size_t eepromAddr;
|
||||
/** Offset of next byte being updated by automatic storage, required with
|
||||
* @ref CO_storage_eeprom. */
|
||||
size_t offset;
|
||||
/** Additional target specific parameters, optional. */
|
||||
void *additionalParameters;
|
||||
} CO_storage_entry_t;
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -147,6 +147,14 @@ extern "C" {
|
|||
* @}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup CO_CANopen_storage CANopen_storage
|
||||
* @{
|
||||
*
|
||||
* CANopen Object Dictionary and other data storage.
|
||||
* @}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup CO_CANopen_extra CANopen_extra
|
||||
* @{
|
||||
|
|
|
|||
1
Doxyfile
1
Doxyfile
|
|
@ -822,6 +822,7 @@ INPUT = README.md \
|
|||
304 \
|
||||
305 \
|
||||
309 \
|
||||
storage \
|
||||
extra \
|
||||
socketCAN
|
||||
|
||||
|
|
|
|||
2
Makefile
2
Makefile
|
|
@ -31,13 +31,13 @@ SOURCES = \
|
|||
$(CANOPEN_SRC)/301/CO_PDO.c \
|
||||
$(CANOPEN_SRC)/301/crc16-ccitt.c \
|
||||
$(CANOPEN_SRC)/301/CO_fifo.c \
|
||||
$(CANOPEN_SRC)/301/CO_storage.c \
|
||||
$(CANOPEN_SRC)/303/CO_LEDs.c \
|
||||
$(CANOPEN_SRC)/304/CO_GFC.c \
|
||||
$(CANOPEN_SRC)/304/CO_SRDO.c \
|
||||
$(CANOPEN_SRC)/305/CO_LSSslave.c \
|
||||
$(CANOPEN_SRC)/305/CO_LSSmaster.c \
|
||||
$(CANOPEN_SRC)/309/CO_gateway_ascii.c \
|
||||
$(CANOPEN_SRC)/storage/CO_storage.c \
|
||||
$(CANOPEN_SRC)/extra/CO_trace.c \
|
||||
$(CANOPEN_SRC)/CANopen.c \
|
||||
$(APPL_SRC)/OD.c \
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@
|
|||
#ifndef CO_STORAGE_BLANK_H
|
||||
#define CO_STORAGE_BLANK_H
|
||||
|
||||
#include "301/CO_storage.h"
|
||||
#include "storage/CO_storage.h"
|
||||
|
||||
#if ((CO_CONFIG_STORAGE) & CO_CONFIG_STORAGE_ENABLE) || defined CO_DOXYGEN
|
||||
|
||||
|
|
@ -33,8 +33,15 @@
|
|||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* See socketCAN/storageLinux.h and 301/CO_storage.h for information and
|
||||
* full example */
|
||||
/* This is very basic example of implementing (object dictionary) data storage.
|
||||
* Data storage is target specific. CO_storageBlank.h and .c files only shows
|
||||
* the basic principle, but does nothing. For complete example of storage see:
|
||||
* - CANopenPIC/PIC32 uses eeprom with CANopenNode/storage/CO_storage.h/.c,
|
||||
* CANopenNode/storage/CO_storageEeprom.h/.c, CANopenNode/storage/CO_eeprom.h
|
||||
* and CANopenPIC/PIC32/CO_eepromPIC32.c files.
|
||||
* - CANopenLinux uses file system with CANopenNode/storage/CO_storage.h/.c and
|
||||
* CANopenLinux/CO_storageLinux.h files.
|
||||
*/
|
||||
|
||||
CO_ReturnError_t CO_storageBlank_init(CO_storage_t *storage,
|
||||
CO_CANmodule_t *CANmodule,
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
CANopen documentation
|
||||
=====================
|
||||
CANopen device documentation
|
||||
============================
|
||||
**New Product**
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -26,9 +26,9 @@ SOURCES = \
|
|||
$(CANOPEN_SRC)/301/CO_TIME.c \
|
||||
$(CANOPEN_SRC)/301/CO_SYNC.c \
|
||||
$(CANOPEN_SRC)/301/CO_PDO.c \
|
||||
$(CANOPEN_SRC)/301/CO_storage.c \
|
||||
$(CANOPEN_SRC)/303/CO_LEDs.c \
|
||||
$(CANOPEN_SRC)/305/CO_LSSslave.c \
|
||||
$(CANOPEN_SRC)/storage/CO_storage.c \
|
||||
$(CANOPEN_SRC)/CANopen.c \
|
||||
$(APPL_SRC)/OD.c \
|
||||
$(DRV_SRC)/main_blank.c
|
||||
|
|
|
|||
|
|
@ -104,9 +104,8 @@ static ODR_t storeLinux(CO_storage_entry_t *entry, CO_CANmodule_t *CANmodule) {
|
|||
|
||||
/* rename existing file to *.old and *.tmp to existing */
|
||||
if (ret == ODR_OK) {
|
||||
if (rename(entry->filename, filename_old) != 0
|
||||
|| rename(filename_tmp, entry->filename) != 0
|
||||
) {
|
||||
rename(entry->filename, filename_old);
|
||||
if (rename(filename_tmp, entry->filename) != 0) {
|
||||
ret = ODR_HW;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@
|
|||
#ifndef CO_STORAGE_LINUX_H
|
||||
#define CO_STORAGE_LINUX_H
|
||||
|
||||
#include "301/CO_storage.h"
|
||||
#include "storage/CO_storage.h"
|
||||
|
||||
#if ((CO_CONFIG_STORAGE) & CO_CONFIG_STORAGE_ENABLE) || defined CO_DOXYGEN
|
||||
|
||||
|
|
|
|||
133
storage/CO_eeprom.h
Normal file
133
storage/CO_eeprom.h
Normal file
|
|
@ -0,0 +1,133 @@
|
|||
/**
|
||||
* 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 CANopenNode, an opensource CANopen Stack.
|
||||
* Project home page is <https://github.com/CANopenNode/CANopenNode>.
|
||||
* For more information on CANopen see <http://www.can-cia.org/>.
|
||||
*
|
||||
* 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 accross 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 */
|
||||
|
|
@ -22,7 +22,7 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "301/CO_storage.h"
|
||||
#include "storage/CO_storage.h"
|
||||
|
||||
#if (CO_CONFIG_STORAGE) & CO_CONFIG_STORAGE_ENABLE
|
||||
|
||||
|
|
@ -41,8 +41,8 @@ extern "C" {
|
|||
#endif
|
||||
|
||||
/**
|
||||
* @defgroup CO_storage Data storage
|
||||
* @ingroup CO_CANopen_301
|
||||
* @defgroup CO_storage Data storage base
|
||||
* @ingroup CO_CANopen_storage
|
||||
* @{
|
||||
*
|
||||
* CANopen provides OD objects 0x1010 and 0x1011 for control of storing and
|
||||
|
|
@ -138,15 +138,9 @@ typedef struct {
|
|||
* @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. Each array element
|
||||
* contains:
|
||||
* - Pointer and length of data, which will be stored or restored,
|
||||
* - subIndexOD, which binds entry to specific subindex in 1010 and 1011 OD
|
||||
* objects. Multiple entries with the same subIndexOD are possible.
|
||||
* - Attribute, which specifies, if data is stored on command or automatically
|
||||
* and also specifies if data is able to restore. @ref CO_storage_attributes_t
|
||||
* - Additional target specific parameters. See @ref CO_storage_entry_t in
|
||||
* CO_driver_target.h file.
|
||||
* 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.
|
||||
268
storage/CO_storageEeprom.c
Normal file
268
storage/CO_storageEeprom.c
Normal file
|
|
@ -0,0 +1,268 @@
|
|||
/*
|
||||
* 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 CANopenNode, an opensource CANopen Stack.
|
||||
* Project home page is <https://github.com/CANopenNode/CANopenNode>.
|
||||
* For more information on CANopen see <http://www.can-cia.org/>.
|
||||
*
|
||||
* 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
|
||||
|
||||
/*
|
||||
* 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) {
|
||||
bool_t writeOk;
|
||||
|
||||
/* save data to the eeprom */
|
||||
CO_LOCK_OD(CANmodule);
|
||||
writeOk = CO_eeprom_writeBlock(entry->storageModule, entry->addr,
|
||||
entry->eepromAddr, entry->len);
|
||||
entry->crc = crc16_ccitt(entry->addr, entry->len, 0);
|
||||
CO_UNLOCK_OD(CANmodule);
|
||||
|
||||
/* 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 = 0xFFFFFFFF;
|
||||
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 == 0
|
||||
|| storageInitError == NULL
|
||||
) {
|
||||
return CO_ERROR_ILLEGAL_ARGUMENT;
|
||||
}
|
||||
|
||||
storage->enabled = false;
|
||||
|
||||
/* Initialize storage hardware */
|
||||
if (!CO_eeprom_init(storageModule)) {
|
||||
*storageInitError = 0xFFFFFFFF;
|
||||
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[entriesCount];
|
||||
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 & CO_storage_auto) != 0;
|
||||
|
||||
/* verify arguments */
|
||||
if (entry->addr == NULL || entry->len == 0 || entry->subIndexOD < 2) {
|
||||
*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 > 31) 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 i = 0; i < storage->entriesCount; i++) {
|
||||
CO_storage_entry_t *entry = &storage->entries[i];
|
||||
|
||||
if ((entry->attr & CO_storage_auto) == 0)
|
||||
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 */
|
||||
131
storage/CO_storageEeprom.h
Normal file
131
storage/CO_storageEeprom.h
Normal file
|
|
@ -0,0 +1,131 @@
|
|||
/**
|
||||
* 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 CANopenNode, an opensource CANopen Stack.
|
||||
* Project home page is <https://github.com/CANopenNode/CANopenNode>.
|
||||
* For more information on CANopen see <http://www.can-cia.org/>.
|
||||
*
|
||||
* 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"
|
||||
|
||||
#if ((CO_CONFIG_STORAGE) & CO_CONFIG_STORAGE_ENABLE) || defined CO_DOXYGEN
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @defgroup CO_storage_eeprom Data storage in eeprom
|
||||
* @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, used for @ref CO_LOCK_OD() macro.
|
||||
* @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
|
||||
* @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 */
|
||||
Loading…
Reference in a new issue