Pass CO_CANmodule_t argument to all the CO_LOCK_...() and CO_UNLOCK_...() macros.
https://github.com/CANopenNode/CANopenNode/issues/162#issuecomment-777438875
This commit is contained in:
parent
9b3f329d52
commit
fc81777097
17 changed files with 146 additions and 71 deletions
|
|
@ -739,7 +739,7 @@ void CO_error(CO_EM_t *em, bool_t setError, const uint8_t errorBit,
|
|||
#endif
|
||||
|
||||
/* safely write data, and increment pointers */
|
||||
CO_LOCK_EMCY();
|
||||
CO_LOCK_EMCY(em->CANdevTx);
|
||||
if (setError) *errorStatusBits |= bitmask;
|
||||
else *errorStatusBits &= ~bitmask;
|
||||
|
||||
|
|
@ -763,7 +763,7 @@ void CO_error(CO_EM_t *em, bool_t setError, const uint8_t errorBit,
|
|||
}
|
||||
#endif /* (CO_CONFIG_EM) & (CO_CONFIG_EM_PRODUCER | CO_CONFIG_EM_HISTORY) */
|
||||
|
||||
CO_UNLOCK_EMCY();
|
||||
CO_UNLOCK_EMCY(em->CANdevTx);
|
||||
|
||||
#if (CO_CONFIG_EM) & CO_CONFIG_FLAG_CALLBACK_PRE
|
||||
#if (CO_CONFIG_EM) & CO_CONFIG_EM_PRODUCER
|
||||
|
|
|
|||
|
|
@ -70,9 +70,7 @@ OD_size_t OD_readOriginal(OD_stream_t *stream, uint8_t subIndex,
|
|||
}
|
||||
}
|
||||
|
||||
CO_LOCK_OD();
|
||||
memcpy(buf, dataOrig, dataLenToCopy);
|
||||
CO_UNLOCK_OD();
|
||||
return dataLenToCopy;
|
||||
}
|
||||
|
||||
|
|
@ -127,9 +125,7 @@ OD_size_t OD_writeOriginal(OD_stream_t *stream, uint8_t subIndex,
|
|||
return 0;
|
||||
}
|
||||
|
||||
CO_LOCK_OD();
|
||||
memcpy(dataOrig, buf, dataLenToCopy);
|
||||
CO_UNLOCK_OD();
|
||||
return dataLenToCopy;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -404,6 +404,10 @@ OD_entry_t *OD_find(OD_t *od, uint16_t index);
|
|||
* Find sub-object with specified sub-index on OD entry returned by OD_find.
|
||||
* Function populates io structure with sub-object data.
|
||||
*
|
||||
* @warning
|
||||
* Read and write functions may be called from different threads, so critical
|
||||
* sections in custom functions must be observed, see @ref CO_critical_sections.
|
||||
*
|
||||
* @param entry OD entry returned by @ref OD_find().
|
||||
* @param subIndex Sub-index of the variable from the OD object.
|
||||
* @param [out] io Structure will be populated on success.
|
||||
|
|
@ -428,6 +432,21 @@ static inline uint16_t OD_getIndex(const OD_entry_t *entry) {
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* Check, if OD variable is mappable to PDO or SRDO.
|
||||
*
|
||||
* If OD variable is mappable, then it may be necessary to protect read/write
|
||||
* access from mainline function. See @ref CO_critical_sections.
|
||||
*
|
||||
* @param stream Object Dictionary stream object.
|
||||
*
|
||||
* @return true, if OD variable is mappable.
|
||||
*/
|
||||
static inline bool_t OD_mappable(OD_stream_t *stream) {
|
||||
return (stream->attribute & (ODA_TRPDO | ODA_TRSRDO)) != 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Restart read or write operation on OD variable
|
||||
*
|
||||
|
|
@ -476,8 +495,7 @@ uint32_t OD_getSDOabCode(ODR_t returnCode);
|
|||
*
|
||||
* @warning
|
||||
* Read and write functions may be called from different threads, so critical
|
||||
* sections in custom functions must be protected with @ref CO_LOCK_OD() and
|
||||
* @ref CO_UNLOCK_OD().
|
||||
* sections in custom functions must be observed, see @ref CO_critical_sections.
|
||||
*
|
||||
* @param entry OD entry returned by @ref OD_find().
|
||||
* @param extension Extension object, which must be initialized externally.
|
||||
|
|
|
|||
|
|
@ -622,9 +622,13 @@ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C,
|
|||
}
|
||||
if (abortCode == CO_SDO_AB_NONE) {
|
||||
ODR_t odRet;
|
||||
bool_t lock = OD_mappable(&SDO_C->OD_IO.stream);
|
||||
|
||||
/* write data to Object Dictionary */
|
||||
if (lock) { CO_LOCK_OD(SDO_C->CANdevTx); }
|
||||
SDO_C->OD_IO.write(&SDO_C->OD_IO.stream, SDO_C->subIndex,
|
||||
buf, count, &odRet);
|
||||
if (lock) { CO_UNLOCK_OD(SDO_C->CANdevTx); }
|
||||
|
||||
/* verify for errors in write */
|
||||
if (odRet != ODR_OK && odRet != ODR_PARTIAL) {
|
||||
|
|
@ -1211,11 +1215,14 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C,
|
|||
? countData : countFifo;
|
||||
uint8_t buf[countBuf + 1];
|
||||
ODR_t odRet;
|
||||
bool_t lock = OD_mappable(&SDO_C->OD_IO.stream);
|
||||
|
||||
/* load data from OD variable into the buffer */
|
||||
if (lock) { CO_LOCK_OD(SDO_C->CANdevTx); }
|
||||
OD_size_t countRd = SDO_C->OD_IO.read(&SDO_C->OD_IO.stream,
|
||||
SDO_C->subIndex,
|
||||
buf, countBuf, &odRet);
|
||||
if (lock) { CO_UNLOCK_OD(SDO_C->CANdevTx); }
|
||||
|
||||
if (odRet != ODR_OK && odRet != ODR_PARTIAL) {
|
||||
abortCode = (CO_SDO_abortCode_t)OD_getSDOabCode(odRet);
|
||||
|
|
|
|||
|
|
@ -552,8 +552,13 @@ static bool_t validateAndWriteToOD(CO_SDOserver_t *SDO,
|
|||
|
||||
/* write data */
|
||||
ODR_t odRet;
|
||||
bool_t lock = OD_mappable(&SDO->OD_IO.stream);
|
||||
|
||||
if (lock) { CO_LOCK_OD(SDO->CANdevTx); }
|
||||
SDO->OD_IO.write(&SDO->OD_IO.stream, SDO->subIndex,
|
||||
SDO->buf, SDO->bufOffsetWr, &odRet);
|
||||
if (lock) { CO_UNLOCK_OD(SDO->CANdevTx); }
|
||||
|
||||
SDO->bufOffsetWr = 0;
|
||||
|
||||
/* verify write error value */
|
||||
|
|
@ -609,10 +614,14 @@ static bool_t readFromOd(CO_SDOserver_t *SDO,
|
|||
/* load data from OD variable into the buffer */
|
||||
ODR_t odRet;
|
||||
uint8_t *bufShifted = SDO->buf + countRemain;
|
||||
bool_t lock = OD_mappable(&SDO->OD_IO.stream);
|
||||
|
||||
if (lock) { CO_LOCK_OD(SDO->CANdevTx); }
|
||||
OD_size_t countRd = SDO->OD_IO.read(&SDO->OD_IO.stream, SDO->subIndex,
|
||||
bufShifted,
|
||||
countRdRequest,
|
||||
&odRet);
|
||||
if (lock) { CO_UNLOCK_OD(SDO->CANdevTx); }
|
||||
|
||||
if (odRet != ODR_OK && odRet != ODR_PARTIAL) {
|
||||
*abortCode = (CO_SDO_abortCode_t)OD_getSDOabCode(odRet);
|
||||
|
|
@ -843,8 +852,13 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO,
|
|||
|
||||
/* Copy data */
|
||||
ODR_t odRet;
|
||||
bool_t lock = OD_mappable(&SDO->OD_IO.stream);
|
||||
|
||||
if (lock) { CO_LOCK_OD(SDO->CANdevTx); }
|
||||
SDO->OD_IO.write(&SDO->OD_IO.stream, SDO->subIndex,
|
||||
buf, dataSizeToWrite, &odRet);
|
||||
if (lock) { CO_UNLOCK_OD(SDO->CANdevTx); }
|
||||
|
||||
if (odRet != ODR_OK) {
|
||||
abortCode = (CO_SDO_abortCode_t)OD_getSDOabCode(odRet);
|
||||
SDO->state = CO_SDO_ST_ABORT;
|
||||
|
|
@ -1283,9 +1297,13 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO,
|
|||
#else /* Expedited transfer only */
|
||||
/* load data from OD variable */
|
||||
ODR_t odRet;
|
||||
bool_t lock = OD_mappable(&SDO->OD_IO.stream);
|
||||
|
||||
if (lock) { CO_LOCK_OD(SDO->CANdevTx); }
|
||||
OD_size_t count = SDO->OD_IO.read(&SDO->OD_IO.stream, SDO->subIndex,
|
||||
&SDO->CANtxBuff->data[4], 4,
|
||||
&odRet);
|
||||
if (lock) { CO_UNLOCK_OD(SDO->CANdevTx); }
|
||||
|
||||
/* strings are allowed to be shorter */
|
||||
if (odRet == ODR_PARTIAL
|
||||
|
|
|
|||
|
|
@ -380,19 +380,30 @@ typedef struct {
|
|||
* Otherwise mutexes or semaphores can be used.
|
||||
*
|
||||
* #### Reentrant functions
|
||||
* Functions CO_CANsend() from C_driver.h, CO_errorReport() from CO_Emergency.h
|
||||
* and CO_errorReset() from CO_Emergency.h may be called from different threads.
|
||||
* Critical sections must be protected. Either by disabling scheduler or
|
||||
* interrupts or by mutexes or semaphores.
|
||||
* Functions CO_CANsend() from C_driver.h, and CO_error() from CO_Emergency.h
|
||||
* may be called from different threads. Critical sections must be protected.
|
||||
* Either by disabling scheduler or interrupts or by mutexes or semaphores.
|
||||
* Lock/unlock macro is called with pointer to CAN module, which may be used
|
||||
* inside.
|
||||
*
|
||||
* #### Object Dictionary variables
|
||||
* In general, there are two threads, which accesses OD variables: mainline and
|
||||
* timer. CANopenNode initialization and SDO server runs in mainline. PDOs runs
|
||||
* in faster timer thread. Processing of PDOs must not be interrupted by
|
||||
* mainline. Mainline thread must protect sections, which accesses the same OD
|
||||
* variables as timer thread. This care must also take the application. Note
|
||||
* that not all variables are allowed to be mapped to PDOs, so they may not need
|
||||
* to be protected. SDO server protects sections with access to OD variables.
|
||||
* In general, there are two threads, which accesses OD variables: mainline
|
||||
* (initialization, storage, SDO access) and timer (PDO access). CANopenNode
|
||||
* uses locking mechanism, where SDO server (or other mainline code) prevents
|
||||
* execution of the real-time thread at the moment it reads or writes OD
|
||||
* variable. CO_LOCK_OD(CAN_MODULE) and CO_UNLOCK_OD(CAN_MODULE) macros
|
||||
* are used to protect:
|
||||
* - Whole real-time thread,
|
||||
* - SDO server protects read/write access to OD variable, if specific OD
|
||||
* variable has ODA_TRPDO or ODA_TRSRDO from @ref OD_attributes_t set. If
|
||||
* those attributes are not set, OD variable is not locked by SDO server.
|
||||
* Locking of long OD variables, not accessible from real-time thread, may
|
||||
* block RT thread.
|
||||
* - Any mainline code, which accesses PDO-mappable OD variable, must protect
|
||||
* read/write with locking macros. Use @ref OD_mappable() for check.
|
||||
* - Other cases, where non-PDO-mappable OD variable is used inside real-time
|
||||
* thread by some other part of the user application must be considered with
|
||||
* special care.
|
||||
*
|
||||
* #### Synchronization functions for CAN receive
|
||||
* After CAN message is received, it is pre-processed in CANrx_callback(), which
|
||||
|
|
@ -411,17 +422,17 @@ typedef struct {
|
|||
*/
|
||||
|
||||
/** Lock critical section in CO_CANsend() */
|
||||
#define CO_LOCK_CAN_SEND()
|
||||
#define CO_LOCK_CAN_SEND(CAN_MODULE)
|
||||
/** Unlock critical section in CO_CANsend() */
|
||||
#define CO_UNLOCK_CAN_SEND()
|
||||
#define CO_UNLOCK_CAN_SEND(CAN_MODULE)
|
||||
/** Lock critical section in CO_errorReport() or CO_errorReset() */
|
||||
#define CO_LOCK_EMCY()
|
||||
#define CO_LOCK_EMCY(CAN_MODULE)
|
||||
/** Unlock critical section in CO_errorReport() or CO_errorReset() */
|
||||
#define CO_UNLOCK_EMCY()
|
||||
#define CO_UNLOCK_EMCY(CAN_MODULE)
|
||||
/** Lock critical section when accessing Object Dictionary */
|
||||
#define CO_LOCK_OD()
|
||||
#define CO_LOCK_OD(CAN_MODULE)
|
||||
/** Unock critical section when accessing Object Dictionary */
|
||||
#define CO_UNLOCK_OD()
|
||||
#define CO_UNLOCK_OD(CAN_MODULE)
|
||||
|
||||
/** Check if new message has arrived */
|
||||
#define CO_FLAG_READ(rxNew) ((rxNew) != NULL)
|
||||
|
|
|
|||
|
|
@ -65,7 +65,7 @@ static OD_size_t OD_write_1010(OD_stream_t *stream, uint8_t subIndex,
|
|||
if (subIndex == 1 || entry->subIndexOD == subIndex) {
|
||||
if (found == 0) found = 1;
|
||||
if ((entry->attr & CO_storage_cmd) != 0) {
|
||||
ODR_t code = storage->store(entry);
|
||||
ODR_t code = storage->store(entry, storage->CANmodule);
|
||||
if (code != ODR_OK) *returnCode = code;
|
||||
found = 2;
|
||||
}
|
||||
|
|
@ -117,7 +117,7 @@ static OD_size_t OD_write_1011(OD_stream_t *stream, uint8_t subIndex,
|
|||
if (subIndex == 1 || entry->subIndexOD == subIndex) {
|
||||
if (found == 0) found = 1;
|
||||
if ((entry->attr & CO_storage_restore) != 0) {
|
||||
ODR_t code = storage->restore(entry);
|
||||
ODR_t code = storage->restore(entry, storage->CANmodule);
|
||||
if (code != ODR_OK) *returnCode = code;
|
||||
found = 2;
|
||||
}
|
||||
|
|
@ -131,10 +131,13 @@ static OD_size_t OD_write_1011(OD_stream_t *stream, uint8_t subIndex,
|
|||
|
||||
|
||||
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),
|
||||
ODR_t (*restore)(CO_storage_entry_t *entry),
|
||||
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)
|
||||
{
|
||||
|
|
@ -144,6 +147,7 @@ CO_ReturnError_t CO_storage_init(CO_storage_t *storage,
|
|||
}
|
||||
|
||||
/* Configure object variables */
|
||||
storage->CANmodule = CANmodule;
|
||||
storage->store = store;
|
||||
storage->restore = restore;
|
||||
storage->entries = entries;
|
||||
|
|
|
|||
|
|
@ -104,8 +104,11 @@ typedef enum {
|
|||
typedef struct {
|
||||
OD_extension_t OD_1010_extension; /**< Extension for OD object */
|
||||
OD_extension_t OD_1011_extension; /**< Extension for OD object */
|
||||
ODR_t (*store)(CO_storage_entry_t *entry); /**< From CO_storage_init() */
|
||||
ODR_t (*restore)(CO_storage_entry_t *entry); /**< From CO_storage_init() */
|
||||
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() */
|
||||
} CO_storage_t;
|
||||
|
|
@ -121,6 +124,7 @@ typedef struct {
|
|||
*
|
||||
* @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 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
|
||||
|
|
@ -146,10 +150,13 @@ typedef struct {
|
|||
* @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),
|
||||
ODR_t (*restore)(CO_storage_entry_t *entry),
|
||||
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);
|
||||
|
||||
|
|
|
|||
|
|
@ -916,6 +916,7 @@ CO_ReturnError_t CO_CANopenInit(CO_t *co,
|
|||
uint8_t nodeId,
|
||||
uint32_t *errInfo)
|
||||
{
|
||||
(void)SDOclientTimeoutTime_ms; (void)SDOclientBlockTransfer;
|
||||
CO_ReturnError_t err;
|
||||
|
||||
if (co == NULL
|
||||
|
|
|
|||
|
|
@ -23,6 +23,8 @@ The term **OD entry** means structure element, which contains some basic propert
|
|||
### Access
|
||||
Application and the stack have access to OD objects via universal @ref OD_t object and @ref OD_find() function. No direct access to custom structures, which define object dictionary, is required. Properties for specific OD variable is fetched with @ref OD_getSub() function. Access to actual variable is via **read** and **write** functions. Pointer to those two functions is fetched by @ref OD_getSub(). See @ref OD_stream_t. See also shortcuts: @ref CO_ODgetSetters, for access to data of different type.
|
||||
|
||||
Note that OD variables can be accessed from different threads. CANopenNode basically runs in two threads: fast real-time (PDO processing, etc.) and time non-critical mainline (SDO etc.). Both threads have access to OD variables, so care must be taken into account. CANopenNode uses locking mechanism, where SDO server prevents execution of the real-time thread at the moment it reads or writes OD variable. The same protection of the OD variables is necessary in @ref CO_storage. For more information see @ref CO_critical_sections in CO_driver.h.
|
||||
|
||||
### Example usage
|
||||
```c
|
||||
extern OD_t *ODxyz;
|
||||
|
|
|
|||
|
|
@ -200,7 +200,7 @@ CO_ReturnError_t CO_CANsend(CO_CANmodule_t *CANmodule, CO_CANtx_t *buffer){
|
|||
err = CO_ERROR_TX_OVERFLOW;
|
||||
}
|
||||
|
||||
CO_LOCK_CAN_SEND();
|
||||
CO_LOCK_CAN_SEND(CANmodule);
|
||||
/* if CAN TX buffer is free, copy message to it */
|
||||
if(1 && CANmodule->CANtxCount == 0){
|
||||
CANmodule->bufferInhibitFlag = buffer->syncFlag;
|
||||
|
|
@ -211,7 +211,7 @@ CO_ReturnError_t CO_CANsend(CO_CANmodule_t *CANmodule, CO_CANtx_t *buffer){
|
|||
buffer->bufferFull = true;
|
||||
CANmodule->CANtxCount++;
|
||||
}
|
||||
CO_UNLOCK_CAN_SEND();
|
||||
CO_UNLOCK_CAN_SEND(CANmodule);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
|
@ -221,7 +221,7 @@ CO_ReturnError_t CO_CANsend(CO_CANmodule_t *CANmodule, CO_CANtx_t *buffer){
|
|||
void CO_CANclearPendingSyncPDOs(CO_CANmodule_t *CANmodule){
|
||||
uint32_t tpdoDeleted = 0U;
|
||||
|
||||
CO_LOCK_CAN_SEND();
|
||||
CO_LOCK_CAN_SEND(CANmodule);
|
||||
/* Abort message from CAN module, if there is synchronous TPDO.
|
||||
* Take special care with this functionality. */
|
||||
if(/*messageIsOnCanBuffer && */CANmodule->bufferInhibitFlag){
|
||||
|
|
@ -244,7 +244,7 @@ void CO_CANclearPendingSyncPDOs(CO_CANmodule_t *CANmodule){
|
|||
buffer++;
|
||||
}
|
||||
}
|
||||
CO_UNLOCK_CAN_SEND();
|
||||
CO_UNLOCK_CAN_SEND(CANmodule);
|
||||
|
||||
|
||||
if(tpdoDeleted != 0U){
|
||||
|
|
|
|||
|
|
@ -233,16 +233,16 @@ typedef struct {
|
|||
|
||||
|
||||
/* (un)lock critical section in CO_CANsend() */
|
||||
#define CO_LOCK_CAN_SEND()
|
||||
#define CO_UNLOCK_CAN_SEND()
|
||||
#define CO_LOCK_CAN_SEND(CAN_MODULE)
|
||||
#define CO_UNLOCK_CAN_SEND(CAN_MODULE)
|
||||
|
||||
/* (un)lock critical section in CO_errorReport() or CO_errorReset() */
|
||||
#define CO_LOCK_EMCY()
|
||||
#define CO_UNLOCK_EMCY()
|
||||
#define CO_LOCK_EMCY(CAN_MODULE)
|
||||
#define CO_UNLOCK_EMCY(CAN_MODULE)
|
||||
|
||||
/* (un)lock critical section when accessing Object Dictionary */
|
||||
#define CO_LOCK_OD()
|
||||
#define CO_UNLOCK_OD()
|
||||
#define CO_LOCK_OD(CAN_MODULE)
|
||||
#define CO_UNLOCK_OD(CAN_MODULE)
|
||||
|
||||
/* Synchronization between CAN receive and message processing threads. */
|
||||
#define CO_MemoryBarrier()
|
||||
|
|
|
|||
|
|
@ -370,34 +370,38 @@ typedef struct {
|
|||
|
||||
|
||||
#ifdef CO_SINGLE_THREAD
|
||||
#define CO_LOCK_CAN_SEND()
|
||||
#define CO_UNLOCK_CAN_SEND()
|
||||
#define CO_LOCK_EMCY()
|
||||
#define CO_UNLOCK_EMCY()
|
||||
#define CO_LOCK_OD()
|
||||
#define CO_UNLOCK_OD()
|
||||
#define CO_LOCK_CAN_SEND(CAN_MODULE)
|
||||
#define CO_UNLOCK_CAN_SEND(CAN_MODULE)
|
||||
#define CO_LOCK_EMCY(CAN_MODULE)
|
||||
#define CO_UNLOCK_EMCY(CAN_MODULE)
|
||||
#define CO_LOCK_OD(CAN_MODULE)
|
||||
#define CO_UNLOCK_OD(CAN_MODULE)
|
||||
#define CO_MemoryBarrier()
|
||||
#else
|
||||
|
||||
/* (un)lock critical section in CO_CANsend() - unused */
|
||||
#define CO_LOCK_CAN_SEND()
|
||||
#define CO_UNLOCK_CAN_SEND()
|
||||
#define CO_LOCK_CAN_SEND(CAN_MODULE)
|
||||
#define CO_UNLOCK_CAN_SEND(CAN_MODULE)
|
||||
|
||||
/* (un)lock critical section in CO_errorReport() or CO_errorReset() */
|
||||
extern pthread_mutex_t CO_EMCY_mutex;
|
||||
static inline int CO_LOCK_EMCY() {
|
||||
static inline int CO_LOCK_EMCY(CO_CANmodule_t *CANmodule) {
|
||||
(void)CANmodule;
|
||||
return pthread_mutex_lock(&CO_EMCY_mutex);
|
||||
}
|
||||
static inline void CO_UNLOCK_EMCY() {
|
||||
static inline void CO_UNLOCK_EMCY(CO_CANmodule_t *CANmodule) {
|
||||
(void)CANmodule;
|
||||
(void)pthread_mutex_unlock(&CO_EMCY_mutex);
|
||||
}
|
||||
|
||||
/* (un)lock critical section when accessing Object Dictionary */
|
||||
extern pthread_mutex_t CO_OD_mutex;
|
||||
static inline int CO_LOCK_OD() {
|
||||
static inline int CO_LOCK_OD(CO_CANmodule_t *CANmodule) {
|
||||
(void)CANmodule;
|
||||
return pthread_mutex_lock(&CO_OD_mutex);
|
||||
}
|
||||
static inline void CO_UNLOCK_OD() {
|
||||
static inline void CO_UNLOCK_OD(CO_CANmodule_t *CANmodule) {
|
||||
(void)CANmodule;
|
||||
(void)pthread_mutex_unlock(&CO_OD_mutex);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -329,7 +329,7 @@ void CO_epoll_processRT(CO_epoll_t *ep,
|
|||
if (!realtime || ep->timerEvent) {
|
||||
uint32_t *pTimerNext_us = realtime ? NULL : &ep->timerNext_us;
|
||||
|
||||
CO_LOCK_OD();
|
||||
CO_LOCK_OD(co->CANmodule);
|
||||
if (!co->nodeIdUnconfigured && co->CANmodule->CANnormal) {
|
||||
bool_t syncWas = false;
|
||||
|
||||
|
|
@ -346,7 +346,7 @@ void CO_epoll_processRT(CO_epoll_t *ep,
|
|||
#endif
|
||||
(void) syncWas; (void) pTimerNext_us;
|
||||
}
|
||||
CO_UNLOCK_OD();
|
||||
CO_UNLOCK_OD(co->CANmodule);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -438,6 +438,7 @@ int main (int argc, char *argv[]) {
|
|||
#if (CO_CONFIG_STORAGE) & CO_CONFIG_STORAGE_ENABLE
|
||||
uint8_t pendingNodeIdOriginal = CO_pending.nodeId;
|
||||
err = CO_storageLinux_init(&storage,
|
||||
CO->CANmodule,
|
||||
OD_ENTRY_H1010_storeParameters,
|
||||
OD_ENTRY_H1011_restoreDefaultParameters,
|
||||
storageEntries,
|
||||
|
|
@ -512,9 +513,9 @@ int main (int argc, char *argv[]) {
|
|||
|
||||
/* Wait rt_thread. */
|
||||
if(!firstRun) {
|
||||
CO_LOCK_OD();
|
||||
CO_LOCK_OD(CO->CANmodule);
|
||||
CO->CANmodule->CANnormal = false;
|
||||
CO_UNLOCK_OD();
|
||||
CO_UNLOCK_OD(CO->CANmodule);
|
||||
}
|
||||
|
||||
/* Enter CAN configuration. */
|
||||
|
|
@ -695,17 +696,17 @@ int main (int argc, char *argv[]) {
|
|||
storageIntervalTimer += epMain.timeDifference_us;
|
||||
}
|
||||
else {
|
||||
uint32_t err = CO_storageLinux_auto_process(&storage, false);
|
||||
if(err != storageErrorPrev && !CO->nodeIdUnconfigured) {
|
||||
if(err != 0) {
|
||||
uint32_t mask = CO_storageLinux_auto_process(&storage, false);
|
||||
if(mask != storageErrorPrev && !CO->nodeIdUnconfigured) {
|
||||
if(mask != 0) {
|
||||
CO_errorReport(CO->em, CO_EM_NON_VOLATILE_AUTO_SAVE,
|
||||
CO_EMC_HARDWARE, err);
|
||||
CO_EMC_HARDWARE, mask);
|
||||
}
|
||||
else {
|
||||
CO_errorReset(CO->em, CO_EM_NON_VOLATILE_AUTO_SAVE, 0);
|
||||
}
|
||||
}
|
||||
storageErrorPrev = err;
|
||||
storageErrorPrev = mask;
|
||||
storageIntervalTimer = 0;
|
||||
}
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -37,7 +37,8 @@
|
|||
*
|
||||
* For more information see file CO_storage.h, CO_storage_entry_t.
|
||||
*/
|
||||
static ODR_t storeLinux(CO_storage_entry_t *entry) {
|
||||
static ODR_t storeLinux(CO_storage_entry_t *entry, CO_CANmodule_t *CANmodule) {
|
||||
(void) CANmodule;
|
||||
ODR_t ret = ODR_OK;
|
||||
uint16_t crc_store;
|
||||
|
||||
|
|
@ -64,10 +65,10 @@ static ODR_t storeLinux(CO_storage_entry_t *entry) {
|
|||
ret = ODR_HW;
|
||||
}
|
||||
else {
|
||||
CO_LOCK_OD();
|
||||
CO_LOCK_OD(CANmodule);
|
||||
size_t cnt = fwrite(entry->addr, 1, entry->len, fp);
|
||||
crc_store = crc16_ccitt(entry->addr, entry->len, 0);
|
||||
CO_UNLOCK_OD();
|
||||
CO_UNLOCK_OD(CANmodule);
|
||||
cnt += fwrite(&crc_store, 1, sizeof(crc_store), fp);
|
||||
fclose(fp);
|
||||
if (cnt != (entry->len + sizeof(crc_store))) {
|
||||
|
|
@ -123,7 +124,8 @@ static ODR_t storeLinux(CO_storage_entry_t *entry) {
|
|||
*
|
||||
* For more information see file CO_storage.h, CO_storage_entry_t.
|
||||
*/
|
||||
static ODR_t restoreLinux(CO_storage_entry_t *entry) {
|
||||
static ODR_t restoreLinux(CO_storage_entry_t *entry, CO_CANmodule_t *CANmodule){
|
||||
(void) CANmodule;
|
||||
ODR_t ret = ODR_OK;
|
||||
|
||||
/* close the file first, if auto storage */
|
||||
|
|
@ -161,6 +163,7 @@ static ODR_t restoreLinux(CO_storage_entry_t *entry) {
|
|||
|
||||
|
||||
CO_ReturnError_t CO_storageLinux_init(CO_storage_t *storage,
|
||||
CO_CANmodule_t *CANmodule,
|
||||
OD_entry_t *OD_1010_StoreParameters,
|
||||
OD_entry_t *OD_1011_RestoreDefaultParam,
|
||||
CO_storage_entry_t *entries,
|
||||
|
|
@ -168,7 +171,6 @@ CO_ReturnError_t CO_storageLinux_init(CO_storage_t *storage,
|
|||
uint32_t *storageInitError)
|
||||
{
|
||||
CO_ReturnError_t ret;
|
||||
*storageInitError = 0;
|
||||
|
||||
/* verify arguments */
|
||||
if (storage == NULL || entries == NULL || entriesCount == 0
|
||||
|
|
@ -179,6 +181,7 @@ CO_ReturnError_t CO_storageLinux_init(CO_storage_t *storage,
|
|||
|
||||
/* initialize storage and OD extensions */
|
||||
ret = CO_storage_init(storage,
|
||||
CANmodule,
|
||||
OD_1010_StoreParameters,
|
||||
OD_1011_RestoreDefaultParam,
|
||||
storeLinux,
|
||||
|
|
@ -190,6 +193,7 @@ CO_ReturnError_t CO_storageLinux_init(CO_storage_t *storage,
|
|||
}
|
||||
|
||||
/* initialize entries */
|
||||
*storageInitError = 0;
|
||||
for (uint8_t i = 0; i < entriesCount; i++) {
|
||||
CO_storage_entry_t *entry = &entries[i];
|
||||
bool_t dataCorrupt = false;
|
||||
|
|
@ -288,9 +292,9 @@ uint32_t CO_storageLinux_auto_process(CO_storage_t *storage,
|
|||
if (crc != entry->crc) {
|
||||
size_t cnt;
|
||||
rewind(entry->fp);
|
||||
CO_LOCK_OD();
|
||||
CO_LOCK_OD(storage->CANmodule);
|
||||
cnt = fwrite(entry->addr, 1, entry->len, entry->fp);
|
||||
CO_UNLOCK_OD();
|
||||
CO_UNLOCK_OD(storage->CANmodule);
|
||||
cnt += fwrite(&crc, 1, sizeof(crc), entry->fp);
|
||||
fflush(entry->fp);
|
||||
if (cnt == (entry->len + sizeof(crc))) {
|
||||
|
|
|
|||
|
|
@ -55,6 +55,7 @@ extern "C" {
|
|||
*
|
||||
* @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 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
|
||||
|
|
@ -70,6 +71,7 @@ extern "C" {
|
|||
* CO_ERROR_ILLEGAL_ARGUMENT or CO_ERROR_OUT_OF_MEMORY.
|
||||
*/
|
||||
CO_ReturnError_t CO_storageLinux_init(CO_storage_t *storage,
|
||||
CO_CANmodule_t *CANmodule,
|
||||
OD_entry_t *OD_1010_StoreParameters,
|
||||
OD_entry_t *OD_1011_RestoreDefaultParam,
|
||||
CO_storage_entry_t *entries,
|
||||
|
|
|
|||
Loading…
Reference in a new issue