@@ -202,7 +202,8 @@ typedef struct {
202202} mbt_pin_hal_t ;
203203
204204typedef 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
244246static inline bool hasbcanswer (const hm2_modbus_cmd_t * cc ) { return 0 != (cc -> cmd .flags & MBCCB_CMDF_BCANSWER ); }
245247static inline bool hasnoanswer (const hm2_modbus_cmd_t * cc ) { return 0 != (cc -> cmd .flags & MBCCB_CMDF_NOANSWER ); }
246248static 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 ); }
247251static inline bool haspinscale (const hm2_modbus_mbccb_type_t * t ) { return 0 != (t -> flags & MBCCB_PINF_SCALE ); }
248252static 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 ;
0 commit comments