Skip to content

Commit

Permalink
Finish v4.1.4
Browse files Browse the repository at this point in the history
  • Loading branch information
michael-hillmann committed Dec 15, 2020
2 parents e5ea6be + c13d503 commit aad6a28
Show file tree
Hide file tree
Showing 14 changed files with 81 additions and 23 deletions.
16 changes: 14 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,21 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and starting with version 4.1.0 this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]
## [unreleased]

no changes

## [4.1.4] - 2020-12-15

### Added

- Allow CAN driver polling for testing and demo purpose (Don't use this in production!).
- Implement a simple NVM driver simulation in RAM.

### Fixed

- Add `CO_TASYNC` in quickstart object entry to trigger PDO transmission on write access.

## [4.1.3] - 2020-10-30

### Added
Expand Down Expand Up @@ -90,7 +101,8 @@ no changes
- First Open Source Release.


[unreleased]: https://github.com/embedded-office/canopen-stack/compare/v4.1.3...HEAD
[unreleased]: https://github.com/embedded-office/canopen-stack/compare/v4.1.4...HEAD
[4.1.4]: https://github.com/embedded-office/canopen-stack/compare/v4.1.3...v4.1.4
[4.1.3]: https://github.com/embedded-office/canopen-stack/compare/v4.1.2...v4.1.3
[4.1.2]: https://github.com/embedded-office/canopen-stack/compare/v4.1.1...v4.1.2
[4.1.1]: https://github.com/embedded-office/canopen-stack/compare/v4.1.0...v4.1.1
Expand Down
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
cmake_minimum_required (VERSION 3.15)
project (CanopenStack VERSION 4.1.3)
project (CanopenStack VERSION 4.1.4)

# Make CANopen library
add_subdirectory(canopen)
Expand Down
14 changes: 11 additions & 3 deletions canopen/include/co_if_can.h
Original file line number Diff line number Diff line change
Expand Up @@ -222,9 +222,16 @@ void COIfCanInit(struct CO_IF_T *cif, struct CO_NODE_T *node);

/*! \brief READ CAN FRAME
*
* This function waits for a CAN frame on the interface without timeout.
* If a CAN frame is received, the given frm will be filled with the
* received data.
* This function usually waits for a CAN frame on the interface without
* timeout. If a CAN frame is received, the given frm will be filled
* with the received data.
*
* For evaluation, demonstration or testing the CAN read may poll for
* a new CAN frame. In this case, the exceptional path with no received
* CAN frame is possible.
*
* \note Don't use the polling mode in production. This communication is
* not reliable, especially when synchronized PDOs are used.
*
* \param cif
* pointer to the interface structure
Expand All @@ -233,6 +240,7 @@ void COIfCanInit(struct CO_IF_T *cif, struct CO_NODE_T *node);
* pointer to the receive frame buffer
*
* \retval >0 the size of CO_IF_FRM on success
* \retval =0 special: nothing received during polling (timeout)
* \retval <0 the CAN driver error code
*/
int16_t COIfCanRead(struct CO_IF_T *cif, CO_IF_FRM *frm);
Expand Down
2 changes: 1 addition & 1 deletion canopen/include/co_ver.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@

#define CO_VER_MAJOR 4
#define CO_VER_MINOR 1
#define CO_VER_BUILD 3
#define CO_VER_BUILD 4

/******************************************************************************
* PUBLIC FUNCTIONS
Expand Down
2 changes: 1 addition & 1 deletion canopen/source/co_core.c
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ void CONodeProcess(CO_NODE *node)
uint8_t allowed;

result = COIfCanRead(&node->If, &frm);
if (result < 0) {
if (result <= 0) {
allowed = 0;
} else {
allowed = node->Nmt.Allowed;
Expand Down
9 changes: 8 additions & 1 deletion canopen/source/co_sdo_srv.c
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ CO_ERR COSdoResponse(CO_SDO *srv)
if ((cmd & 0xE3) == 0xC1) {
result = COSdoEndDownloadBlock(srv);
} else {
srv->Blk.State = BLK_DOWNLOAD;
srv->Blk.State = BLK_DOWNLOAD;
result = COSdoDownloadBlock(srv);
}
return (result);
Expand Down Expand Up @@ -214,6 +214,9 @@ CO_ERR COSdoResponse(CO_SDO *srv)
COSdoAbort(srv, CO_SDO_ERR_CMD);
}

/* set DLC for the SDO response */
CO_SET_DLC(srv->Frm, 8u);

return (result);
}

