C++ OptoMMP SDK function for getting/setting engineering units?

Hello,

I was wondering if there was a function/method that was part of the C++ OptoMMP SDK that would allow you to either set and/or get the engineering units for a given channel. Basically looking on how to programmatically get the Unit value from below:

The closet functions I could find seemed to be GetPointConfigurationEx4() or SetPointConfigurationEx4(). However the struct passed to this (SIOMM_PointConfigArea4) doesn’t have a Unit member. Tried searching the documentation but failed to find anything.

Or is this something that you would have to use the ReadBlock()/WriteBlock() functions and supply the correct offset and length to read/write?

The SDK predates the Unit field, so yeah, best course would be to try a generic Write Block, but I’m not sure if that will even work as the MMP protocol guide shows that the MMP server does not modify that area - not sure exactly what that means:

You may want to test writing to that area in groov manage and see what happens.

2 Likes

Thanks for the info on that. Was able to verify writing directly to that area in the Generic MMP section then updated it when viewing that channel. Will go the route of ReadBlock/WriteBlock when needing to programmatically access that data.

One final question, do you know if there are any plans to update the SDK to include this new field? Thanks again!

1 Like

That is up to Opto - it looks like it does get updated every once in a while - I didn’t have a GetPointConfigurationEx4() area on the one I have.

Since you have the source, you can probably just add a new function that includes that area - wouldn’t be that hard to do.

3 Likes

Thanks for the suggestion on updating the SDK to include that functionality. In case anyone else is interested, these are the modifications I made to the SDK to support this.

In O22SIOUT.h added the following definitions

#define SIOMM4096_POINT_CONFIG_UNIT_SIZE 0x00000010
#define SIOMM4096_POINT_CONFIG_UNIT_SIZE_NO_NULL 0x0000000F

In O22STRCT.h added the following struct

typedef struct SIOMM_PointConfigArea5 {
int nModuleType; ///< Read only.
int nPointType; ///< Read/Write
int nFeature; ///< Read/Write. Only used for digital points
float fOffset; ///< Read/Write. Only used for analog points
float fGain; ///< Read/Write. Only used for analog points
float fHiScale; ///< Read/Write. Only used for analog points
float fLoScale; ///< Read/Write. Only used for analog points
float fFilterWeight; ///< Read/Write. Only used for analog points
float fWatchdogValue; ///< Read/Write
int nWatchdogEnabled; ///< Read/Write
unsigned char byName[51]; ///< Read/Write
unsigned char byUnits[10]; ///< Read/Write
} O22_SIOMM_PointConfigArea5;

In O22SIOMM.h added the following function definitions

int SetPointConfigurationEx5(int nModule, int nPoint, SIOMM_PointConfigArea5 PtConfigData);
int GetPointConfigurationEx5(int nModule, int nPoint, SIOMM_PointConfigArea5 *pData);

And finally in O22SIOMM.cpp implemented the functions

