/* * CANopen Object Dictionary interface * * @file CO_ODinterface.c * @author Janez Paternoster * @copyright 2020 Janez Paternoster * * This file is part of CANopenNode, an opensource CANopen Stack. * Project home page is . * For more information on CANopen see . * * 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 #define OD_DEFINITION #include "301/CO_ODinterface.h" /******************************************************************************/ OD_size_t OD_readOriginal(OD_stream_t *stream, uint8_t subIndex, void *buf, OD_size_t count, ODR_t *returnCode) { (void) subIndex; if (stream == NULL || buf == NULL || returnCode == NULL) { if (returnCode != NULL) *returnCode = ODR_DEV_INCOMPAT; return 0; } OD_size_t dataLenToCopy = stream->dataLength; /* length of OD variable */ const char *odData = (const char *)stream->dataObjectOriginal; if (odData == NULL) { *returnCode = ODR_SUB_NOT_EXIST; return 0; } *returnCode = ODR_OK; /* If previous read was partial or OD variable length is larger than * current buffer len, then data was (will be) read in several segments */ if (stream->dataOffset > 0 || dataLenToCopy > count) { if (stream->dataOffset >= dataLenToCopy) { *returnCode = ODR_DEV_INCOMPAT; return 0; } /* reduce for already copied data */ dataLenToCopy -= stream->dataOffset; odData += stream->dataOffset; if (dataLenToCopy > count) { /* not enough space in destionation buffer */ dataLenToCopy = count; stream->dataOffset += dataLenToCopy; *returnCode = ODR_PARTIAL; } else { stream->dataOffset = 0; /* copy finished, reset offset */ } } CO_LOCK_OD(); memcpy(buf, odData, dataLenToCopy); CO_UNLOCK_OD(); return dataLenToCopy; } /******************************************************************************/ OD_size_t OD_writeOriginal(OD_stream_t *stream, uint8_t subIndex, const void *buf, OD_size_t count, ODR_t *returnCode) { (void) subIndex; if (stream == NULL || buf == NULL || returnCode == NULL) { if (returnCode != NULL) *returnCode = ODR_DEV_INCOMPAT; return 0; } OD_size_t dataLenToCopy = stream->dataLength; /* length of OD variable */ char *odData = (char *)stream->dataObjectOriginal; if (odData == NULL) { *returnCode = ODR_SUB_NOT_EXIST; return 0; } *returnCode = ODR_OK; /* If previous write was partial or OD variable length is larger than * current data len, then data was (will be) written in several segments */ if (stream->dataOffset > 0 || dataLenToCopy > count) { if (stream->dataOffset >= dataLenToCopy) { *returnCode = ODR_DEV_INCOMPAT; return 0; } /* reduce for already copied data */ dataLenToCopy -= stream->dataOffset; odData += stream->dataOffset; if (dataLenToCopy > count) { /* Reamining data space in OD variable is larger than current count * of data, so only current count of data will be copied */ dataLenToCopy = count; stream->dataOffset += dataLenToCopy; *returnCode = ODR_PARTIAL; } else { stream->dataOffset = 0; /* copy finished, reset offset */ } } if (dataLenToCopy < count) { /* OD variable is smaller than current ammount of data */ *returnCode = ODR_DATA_LONG; return 0; } else { CO_LOCK_OD(); memcpy(odData, buf, dataLenToCopy); CO_UNLOCK_OD(); return dataLenToCopy; } } /* Read value from variable from Object Dictionary disabled, see OD_subEntry_t*/ static OD_size_t OD_readDisabled(OD_stream_t *stream, uint8_t subIndex, void *buf, OD_size_t count, ODR_t *returnCode) { (void) stream; (void) subIndex; (void) buf; (void) count; if (returnCode != NULL) *returnCode = ODR_WRITEONLY; return 0; } /* Write value to variable from Object Dictionary disabled, see OD_subEntry_t */ static OD_size_t OD_writeDisabled(OD_stream_t *stream, uint8_t subIndex, const void *buf, OD_size_t count, ODR_t *returnCode) { (void) stream; (void) subIndex; (void) buf; (void) count; if (returnCode != NULL) *returnCode = ODR_READONLY; return 0; } /******************************************************************************/ const OD_entry_t *OD_find(const OD_t *od, uint16_t index) { unsigned int cur; unsigned int min = 0; unsigned int max = od->size - 1; if (od == NULL || od->size == 0) { return NULL; } /* Fast search in ordered Object Dictionary. If indexes are mixed, * this won't work. If Object Dictionary has up to 2^N entries, then N is * max number of loop passes. */ while (min < max) { /* get entry between min and max */ cur = (min + max) >> 1; const OD_entry_t* entry = &od->list[cur]; if (index == entry->index) { return entry; } else if (index < entry->index) { max = cur; if(max > 0) max--; } else { min = cur + 1; } } if (min == max) { const OD_entry_t* entry = &od->list[min]; if (index == entry->index) { return entry; } } return NULL; /* entry does not exist in OD */ } /******************************************************************************/ ODR_t OD_getSub(const OD_entry_t *entry, uint8_t subIndex, OD_subEntry_t *subEntry, OD_stream_t *stream, bool_t odOrig) { if (entry == NULL || entry->odObject == NULL) return ODR_IDX_NOT_EXIST; else if (subIndex > entry->maxSubIndex) return ODR_SUB_NOT_EXIST; else if (subEntry == NULL || stream == NULL) return ODR_DEV_INCOMPAT; const void *odObjectOrig = entry->odObject; const OD_obj_extended_t *odObjectExt = NULL; uint8_t odBasicType = entry->odObjectType & ODT_TYPE_MASK; /* Is object type extended? */ if ((entry->odObjectType & ODT_EXTENSION_MASK) != 0) { odObjectExt = (const OD_obj_extended_t *)odObjectOrig; odObjectOrig = odObjectExt->odObjectOriginal; if (odObjectOrig == NULL) return ODR_DEV_INCOMPAT; } /* common properties */ subEntry->index = entry->index; subEntry->subIndex = subIndex; subEntry->maxSubIndex = entry->maxSubIndex; subEntry->storageGroup = entry->storageGroup; subEntry->flagsPDO = (odObjectExt != NULL ) ? odObjectExt->flagsPDO : NULL; stream->dataOffset = 0; /* attribute, dataObjectOriginal and dataLength, depends on object type */ if (odBasicType == ODT_VAR) { const OD_obj_var_t *odo = (const OD_obj_var_t *)odObjectOrig; subEntry->attribute = odo->attribute; stream->dataObjectOriginal = odo->data; stream->dataLength = odo->dataLength; } else if (odBasicType == ODT_ARR) { const OD_obj_array_t *odo = (const OD_obj_array_t *)odObjectOrig; if (subIndex == 0) { subEntry->attribute = odo->attribute0; stream->dataObjectOriginal = odo->data0; stream->dataLength = 1; } else { char *data = (char *)odo->data; int i = subIndex - 1; subEntry->attribute = odo->attribute; if (data == NULL) return ODR_DEV_INCOMPAT; stream->dataObjectOriginal = data + odo->dataElementSizeof * i; stream->dataLength = odo->dataElementLength; } } else if (odBasicType == ODT_REC) { const OD_obj_var_t *odo_rec = (const OD_obj_var_t *)odObjectOrig; const OD_obj_var_t *odo = &odo_rec[subIndex]; subEntry->attribute = odo->attribute; stream->dataObjectOriginal = odo->data; stream->dataLength = odo->dataLength; } else { return ODR_DEV_INCOMPAT; } /* read, write and dataObject, direct or with IO extension */ if (odObjectExt == NULL || odObjectExt->extIO == NULL || odOrig) { subEntry->read = OD_readOriginal; subEntry->write = OD_writeOriginal; stream->object = NULL; } else { subEntry->read = odObjectExt->extIO->read != NULL ? odObjectExt->extIO->read : OD_readDisabled; subEntry->write = odObjectExt->extIO->write != NULL ? odObjectExt->extIO->write : OD_writeDisabled; stream->object = odObjectExt->extIO->object; } return ODR_OK; } /******************************************************************************/ uint32_t OD_getSDOabCode(ODR_t returnCode) { static const uint32_t abortCodes[ODR_COUNT] = { 0x00000000UL, /* No abort */ 0x05040005UL, /* Out of memory */ 0x06010000UL, /* Unsupported access to an object */ 0x06010001UL, /* Attempt to read a write only object */ 0x06010002UL, /* Attempt to write a read only object */ 0x06020000UL, /* Object does not exist in the object dictionary */ 0x06040041UL, /* Object cannot be mapped to the PDO */ 0x06040042UL, /* Num and len of object to be mapped exceeds PDO len */ 0x06040043UL, /* General parameter incompatibility reasons */ 0x06040047UL, /* General internal incompatibility in device */ 0x06060000UL, /* Access failed due to hardware error */ 0x06070010UL, /* Data type does not match, length does not match */ 0x06070012UL, /* Data type does not match, length too high */ 0x06070013UL, /* Data type does not match, length too short */ 0x06090011UL, /* Sub index does not exist */ 0x06090030UL, /* Invalid value for parameter (download only). */ 0x06090031UL, /* Value range of parameter written too high */ 0x06090032UL, /* Value range of parameter written too low */ 0x06090036UL, /* Maximum value is less than minimum value. */ 0x060A0023UL, /* Resource not available: SDO connection */ 0x08000000UL, /* General error */ 0x08000020UL, /* Data cannot be transferred or stored to application */ 0x08000021UL, /* Data cannot be transf. because of local control */ 0x08000022UL, /* Data cannot be tran. because of present device state */ 0x08000023UL, /* Object dict. not present or dynamic generation fails */ 0x08000024UL /* No data available */ }; return (returnCode < 0 || returnCode >= ODR_COUNT) ? abortCodes[ODR_DEV_INCOMPAT] : abortCodes[returnCode]; } /******************************************************************************/ bool_t OD_extensionIO_init(const OD_entry_t *entry, void *object, OD_size_t (*read)(OD_stream_t *stream, uint8_t subIndex, void *buf, OD_size_t count, ODR_t *returnCode), OD_size_t (*write)(OD_stream_t *stream, uint8_t subIndex, const void *buf, OD_size_t count, ODR_t *returnCode)) { if (entry == NULL || (entry->odObjectType & ODT_EXTENSION_MASK) == 0) { return false; } const OD_obj_extended_t *odo = (const OD_obj_extended_t *) entry->odObject; if (odo->extIO == NULL) { return false; } odo->extIO->object = object; odo->extIO->read = read; odo->extIO->write = write; return true; } /******************************************************************************/ ODR_t OD_get_i8(const OD_entry_t *entry, uint8_t subIndex, int8_t *val, bool_t odOrig) { OD_subEntry_t subEntry; OD_stream_t st; ODR_t ret = OD_getSub(entry, subIndex, &subEntry, &st, odOrig); if (ret == ODR_OK && st.dataLength != sizeof(*val)) ret = ODR_TYPE_MISMATCH; if (ret == ODR_OK) subEntry.read(&st, subIndex, val, sizeof(*val), &ret); return ret; } ODR_t OD_get_i16(const OD_entry_t *entry, uint8_t subIndex, int16_t *val, bool_t odOrig) { OD_subEntry_t subEntry; OD_stream_t st; ODR_t ret = OD_getSub(entry, subIndex, &subEntry, &st, odOrig); if (ret == ODR_OK && st.dataLength != sizeof(*val)) ret = ODR_TYPE_MISMATCH; if (ret == ODR_OK) subEntry.read(&st, subIndex, val, sizeof(*val), &ret); return ret; } ODR_t OD_get_i32(const OD_entry_t *entry, uint8_t subIndex, int32_t *val, bool_t odOrig) { OD_subEntry_t subEntry; OD_stream_t st; ODR_t ret = OD_getSub(entry, subIndex, &subEntry, &st, odOrig); if (ret == ODR_OK && st.dataLength != sizeof(*val)) ret = ODR_TYPE_MISMATCH; if (ret == ODR_OK) subEntry.read(&st, subIndex, val, sizeof(*val), &ret); return ret; } ODR_t OD_get_i64(const OD_entry_t *entry, uint8_t subIndex, int64_t *val, bool_t odOrig) { OD_subEntry_t subEntry; OD_stream_t st; ODR_t ret = OD_getSub(entry, subIndex, &subEntry, &st, odOrig); if (ret == ODR_OK && st.dataLength != sizeof(*val)) ret = ODR_TYPE_MISMATCH; if (ret == ODR_OK) subEntry.read(&st, subIndex, val, sizeof(*val), &ret); return ret; } ODR_t OD_get_u8(const OD_entry_t *entry, uint8_t subIndex, uint8_t *val, bool_t odOrig) { OD_subEntry_t subEntry; OD_stream_t st; ODR_t ret = OD_getSub(entry, subIndex, &subEntry, &st, odOrig); if (ret == ODR_OK && st.dataLength != sizeof(*val)) ret = ODR_TYPE_MISMATCH; if (ret == ODR_OK) subEntry.read(&st, subIndex, val, sizeof(*val), &ret); return ret; } ODR_t OD_get_u16(const OD_entry_t *entry, uint8_t subIndex, uint16_t *val, bool_t odOrig) { OD_subEntry_t subEntry; OD_stream_t st; ODR_t ret = OD_getSub(entry, subIndex, &subEntry, &st, odOrig); if (ret == ODR_OK && st.dataLength != sizeof(*val)) ret = ODR_TYPE_MISMATCH; if (ret == ODR_OK) subEntry.read(&st, subIndex, val, sizeof(*val), &ret); return ret; } ODR_t OD_get_u32(const OD_entry_t *entry, uint8_t subIndex, uint32_t *val, bool_t odOrig) { OD_subEntry_t subEntry; OD_stream_t st; ODR_t ret = OD_getSub(entry, subIndex, &subEntry, &st, odOrig); if (ret == ODR_OK && st.dataLength != sizeof(*val)) ret = ODR_TYPE_MISMATCH; if (ret == ODR_OK) subEntry.read(&st, subIndex, val, sizeof(*val), &ret); return ret; } ODR_t OD_get_u64(const OD_entry_t *entry, uint8_t subIndex, uint64_t *val, bool_t odOrig) { OD_subEntry_t subEntry; OD_stream_t st; ODR_t ret = OD_getSub(entry, subIndex, &subEntry, &st, odOrig); if (ret == ODR_OK && st.dataLength != sizeof(*val)) ret = ODR_TYPE_MISMATCH; if (ret == ODR_OK) subEntry.read(&st, subIndex, val, sizeof(*val), &ret); return ret; } ODR_t OD_get_r32(const OD_entry_t *entry, uint8_t subIndex, float32_t *val, bool_t odOrig) { OD_subEntry_t subEntry; OD_stream_t st; ODR_t ret = OD_getSub(entry, subIndex, &subEntry, &st, odOrig); if (ret == ODR_OK && st.dataLength != sizeof(*val)) ret = ODR_TYPE_MISMATCH; if (ret == ODR_OK) subEntry.read(&st, subIndex, val, sizeof(*val), &ret); return ret; } ODR_t OD_get_r64(const OD_entry_t *entry, uint8_t subIndex, float64_t *val, bool_t odOrig) { OD_subEntry_t subEntry; OD_stream_t st; ODR_t ret = OD_getSub(entry, subIndex, &subEntry, &st, odOrig); if (ret == ODR_OK && st.dataLength != sizeof(*val)) ret = ODR_TYPE_MISMATCH; if (ret == ODR_OK) subEntry.read(&st, subIndex, val, sizeof(*val), &ret); return ret; } /******************************************************************************/ ODR_t OD_set_i8(const OD_entry_t *entry, uint8_t subIndex, int8_t val, bool_t odOrig) { OD_subEntry_t subEntry; OD_stream_t st; ODR_t ret = OD_getSub(entry, subIndex, &subEntry, &st, odOrig); if (ret == ODR_OK && st.dataLength != sizeof(val)) ret = ODR_TYPE_MISMATCH; if (ret == ODR_OK) subEntry.write(&st, subIndex, &val, sizeof(val), &ret); return ret; } ODR_t OD_set_i16(const OD_entry_t *entry, uint8_t subIndex, int16_t val, bool_t odOrig) { OD_subEntry_t subEntry; OD_stream_t st; ODR_t ret = OD_getSub(entry, subIndex, &subEntry, &st, odOrig); if (ret == ODR_OK && st.dataLength != sizeof(val)) ret = ODR_TYPE_MISMATCH; if (ret == ODR_OK) subEntry.write(&st, subIndex, &val, sizeof(val), &ret); return ret; } ODR_t OD_set_i32(const OD_entry_t *entry, uint8_t subIndex, int32_t val, bool_t odOrig) { OD_subEntry_t subEntry; OD_stream_t st; ODR_t ret = OD_getSub(entry, subIndex, &subEntry, &st, odOrig); if (ret == ODR_OK && st.dataLength != sizeof(val)) ret = ODR_TYPE_MISMATCH; if (ret == ODR_OK) subEntry.write(&st, subIndex, &val, sizeof(val), &ret); return ret; } ODR_t OD_set_i64(const OD_entry_t *entry, uint8_t subIndex, int64_t val, bool_t odOrig) { OD_subEntry_t subEntry; OD_stream_t st; ODR_t ret = OD_getSub(entry, subIndex, &subEntry, &st, odOrig); if (ret == ODR_OK && st.dataLength != sizeof(val)) ret = ODR_TYPE_MISMATCH; if (ret == ODR_OK) subEntry.write(&st, subIndex, &val, sizeof(val), &ret); return ret; } ODR_t OD_set_u8(const OD_entry_t *entry, uint8_t subIndex, uint8_t val, bool_t odOrig) { OD_subEntry_t subEntry; OD_stream_t st; ODR_t ret = OD_getSub(entry, subIndex, &subEntry, &st, odOrig); if (ret == ODR_OK && st.dataLength != sizeof(val)) ret = ODR_TYPE_MISMATCH; if (ret == ODR_OK) subEntry.write(&st, subIndex, &val, sizeof(val), &ret); return ret; } ODR_t OD_set_u16(const OD_entry_t *entry, uint8_t subIndex, uint16_t val, bool_t odOrig) { OD_subEntry_t subEntry; OD_stream_t st; ODR_t ret = OD_getSub(entry, subIndex, &subEntry, &st, odOrig); if (ret == ODR_OK && st.dataLength != sizeof(val)) ret = ODR_TYPE_MISMATCH; if (ret == ODR_OK) subEntry.write(&st, subIndex, &val, sizeof(val), &ret); return ret; } ODR_t OD_set_u32(const OD_entry_t *entry, uint8_t subIndex, uint32_t val, bool_t odOrig) { OD_subEntry_t subEntry; OD_stream_t st; ODR_t ret = OD_getSub(entry, subIndex, &subEntry, &st, odOrig); if (ret == ODR_OK && st.dataLength != sizeof(val)) ret = ODR_TYPE_MISMATCH; if (ret == ODR_OK) subEntry.write(&st, subIndex, &val, sizeof(val), &ret); return ret; } ODR_t OD_set_u64(const OD_entry_t *entry, uint8_t subIndex, uint64_t val, bool_t odOrig) { OD_subEntry_t subEntry; OD_stream_t st; ODR_t ret = OD_getSub(entry, subIndex, &subEntry, &st, odOrig); if (ret == ODR_OK && st.dataLength != sizeof(val)) ret = ODR_TYPE_MISMATCH; if (ret == ODR_OK) subEntry.write(&st, subIndex, &val, sizeof(val), &ret); return ret; } ODR_t OD_set_r32(const OD_entry_t *entry, uint8_t subIndex, float32_t val, bool_t odOrig) { OD_subEntry_t subEntry; OD_stream_t st; ODR_t ret = OD_getSub(entry, subIndex, &subEntry, &st, odOrig); if (ret == ODR_OK && st.dataLength != sizeof(val)) ret = ODR_TYPE_MISMATCH; if (ret == ODR_OK) subEntry.write(&st, subIndex, &val, sizeof(val), &ret); return ret; } ODR_t OD_set_r64(const OD_entry_t *entry, uint8_t subIndex, float64_t val, bool_t odOrig) { OD_subEntry_t subEntry; OD_stream_t st; ODR_t ret = OD_getSub(entry, subIndex, &subEntry, &st, odOrig); if (ret == ODR_OK && st.dataLength != sizeof(val)) ret = ODR_TYPE_MISMATCH; if (ret == ODR_OK) subEntry.write(&st, subIndex, &val, sizeof(val), &ret); return ret; } /******************************************************************************/ ODR_t OD_getPtr_i8(const OD_entry_t *entry, uint8_t subIndex, int8_t **val) { OD_subEntry_t subEntry; OD_stream_t st; ODR_t ret = OD_getSub(entry, subIndex, &subEntry, &st, true); if (ret == ODR_OK && st.dataLength != sizeof(**val))ret = ODR_TYPE_MISMATCH; if (ret == ODR_OK) *val = (int8_t *)st.dataObjectOriginal; if (*val == NULL) ret = ODR_DEV_INCOMPAT; return ret; } ODR_t OD_getPtr_i16(const OD_entry_t *entry, uint8_t subIndex, int16_t **val) { OD_subEntry_t subEntry; OD_stream_t st; ODR_t ret = OD_getSub(entry, subIndex, &subEntry, &st, true); if (ret == ODR_OK && st.dataLength != sizeof(**val))ret = ODR_TYPE_MISMATCH; if (ret == ODR_OK) *val = (int16_t *)st.dataObjectOriginal; if (*val == NULL) ret = ODR_DEV_INCOMPAT; return ret; } ODR_t OD_getPtr_i32(const OD_entry_t *entry, uint8_t subIndex, int32_t **val) { OD_subEntry_t subEntry; OD_stream_t st; ODR_t ret = OD_getSub(entry, subIndex, &subEntry, &st, true); if (ret == ODR_OK && st.dataLength != sizeof(**val))ret = ODR_TYPE_MISMATCH; if (ret == ODR_OK) *val = (int32_t *)st.dataObjectOriginal; if (*val == NULL) ret = ODR_DEV_INCOMPAT; return ret; } ODR_t OD_getPtr_i64(const OD_entry_t *entry, uint8_t subIndex, int64_t **val) { OD_subEntry_t subEntry; OD_stream_t st; ODR_t ret = OD_getSub(entry, subIndex, &subEntry, &st, true); if (ret == ODR_OK && st.dataLength != sizeof(**val))ret = ODR_TYPE_MISMATCH; if (ret == ODR_OK) *val = (int64_t *)st.dataObjectOriginal; if (*val == NULL) ret = ODR_DEV_INCOMPAT; return ret; } ODR_t OD_getPtr_u8(const OD_entry_t *entry, uint8_t subIndex, uint8_t **val) { OD_subEntry_t subEntry; OD_stream_t st; ODR_t ret = OD_getSub(entry, subIndex, &subEntry, &st, true); if (ret == ODR_OK && st.dataLength != sizeof(**val))ret = ODR_TYPE_MISMATCH; if (ret == ODR_OK) *val = (uint8_t *)st.dataObjectOriginal; if (*val == NULL) ret = ODR_DEV_INCOMPAT; return ret; } ODR_t OD_getPtr_u16(const OD_entry_t *entry, uint8_t subIndex, uint16_t **val) { OD_subEntry_t subEntry; OD_stream_t st; ODR_t ret = OD_getSub(entry, subIndex, &subEntry, &st, true); if (ret == ODR_OK && st.dataLength != sizeof(**val))ret = ODR_TYPE_MISMATCH; if (ret == ODR_OK) *val = (uint16_t *)st.dataObjectOriginal; if (*val == NULL) ret = ODR_DEV_INCOMPAT; return ret; } ODR_t OD_getPtr_u32(const OD_entry_t *entry, uint8_t subIndex, uint32_t **val) { OD_subEntry_t subEntry; OD_stream_t st; ODR_t ret = OD_getSub(entry, subIndex, &subEntry, &st, true); if (ret == ODR_OK && st.dataLength != sizeof(**val))ret = ODR_TYPE_MISMATCH; if (ret == ODR_OK) *val = (uint32_t *)st.dataObjectOriginal; if (*val == NULL) ret = ODR_DEV_INCOMPAT; return ret; } ODR_t OD_getPtr_u64(const OD_entry_t *entry, uint8_t subIndex, uint64_t **val) { OD_subEntry_t subEntry; OD_stream_t st; ODR_t ret = OD_getSub(entry, subIndex, &subEntry, &st, true); if (ret == ODR_OK && st.dataLength != sizeof(**val))ret = ODR_TYPE_MISMATCH; if (ret == ODR_OK) *val = (uint64_t *)st.dataObjectOriginal; if (*val == NULL) ret = ODR_DEV_INCOMPAT; return ret; } ODR_t OD_getPtr_r32(const OD_entry_t *entry, uint8_t subIndex, float32_t **val){ OD_subEntry_t subEntry; OD_stream_t st; ODR_t ret = OD_getSub(entry, subIndex, &subEntry, &st, true); if (ret == ODR_OK && st.dataLength != sizeof(**val))ret = ODR_TYPE_MISMATCH; if (ret == ODR_OK) *val = (float32_t *)st.dataObjectOriginal; if (*val == NULL) ret = ODR_DEV_INCOMPAT; return ret; } ODR_t OD_getPtr_r64(const OD_entry_t *entry, uint8_t subIndex, float64_t **val){ OD_subEntry_t subEntry; OD_stream_t st; ODR_t ret = OD_getSub(entry, subIndex, &subEntry, &st, true); if (ret == ODR_OK && st.dataLength != sizeof(**val))ret = ODR_TYPE_MISMATCH; if (ret == ODR_OK) *val = (float64_t *)st.dataObjectOriginal; if (*val == NULL) ret = ODR_DEV_INCOMPAT; return ret; }