Skip to content

Commit 907ed99

Browse files
committed
Add command based disable pins to control individual commands.
Fix write flush and global reset to prevent being run on initlist entries.
1 parent 670a339 commit 907ed99

3 files changed

Lines changed: 129 additions & 65 deletions

File tree

src/hal/drivers/mesa-hostmot2/hm2_modbus.c

Lines changed: 118 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -202,7 +202,8 @@ typedef struct {
202202
} mbt_pin_hal_t;
203203

204204
typedef struct {
205-
hal_bit_t *disabled; // Command disable
205+
hal_bit_t *disable; // Command disable input
206+
hal_bit_t *disabled; // Command disable output
206207
hal_bit_t *reset; // Reset errors and re-enable on rising edge
207208
hal_u32_t *error; // Command error counter
208209
hal_u32_t *errorcode; // Last error code
@@ -235,6 +236,7 @@ typedef struct {
235236
int pinref; // What pin to start with
236237
bool disabled; // Skipped if set
237238
bool prevreset; // To track the rising edge
239+
bool prevdisable; // To track the rising edge
238240
int errors; // Count the errors
239241
int datalen; // Number of bytes in 'data' buffer
240242
rtapi_u8 data[MAX_PKT_LEN]; // PDU: 2-byte header, MAX_MSG_LEN payload, 2-byte CRC
@@ -244,6 +246,8 @@ static inline bool hastimesout(const hm2_modbus_cmd_t *cc) { return 0 != (cc->c
244246
static inline bool hasbcanswer(const hm2_modbus_cmd_t *cc) { return 0 != (cc->cmd.flags & MBCCB_CMDF_BCANSWER); }
245247
static inline bool hasnoanswer(const hm2_modbus_cmd_t *cc) { return 0 != (cc->cmd.flags & MBCCB_CMDF_NOANSWER); }
246248
static inline bool hasresend(const hm2_modbus_cmd_t *cc) { return 0 != (cc->cmd.flags & MBCCB_CMDF_RESEND); }
249+
static inline bool haswflush(const hm2_modbus_cmd_t *cc) { return 0 != (cc->cmd.flags & MBCCB_CMDF_WFLUSH); }
250+
static inline bool hasdisabled(const hm2_modbus_cmd_t *cc) { return 0 != (cc->cmd.flags & MBCCB_CMDF_DISABLED); }
247251
static inline bool haspinscale(const hm2_modbus_mbccb_type_t *t) { return 0 != (t->flags & MBCCB_PINF_SCALE); }
248252
static inline bool haspinclamp(const hm2_modbus_mbccb_type_t *t) { return 0 != (t->flags & MBCCB_PINF_CLAMP); }
249253

@@ -463,7 +467,7 @@ static void set_error(hm2_modbus_inst_t *inst, int errcode)
463467
hm2_modbus_cmd_t *cc = current_cmd(inst);
464468
if(++cc->errors >= MAX_ERRORS || cc->disabled) {
465469
cc->disabled = 1;
466-
*(inst->hal->cmds[inst->cmdidx].disabled) = cc->disabled;
470+
*(inst->hal->cmds[inst->cmdidx].disabled) = 1;
467471
*(inst->hal->cmds[inst->cmdidx].errorcode) = errcode;
468472
}
469473
*(inst->hal->cmds[inst->cmdidx].error) = cc->errors;
@@ -514,6 +518,73 @@ static inline void force_resend(hm2_modbus_inst_t *inst)
514518
cc->interval = -1;
515519
}
516520

521+
//
522+
// Write flush command sets a specific command data to the current values.
523+
// Only Modbus write function are pre-calculated.
524+
//
525+
static void write_flush_cmd(hm2_modbus_inst_t *inst, unsigned idx)
526+
{
527+
if(handling_inits(inst)) { // Cannot flush init list
528+
MSG_ERR("%s: error: Called write_flush_cmd() while handling inits\n", inst->name);
529+
return;
530+
}
531+
532+
if(idx >= inst->ncmds) {
533+
MSG_ERR("%s: error: Command index out of range (%u >= %u) in write_flush_cmd()\n", inst->name, idx, inst->ncmds);
534+
return;
535+
}
536+
537+
hm2_modbus_cmd_t *cc = &inst->_cmds[idx]; // so this is the one we want
538+
switch(cc->cmd.func) {
539+
case MBCMD_W_COIL:
540+
case MBCMD_W_COILS:
541+
case MBCMD_W_REGISTER:
542+
case MBCMD_W_REGISTERS:
543+
break; // Only write functions shall be built
544+
default:
545+
return;
546+
}
547+
// Pre build the frame, even when disabled. When the WFLUSH flag is
548+
// set, then we still want timed out writes that are disabled, and
549+
// re-enabled due to a reset, to adhere to the flush setting when they
550+
// suddenly no longer timeout.
551+
if(!haswflush(cc)) // Must have flag set
552+
return;
553+
554+
unsigned oldidx = inst->cmdidx; // Save the position
555+
inst->cmdidx = idx; // This sets the current command index
556+
557+
int r = build_data_frame(inst);
558+
if(r < 0) {
559+
// We cannot recover from data frames that cannot be build. They
560+
// would always result in the same error.
561+
if(!cc->disabled) {
562+
MSG_ERR("%s: error: Build data frame failed (%d) in write_flush_cmd for command %d, disabling\n", inst->name, r, idx);
563+
cc->disabled = 1;
564+
}
565+
set_error(inst, -r);
566+
}
567+
inst->cmdidx = oldidx; // Restore position
568+
}
569+
570+
//
571+
// Write flush sets all command data to the current values.
572+
//
573+
static void write_flush(hm2_modbus_inst_t *inst)
574+
{
575+
// We must ensure to handle the command list and not the init list.
576+
// This switcheroo sucks but we have no choice as these variables are
577+
// instance global.
578+
hm2_modbus_cmd_t *oldcmds = inst->cmds;
579+
inst->cmds = inst->_cmds;
580+
581+
for(unsigned i = 0; i < inst->ncmds; i++) {
582+
write_flush_cmd(inst, i);
583+
}
584+
585+
inst->cmds = oldcmds;
586+
}
587+
517588
//
518589
// Advance to the next command in the list
519590
// A switch to the normal command list is made when it is the end of initlist.
@@ -549,6 +620,22 @@ static inline int next_command(hm2_modbus_inst_t *inst)
549620
*(inst->hal->cmds[i].disabled) = 0;
550621
*(inst->hal->cmds[i].error) = 0;
551622
*(inst->hal->cmds[i].errorcode) = 0;
623+
// Honor the writeflush flag when coming out of disable.
624+
write_flush_cmd(inst, i);
625+
}
626+
}
627+
628+
// The run-time disabling of a command takes precedens over reset.
629+
// Set it on the rising edge of the 'disable' pin
630+
b = !!*(inst->hal->cmds[i].disable);
631+
if(inst->cmds[i].prevdisable != b) {
632+
inst->cmds[i].prevdisable = !inst->cmds[i].prevdisable;
633+
if(inst->cmds[i].prevdisable) {
634+
inst->cmds[i].disabled = 1;
635+
inst->cmds[i].errors = 0;
636+
*(inst->hal->cmds[i].disabled) = 1;
637+
*(inst->hal->cmds[i].error) = 0;
638+
*(inst->hal->cmds[i].errorcode) = EAGAIN;
552639
}
553640
}
554641
} while(inst->cmdidx < inst->ncmds && inst->cmds[inst->cmdidx].disabled);
@@ -641,45 +728,6 @@ static void do_timeout(hm2_modbus_inst_t *inst)
641728
}
642729
}
643730