Expand Down Expand Up @@ -819,6 +822,10 @@ CO_ERR COSdoUploadBlock(CO_SDO *srv)
srv->Blk.Size = 0;
}
}

/* set DLC for block transfers */
CO_SET_DLC(srv->Frm, 8u);

srv->Blk.State = BLK_UPLOAD;
srv->Blk.SegCnt = 1;
while ((srv->Blk.SegCnt <= srv->Blk.SegNum) && (finished == 0)) {
Expand Down
5 changes: 4 additions & 1 deletion docs/_api_interface/co-if-read.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ This function waits for a CAN frame on the interface without timeout.

If a CAN frame is received, the given receive frame buffer will be filled with the received data. The read function is rarely used from within the application, because the CANopen will receive all messages by default and allows to work on all non-CANopen messages with a callback function.

*For evaluation, demonstration, or testing purpose this CAN read function may poll for a new CAN frame. In this special case, the additional return value with no received CAN frame is possible. Don't use the polling mode in production; you should use interrupt driven CAN communication. The CAN polling is not suitable for CANopen.*

#### Prototype

```c
Expand All @@ -29,6 +31,7 @@ int16_t COIfCanRead(CO_IF *cif, CO_IF_FRM *frm);
#### Returned Value
- `>0` : size of `CO_IF_FRM` on success
- `=0` : special: nothing received during polling (timeout)
- `<0` : an error is detected
### Example
Expand All @@ -40,7 +43,7 @@ If necessary, the following example show how to call the blocking receive functi
int16_t err;
:
err = COIfCanRead (&(AppNode.If), &frame);
if (err < 0) {
if (err <= 0) {
/* error in interface layer */
} else {
/* frame contains received data */
Expand Down
15 changes: 12 additions & 3 deletions docs/_examples/quickstart.md
Original file line number Diff line number Diff line change
Expand Up @@ -172,10 +172,16 @@ These entries are created using the following lines of code:
{CO_KEY(0x2100, 0, CO_UNSIGNED8 |CO_OBJ_D__R_), 0, (uintptr_t)3},
{CO_KEY(0x2100, 1, CO_UNSIGNED32|CO_OBJ___PR_), 0, (uintptr_t)&Obj2100_01_20},
{CO_KEY(0x2100, 2, CO_UNSIGNED8 |CO_OBJ___PR_), 0, (uintptr_t)&Obj2100_02_08},
{CO_KEY(0x2100, 3, CO_UNSIGNED8 |CO_OBJ___PR_), 0, (uintptr_t)&Obj2100_03_08},
{CO_KEY(0x2100, 3, CO_UNSIGNED8 |CO_OBJ___PR_), CO_TASYNC, (uintptr_t)&Obj2100_03_08},
:
```

**Note:**
The type `CO_TASYNC` for the object entry `2100h:03` indicates the transmission
of all PDOs, which includes this object. We use this mechanism to achieve the
PDO transmission on each write access to the second.
{:.info}

We also need to create three global variables to hold the runtime values of the
clock object:

Expand Down Expand Up @@ -406,13 +412,16 @@ static void AppClock(void *p_arg)
hour++;
}
COObjWrValue(od_sec, node, (void *)&second, sizeof(second), 0);
COObjWrValue(od_min, node, (void *)&minute, sizeof(minute), 0);
COObjWrValue(od_hr , node, (void *)&hour , sizeof(hour), 0);
COObjWrValue(od_min, node, (void *)&minute, sizeof(minute), 0);
COObjWrValue(od_sec, node, (void *)&second, sizeof(second), 0);
}
}
```

**Note:** The last write access with `COObjWrValue()` triggers the transmission of the PDO, because the corresponding object entry is defined as type `CO_TASYNC`.
{:.info}

### Hardware Connection

Next, you will need to add drivers to your project to interface the stack with
Expand Down
2 changes: 2 additions & 0 deletions docs/docs/hardware/can/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,8 @@ int16_t DrvCanRead(CO_IF_FRM *frm);

*Note: you must ensure that the messages are processed in the same order as they arrived from the CAN bus. Check the behavior of your CAN controller when you want to use multiple message buffers for a queued receiption.*

**Attention:** For evaluation, demonstration, or testing purpose this CAN read function may poll for a new CAN frame. In this special case, the additional return value with no received CAN frame is possible. Don't use the polling mode in production; you should use interrupt driven CAN communication (ideally with some kind of CAN frame queueing). The CAN polling is not suitable for robust CANopen communication.
{:.warning}

#### CAN Reset

Expand Down
1 change: 0 additions & 1 deletion docs/docs/start/structure.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ The following description explains the directories within this repository.
| +- quickstart : quickstart files
+- testsuite : --- testsuite ---
| +- app : test application
| +- driver : CAN simulation driver
| +- testfrm : test framework
| +- tests : tests for CANopen Stack
```
Expand Down
4 changes: 2 additions & 2 deletions driver/include/co_nvm_dummy.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@
/* TODO: rename the include protection to match the naming convention:
* CO_NVM_<device>_H_
*/
#ifndef CO_NVM_SIM_H_
#define CO_NVM_SIM_H_
#ifndef CO_NVM_DUMMY_H_
#define CO_NVM_DUMMY_H_

