2014-09-12 16:01:33 +02:00
|
|
|
/*
|
2017-10-25 13:39:20 +02:00
|
|
|
* Licensed under the GNU General Public License version 2 with exceptions. See
|
|
|
|
* LICENSE file in the project root for full license information
|
2014-09-12 16:01:33 +02:00
|
|
|
*/
|
|
|
|
|
2015-05-07 17:43:02 +02:00
|
|
|
/** \file
|
2014-09-12 16:01:33 +02:00
|
|
|
* \brief
|
|
|
|
* CAN over EtherCAT (CoE) module.
|
|
|
|
*
|
|
|
|
* SDO read / write and SDO service functions
|
|
|
|
*/
|
2015-05-07 17:43:02 +02:00
|
|
|
|
2015-05-21 10:12:45 +02:00
|
|
|
#include <stddef.h>
|
2014-09-12 16:01:33 +02:00
|
|
|
#include <string.h>
|
2015-05-07 16:25:17 +02:00
|
|
|
#include <cc.h>
|
2014-09-12 16:01:33 +02:00
|
|
|
#include "esc.h"
|
|
|
|
#include "esc_coe.h"
|
|
|
|
|
|
|
|
#define BITS2BYTES(b) ((b + 7) >> 3)
|
|
|
|
|
2019-01-20 15:35:23 +01:00
|
|
|
/* Fetch value from object dictionary */
|
|
|
|
#define OBJ_VALUE_FETCH(v, o) \
|
|
|
|
((o).data ? *(__typeof__ (v) *)(o).data : (__typeof__ (v))(o).value)
|
|
|
|
|
2017-10-25 14:31:30 +02:00
|
|
|
/** Search for an object sub-index.
|
|
|
|
*
|
|
|
|
* @param[in] nidx = local array index of object we want to find sub-index to
|
|
|
|
* @param[in] subindex = value on sub-index of object we want to locate
|
|
|
|
* @return local array index if we succeed, -1 if we didn't find the index.
|
|
|
|
*/
|
|
|
|
int16_t SDO_findsubindex (int16_t nidx, uint8_t subindex)
|
|
|
|
{
|
|
|
|
const _objd *objd;
|
|
|
|
int16_t n = 0;
|
|
|
|
uint8_t maxsub;
|
|
|
|
objd = SDOobjects[nidx].objdesc;
|
|
|
|
maxsub = SDOobjects[nidx].maxsub;
|
|
|
|
while (((objd + n)->subindex < subindex) && (n < maxsub))
|
|
|
|
{
|
|
|
|
n++;
|
|
|
|
}
|
|
|
|
if ((objd + n)->subindex != subindex)
|
|
|
|
{
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
return n;
|
|
|
|
}
|
2014-09-12 16:01:33 +02:00
|
|
|
|
|
|
|
/** Search for an object index matching the wanted value in the Object List.
|
|
|
|
*
|
|
|
|
* @param[in] index = value on index of object we want to locate
|
|
|
|
* @return local array index if we succeed, -1 if we didn't find the index.
|
|
|
|
*/
|
2015-05-21 10:41:13 +02:00
|
|
|
int32_t SDO_findobject (uint16_t index)
|
2014-09-12 16:01:33 +02:00
|
|
|
{
|
2015-05-21 10:41:13 +02:00
|
|
|
int32_t n = 0;
|
2014-09-12 16:01:33 +02:00
|
|
|
while (SDOobjects[n].index < index)
|
|
|
|
{
|
|
|
|
n++;
|
|
|
|
}
|
|
|
|
if (SDOobjects[n].index != index)
|
|
|
|
{
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
return n;
|
|
|
|
}
|
|
|
|
|
2019-01-20 15:35:23 +01:00
|
|
|
/**
|
|
|
|
* Calculate the size in Bytes of RxPDO or TxPDOs by adding the
|
|
|
|
* objects in SyncManager SDO 1C1x.
|
2014-09-12 16:01:33 +02:00
|
|
|
*
|
2019-04-09 12:05:20 +02:00
|
|
|
* A list of mapped objects is created for fast lookup of
|
|
|
|
* dynamically mapped process data. The max size of the list (@a
|
|
|
|
* max_mappings) can be set to 0 if dynamic processdata is not
|
|
|
|
* supported.
|
|
|
|
*
|
|
|
|
* The output variable @a nmappings is set to 0 if dynamic processdata
|
|
|
|
* is not supported. It is set to the number of mapped objects if
|
|
|
|
* dynamic processdata is supported, or -1 if the mapping was
|
|
|
|
* incorrect.
|
|
|
|
|
2019-01-20 15:35:23 +01:00
|
|
|
* @param[in] index = SM index
|
|
|
|
* @param[out] nmappings = number of mapped objects in SM, or -1 if
|
|
|
|
* mapping is invalid
|
|
|
|
* @param[out] mappings = list of mapped objects in SM
|
|
|
|
* @param[out] max_mappings = max number of mapped objects in SM
|
2017-10-25 14:31:30 +02:00
|
|
|
* @return size of RxPDO or TxPDOs in Bytes.
|
2014-09-12 16:01:33 +02:00
|
|
|
*/
|
2019-04-09 12:05:20 +02:00
|
|
|
uint16_t sizeOfPDO (uint16_t index, int * nmappings, _SMmap * mappings,
|
2019-01-20 15:35:23 +01:00
|
|
|
int max_mappings)
|
2014-09-12 16:01:33 +02:00
|
|
|
{
|
2019-01-20 15:35:23 +01:00
|
|
|
uint16_t offset = 0, hobj;
|
|
|
|
uint8_t si, sic, c;
|
2015-05-21 10:41:13 +02:00
|
|
|
int16_t nidx;
|
2015-05-21 10:21:37 +02:00
|
|
|
const _objd *objd;
|
2017-10-25 14:31:30 +02:00
|
|
|
const _objd *objd1c1x;
|
2019-01-20 15:35:23 +01:00
|
|
|
int mapIx = 0;
|
2014-09-12 16:01:33 +02:00
|
|
|
|
2019-01-20 15:35:23 +01:00
|
|
|
if ((index != RX_PDO_OBJIDX) && (index != TX_PDO_OBJIDX))
|
2014-09-12 16:01:33 +02:00
|
|
|
{
|
2019-01-20 15:35:23 +01:00
|
|
|
return 0;
|
2014-09-12 16:01:33 +02:00
|
|
|
}
|
2019-01-20 15:35:23 +01:00
|
|
|
|
|
|
|
nidx = SDO_findobject (index);
|
|
|
|
if(nidx < 0)
|
2014-09-12 16:01:33 +02:00
|
|
|
{
|
2019-01-20 15:35:23 +01:00
|
|
|
return 0;
|
2014-09-12 16:01:33 +02:00
|
|
|
}
|
|
|
|
|
2019-01-20 15:35:23 +01:00
|
|
|
objd1c1x = SDOobjects[nidx].objdesc;
|
2014-09-12 16:01:33 +02:00
|
|
|
|
2019-01-20 15:35:23 +01:00
|
|
|
si = OBJ_VALUE_FETCH (si, objd1c1x[0]);
|
2017-10-25 14:31:30 +02:00
|
|
|
if (si)
|
2014-09-12 16:01:33 +02:00
|
|
|
{
|
|
|
|
for (sic = 1; sic <= si; sic++)
|
|
|
|
{
|
2019-01-20 15:35:23 +01:00
|
|
|
hobj = OBJ_VALUE_FETCH (hobj, objd1c1x[sic]);
|
2014-09-12 16:01:33 +02:00
|
|
|
nidx = SDO_findobject (hobj);
|
2019-01-20 15:35:23 +01:00
|
|
|
if (nidx >= 0)
|
2014-09-12 16:01:33 +02:00
|
|
|
{
|
2019-01-20 15:35:23 +01:00
|
|
|
uint8_t maxsub;
|
|
|
|
|
2014-09-12 16:01:33 +02:00
|
|
|
objd = SDOobjects[nidx].objdesc;
|
2019-01-20 15:35:23 +01:00
|
|
|
maxsub = OBJ_VALUE_FETCH (maxsub, objd[0]);
|
|
|
|
|
|
|
|
for (c = 1; c <= maxsub; c++)
|
2014-09-12 16:01:33 +02:00
|
|
|
{
|
2019-01-20 15:35:23 +01:00
|
|
|
uint32_t value = OBJ_VALUE_FETCH (value, objd[c]);
|
|
|
|
uint8_t bitlength = value & 0xFF;
|
|
|
|
|
2019-04-09 12:05:20 +02:00
|
|
|
if (max_mappings > 0)
|
2019-01-20 15:35:23 +01:00
|
|
|
{
|
2019-04-09 12:05:20 +02:00
|
|
|
uint16_t index = value >> 16;
|
|
|
|
uint8_t subindex = (value >> 8) & 0xFF;
|
|
|
|
const _objd * mapping;
|
2019-01-20 15:35:23 +01:00
|
|
|
|
2019-04-09 12:05:20 +02:00
|
|
|
if (mapIx == max_mappings)
|
|
|
|
{
|
|
|
|
/* Too many mapped objects */
|
|
|
|
*nmappings = -1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
DPRINT ("%04x:%02x @ %d\n", index, subindex, offset);
|
2019-01-20 15:35:23 +01:00
|
|
|
|
2019-04-09 12:05:20 +02:00
|
|
|
if (index == 0 && subindex == 0)
|
2019-01-20 15:35:23 +01:00
|
|
|
{
|
2019-04-09 12:05:20 +02:00
|
|
|
/* Padding element */
|
2019-01-20 15:35:23 +01:00
|
|
|
mapping = NULL;
|
|
|
|
}
|
2019-04-09 12:05:20 +02:00
|
|
|
else
|
|
|
|
{
|
|
|
|
nidx = SDO_findobject (index);
|
|
|
|
if (nidx >= 0)
|
|
|
|
{
|
|
|
|
int16_t nsub;
|
|
|
|
|
|
|
|
nsub = SDO_findsubindex (nidx, subindex);
|
|
|
|
if (nsub < 0)
|
|
|
|
{
|
|
|
|
/* Mapped subindex does not exist */
|
|
|
|
*nmappings = -1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
mapping = &SDOobjects[nidx].objdesc[nsub];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Mapped index does not exist */
|
|
|
|
*nmappings = -1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
2019-01-20 15:35:23 +01:00
|
|
|
|
2019-04-09 12:05:20 +02:00
|
|
|
mappings[mapIx].obj = mapping;
|
|
|
|
mappings[mapIx++].offset = offset;
|
2019-01-20 15:35:23 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
offset += bitlength;
|
2014-09-12 16:01:33 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-04-09 12:05:20 +02:00
|
|
|
|
|
|
|
if (max_mappings > 0)
|
|
|
|
{
|
|
|
|
*nmappings = mapIx;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
*nmappings = 0;
|
|
|
|
}
|
|
|
|
|
2019-01-20 15:35:23 +01:00
|
|
|
return BITS2BYTES (offset);
|
2014-09-12 16:01:33 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/** Copy to mailbox.
|
|
|
|
*
|
|
|
|
* @param[in] source = pointer to source
|
|
|
|
* @param[in] dest = pointer to destination
|
|
|
|
* @param[in] size = Size to copy
|
|
|
|
*/
|
2015-05-21 10:41:13 +02:00
|
|
|
void copy2mbx (void *source, void *dest, uint16_t size)
|
2014-09-12 16:01:33 +02:00
|
|
|
{
|
|
|
|
memcpy (dest, source, size);
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Function for sending an SDO Abort reply.
|
|
|
|
*
|
|
|
|
* @param[in] index = index of object causing abort reply
|
|
|
|
* @param[in] sub-index = sub-index of object causing abort reply
|
|
|
|
* @param[in] abortcode = abort code to send in reply
|
|
|
|
*/
|
2015-05-21 10:41:13 +02:00
|
|
|
void SDO_abort (uint16_t index, uint8_t subindex, uint32_t abortcode)
|
2014-09-12 16:01:33 +02:00
|
|
|
{
|
2015-05-21 10:41:13 +02:00
|
|
|
uint8_t MBXout;
|
2014-09-12 16:01:33 +02:00
|
|
|
_COEsdo *coeres;
|
|
|
|
MBXout = ESC_claimbuffer ();
|
|
|
|
if (MBXout)
|
|
|
|
{
|
2017-10-25 14:31:30 +02:00
|
|
|
coeres = (_COEsdo *) &MBX[MBXout * ESC_MBXSIZE];
|
2014-09-12 16:01:33 +02:00
|
|
|
coeres->mbxheader.length = htoes (COE_DEFAULTLENGTH);
|
|
|
|
coeres->mbxheader.mbxtype = MBXCOE;
|
|
|
|
coeres->coeheader.numberservice =
|
|
|
|
htoes ((0 & 0x01f) | (COE_SDOREQUEST << 12));
|
|
|
|
coeres->index = htoes (index);
|
|
|
|
coeres->subindex = subindex;
|
|
|
|
coeres->command = COE_COMMAND_SDOABORT;
|
|
|
|
coeres->size = htoel (abortcode);
|
|
|
|
MBXcontrol[MBXout].state = MBXstate_outreq;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Function for responding on requested SDO Upload, sending the content
|
|
|
|
* requested in a free Mailbox buffer. Depending of size of data expedited,
|
|
|
|
* normal or segmented transfer is used. On error an SDO Abort will be sent.
|
|
|
|
*/
|
|
|
|
void SDO_upload (void)
|
|
|
|
{
|
|
|
|
_COEsdo *coesdo, *coeres;
|
2015-05-21 10:41:13 +02:00
|
|
|
uint16_t index;
|
|
|
|
uint8_t subindex;
|
|
|
|
int16_t nidx, nsub;
|
|
|
|
uint8_t MBXout;
|
|
|
|
uint32_t size;
|
|
|
|
uint8_t dss;
|
2015-05-21 10:21:37 +02:00
|
|
|
const _objd *objd;
|
2014-09-12 16:01:33 +02:00
|
|
|
coesdo = (_COEsdo *) &MBX[0];
|
|
|
|
index = etohs (coesdo->index);
|
|
|
|
subindex = coesdo->subindex;
|
|
|
|
nidx = SDO_findobject (index);
|
|
|
|
if (nidx >= 0)
|
|
|
|
{
|
|
|
|
nsub = SDO_findsubindex (nidx, subindex);
|
|
|
|
if (nsub >= 0)
|
|
|
|
{
|
|
|
|
objd = SDOobjects[nidx].objdesc;
|
|
|
|
MBXout = ESC_claimbuffer ();
|
|
|
|
if (MBXout)
|
|
|
|
{
|
2017-10-25 14:31:30 +02:00
|
|
|
coeres = (_COEsdo *) &MBX[MBXout * ESC_MBXSIZE];
|
2014-09-12 16:01:33 +02:00
|
|
|
coeres->mbxheader.length = htoes (COE_DEFAULTLENGTH);
|
|
|
|
coeres->mbxheader.mbxtype = MBXCOE;
|
|
|
|
coeres->coeheader.numberservice =
|
|
|
|
htoes ((0 & 0x01f) | (COE_SDORESPONSE << 12));
|
|
|
|
size = (objd + nsub)->bitlength;
|
|
|
|
/* expedited bits used calculation */
|
|
|
|
dss = 0x0c;
|
|
|
|
if (size > 8)
|
|
|
|
{
|
|
|
|
dss = 0x08;
|
|
|
|
}
|
|
|
|
if (size > 16)
|
|
|
|
{
|
|
|
|
dss = 0x04;
|
|
|
|
}
|
|
|
|
if (size > 24)
|
|
|
|
{
|
|
|
|
dss = 0x00;
|
|
|
|
}
|
|
|
|
coeres->index = htoes (index);
|
|
|
|
coeres->subindex = subindex;
|
|
|
|
if (size <= 32)
|
|
|
|
{
|
|
|
|
/* expedited response i.e. length<=4 bytes */
|
|
|
|
coeres->command = COE_COMMAND_UPLOADRESPONSE +
|
|
|
|
COE_SIZE_INDICATOR + COE_EXPEDITED_INDICATOR + dss;
|
2015-05-21 10:12:45 +02:00
|
|
|
if ((objd + nsub)->data == NULL)
|
2014-09-12 16:01:33 +02:00
|
|
|
{
|
|
|
|
/* use constant value */
|
|
|
|
coeres->size = htoel ((objd + nsub)->value);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* convert bits to bytes */
|
|
|
|
size = (size + 7) >> 3;
|
|
|
|
/* use dynamic data */
|
|
|
|
copy2mbx ((objd + nsub)->data, &(coeres->size), size);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* normal response i.e. length>4 bytes */
|
|
|
|
coeres->command = COE_COMMAND_UPLOADRESPONSE +
|
|
|
|
COE_SIZE_INDICATOR;
|
|
|
|
/* convert bits to bytes */
|
|
|
|
size = (size + 7) >> 3;
|
|
|
|
coeres->size = htoel (size);
|
2017-10-25 14:31:30 +02:00
|
|
|
if ((size + COE_HEADERSIZE) > ESC_MBXDSIZE)
|
2014-09-12 16:01:33 +02:00
|
|
|
{
|
|
|
|
/* segmented transfer needed */
|
|
|
|
/* set total size in bytes */
|
|
|
|
ESCvar.frags = size;
|
|
|
|
/* limit to mailbox size */
|
2017-10-25 14:31:30 +02:00
|
|
|
size = ESC_MBXDSIZE - COE_HEADERSIZE;
|
2014-09-12 16:01:33 +02:00
|
|
|
/* number of bytes done */
|
|
|
|
ESCvar.fragsleft = size;
|
|
|
|
/* signal segmented transfer */
|
|
|
|
ESCvar.segmented = MBXSEU;
|
|
|
|
ESCvar.data = (objd + nsub)->data;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ESCvar.segmented = 0;
|
|
|
|
}
|
|
|
|
coeres->mbxheader.length = htoes (COE_HEADERSIZE + size);
|
|
|
|
/* use dynamic data */
|
|
|
|
copy2mbx ((objd + nsub)->data, (&(coeres->size)) + 1, size);
|
|
|
|
}
|
|
|
|
MBXcontrol[MBXout].state = MBXstate_outreq;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
SDO_abort (index, subindex, ABORT_NOSUBINDEX);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
SDO_abort (index, subindex, ABORT_NOOBJECT);
|
|
|
|
}
|
|
|
|
MBXcontrol[0].state = MBXstate_idle;
|
|
|
|
ESCvar.xoe = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Function for handling the following SDO Upload if previous SDOUpload
|
|
|
|
* response was flagged it needed to be segmented.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
void SDO_uploadsegment (void)
|
|
|
|
{
|
|
|
|
_COEsdo *coesdo, *coeres;
|
2015-05-21 10:41:13 +02:00
|
|
|
uint8_t MBXout;
|
|
|
|
uint32_t size, offset;
|
2014-09-12 16:01:33 +02:00
|
|
|
coesdo = (_COEsdo *) &MBX[0];
|
|
|
|
MBXout = ESC_claimbuffer ();
|
|
|
|
if (MBXout)
|
|
|
|
{
|
2017-10-25 14:31:30 +02:00
|
|
|
coeres = (_COEsdo *) &MBX[MBXout * ESC_MBXSIZE];
|
2014-09-12 16:01:33 +02:00
|
|
|
offset = ESCvar.fragsleft;
|
|
|
|
size = ESCvar.frags - ESCvar.fragsleft;
|
|
|
|
coeres->mbxheader.mbxtype = MBXCOE;
|
|
|
|
coeres->coeheader.numberservice =
|
|
|
|
htoes ((0 & 0x01f) | (COE_SDORESPONSE << 12));
|
|
|
|
coeres->command = COE_COMMAND_UPLOADSEGMENT + (coesdo->command & COE_TOGGLEBIT); // copy toggle bit
|
2017-10-25 14:31:30 +02:00
|
|
|
if ((size + COE_SEGMENTHEADERSIZE) > ESC_MBXDSIZE)
|
2014-09-12 16:01:33 +02:00
|
|
|
{
|
|
|
|
/* more segmented transfer needed */
|
|
|
|
/* limit to mailbox size */
|
2017-10-25 14:31:30 +02:00
|
|
|
size = ESC_MBXDSIZE - COE_SEGMENTHEADERSIZE;
|
2014-09-12 16:01:33 +02:00
|
|
|
/* number of bytes done */
|
|
|
|
ESCvar.fragsleft += size;
|
|
|
|
coeres->mbxheader.length = htoes (COE_SEGMENTHEADERSIZE + size);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* last segment */
|
|
|
|
ESCvar.segmented = 0;
|
|
|
|
ESCvar.frags = 0;
|
|
|
|
ESCvar.fragsleft = 0;
|
|
|
|
coeres->command += COE_COMMAND_LASTSEGMENTBIT;
|
|
|
|
if (size >= 7)
|
|
|
|
{
|
|
|
|
coeres->mbxheader.length = htoes (COE_SEGMENTHEADERSIZE + size);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
coeres->command += (7 - size) << 1;
|
|
|
|
coeres->mbxheader.length = htoes (COE_DEFAULTLENGTH);
|
|
|
|
}
|
|
|
|
}
|
2015-05-21 10:41:13 +02:00
|
|
|
copy2mbx ((uint8_t *) ESCvar.data + offset, (&(coeres->command)) + 1, size); //copy to mailbox
|
2014-09-12 16:01:33 +02:00
|
|
|
|
|
|
|
MBXcontrol[MBXout].state = MBXstate_outreq;
|
|
|
|
}
|
|
|
|
MBXcontrol[0].state = MBXstate_idle;
|
|
|
|
ESCvar.xoe = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/** Function for handling incoming requested SDO Download, validating the
|
|
|
|
* request and sending an response. On error an SDO Abort will be sent.
|
|
|
|
*/
|
|
|
|
void SDO_download (void)
|
|
|
|
{
|
|
|
|
_COEsdo *coesdo, *coeres;
|
2015-05-21 10:41:13 +02:00
|
|
|
uint16_t index;
|
|
|
|
uint8_t subindex;
|
|
|
|
int16_t nidx, nsub;
|
|
|
|
uint8_t MBXout;
|
|
|
|
uint16_t size, actsize;
|
2015-05-21 10:21:37 +02:00
|
|
|
const _objd *objd;
|
2015-05-21 10:41:13 +02:00
|
|
|
uint32_t *mbxdata;
|
2019-01-20 15:35:23 +01:00
|
|
|
uint32_t abort;
|
|
|
|
|
2014-09-12 16:01:33 +02:00
|
|
|
coesdo = (_COEsdo *) &MBX[0];
|
|
|
|
index = etohs (coesdo->index);
|
|
|
|
subindex = coesdo->subindex;
|
|
|
|
nidx = SDO_findobject (index);
|
|
|
|
if (nidx >= 0)
|
|
|
|
{
|
|
|
|
nsub = SDO_findsubindex (nidx, subindex);
|
|
|
|
if (nsub >= 0)
|
|
|
|
{
|
|
|
|
objd = SDOobjects[nidx].objdesc;
|
2019-04-02 21:26:46 +02:00
|
|
|
uint8_t access = (objd + nsub)->flags & 0x3f;
|
2019-01-30 18:53:00 +01:00
|
|
|
uint8_t state = ESCvar.ALstatus & 0x0f;
|
|
|
|
if (access == ATYPE_RW ||
|
|
|
|
(access == ATYPE_RWpre && state == ESCpreop))
|
2014-09-12 16:01:33 +02:00
|
|
|
{
|
|
|
|
/* expedited? */
|
|
|
|
if (coesdo->command & COE_EXPEDITED_INDICATOR)
|
|
|
|
{
|
|
|
|
size = 4 - ((coesdo->command & 0x0c) >> 2);
|
|
|
|
mbxdata = &(coesdo->size);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2019-01-30 11:07:46 +01:00
|
|
|
/* normal download */
|
2016-01-27 22:14:36 +01:00
|
|
|
size = (etohl (coesdo->size) & 0xffff);
|
2014-09-12 16:01:33 +02:00
|
|
|
mbxdata = (&(coesdo->size)) + 1;
|
|
|
|
}
|
|
|
|
actsize = ((objd + nsub)->bitlength + 7) >> 3;
|
|
|
|
if (actsize == size)
|
|
|
|
{
|
2019-01-20 15:35:23 +01:00
|
|
|
abort = ESC_pre_objecthandler (
|
|
|
|
index,
|
|
|
|
subindex,
|
|
|
|
mbxdata,
|
|
|
|
size,
|
2019-04-02 21:26:46 +02:00
|
|
|
(objd + nsub)->flags
|
2019-01-20 15:35:23 +01:00
|
|
|
);
|
|
|
|
if (abort == 0)
|
2014-09-12 16:01:33 +02:00
|
|
|
{
|
2016-01-27 22:14:36 +01:00
|
|
|
copy2mbx (mbxdata, (objd + nsub)->data, size);
|
2014-09-12 16:01:33 +02:00
|
|
|
MBXout = ESC_claimbuffer ();
|
|
|
|
if (MBXout)
|
|
|
|
{
|
2017-10-25 14:31:30 +02:00
|
|
|
coeres = (_COEsdo *) &MBX[MBXout * ESC_MBXSIZE];
|
2014-09-12 16:01:33 +02:00
|
|
|
coeres->mbxheader.length = htoes (COE_DEFAULTLENGTH);
|
|
|
|
coeres->mbxheader.mbxtype = MBXCOE;
|
|
|
|
coeres->coeheader.numberservice =
|
|
|
|
htoes ((0 & 0x01f) | (COE_SDORESPONSE << 12));
|
|
|
|
coeres->index = htoes (index);
|
|
|
|
coeres->subindex = subindex;
|
|
|
|
coeres->command = COE_COMMAND_DOWNLOADRESPONSE;
|
|
|
|
coeres->size = htoel (0);
|
|
|
|
MBXcontrol[MBXout].state = MBXstate_outreq;
|
|
|
|
}
|
2019-01-20 15:35:23 +01:00
|
|
|
/* external object write handler */
|
2019-04-02 21:26:46 +02:00
|
|
|
ESC_objecthandler (index, subindex, (objd + nsub)->flags);
|
2019-01-20 15:35:23 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
SDO_abort (index, subindex, abort);
|
2014-09-12 16:01:33 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
SDO_abort (index, subindex, ABORT_TYPEMISMATCH);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2019-01-30 18:53:00 +01:00
|
|
|
if (access == ATYPE_RWpre)
|
2014-09-12 16:01:33 +02:00
|
|
|
{
|
|
|
|
SDO_abort (index, subindex, ABORT_NOTINTHISSTATE);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
SDO_abort (index, subindex, ABORT_READONLY);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
SDO_abort (index, subindex, ABORT_NOSUBINDEX);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
SDO_abort (index, subindex, ABORT_NOOBJECT);
|
|
|
|
}
|
|
|
|
MBXcontrol[0].state = MBXstate_idle;
|
|
|
|
ESCvar.xoe = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Function for sending an SDO Info Error reply.
|
|
|
|
*
|
|
|
|
* @param[in] abortcode = = abort code to send in reply
|
|
|
|
*/
|
2015-05-21 10:41:13 +02:00
|
|
|
void SDO_infoerror (uint32_t abortcode)
|
2014-09-12 16:01:33 +02:00
|
|
|
{
|
2015-05-21 10:41:13 +02:00
|
|
|
uint8_t MBXout;
|
2014-09-12 16:01:33 +02:00
|
|
|
_COEobjdesc *coeres;
|
|
|
|
MBXout = ESC_claimbuffer ();
|
|
|
|
if (MBXout)
|
|
|
|
{
|
2017-10-25 14:31:30 +02:00
|
|
|
coeres = (_COEobjdesc *) &MBX[MBXout * ESC_MBXSIZE];
|
2015-05-21 10:41:13 +02:00
|
|
|
coeres->mbxheader.length = htoes ((uint16_t) 0x0a);
|
2014-09-12 16:01:33 +02:00
|
|
|
coeres->mbxheader.mbxtype = MBXCOE;
|
|
|
|
coeres->coeheader.numberservice =
|
|
|
|
htoes ((0 & 0x01f) | (COE_SDOINFORMATION << 12));
|
|
|
|
/* SDO info error request */
|
|
|
|
coeres->infoheader.opcode = COE_INFOERROR;
|
|
|
|
coeres->infoheader.incomplete = 0;
|
|
|
|
coeres->infoheader.reserved = 0x00;
|
|
|
|
coeres->infoheader.fragmentsleft = 0;
|
2019-03-04 16:40:48 +01:00
|
|
|
coeres->index = (uint16_t)htoel (abortcode);
|
|
|
|
coeres->datatype = (uint16_t)(htoel (abortcode) >> 16);
|
2014-09-12 16:01:33 +02:00
|
|
|
MBXcontrol[MBXout].state = MBXstate_outreq;
|
2017-10-25 14:38:38 +02:00
|
|
|
MBXcontrol[0].state = MBXstate_idle;
|
|
|
|
ESCvar.xoe = 0;
|
2014-09-12 16:01:33 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-10-25 14:31:30 +02:00
|
|
|
#define ODLISTSIZE ((ESC_MBX1_sml - ESC_MBXHSIZE - sizeof(_COEh) - sizeof(_INFOh) - 2) & 0xfffe)
|
2014-09-12 16:01:33 +02:00
|
|
|
|
|
|
|
/** Function for handling incoming requested SDO Get OD List, validating the
|
|
|
|
* request and sending an response. On error an SDO Info Error will be sent.
|
|
|
|
*/
|
|
|
|
void SDO_getodlist (void)
|
|
|
|
{
|
2015-05-21 10:41:13 +02:00
|
|
|
uint16_t frags;
|
|
|
|
uint8_t MBXout = 0;
|
|
|
|
uint16_t entries = 0;
|
|
|
|
uint16_t i, n;
|
|
|
|
uint16_t *p;
|
2014-09-12 16:01:33 +02:00
|
|
|
_COEobjdesc *coel, *coer;
|
|
|
|
|
|
|
|
while (SDOobjects[entries].index != 0xffff)
|
|
|
|
{
|
|
|
|
entries++;
|
|
|
|
}
|
|
|
|
ESCvar.entries = entries;
|
|
|
|
frags = ((entries << 1) + ODLISTSIZE - 1);
|
|
|
|
frags /= ODLISTSIZE;
|
|
|
|
coer = (_COEobjdesc *) &MBX[0];
|
|
|
|
/* check for unsupported opcodes */
|
|
|
|
if (etohs (coer->index) > 0x01)
|
|
|
|
{
|
|
|
|
SDO_infoerror (ABORT_UNSUPPORTED);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
MBXout = ESC_claimbuffer ();
|
|
|
|
}
|
|
|
|
if (MBXout)
|
|
|
|
{
|
2017-10-25 14:31:30 +02:00
|
|
|
coel = (_COEobjdesc *) &MBX[MBXout * ESC_MBXSIZE];
|
2014-09-12 16:01:33 +02:00
|
|
|
coel->mbxheader.mbxtype = MBXCOE;
|
|
|
|
coel->coeheader.numberservice =
|
|
|
|
htoes ((0 & 0x01f) | (COE_SDOINFORMATION << 12));
|
|
|
|
coel->infoheader.opcode = COE_GETODLISTRESPONSE;
|
|
|
|
/* number of objects request */
|
|
|
|
if (etohs (coer->index) == 0x00)
|
|
|
|
{
|
2015-05-21 10:41:13 +02:00
|
|
|
coel->index = htoes ((uint16_t) 0x00);
|
2014-09-12 16:01:33 +02:00
|
|
|
coel->infoheader.incomplete = 0;
|
|
|
|
coel->infoheader.reserved = 0x00;
|
2015-05-21 10:41:13 +02:00
|
|
|
coel->infoheader.fragmentsleft = htoes ((uint16_t) 0);
|
2014-09-12 16:01:33 +02:00
|
|
|
MBXcontrol[0].state = MBXstate_idle;
|
|
|
|
ESCvar.xoe = 0;
|
|
|
|
ESCvar.frags = frags;
|
|
|
|
ESCvar.fragsleft = frags - 1;
|
|
|
|
p = &(coel->datatype);
|
|
|
|
*p = htoes (entries);
|
|
|
|
p++;
|
|
|
|
*p = 0;
|
|
|
|
p++;
|
|
|
|
*p = 0;
|
|
|
|
p++;
|
|
|
|
*p = 0;
|
|
|
|
p++;
|
|
|
|
*p = 0;
|
|
|
|
coel->mbxheader.length = htoes (0x08 + (5 << 1));
|
|
|
|
}
|
|
|
|
/* only return all objects */
|
|
|
|
if (etohs (coer->index) == 0x01)
|
|
|
|
{
|
|
|
|
if (frags > 1)
|
|
|
|
{
|
|
|
|
coel->infoheader.incomplete = 1;
|
|
|
|
ESCvar.xoe = MBXCOE + MBXODL;
|
|
|
|
n = ODLISTSIZE >> 1;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
coel->infoheader.incomplete = 0;
|
|
|
|
MBXcontrol[0].state = MBXstate_idle;
|
|
|
|
ESCvar.xoe = 0;
|
|
|
|
n = entries;
|
|
|
|
}
|
|
|
|
coel->infoheader.reserved = 0x00;
|
|
|
|
ESCvar.frags = frags;
|
|
|
|
ESCvar.fragsleft = frags - 1;
|
|
|
|
coel->infoheader.fragmentsleft = htoes (ESCvar.fragsleft);
|
2015-05-21 10:41:13 +02:00
|
|
|
coel->index = htoes ((uint16_t) 0x01);
|
2014-09-12 16:01:33 +02:00
|
|
|
|
|
|
|
p = &(coel->datatype);
|
|
|
|
for (i = 0; i < n; i++)
|
|
|
|
{
|
|
|
|
*p = htoes (SDOobjects[i].index);
|
|
|
|
p++;
|
|
|
|
}
|
|
|
|
|
|
|
|
coel->mbxheader.length = htoes (0x08 + (n << 1));
|
|
|
|
}
|
|
|
|
MBXcontrol[MBXout].state = MBXstate_outreq;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/** Function for continuing sending left overs from previous requested
|
|
|
|
* SDO Get OD List, validating the request and sending an response.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
void SDO_getodlistcont (void)
|
|
|
|
{
|
2015-05-21 10:41:13 +02:00
|
|
|
uint8_t MBXout;
|
|
|
|
uint16_t i, n, s;
|
|
|
|
uint16_t *p;
|
2014-09-12 16:01:33 +02:00
|
|
|
_COEobjdesc *coel;
|
|
|
|
|
|
|
|
MBXout = ESC_claimbuffer ();
|
|
|
|
if (MBXout)
|
|
|
|
{
|
2017-10-25 14:31:30 +02:00
|
|
|
coel = (_COEobjdesc *) &MBX[MBXout * ESC_MBXSIZE];
|
2014-09-12 16:01:33 +02:00
|
|
|
coel->mbxheader.mbxtype = MBXCOE;
|
|
|
|
coel->coeheader.numberservice =
|
|
|
|
htoes ((0 & 0x01f) | (COE_SDOINFORMATION << 12));
|
|
|
|
coel->infoheader.opcode = COE_GETODLISTRESPONSE;
|
|
|
|
s = (ESCvar.frags - ESCvar.fragsleft) * (ODLISTSIZE >> 1);
|
|
|
|
if (ESCvar.fragsleft > 1)
|
|
|
|
{
|
|
|
|
coel->infoheader.incomplete = 1;
|
|
|
|
n = s + (ODLISTSIZE >> 1);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
coel->infoheader.incomplete = 0;
|
|
|
|
MBXcontrol[0].state = MBXstate_idle;
|
|
|
|
ESCvar.xoe = 0;
|
|
|
|
n = ESCvar.entries;
|
|
|
|
}
|
|
|
|
coel->infoheader.reserved = 0x00;
|
|
|
|
ESCvar.fragsleft--;
|
|
|
|
coel->infoheader.fragmentsleft = htoes (ESCvar.fragsleft);
|
|
|
|
/* pointer 2 bytes back to exclude index */
|
|
|
|
p = &(coel->index);
|
|
|
|
for (i = s; i < n; i++)
|
|
|
|
{
|
|
|
|
*p = htoes (SDOobjects[i].index);
|
|
|
|
p++;
|
|
|
|
}
|
|
|
|
coel->mbxheader.length = htoes (0x06 + ((n - s) << 1));
|
|
|
|
MBXcontrol[MBXout].state = MBXstate_outreq;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Function for handling incoming requested SDO Get Object Description,
|
|
|
|
* validating the request and sending an response. On error an
|
|
|
|
* SDO Info Error will be sent.
|
|
|
|
*/
|
|
|
|
void SDO_getod (void)
|
|
|
|
{
|
2015-05-21 10:41:13 +02:00
|
|
|
uint8_t MBXout;
|
|
|
|
uint16_t index;
|
|
|
|
int32_t nidx;
|
|
|
|
uint8_t *d;
|
|
|
|
const uint8_t *s;
|
|
|
|
uint8_t n = 0;
|
2014-09-12 16:01:33 +02:00
|
|
|
_COEobjdesc *coer, *coel;
|
|
|
|
coer = (_COEobjdesc *) &MBX[0];
|
|
|
|
index = etohs (coer->index);
|
|
|
|
nidx = SDO_findobject (index);
|
|
|
|
if (nidx >= 0)
|
|
|
|
{
|
|
|
|
MBXout = ESC_claimbuffer ();
|
|
|
|
if (MBXout)
|
|
|
|
{
|
2017-10-25 14:31:30 +02:00
|
|
|
coel = (_COEobjdesc *) &MBX[MBXout * ESC_MBXSIZE];
|
2014-09-12 16:01:33 +02:00
|
|
|
coel->mbxheader.mbxtype = MBXCOE;
|
|
|
|
coel->coeheader.numberservice =
|
|
|
|
htoes ((0 & 0x01f) | (COE_SDOINFORMATION << 12));
|
|
|
|
coel->infoheader.opcode = COE_GETODRESPONSE;
|
|
|
|
coel->infoheader.incomplete = 0;
|
|
|
|
coel->infoheader.reserved = 0x00;
|
|
|
|
coel->infoheader.fragmentsleft = htoes (0);
|
|
|
|
coel->index = htoes (index);
|
|
|
|
if (SDOobjects[nidx].objtype == OTYPE_VAR)
|
|
|
|
{
|
2015-05-21 10:41:13 +02:00
|
|
|
int32_t nsub = SDO_findsubindex (nidx, 0);
|
2015-05-21 10:21:37 +02:00
|
|
|
const _objd *objd = SDOobjects[nidx].objdesc;
|
2014-09-12 16:01:33 +02:00
|
|
|
coel->datatype = htoes ((objd + nsub)->datatype);
|
2019-03-27 14:17:02 +01:00
|
|
|
coel->maxsub = SDOobjects[nidx].maxsub;
|
|
|
|
}
|
|
|
|
else if (SDOobjects[nidx].objtype == OTYPE_ARRAY)
|
|
|
|
{
|
|
|
|
int32_t nsub = SDO_findsubindex (nidx, 0);
|
|
|
|
const _objd *objd = SDOobjects[nidx].objdesc;
|
|
|
|
coel->datatype = htoes ((objd + nsub)->datatype);
|
|
|
|
coel->maxsub = SDOobjects[nidx].objdesc->value;
|
2014-09-12 16:01:33 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
coel->datatype = htoes (0);
|
2019-03-27 14:17:02 +01:00
|
|
|
coel->maxsub = SDOobjects[nidx].objdesc->value;
|
2014-09-12 16:01:33 +02:00
|
|
|
}
|
|
|
|
coel->objectcode = SDOobjects[nidx].objtype;
|
2015-05-21 10:41:13 +02:00
|
|
|
s = (uint8_t *) SDOobjects[nidx].name;
|
|
|
|
d = (uint8_t *) &(coel->name);
|
2017-10-25 14:31:30 +02:00
|
|
|
while (*s && (n < (ESC_MBXDSIZE - 0x0c)))
|
2014-09-12 16:01:33 +02:00
|
|
|
{
|
|
|
|
*d = *s;
|
|
|
|
n++;
|
|
|
|
s++;
|
|
|
|
d++;
|
|
|
|
}
|
|
|
|
*d = *s;
|
2015-05-21 10:41:13 +02:00
|
|
|
coel->mbxheader.length = htoes ((uint16_t) 0x0c + n);
|
2014-09-12 16:01:33 +02:00
|
|
|
MBXcontrol[MBXout].state = MBXstate_outreq;
|
|
|
|
MBXcontrol[0].state = MBXstate_idle;
|
|
|
|
ESCvar.xoe = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
SDO_infoerror (ABORT_NOOBJECT);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Function for handling incoming requested SDO Get Entry Description,
|
|
|
|
* validating the request and sending an response. On error an
|
|
|
|
* SDO Info Error will be sent.
|
|
|
|
*/
|
|
|
|
void SDO_geted (void)
|
|
|
|
{
|
2015-05-21 10:41:13 +02:00
|
|
|
uint8_t MBXout;
|
|
|
|
uint16_t index;
|
|
|
|
int32_t nidx, nsub;
|
|
|
|
uint8_t subindex;
|
|
|
|
uint8_t *d;
|
|
|
|
const uint8_t *s;
|
2015-05-21 10:21:37 +02:00
|
|
|
const _objd *objd;
|
2015-05-21 10:41:13 +02:00
|
|
|
uint8_t n = 0;
|
2014-09-12 16:01:33 +02:00
|
|
|
_COEentdesc *coer, *coel;
|
|
|
|
coer = (_COEentdesc *) &MBX[0];
|
|
|
|
index = etohs (coer->index);
|
|
|
|
subindex = coer->subindex;
|
|
|
|
nidx = SDO_findobject (index);
|
|
|
|
if (nidx >= 0)
|
|
|
|
{
|
|
|
|
nsub = SDO_findsubindex (nidx, subindex);
|
|
|
|
if (nsub >= 0)
|
|
|
|
{
|
|
|
|
objd = SDOobjects[nidx].objdesc;
|
|
|
|
MBXout = ESC_claimbuffer ();
|
|
|
|
if (MBXout)
|
|
|
|
{
|
2017-10-25 14:31:30 +02:00
|
|
|
coel = (_COEentdesc *) &MBX[MBXout * ESC_MBXSIZE];
|
2014-09-12 16:01:33 +02:00
|
|
|
coel->mbxheader.mbxtype = MBXCOE;
|
|
|
|
coel->coeheader.numberservice =
|
|
|
|
htoes ((0 & 0x01f) | (COE_SDOINFORMATION << 12));
|
|
|
|
coel->infoheader.opcode = COE_ENTRYDESCRIPTIONRESPONSE;
|
|
|
|
coel->infoheader.incomplete = 0;
|
|
|
|
coel->infoheader.reserved = 0x00;
|
2015-05-21 10:41:13 +02:00
|
|
|
coel->infoheader.fragmentsleft = htoes ((uint16_t) 0);
|
2014-09-12 16:01:33 +02:00
|
|
|
coel->index = htoes (index);
|
|
|
|
coel->subindex = subindex;
|
|
|
|
coel->valueinfo = COE_VALUEINFO_ACCESS +
|
|
|
|
COE_VALUEINFO_OBJECT + COE_VALUEINFO_MAPPABLE;
|
|
|
|
coel->datatype = htoes ((objd + nsub)->datatype);
|
|
|
|
coel->bitlength = htoes ((objd + nsub)->bitlength);
|
2019-04-02 21:26:46 +02:00
|
|
|
coel->access = htoes ((objd + nsub)->flags);
|
2015-05-21 10:41:13 +02:00
|
|
|
s = (uint8_t *) (objd + nsub)->name;
|
|
|
|
d = (uint8_t *) &(coel->name);
|
2017-10-25 14:31:30 +02:00
|
|
|
while (*s && (n < (ESC_MBXDSIZE - 0x10)))
|
2014-09-12 16:01:33 +02:00
|
|
|
{
|
|
|
|
*d = *s;
|
|
|
|
n++;
|
|
|
|
s++;
|
|
|
|
d++;
|
|
|
|
}
|
|
|
|
*d = *s;
|
2015-05-21 10:41:13 +02:00
|
|
|
coel->mbxheader.length = htoes ((uint16_t) 0x10 + n);
|
2014-09-12 16:01:33 +02:00
|
|
|
MBXcontrol[MBXout].state = MBXstate_outreq;
|
|
|
|
MBXcontrol[0].state = MBXstate_idle;
|
|
|
|
ESCvar.xoe = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
SDO_infoerror (ABORT_NOSUBINDEX);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
SDO_infoerror (ABORT_NOOBJECT);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Main CoE function checking the status on current mailbox buffers carrying
|
|
|
|
* data, distributing the mailboxes to appropriate CoE functions.
|
|
|
|
* On Error an MBX_error or SDO Abort will be sent depending on error cause.
|
|
|
|
*/
|
|
|
|
void ESC_coeprocess (void)
|
|
|
|
{
|
|
|
|
_MBXh *mbh;
|
|
|
|
_COEsdo *coesdo;
|
|
|
|
_COEobjdesc *coeobjdesc;
|
2015-05-21 10:41:13 +02:00
|
|
|
uint8_t service;
|
2017-10-25 20:28:13 +02:00
|
|
|
if (ESCvar.MBXrun == 0)
|
2014-09-12 16:01:33 +02:00
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (!ESCvar.xoe && (MBXcontrol[0].state == MBXstate_inclaim))
|
|
|
|
{
|
|
|
|
mbh = (_MBXh *) &MBX[0];
|
|
|
|
if (mbh->mbxtype == MBXCOE)
|
|
|
|
{
|
2016-01-27 22:14:36 +01:00
|
|
|
if (etohs (mbh->length) < COE_MINIMUM_LENGTH)
|
2014-09-12 16:01:33 +02:00
|
|
|
{
|
|
|
|
MBX_error (MBXERR_INVALIDSIZE);
|
|
|
|
}
|
|
|
|
else
|
2016-01-27 22:14:36 +01:00
|
|
|
{
|
2014-09-12 16:01:33 +02:00
|
|
|
ESCvar.xoe = MBXCOE;
|
2016-01-27 22:14:36 +01:00
|
|
|
}
|
2014-09-12 16:01:33 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if ((ESCvar.xoe == (MBXCOE + MBXODL)) && (!ESCvar.mbxoutpost))
|
|
|
|
{
|
|
|
|
/* continue get OD list */
|
|
|
|
SDO_getodlistcont ();
|
|
|
|
}
|
|
|
|
if (ESCvar.xoe == MBXCOE)
|
|
|
|
{
|
|
|
|
coesdo = (_COEsdo *) &MBX[0];
|
|
|
|
coeobjdesc = (_COEobjdesc *) &MBX[0];
|
|
|
|
service = etohs (coesdo->coeheader.numberservice) >> 12;
|
|
|
|
/* initiate SDO upload request */
|
|
|
|
if ((service == COE_SDOREQUEST)
|
|
|
|
&& (coesdo->command == COE_COMMAND_UPLOADREQUEST)
|
|
|
|
&& (etohs (coesdo->mbxheader.length) == 0x0a))
|
|
|
|
{
|
|
|
|
SDO_upload ();
|
|
|
|
}
|
|
|
|
/* SDO upload segment request */
|
|
|
|
if ((service == COE_SDOREQUEST)
|
|
|
|
&& ((coesdo->command & 0xef) == COE_COMMAND_UPLOADSEGREQ)
|
|
|
|
&& (etohs (coesdo->mbxheader.length) == 0x0a)
|
|
|
|
&& (ESCvar.segmented == MBXSEU))
|
|
|
|
{
|
|
|
|
SDO_uploadsegment ();
|
|
|
|
}
|
|
|
|
/* initiate SDO download request */
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if ((service == COE_SDOREQUEST) && ((coesdo->command & 0xf1) == 0x21))
|
|
|
|
{
|
|
|
|
SDO_download ();
|
|
|
|
}
|
|
|
|
/* initiate SDO get OD list */
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if ((service == COE_SDOINFORMATION)
|
|
|
|
&& (coeobjdesc->infoheader.opcode == 0x01))
|
|
|
|
{
|
|
|
|
SDO_getodlist ();
|
|
|
|
}
|
|
|
|
/* initiate SDO get OD */
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if ((service == COE_SDOINFORMATION)
|
|
|
|
&& (coeobjdesc->infoheader.opcode == 0x03))
|
|
|
|
{
|
|
|
|
SDO_getod ();
|
|
|
|
}
|
|
|
|
/* initiate SDO get ED */
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if ((service == COE_SDOINFORMATION)
|
|
|
|
&& (coeobjdesc->infoheader.opcode == 0x05))
|
|
|
|
{
|
|
|
|
SDO_geted ();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* COE not recognised above */
|
|
|
|
if (ESCvar.xoe == MBXCOE)
|
|
|
|
{
|
|
|
|
if (service == 0)
|
|
|
|
{
|
|
|
|
MBX_error (MBXERR_INVALIDHEADER);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2014-10-27 16:12:37 +01:00
|
|
|
SDO_abort (etohs (coesdo->index), coesdo->subindex, ABORT_UNSUPPORTED);
|
2014-09-12 16:01:33 +02:00
|
|
|
}
|
|
|
|
MBXcontrol[0].state = MBXstate_idle;
|
|
|
|
ESCvar.xoe = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-01-20 15:35:23 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Get value from bitmap
|
|
|
|
*
|
|
|
|
* This function gets a value from a bitmap.
|
|
|
|
*
|
|
|
|
* @param[in] bitmap = bitmap containing value
|
|
|
|
* @param[in] offset = start offset
|
|
|
|
* @param[in] length = number of bits to get
|
|
|
|
* @return bitslice value
|
|
|
|
*/
|
|
|
|
static uint64_t COE_bitsliceGet (uint64_t * bitmap, int offset, int length)
|
|
|
|
{
|
|
|
|
const int word_offset = offset / 64;
|
|
|
|
const int bit_offset = offset % 64;
|
|
|
|
const uint64_t mask = (length == 64) ? UINT64_MAX : (1ULL << length) - 1;
|
|
|
|
uint64_t w0;
|
|
|
|
uint64_t w1 = 0;
|
|
|
|
|
|
|
|
/* Get the least significant word */
|
|
|
|
w0 = bitmap[word_offset];
|
|
|
|
w0 = w0 >> bit_offset;
|
|
|
|
|
|
|
|
/* Get the most significant word, if required */
|
|
|
|
if (length + bit_offset > 64)
|
|
|
|
{
|
|
|
|
w1 = bitmap[word_offset + 1];
|
|
|
|
w1 = w1 << (64 - bit_offset);
|
|
|
|
}
|
|
|
|
|
|
|
|
w0 = (w1 | w0);
|
|
|
|
return (w0 & mask);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Set value in bitmap
|
|
|
|
*
|
|
|
|
* This function sets a value in a bitmap.
|
|
|
|
*
|
|
|
|
* @param[in] bitmap = bitmap to contain value
|
|
|
|
* @param[in] offset = start offset
|
|
|
|
* @param[in] length = number of bits to set
|
|
|
|
* @param[in] value = value to set
|
|
|
|
*/
|
|
|
|
static void COE_bitsliceSet (uint64_t * bitmap, int offset, int length,
|
|
|
|
uint64_t value)
|
|
|
|
{
|
|
|
|
const int word_offset = offset / 64;
|
|
|
|
const int bit_offset = offset % 64;
|
|
|
|
const uint64_t mask = (length == 64) ? UINT64_MAX : (1ULL << length) - 1;
|
|
|
|
const uint64_t mask0 = mask << bit_offset;
|
|
|
|
uint64_t v0 = value << bit_offset;
|
|
|
|
uint64_t w0 = bitmap[word_offset];
|
|
|
|
|
|
|
|
/* Set the least significant word */
|
|
|
|
w0 = (w0 & ~mask0) | (v0 & mask0);
|
|
|
|
bitmap[word_offset] = w0;
|
|
|
|
|
|
|
|
/* Set the most significant word, if required */
|
|
|
|
if (length + bit_offset > 64)
|
|
|
|
{
|
|
|
|
const uint64_t mask1 = mask >> (64 - bit_offset);
|
|
|
|
uint64_t v1 = value >> (64 - bit_offset);
|
|
|
|
uint64_t w1 = bitmap[word_offset + 1];
|
|
|
|
|
|
|
|
w1 = (w1 & ~mask1) | (v1 & mask1);
|
|
|
|
bitmap[word_offset + 1] = w1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get object value
|
|
|
|
*
|
|
|
|
* This function atomically gets an object value.
|
|
|
|
*
|
|
|
|
* @param[in] obj = object description
|
|
|
|
* @return object value
|
|
|
|
*/
|
|
|
|
static uint64_t COE_getValue (const _objd * obj)
|
|
|
|
{
|
|
|
|
uint64_t value = 0;
|
|
|
|
|
|
|
|
/* TODO: const data */
|
|
|
|
|
|
|
|
switch(obj->datatype)
|
|
|
|
{
|
|
|
|
case DTYPE_BIT1:
|
|
|
|
case DTYPE_BIT2:
|
|
|
|
case DTYPE_BIT3:
|
|
|
|
case DTYPE_BIT4:
|
|
|
|
case DTYPE_BIT5:
|
|
|
|
case DTYPE_BIT6:
|
|
|
|
case DTYPE_BIT7:
|
|
|
|
case DTYPE_BIT8:
|
|
|
|
case DTYPE_BOOLEAN:
|
|
|
|
case DTYPE_UNSIGNED8:
|
|
|
|
case DTYPE_INTEGER8:
|
|
|
|
value = *(uint8_t *)obj->data;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case DTYPE_UNSIGNED16:
|
|
|
|
case DTYPE_INTEGER16:
|
|
|
|
value = *(uint16_t *)obj->data;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case DTYPE_REAL32:
|
|
|
|
case DTYPE_UNSIGNED32:
|
|
|
|
case DTYPE_INTEGER32:
|
|
|
|
value = *(uint32_t *)obj->data;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case DTYPE_REAL64:
|
|
|
|
case DTYPE_UNSIGNED64:
|
|
|
|
case DTYPE_INTEGER64:
|
|
|
|
/* FIXME: must be atomic */
|
|
|
|
value = *(uint64_t *)obj->data;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
CC_ASSERT (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Set object value
|
|
|
|
*
|
|
|
|
* This function atomically sets an object value.
|
|
|
|
*
|
|
|
|
* @param[in] obj = object description
|
|
|
|
* @param[in] value = new value
|
|
|
|
*/
|
|
|
|
static void COE_setValue (const _objd * obj, uint64_t value)
|
|
|
|
{
|
|
|
|
switch(obj->datatype)
|
|
|
|
{
|
|
|
|
case DTYPE_BIT1:
|
|
|
|
case DTYPE_BIT2:
|
|
|
|
case DTYPE_BIT3:
|
|
|
|
case DTYPE_BIT4:
|
|
|
|
case DTYPE_BIT5:
|
|
|
|
case DTYPE_BIT6:
|
|
|
|
case DTYPE_BIT7:
|
|
|
|
case DTYPE_BIT8:
|
|
|
|
case DTYPE_BOOLEAN:
|
|
|
|
case DTYPE_UNSIGNED8:
|
|
|
|
case DTYPE_INTEGER8:
|
|
|
|
*(uint8_t *)obj->data = value & UINT8_MAX;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case DTYPE_UNSIGNED16:
|
|
|
|
case DTYPE_INTEGER16:
|
|
|
|
*(uint16_t *)obj->data = value & UINT16_MAX;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case DTYPE_REAL32:
|
|
|
|
case DTYPE_UNSIGNED32:
|
|
|
|
case DTYPE_INTEGER32:
|
|
|
|
*(uint32_t *)obj->data = value & UINT32_MAX;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case DTYPE_REAL64:
|
|
|
|
case DTYPE_UNSIGNED64:
|
|
|
|
case DTYPE_INTEGER64:
|
|
|
|
/* FIXME: must be atomic */
|
|
|
|
*(uint64_t *)obj->data = value;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
DPRINT ("ignored\n");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Init default values for SDO objects
|
|
|
|
*/
|
|
|
|
void COE_initDefaultValues (void)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
const _objd *objd;
|
|
|
|
int n;
|
|
|
|
uint8_t maxsub;
|
|
|
|
|
2019-04-02 14:16:26 +02:00
|
|
|
/* Set default values from object descriptor */
|
2019-01-20 15:35:23 +01:00
|
|
|
for (n = 0; SDOobjects[n].index != 0xffff; n++)
|
|
|
|
{
|
|
|
|
objd = SDOobjects[n].objdesc;
|
|
|
|
maxsub = SDOobjects[n].maxsub;
|
|
|
|
|
|
|
|
i = 0;
|
|
|
|
do
|
|
|
|
{
|
2019-07-10 11:19:11 +02:00
|
|
|
if (objd[i].data != NULL && objd[i].bitlength <= sizeof(objd[i].value))
|
2019-01-20 15:35:23 +01:00
|
|
|
{
|
|
|
|
COE_setValue (&objd[i], objd[i].value);
|
|
|
|
DPRINT ("%04x:%02x = %x\n", SDOobjects[n].index, objd[i].subindex, objd[i].value);
|
|
|
|
}
|
|
|
|
} while (objd[i++].subindex < maxsub);
|
|
|
|
}
|
2019-04-02 14:16:26 +02:00
|
|
|
|
|
|
|
/* Let application override default values */
|
|
|
|
if (ESCvar.set_defaults_hook != NULL)
|
|
|
|
{
|
|
|
|
ESCvar.set_defaults_hook();
|
|
|
|
}
|
2019-01-20 15:35:23 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Pack process data
|
|
|
|
*
|
|
|
|
* This function reads mapped objects and constructs the process data
|
|
|
|
* inputs (TXPDO).
|
|
|
|
*
|
|
|
|
* @param[in] buffer = input process data
|
|
|
|
* @param[in] nmappings = number of mappings in sync manager
|
|
|
|
* @param[in] mappings = list of mapped objects in sync manager
|
|
|
|
*/
|
|
|
|
void COE_pdoPack (uint8_t * buffer, int nmappings, _SMmap * mappings)
|
|
|
|
{
|
|
|
|
int ix;
|
|
|
|
|
|
|
|
/* Check that buffer is aligned on 64-bit boundary */
|
|
|
|
CC_ASSERT (((uintptr_t)buffer & 0x07) == 0);
|
|
|
|
|
|
|
|
for (ix = 0; ix < nmappings; ix++)
|
|
|
|
{
|
|
|
|
const _objd * obj = mappings[ix].obj;
|
|
|
|
uint16_t offset = mappings[ix].offset;
|
|
|
|
|
|
|
|
if (obj != NULL)
|
|
|
|
{
|
|
|
|
if (obj->bitlength > 64)
|
|
|
|
{
|
|
|
|
memcpy (
|
|
|
|
&buffer[BITS2BYTES (offset)],
|
|
|
|
obj->data,
|
|
|
|
BITS2BYTES (obj->bitlength)
|
|
|
|
);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Atomically get object value */
|
|
|
|
uint64_t value = COE_getValue (obj);
|
|
|
|
COE_bitsliceSet (
|
|
|
|
(uint64_t *)buffer,
|
|
|
|
offset,
|
|
|
|
obj->bitlength,
|
|
|
|
value
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Unpack process data
|
|
|
|
*
|
|
|
|
* This function unpacks process data output (RXPDO) and writes to the
|
|
|
|
* mapped objects.
|
|
|
|
*
|
|
|
|
* @param[in] buffer = output process data
|
|
|
|
* @param[in] nmappings = number of mappings in sync manager
|
|
|
|
* @param[in] mappings = list of mapped objects in sync manager
|
|
|
|
*/
|
|
|
|
void COE_pdoUnpack (uint8_t * buffer, int nmappings, _SMmap * mappings)
|
|
|
|
{
|
|
|
|
int ix;
|
|
|
|
|
|
|
|
/* Check that buffer is aligned on 64-bit boundary */
|
|
|
|
CC_ASSERT (((uintptr_t)buffer & 0x07) == 0);
|
|
|
|
|
|
|
|
for (ix = 0; ix < nmappings; ix++)
|
|
|
|
{
|
|
|
|
const _objd * obj = mappings[ix].obj;
|
|
|
|
uint16_t offset = mappings[ix].offset;
|
|
|
|
|
|
|
|
if (obj != NULL)
|
|
|
|
{
|
|
|
|
if (obj->bitlength > 64)
|
|
|
|
{
|
|
|
|
memcpy (
|
|
|
|
obj->data,
|
|
|
|
&buffer[BITS2BYTES (offset)],
|
|
|
|
BITS2BYTES (obj->bitlength)
|
|
|
|
);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Atomically set object value */
|
|
|
|
uint64_t value = COE_bitsliceGet (
|
|
|
|
(uint64_t *)buffer,
|
|
|
|
offset,
|
|
|
|
obj->bitlength
|
|
|
|
);
|
|
|
|
COE_setValue (obj, value);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Fetch max subindex
|
|
|
|
*
|
|
|
|
* This function fetches the value of subindex 0 (max subindex).
|
|
|
|
*
|
|
|
|
* @param[in] index = object index
|
|
|
|
*/
|
|
|
|
uint8_t COE_maxSub (uint16_t index)
|
|
|
|
{
|
|
|
|
int nidx;
|
|
|
|
uint8_t maxsub;
|
|
|
|
|
|
|
|
nidx = SDO_findobject (index);
|
|
|
|
if (nidx == -1)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
maxsub = OBJ_VALUE_FETCH (maxsub, SDOobjects[nidx].objdesc[0]);
|
|
|
|
return maxsub;
|
|
|
|
}
|