644-
//
645-
// Write flush sets all command data to the current values.
646-
// Only Modbus write function are pre-calculated.
647-
//
648-
static void write_flush(hm2_modbus_inst_t *inst)
649-
{
650-
unsigned oldidx = inst->cmdidx; // Save the position
651-
for(unsigned i = 0; i < inst->ncmds; i++) {
652-
inst->cmdidx = i; // This sets the current command index
653-
hm2_modbus_cmd_t *cc = current_cmd(inst); // so this is the one we want
654-
switch(cc->cmd.func) {
655-
case MBCMD_W_COIL:
656-
case MBCMD_W_COILS:
657-
case MBCMD_W_REGISTER:
658-
case MBCMD_W_REGISTERS:
659-
break; // Only write functions shall be built
660-
default:
661-
continue;
662-
}
663-
// Pre build the frame, even when disabled. When the WFLUSH flag is
664-
// set, then we still want timed out writes that are disabled, and
665-
// re-enabled due to a reset, to adhere to the flush setting when they
666-
// suddenly no longer timeout.
667-
if(!(cc->cmd.flags & MBCCB_CMDF_WFLUSH)) // Must have flag set
668-
continue;
669-
int r = build_data_frame(inst);
670-
if(r < 0) {
671-
// We cannot recover from data frames that cannot be build. They
672-
// would always result in the same error.
673-
if(!cc->disabled) {
674-
MSG_ERR("%s: error: Build data frame failed in write_flush for command %d, disabling\n", inst->name, inst->cmdidx);
675-
cc->disabled = 1;
676-
}
677-
set_error(inst, -r);
678-
}
679-
}
680-
inst->cmdidx = oldidx; // Restore position
681-
}
682-
683731
//
684732
// The main process Modbus state-machine.
685733
//
@@ -716,30 +764,33 @@ static void process(void *arg, long period)
716764
rtapi_u32 rxstatus = hm2_pktuart_get_rx_status(inst->uart);
717765
rtapi_u32 txstatus = hm2_pktuart_get_tx_status(inst->uart);
718766