#ifdef __cplusplus /* for compatibility with C++ environments */
extern "C" {
Expand Down
26 changes: 22 additions & 4 deletions driver/source/co_nvm_sim.c
Original file line number Diff line number Diff line change
Expand Up @@ -66,14 +66,32 @@ static void DrvNvmInit(void)

static uint32_t DrvNvmRead(uint32_t start, uint8_t *buffer, uint32_t size)
{
uint32_t bytes = 0;
uint32_t idx = 0;
uint32_t pos;

idx = 0;
pos = start;
while ((pos < NVM_SIM_SIZE) && (size > 0)) {
buffer[idx] = NvmMemory[pos];
idx++;
pos++;
}

return (bytes);
return (idx);
}

static uint32_t DrvNvmWrite(uint32_t start, uint8_t *buffer, uint32_t size)
{
uint32_t bytes = 0;
uint32_t idx = 0;
uint32_t pos;

idx = 0;
pos = start;
while ((pos < NVM_SIM_SIZE) && (size > 0)) {
NvmMemory[pos] = buffer[idx];
idx++;
pos++;
}

return (bytes);
return (idx);
}
4 changes: 2 additions & 2 deletions example/quickstart/app/clock_app.c
Original file line number Diff line number Diff line change
Expand Up @@ -76,9 +76,9 @@ static void AppClock(void *p_arg)
hour++;
}

COObjWrValue(od_sec, node, (void *)&second, sizeof(second), 0);
COObjWrValue(od_min, node, (void *)&minute, sizeof(minute), 0);
COObjWrValue(od_hr , node, (void *)&hour , sizeof(hour), 0);
COObjWrValue(od_min, node, (void *)&minute, sizeof(minute), 0);
COObjWrValue(od_sec, node, (void *)&second, sizeof(second), 0);
}
}

Expand Down
2 changes: 1 addition & 1 deletion example/quickstart/app/clock_spec.c
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ static struct CO_OBJ_T ClockOD[APP_OBJ_N] = {
{CO_KEY(0x2100, 0, CO_UNSIGNED8 |CO_OBJ_D__R_), 0, (uintptr_t)3},
{CO_KEY(0x2100, 1, CO_UNSIGNED32|CO_OBJ___PR_), 0, (uintptr_t)&Obj2100_01_20},
{CO_KEY(0x2100, 2, CO_UNSIGNED8 |CO_OBJ___PR_), 0, (uintptr_t)&Obj2100_02_08},
{CO_KEY(0x2100, 3, CO_UNSIGNED8 |CO_OBJ___PR_), 0, (uintptr_t)&Obj2100_03_08},
{CO_KEY(0x2100, 3, CO_UNSIGNED8 |CO_OBJ___PR_), CO_TASYNC, (uintptr_t)&Obj2100_03_08},

CO_OBJ_DIR_ENDMARK /* mark end of used objects */
};
Expand Down

0 comments on commit aad6a28

Please sign in to comment.