Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix signedness handling for EL3XXX and EL4XXX terminals #67

Merged
merged 3 commits into from
Aug 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions ek9000App/src/devEL3XXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,8 @@ struct EL30XXStandardInputPDO_t {
uint8_t _r2 : 6; // Last bit in this align is Sync error for EL31XX
uint8_t txpdo_state : 1;
uint8_t txpdo_toggle : 1;
uint16_t value;
int16_t value; // Must be signed to accommodate bipolar terminals. Unsigned representation still defines range as
// 0-32767, so this is safe.
};
#pragma pack()

Expand Down Expand Up @@ -339,7 +340,7 @@ struct EL331XInputPDO_t {
uint8_t error : 1;
uint8_t txpdo_state : 1;
uint8_t txpdo_toggle : 1;
uint16_t value;
int16_t value;
};

struct EL3314_0010_InputPDO_t {
Expand All @@ -351,7 +352,7 @@ struct EL3314_0010_InputPDO_t {
uint8_t txpdo_state : 1;
uint8_t txpdo_toggle : 1;
uint8_t padding1 : 7; // Pad it out to byte boundary
uint16_t value;
int16_t value;
};
#pragma pack()

Expand Down
51 changes: 39 additions & 12 deletions ek9000App/src/devEL4XXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@ static long EL40XX_init_record(void* record);
static long EL40XX_write_record(void* record);
static long EL40XX_linconv(void* precord, int after);

struct EL40XXDpvt_t : public TerminalDpvt_t {
bool sign = false;
};

struct devEL40XX_t {
long num;
DEVSUPFUN report;
Expand All @@ -54,6 +58,11 @@ struct devEL40XX_t {

epicsExportAddress(dset, devEL40XX);

// The default representation for all of these terminals is signed. Unsigned may also be set, even for the bipolar
// terminals that may produce a negative value. To retain some level of support for unsigned representation, terminals
// that have a positive output range use uint16_t as the PDO type. Bipolar terminals always use int16_t to support
// negative values and will behave incorrectly if you choose the unsigned (or absolute w/MSB sign) representation.

DEFINE_SINGLE_CHANNEL_OUTPUT_PDO(uint16_t, EL4001);
DEFINE_SINGLE_CHANNEL_OUTPUT_PDO(uint16_t, EL4002);
DEFINE_SINGLE_CHANNEL_OUTPUT_PDO(uint16_t, EL4004);
Expand All @@ -66,23 +75,33 @@ DEFINE_SINGLE_CHANNEL_OUTPUT_PDO(uint16_t, EL4021);
DEFINE_SINGLE_CHANNEL_OUTPUT_PDO(uint16_t, EL4022);
DEFINE_SINGLE_CHANNEL_OUTPUT_PDO(uint16_t, EL4024);
DEFINE_SINGLE_CHANNEL_OUTPUT_PDO(uint16_t, EL4028);
DEFINE_SINGLE_CHANNEL_OUTPUT_PDO(uint16_t, EL4031);
DEFINE_SINGLE_CHANNEL_OUTPUT_PDO(uint16_t, EL4032);
DEFINE_SINGLE_CHANNEL_OUTPUT_PDO(uint16_t, EL4034);
DEFINE_SINGLE_CHANNEL_OUTPUT_PDO(uint16_t, EL4038);
DEFINE_SINGLE_CHANNEL_OUTPUT_PDO(int16_t, EL4031); // EL403X support negative output values.
DEFINE_SINGLE_CHANNEL_OUTPUT_PDO(int16_t, EL4032);
DEFINE_SINGLE_CHANNEL_OUTPUT_PDO(int16_t, EL4034);
DEFINE_SINGLE_CHANNEL_OUTPUT_PDO(int16_t, EL4038);
DEFINE_SINGLE_CHANNEL_OUTPUT_PDO(uint16_t, EL4102);
DEFINE_SINGLE_CHANNEL_OUTPUT_PDO(uint16_t, EL4104);
DEFINE_SINGLE_CHANNEL_OUTPUT_PDO(uint16_t, EL4112);
DEFINE_SINGLE_CHANNEL_OUTPUT_PDO(uint16_t, EL4114);
DEFINE_SINGLE_CHANNEL_OUTPUT_PDO(int16_t, EL4112); // EL411X support negative output values.
DEFINE_SINGLE_CHANNEL_OUTPUT_PDO(int16_t, EL4114);
DEFINE_SINGLE_CHANNEL_OUTPUT_PDO(uint16_t, EL4122);
DEFINE_SINGLE_CHANNEL_OUTPUT_PDO(uint16_t, EL4132);
DEFINE_SINGLE_CHANNEL_OUTPUT_PDO(uint16_t, EL4134);
DEFINE_SINGLE_CHANNEL_OUTPUT_PDO(int16_t, EL4132); // EL413X support negative output values.
DEFINE_SINGLE_CHANNEL_OUTPUT_PDO(int16_t, EL4134);

static bool isTerminalSigned(int id) {
if (id <= 4039 && id >= 4030)
return true; // EL403X
if (id <= 4119 && id >= 4110)
return true; // EL411X
if (id <= 4139 && id >= 4130)
return true; // EL413X
return false;
}

static void EL40XX_WriteCallback(CALLBACK* callback) {
void* record = NULL;
callbackGetUser(record, callback);
aoRecord* pRecord = (aoRecord*)record;
TerminalDpvt_t* dpvt = (TerminalDpvt_t*)pRecord->dpvt;
EL40XXDpvt_t* dpvt = (EL40XXDpvt_t*)pRecord->dpvt;
free(callback);
int status = 0;

Expand All @@ -103,9 +122,14 @@ static void EL40XX_WriteCallback(CALLBACK* callback) {
}

/* Set buffer & do write */
uint16_t buf = (int16_t)pRecord->rval;
char buf[2];
if (dpvt->sign)
*(int16_t*)buf = (int16_t)pRecord->rval;
else
*(uint16_t*)buf = (uint16_t)pRecord->rval;

status = dpvt->pterm->doEK9000IO(MODBUS_WRITE_MULTIPLE_REGISTERS,
dpvt->pterm->m_outputStart + (dpvt->channel - 1), &buf, 1);
dpvt->pterm->m_outputStart + (dpvt->channel - 1), (uint16_t*)buf, 1);
}

/* Check error */
Expand Down Expand Up @@ -135,7 +159,7 @@ static long EL40XX_init(int) {
static long EL40XX_init_record(void* record) {
aoRecord* pRecord = (aoRecord*)record;
pRecord->dpvt = util::allocDpvt();
TerminalDpvt_t* dpvt = (TerminalDpvt_t*)pRecord->dpvt;
EL40XXDpvt_t* dpvt = (EL40XXDpvt_t*)pRecord->dpvt;
uint16_t termid = 0;

/* Verify terminal */
Expand Down Expand Up @@ -164,6 +188,9 @@ static long EL40XX_init_record(void* record) {
return 1;
}

/* Determine if it's signed or not */
dpvt->sign = isTerminalSigned(termid);

return 0;
}

Expand Down
Loading