719-
if(inst->cmds == inst->_cmds) {
767+
if(!handling_inits(inst)) {
720768
// Only count timeout when running the command list
721769
for(unsigned i = 0; i < inst->ncmds; i++) {
722770
inst->cmds[i].interval -= period; // Keep counting nanoseconds
723771
}
724-
}
725772

726-
inst->timeout -= period; // Current timeout count
727-
728-
// Re-enable all commands on rising edge of global reset pin
729-
bool b = !!*(inst->hal->reset); // Make sure its value is bool-worthy
730-
if(inst->prevreset != b) {
731-
inst->prevreset = !inst->prevreset;
732-
if(inst->prevreset) {
733-
for(unsigned i = 0; i < inst->ncmds; i++) {
734-
inst->cmds[i].disabled = 0;
735-
inst->cmds[i].errors = 0;
736-
*(inst->hal->cmds[i].disabled) = 0;
737-
*(inst->hal->cmds[i].error) = 0;
738-
*(inst->hal->cmds[i].errorcode) = 0;
773+
// Re-enable all commands on rising edge of global reset pin
774+
bool b = !!*(inst->hal->reset); // Make sure its value is bool-worthy
775+
if(inst->prevreset != b) {
776+
inst->prevreset = !inst->prevreset;
777+
if(inst->prevreset) {
778+
for(unsigned i = 0; i < inst->ncmds; i++) {
779+
if(inst->cmds[i].disabled) {
780+
inst->cmds[i].disabled = 0;
781+
*(inst->hal->cmds[i].disabled) = 0;
782+
write_flush_cmd(inst, i);
783+
}
784+
*(inst->hal->cmds[i].errorcode) = 0;
785+
*(inst->hal->cmds[i].error) = 0;
786+
inst->cmds[i].errors = 0;
787+
}
739788
}
740789
}
741790
}
742791

792+
inst->timeout -= period; // Current timeout count
793+
743794
switch(inst->state) {
744795
case STATE_START:
745796
#ifdef DEBUG_STATE
@@ -2879,6 +2930,8 @@ int rtapi_app_main(void)
28792930
#define CPTR(x) ((const char *)((x) + 1))
28802931
for(unsigned c = 0; c < inst->ncmds; c++) {
28812932
// First create command status pins
2933+
CHECK(hal_pin_bit_newf(HAL_IN, &(inst->hal->cmds[c].disable),
2934+
comp_id, "%s.command.%02d.disable", inst->name, c));
28822935
CHECK(hal_pin_bit_newf(HAL_OUT, &(inst->hal->cmds[c].disabled),
28832936
comp_id, "%s.command.%02d.disabled", inst->name, c));
28842937
CHECK(hal_pin_u32_newf(HAL_OUT, &(inst->hal->cmds[c].error),
@@ -2888,8 +2941,16 @@ int rtapi_app_main(void)
28882941
CHECK(hal_pin_bit_newf(HAL_IN, &(inst->hal->cmds[c].reset),
28892942
comp_id, "%s.command.%02d.reset", inst->name, c));
28902943

2891-
// Now create the pins associated with the command
28922944
hm2_modbus_cmd_t *cc = &inst->_cmds[c];
2945+
2946+
// If the command is disabled, set it so
2947+
if(hasdisabled(cc)) {
2948+
cc->disabled = 1;
2949+
*(inst->hal->cmds[c].disabled) = 1;
2950+
*(inst->hal->cmds[c].errorcode) = EAGAIN;
2951+
}
2952+
2953+
// Now create the pins associated with the command
28932954
int dir = HAL_IN;
28942955
const rtapi_u8 *dptr = inst->dataptr + cc->cmd.cdataptr;
28952956
cc->pinref = p;

src/hal/drivers/mesa-hostmot2/hm2_modbus.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,12 +80,13 @@ typedef struct {
8080
#define MBCCB_CMDF_BCANSWER 0x0002 // Broadcasts will get an answer, ignore it
8181
#define MBCCB_CMDF_NOANSWER 0x0004 // Don't expect an answer
8282
#define MBCCB_CMDF_RESEND 0x0008 // Resend the write even if no pins are changed
83-
#define MBCCB_CMDF_WFLUSH 0x0010 // Don't write initial pin values but flush the output
83+
#define MBCCB_CMDF_WFLUSH 0x0010 // Don't write initial pin values but flush the output
84+
#define MBCCB_CMDF_DISABLED 0x0020 // Start this command in disabled mode and must be reset
8485
#define MBCCB_CMDF_PARITYEN 0x0100 // Init-only parity change
8586
#define MBCCB_CMDF_PARITYODD 0x0200 // Init-only parity change
8687
#define MBCCB_CMDF_STOPBITS2 0x0400 // Init-only stopbits change
8788
#define MBCCB_CMDF_INITMASK 0x0707 // sum of allowed flags in init
88-
#define MBCCB_CMDF_MASK 0x001f // sum of allowed normal command flags
89+
#define MBCCB_CMDF_MASK 0x003f // sum of allowed normal command flags
8990

9091
#define MBCCB_PINF_SCALE 0x01 // Add scale/offset pins
9192
#define MBCCB_PINF_CLAMP 0x02 // Clamp values to fit target

src/hal/drivers/mesa-hostmot2/mesambccc.py

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -304,22 +304,23 @@ def mbtType(mtype):
304304
MBCCB_CMDF_NOANSWER = 0x0004
305305
MBCCB_CMDF_RESEND = 0x0008
306306
MBCCB_CMDF_WFLUSH = 0x0010
307+
MBCCB_CMDF_DISABLED = 0x0020
307308
MBCCB_CMDF_PARITYEN = 0x0100
308309
MBCCB_CMDF_PARITYODD= 0x0200
309310
MBCCB_CMDF_STOPBITS2= 0x0400
310311
MBCCB_CMDF_INITMASK = 0x0707 # sum of allowed flags in init
311-
MBCCB_CMDF_MASK = 0x001f # sum of allowed normal command flags
312+
MBCCB_CMDF_MASK = 0x003f # sum of allowed normal command flags
312313

313314
# Allowed attributes in <mesamodbus>
314315
MESAATTRIB = [ 'baudrate', 'drivedelay', 'duplex', 'icdelay', 'interval',
315316
'parity', 'rxdelay', 'stopbits', 'suspend', 'timeout',
316317
'txdelay', 'writeflush' ]
317318

318319
# Allowed attributes in <commands>/<command>
319-
CMDSATTRIB = [ 'address', 'bcanswer', 'clamp', 'count', 'delay',
320-
'device', 'function', 'haltype', 'interval', 'modbustype',
321-
'name', 'noanswer', 'resend', 'scale', 'timeout',
322-
'timeoutbits', 'timesout', 'writeflush' ]
320+
CMDSATTRIB = [ 'address', 'bcanswer', 'clamp', 'count', 'delay',
321+
'device', 'disabled', 'function', 'haltype', 'interval',
322+
'modbustype', 'name', 'noanswer', 'resend', 'scale',
323+
'timeout', 'timeoutbits', 'timesout', 'writeflush' ]
323324

324325
# Allowed attributes in <commands>/<command>/<pin>
325326
PINSATTRIB = [ 'clamp', 'name', 'haltype', 'modbustype', 'scale' ]
@@ -492,7 +493,7 @@ def cflagList(flags):
492493
return "<none>"
493494
l = { MBCCB_CMDF_TIMESOUT: 'timesout', MBCCB_CMDF_BCANSWER: 'bcanswer',
494495
MBCCB_CMDF_NOANSWER: 'noanswer', MBCCB_CMDF_RESEND: 'resend',
495-
MBCCB_CMDF_WFLUSH: 'writeflush' }
496+
MBCCB_CMDF_DISABLED: 'disabled', MBCCB_CMDF_WFLUSH: 'writeflush' }
496497
return ','.join([l[v] for v in l.keys() if flags & v])
497498

498499
def pflagList(flags):
@@ -625,6 +626,7 @@ def parseOptFlags(dev, attrs, cflags, pflags, ers):
625626
cflags |= MBCCB_CMDF_BCANSWER if getBoolean(attrs, 'bcanswer') else 0
626627
cflags |= MBCCB_CMDF_NOANSWER if getBoolean(attrs, 'noanswer') else 0
627628
cflags |= MBCCB_CMDF_RESEND if getBoolean(attrs, 'resend') else 0
629+
cflags |= MBCCB_CMDF_DISABLED if getBoolean(attrs, 'disabled') else 0
628630
# The default of writeflush depends on the global setting
629631
cflags |= MBCCB_CMDF_WFLUSH if getBoolean(attrs, 'writeflush') else 0
630632
cflags &= ~MBCCB_CMDF_WFLUSH if False == getBoolean(attrs, 'writeflush') else ~0

0 commit comments

Comments
 (0)