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

#44 refactor for MODBUS-RTU client features #57

Merged
merged 1 commit into from
Jul 9, 2022
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
58 changes: 58 additions & 0 deletions MBBASE
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
\ STM8EF-MODBUS Base words for server and client

#require UARTISR
#require CRC16

NVM
VARIABLE mbp 2 ALLOT \ MODBUS parameter 1 and 2

\ 1st MODBUS FC parameter
: mbp1 ( -- n )
mbp @
;

\ 2nd MODBUS FC parameter
: mbp2 ( -- n )
mbp 2+ @
;

\ MODBUS write response (e.g FC05, FC06, FC15, FC16)
: MBWR ( -- )
mbp1 tx+ mbp2 tx+ \ copy 1st and 2nd parameter
;

\ MB loop (xt) from mbp1 to mbp1+mbp2
: mbloop ( xt -- )
mbp1 mbp2 OVER + SWAP DO
( xt ) I OVER EXECUTE
LOOP
( xt ) DROP
;

\ MB looped bit read with action xt, build response (FC01, FC02, FC03, FC04)
: mbread ( xt bpu -- )
( xt bpu ) DUP mbp2 * ( bpu bits )
\ N* as quantity of bits / 8, if the remainder is different of 0 => N=N+1
( bits ) 1- 8 / 1+ ( N* ) DUP txc+
( bpu N* ) SWAP ( bpu ) 1 = IF
( N* ) 1- FOR 0 txc+ NEXT \ init bytes in response with 0
ELSE
( N* ) DROP \ not a bitfield, no memory init
THEN
( xt ) mbloop
;

\ execute xt if not 0
: @?EXEC ( a -- ) @ ?DUP IF
( xt ) EXECUTE
THEN
;

\ calc CRC16 from buffer a0 to a1
: MBCRC ( a1 a0 -- crc-le )
-1 ROT ROT ( -1 a1 a0 ) DO
I C@ CRC16
LOOP
( CRC16 ) EXG ( CRC-LE )
;
RAM
63 changes: 63 additions & 0 deletions MBCLIENT
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
\ STM8 eForth MODBUS basic client routines

#require MBUTILS

NVM
VARIABLE clrec \ XT for client receive handler
VARIABLE clerr \ XT for client error handler
VARIABLE clnfc \ requested MODBUS Node ID and FC
VARIABLE crcerr \ CRC error counter

\ MODBUS protocol handler
: CLPROTO ( -- )
rtbuf rxp @ - ( rx ) \ data has been received
1 TIM tstamp @ - < ( gap ) \ gap signals message complete
( rx gap ) AND IF
rxp @ 2- ( a1 ) DUP rtbuf ( a1 a1 a0 )
MBCRC ( a1 crc-le ) SWAP @ = ( crc-OK ) IF
rtbuf @ clnfc @ = IF \ node address abd FC match
clrec @?EXEC
ELSE
clerr @?EXEC
THEN
ELSE
1 crcerr +!
THEN
rxres
THEN
;

RAM

\ Example

\ Minimal MODBUS client with a FC06 "Write Single Register" handler

#require CLPROTO

RAM
#require WIPE

#require 'IDLE

NVM
#require MBDUMP
: tst ( -- )
txres
1 256 * ( node ) 3 ( fc ) +
DUP rtbuf ! clnfc !

$EA60 tx+ $0005 tx+

tbp @ rtbuf ( a1 a0 ) MBCRC ( CRC-LE ) tx+
send
;

: init ( -- )
0 UARTISR \ init UART handler w/ default baud rate
[ ' MBDUMP ] LITERAL clrec ! \ MB Client receive action
[ ' CLPROTO ] LITERAL 'IDLE ! \ run MB Client protocol handler as idle task
;

' init 'BOOT !
WIPE RAM
69 changes: 8 additions & 61 deletions MBPROTO
Original file line number Diff line number Diff line change
@@ -1,32 +1,28 @@
\ STM8 eForth MODBUS protocol handler - intended to run as an IDLE task

#require UARTISR
#require CRC16
#require MBBASE
#require ]B!
#require WIPE

NVM
VARIABLE mbnode \ MODBUS node id
VARIABLE crcerr \ CRC error counter
VARIABLE mbpre \ xt for FC preparation (e.g. reading inputs)
VARIABLE mbact \ xt for output action (e.g. output, debugging)
VARIABLE mbdef \ xt for default handler
VARIABLE mbp 2 ALLOT \ MODBUS parameter 1 and 2

\ calc CRC16 from buffer a0 to a1
: MBCRC ( a1 a0 -- crc-le )
-1 ROT ROT ( -1 a1 a0 ) DO
I C@ CRC16
LOOP
( CRC16 ) EXG ( CRC-LE )
;

\ flag MODBUS Exception and set code
: MBEC ( ec -- )
[ 1 rtbuf 1+ 7 ]B! \ flag error in FC field
( ec ) txc+ \ and put EC
;

\ true if n in range mbp1,mbp2, else false and MODBUS EC=2
: mbrange? ( n -- b )
-1 ( b ) SWAP mbp1 mbp2 + - 0< IF
2 MBEC ( b ) NOT
THEN
;

\ default FC handler - raise EC 1 "ILLEGAL FUNCTION"
: FCDEF ( -- )
mbdef @ ?DUP IF
Expand All @@ -49,60 +45,11 @@ NVM
2* ( [ tab ] ) LITERAL +
;

\ execute xt if not 0
: @?EXEC ( xt -- ) @ ?DUP IF
( xt ) EXECUTE
THEN
;

\ get MODBUS FC
: mbfc ( -- c )
rtbuf 1+ C@
;

\ 1st MODBUS FC parameter
: mbp1 ( -- n )
mbp @
;

\ 2nd MODBUS FC parameter
: mbp2 ( -- n )
mbp 2+ @
;

\ MODBUS write response (e.g FC05, FC06, FC15, FC16)
: MBWR ( -- )
mbp1 tx+ mbp2 tx+ \ copy 1st and 2nd parameter
;

\ true if n in range mbp1,mbp2, else false and MODBUS EC=2
: mbrange? ( n -- b )
-1 ( b ) SWAP mbp1 mbp2 + - 0< IF
2 MBEC ( b ) NOT
THEN
;

\ MB loop (xt) from mbp1 to mbp1+mbp2
: mbloop ( xt -- )
mbp1 mbp2 OVER + SWAP DO
( xt ) I OVER EXECUTE
LOOP
( xt ) DROP
;

\ MB looped bit read with action xt, build response (FC01, FC02, FC03, FC04)
: mbread ( xt bpu -- )
( xt bpu ) DUP mbp2 * ( bpu bits )
\ N* as quantity of bits / 8, if the remainder is different of 0 => N=N+1
( bits ) 1- 8 / 1+ ( N* ) DUP txc+
( bpu N* ) SWAP ( bpu ) 1 = IF
( N* ) 1- FOR 0 txc+ NEXT \ init bytes in response with 0
ELSE
( N* ) DROP \ not a bitfield, no memory init
THEN
( xt ) mbloop
;

\ MODBUS protocol handler
: MBPROTO ( -- )
rtbuf rxp @ - ( rx )
Expand Down