int O22SnapIoMemMap::SetPointConfigurationEx5(int nModule, int nPoint, SIOMM_PointConfigArea5 PtConfigData)
//-------------------------------------------------------------------------------------------------
// Configure a digital or analog point
//-------------------------------------------------------------------------------------------------
{
check(nModule >= 0 && nModule < SIOMM4096_MAX_MODULES, SIOMM_ERROR);
check(nPoint >= 0 && nPoint < SIOMM4096_MAX_POINTS, SIOMM_ERROR);
int nResult;
uint8_t arrbyData[SIOMM4096_POINT_CONFIG_BOUNDARY]; // buffer for the data to be written
memset(arrbyData, 0, SIOMM4096_POINT_CONFIG_BOUNDARY);
// Build the data area
O22FILL_ARRAY_FROM_INT32(arrbyData, 0, PtConfigData.nPointType);
O22FILL_ARRAY_FROM_INT32(arrbyData, 4, PtConfigData.nFeature);
O22FILL_ARRAY_FROM_FLOAT(arrbyData, 8, PtConfigData.fOffset);
O22FILL_ARRAY_FROM_FLOAT(arrbyData, 12, PtConfigData.fGain);
O22FILL_ARRAY_FROM_FLOAT(arrbyData, 16, PtConfigData.fHiScale);
O22FILL_ARRAY_FROM_FLOAT(arrbyData, 20, PtConfigData.fLoScale);
// Bytes 24-27 are not used at this time.
O22FILL_ARRAY_FROM_FLOAT(arrbyData, 28, PtConfigData.fFilterWeight);
O22FILL_ARRAY_FROM_FLOAT(arrbyData, 32, PtConfigData.fWatchdogValue);
O22FILL_ARRAY_FROM_INT32(arrbyData, 36, PtConfigData.nWatchdogEnabled);
memcpy(arrbyData + 44, PtConfigData.byName, SIOMM4096_POINT_CONFIG_NAME_SIZE_NO_NULL);
memcpy(arrbyData + 116, PtConfigData.byUnits, SIOMM4096_POINT_CONFIG_UNIT_SIZE_NO_NULL);
int nPointOffset = nModule * 64 + nPoint;
// Write the first section
nResult = WriteBlock(SIOMM4096_POINT_CONFIG_WRITE_TYPE_BASE +
(SIOMM4096_POINT_CONFIG_BOUNDARY * nPointOffset),
24, (uint8_t*)arrbyData);
// Check for error
if (SIOMM_OK != nResult)
return nResult;
// Write the second section
nResult = WriteBlock(SIOMM4096_POINT_CONFIG_WRITE_TYPE_BASE + 28 +
(SIOMM4096_POINT_CONFIG_BOUNDARY * nPointOffset),
12, (uint8_t*)(&(arrbyData[28])));
// Check for error
if (SIOMM_OK != nResult)
return nResult;
// Write the third section
nResult = WriteBlock(SIOMM4096_POINT_CONFIG_WRITE_TYPE_BASE + 44 +
(SIOMM4096_POINT_CONFIG_BOUNDARY * nPointOffset),
SIOMM4096_POINT_CONFIG_NAME_SIZE_NO_NULL, (uint8_t*)(&(arrbyData[44])));
// Check for error
if (SIOMM_OK != nResult)
return nResult;
// Write the fourth section (unit)
return WriteBlock(SIOMM4096_POINT_CONFIG_WRITE_TYPE_BASE + 116 +
(SIOMM4096_POINT_CONFIG_BOUNDARY * nPointOffset),
SIOMM4096_POINT_CONFIG_UNIT_SIZE_NO_NULL, (uint8_t*)(&(arrbyData[116])));}

int O22SnapIoMemMap::GetPointConfigurationEx5(int nModule, int nPoint, SIOMM_PointConfigArea5 pPtConfigData)
//-------------------------------------------------------------------------------------------------
// Get the configuration for a point
//-------------------------------------------------------------------------------------------------
{
check(nModule >= 0 && nModule < SIOMM4096_MAX_MODULES, SIOMM_ERROR);
check(nPoint >= 0 && nPoint < SIOMM4096_MAX_POINTS, SIOMM_ERROR);
check(pPtConfigData != NULL, SIOMM_ERROR);
int nResult;
uint8_t arrbyData[SIOMM4096_POINT_CONFIG_BOUNDARY]; // buffer for the data to be read
memset(arrbyData, 0, SIOMM4096_POINT_CONFIG_BOUNDARY);
// Read the data
nResult = ReadBlock(SIOMM4096_POINT_CONFIG_READ_MOD_TYPE_BASE +
(SIOMM4096_POINT_CONFIG_BOUNDARY * (nModule * 64 + nPoint)),
SIOMM4096_POINT_CONFIG_BOUNDARY, (uint8_t
)arrbyData);
// Check for error
if (SIOMM_OK == nResult)
{
// If everything is okay, go ahead and fill the structure
pPtConfigData->nModuleType = O22MAKELONG2(arrbyData, 0);
pPtConfigData->nPointType = O22MAKELONG2(arrbyData, 4);
pPtConfigData->nFeature = O22MAKELONG2(arrbyData, 8);
pPtConfigData->fOffset = O22MAKEFLOAT2(arrbyData, 12);
pPtConfigData->fGain = O22MAKEFLOAT2(arrbyData, 16);
pPtConfigData->fHiScale = O22MAKEFLOAT2(arrbyData, 20);
pPtConfigData->fLoScale = O22MAKEFLOAT2(arrbyData, 24);
// Bytes 28-31 are not used at this time
pPtConfigData->fFilterWeight = O22MAKEFLOAT2(arrbyData, 32);
pPtConfigData->fWatchdogValue = O22MAKEFLOAT2(arrbyData, 36);
pPtConfigData->nWatchdogEnabled = O22MAKELONG2(arrbyData, 40);
memcpy(pPtConfigData->byName, arrbyData + 48, SIOMM4096_POINT_CONFIG_NAME_SIZE);
memcpy(pPtConfigData->byUnits, arrbyData + 120, SIOMM4096_POINT_CONFIG_UNIT_SIZE);
}
return nResult;}

Have only done light testing, but was able to verify setting and getting the units using those functions.

4 Likes

Wow. Thanks @adam2 (and @philip for helping out on this thread) for sharing the code changes!!!