📄 modbus.asm
字号:
; This files contains function that decodes and assemble modbus
; data patterns, over TCP or the OnChip USART.
; This is ugliest code i have ever written :-(
.incld proj.inc
.extrn ne_w_b, ne_d_w_B, ne_d_r_B, ne_d_r_X_crc, ne_d_w_X, ne_d_rs
.extrn USART_tx_byte_fromX, USART_rx_byte_toX, USART_rx_byte_toXinc, USART_rx_byte_toXdec
.extrn usart_flags
.extrn usart_chgbaud
.extrn curr_tpsr, tcp_data_len, tcp_ip_mk_hdr, tcp_mk_hdr_app_crc, tcp_crc_add, tcp_code, crc_add_alt
.extrn rx_finish, ne_d_ab, tx_transmit_packet
.extrn sleep
.sect modbus_ram, RAM
xact_id: .dsb 0x02
proto_id: .dsb 0x02
mb_pkt_len: .dsb 0x02
; Macros for Modbus.
; Read ROM table macro. Returns value into "ISPRD".
.macro readrom, addrhi, addrlo
ld ISPADHI, addrhi
ld A, addrlo
x A, ISPADLO
ld ISPKEY, #KEY
jsrb #0x11 ; READ BYTE
.endm
.sect modbus_rom, ROM
.public mb_tcp_forward, usart_mb_forward
mb_tcp_forward:
; Read transaction ID.
ld B, #xact_id
jsr ne_d_r_B
; Read protocol ID. Usually 0x00 0x00.
ld B, #proto_id
jsr ne_d_r_B
; Read length field.
ld B, #T0
jsr ne_d_r_B
; Convert to word count.
ld A, T1
push A ; Store byte count for later use.
rrc A
x A, T1
; Initialize Checksum holder.
ld crc_l, #0xFF
ld crc_h, #0xFF
; Loop until we have forwarded all to the USART.
mb_tcp_forward_toUsart:
ld X, #a_l
jsr ne_d_r_X_crc
jsr mb_crc_add
jsr USART_tx_byte_fromX
jsr mb_crc_add
jsr USART_tx_byte_fromX
drsz T1
jmp mb_tcp_forward_toUsart
pop A ; Now we check if byte count was odd.
andsz A, #0x01
jp mb_tcp_forward_toUsart_extra
jp mb_tcp_forward_toUsart_exit
mb_tcp_forward_toUsart_extra:
ld X, #a_l
jsr ne_d_r_X_crc
jsr mb_crc_add
jsr USART_tx_byte_fromX
mb_tcp_forward_toUsart_exit:
;ne_d_rd_stop
jsr rx_finish
; Append Checksum.
ld X, #crc_h
jsr USART_tx_byte_fromX
ld X, #crc_l
jsr USART_tx_byte_fromX
; Dummy read to reset RBFL bit of ENU. Init usart data pointer.
rbit ERI, ENUI
ld usart_data_ptr, #0x00
ld A, RBUF
sbit ERI, ENUI
sbit USART_FLG_RXPNG, usart_flags
; Enable Timeout timer.
;rbit T2C0, T2CNTRL
;rbit T2PNDA, T2CNTRL
;ld TMR2LO, #0xff
;ld TMR2HI, #0xff
;sbit T2ENA, T2CNTRL
;sbit T2C0, T2CNTRL
; ModbusTCP Packet forwarded to USART. Lets go back to business
ret
; Forward ModBus RTU to NIC.
usart_mb_forward:
; Reinitialize CRC holder.
ld crc_h, #0xFF
ld crc_l, #0xFF
; Set TCP CODE (header field).
ld tcp_code, #(TCP_ACK+TCP_PSH)
; Obtain mb_pkt_len.
; Wait until ModBus header is read into USART buffer or timeout.
mb_tcp_forward_toN_read3:
; Check if we are ready (3 bytes have arrived).
ld A, usart_data_ptr
ifgt A, #0x02
jmp mb_tcp_forward_toN_read3done
; Loop until timeout
ifeq usart_data_ptr, #0x00
jmp mb_tcp_forward_toN_timeout
jmp mb_tcp_forward_toN_read3
mb_tcp_forward_toN_read3done:
ld S, #SEG_USART
; Copy Data length field into T0. mb_pkt_len isn't accesable here.
ld A, 0x02
x A, T0
; Copy function byte to check for exception status flag.
ld A, 0x01
x A, T1
ld S, #0x00
; Check function byte for Exception status and fixed length packet situations.
ifbit 7, T1
ld T0, #0x00
ifeq T1, #0x05
ld T0, #0x03
ifeq T1, #0x06
ld T0, #0x03
ifeq T1, #0x07
ld T0, #0x03
ifeq T1, #0x0F
ld T0, #0x03
ifeq T1, #0x10
ld T0, #0x03
ifeq T1, #0x16
ld T0, #0x05
; Copy ModBus packet length (T0) into mb_pkt_len.
ld B, #(mb_pkt_len+1)
ld A, T0
x A, [B-]
clr A
x A, [B+]
; Add Modbus header.
;ld B, #(mb_pkt_len+1)
ld A, [B]
rc
ADC A, #0x03 ; ModBus header length = 0x03.
x A, [B-]
ld A, [B]
IFC
inc A
x A, [B]
; Make tcp_data_len.
ld A, #0x06 ; 0x06 = MB/TCP header.
rc
ADC A, (mb_pkt_len+1)
x A, tcp_data_len
ld A, mb_pkt_len
IFC
inc A
x A, (tcp_data_len+1)
; START TCP/IP PACKET ASSEMBLY.
; Make TCP/IP header.
jsr tcp_ip_mk_hdr
; Write xact ID.
ld X, #xact_id
jsr tcp_crc_add
jsr ne_d_w_X
; Write Protocol ID
ld X, #proto_id
jsr tcp_crc_add
jsr ne_d_w_X
; Write data length.
ld X, #mb_pkt_len
jsr tcp_crc_add
jsr ne_d_w_X
; Wait for complete serial packet to arrive on usart data buffer.
mb_tcp_forward_toN_wait_usart_data:
ld A, usart_data_ptr
dec A
ifgt A, (mb_pkt_len+1)
jp mb_tcp_forward_toN_wait_usart_data_done
; Check timeout.
ifeq usart_data_ptr, #0x00
jp mb_tcp_forward_toN_dump_timeout
jp mb_tcp_forward_toN_wait_usart_data
mb_tcp_forward_toN_wait_usart_data_done:
; Disable further USART activity and timeout counter
;rbit T2ENB, T2CNTRL
rbit T2C0, T2CNTRL
rbit T2PNDA, T2CNTRL
rbit T2ENA, T2CNTRL
rbit 7, X
rbit ERI, ENUI
ld usart_data_ptr, #0x00
; Dump the packet from SEG_USART into the NIC buffer.
ld A, (mb_pkt_len+1)
x A, T2
; mb_pkt_len MSB is ingored, because of ModBus/TCP specification: Byte count MSB is always cero.
ld X, #0x00
ld S, #SEG_USART
mb_tcp_forward_toN_dump:
; Check if we are done.
ld A, T2
dec A
ifgt A, X
jp mb_tcp_forward_toN_dump_write_next
; Align data if total byte count is odd for final byte write.
ifbit 0, T2
jp mb_tcp_forward_toN_dump_aligndata
jp mb_tcp_forward_toN_dump_done
mb_tcp_forward_toN_dump_aligndata:
rbit 7, X
ld A, [X]
x A, a_l
ld a_h, #0x00
ld X, #a_l
jsr mb_crc_add
jsr tcp_crc_add
jsr ne_d_w_X
ld A, T2
x A, X
jp mb_tcp_forward_toN_dump_done
mb_tcp_forward_toN_dump_write_next:
; Transfer another word to nic buffer.
rbit 7, X
jsr mb_crc_add_word
jsr tcp_crc_add
jsr ne_d_w_X
ifbit 7, X
ld S, #(SEG_USART+1)
ifeq S, #(SEG_USART+1)
sbit 7, X
jp mb_tcp_forward_toN_dump
mb_tcp_forward_toN_dump_done:
; Verify Checksum. If checksum fail, abort anything.
ifbit 7, X
ld S, #(SEG_USART+1)
rbit 7, X ; Maybe we are just on the segment boundary.
ld A, [X+]
ifne A, crc_h
jp mb_tcp_forward_toN_dump_badchksum
ifbit 7, X
ld S, #(SEG_USART+1)
rbit 7, X ; Maybe we are just on the segment boundary.
ld A, [X]
ifne A, crc_l
jp mb_tcp_forward_toN_dump_badchksum
ld S, #0x00
; Append TCP CRC to NIC buffer.
jsr tcp_mk_hdr_app_crc
jmp tx_transmit_packet
mb_tcp_forward_toN_dump_timeout:
ld S, #0x00
jsr ne_d_ab
mb_tcp_forward_toN_timeout:
.ifdef __DEBUG__
ld A, PORTED
xor A, #0x20
x A, PORTED
.endif
ret
mb_tcp_forward_toN_dump_badchksum:
ld S, #0x00
; Bad Checksum indicator
.ifdef __DEBUG__
ld A, PORTED
xor A, #0x40
x A, PORTED
.endif
ret
; Checksum generator (on the fly CRC generator).
; X points to data.
; a_l is const array index.
mb_crc_add:
; Achtung baby! : Pointer B gets lost on "readrom". Thats why we use X instead.
ld A, [X]
xor A, crc_h
x A, T0 ;T0 = [X] xor crc_h
readrom #HIGH(auchCRCHi), T0
ld A, ISPRD ;A = auchCRCHi[T0]
xor A, crc_l
x A, crc_h ;crc_h = auchCRCHi[T0] xor crc_l
readrom #HIGH(auchCRCLo), T0
ld A, ISPRD ;A = auchCRCLO[T0]
x A, crc_l ;crc_l = auchCRCLO[T0]
ret
mb_crc_add_word:
; Achtung baby! : Pointer B gets lost on "readrom". Thats why we use X instead.
ld A, [X+]
xor A, crc_h
x A, T0 ;T0 = [X] xor crc_h
readrom #HIGH(auchCRCHi), T0
ld A, ISPRD ;A = auchCRCHi[T0]
xor A, crc_l
x A, crc_h ;crc_h = auchCRCHi[T0] xor crc_l
readrom #HIGH(auchCRCLo), T0
ld A, ISPRD ;A = auchCRCLO[T0]
x A, crc_l ;crc_l = auchCRCLO[T0]
; Second byte
ld A, [X-]
xor A, crc_h
x A, T0 ;T0 = [X] xor crc_h
readrom #HIGH(auchCRCHi), T0
ld A, ISPRD ;A = auchCRCHi[T0]
xor A, crc_l
x A, crc_h ;crc_h = auchCRCHi[T0] xor crc_l
readrom #HIGH(auchCRCLo), T0
ld A, ISPRD ;A = auchCRCLO[T0]
x A, crc_l ;crc_l = auchCRCLO[T0]
ret
; CRC tables.
.sect modbus_crc, ROM, ABS = 0x1D00
auchCRCHi:
.db 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0
.db 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41
.db 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0
.db 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40
.db 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1
.db 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41
.db 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1
.db 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41
.db 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0
.db 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40
.db 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1
.db 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40
.db 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0
.db 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40
.db 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0
.db 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40
.db 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0
.db 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41
.db 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0
.db 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41
.db 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0
.db 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40
.db 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1
.db 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41
.db 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0
.db 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40
auchCRCLo:
.db 0x00, 0xC0, 0xC1, 0x01, 0xC3, 0x03, 0x02, 0xC2, 0xC6, 0x06
.db 0x07, 0xC7, 0x05, 0xC5, 0xC4, 0x04, 0xCC, 0x0C, 0x0D, 0xCD
.db 0x0F, 0xCF, 0xCE, 0x0E, 0x0A, 0xCA, 0xCB, 0x0B, 0xC9, 0x09
.db 0x08, 0xC8, 0xD8, 0x18, 0x19, 0xD9, 0x1B, 0xDB, 0xDA, 0x1A
.db 0x1E, 0xDE, 0xDF, 0x1F, 0xDD, 0x1D, 0x1C, 0xDC, 0x14, 0xD4
.db 0xD5, 0x15, 0xD7, 0x17, 0x16, 0xD6, 0xD2, 0x12, 0x13, 0xD3
.db 0x11, 0xD1, 0xD0, 0x10, 0xF0, 0x30, 0x31, 0xF1, 0x33, 0xF3
.db 0xF2, 0x32, 0x36, 0xF6, 0xF7, 0x37, 0xF5, 0x35, 0x34, 0xF4
.db 0x3C, 0xFC, 0xFD, 0x3D, 0xFF, 0x3F, 0x3E, 0xFE, 0xFA, 0x3A
.db 0x3B, 0xFB, 0x39, 0xF9, 0xF8, 0x38, 0x28, 0xE8, 0xE9, 0x29
.db 0xEB, 0x2B, 0x2A, 0xEA, 0xEE, 0x2E, 0x2F, 0xEF, 0x2D, 0xED
.db 0xEC, 0x2C, 0xE4, 0x24, 0x25, 0xE5, 0x27, 0xE7, 0xE6, 0x26
.db 0x22, 0xE2, 0xE3, 0x23, 0xE1, 0x21, 0x20, 0xE0, 0xA0, 0x60
.db 0x61, 0xA1, 0x63, 0xA3, 0xA2, 0x62, 0x66, 0xA6, 0xA7, 0x67
.db 0xA5, 0x65, 0x64, 0xA4, 0x6C, 0xAC, 0xAD, 0x6D, 0xAF, 0x6F
.db 0x6E, 0xAE, 0xAA, 0x6A, 0x6B, 0xAB, 0x69, 0xA9, 0xA8, 0x68
.db 0x78, 0xB8, 0xB9, 0x79, 0xBB, 0x7B, 0x7A, 0xBA, 0xBE, 0x7E
.db 0x7F, 0xBF, 0x7D, 0xBD, 0xBC, 0x7C, 0xB4, 0x74, 0x75, 0xB5
.db 0x77, 0xB7, 0xB6, 0x76, 0x72, 0xB2, 0xB3, 0x73, 0xB1, 0x71
.db 0x70, 0xB0, 0x50, 0x90, 0x91, 0x51, 0x93, 0x53, 0x52, 0x92
.db 0x96, 0x56, 0x57, 0x97, 0x55, 0x95, 0x94, 0x54, 0x9C, 0x5C
.db 0x5D, 0x9D, 0x5F, 0x9F, 0x9E, 0x5E, 0x5A, 0x9A, 0x9B, 0x5B
.db 0x99, 0x59, 0x58, 0x98, 0x88, 0x48, 0x49, 0x89, 0x4B, 0x8B
.db 0x8A, 0x4A, 0x4E, 0x8E, 0x8F, 0x4F, 0x8D, 0x4D, 0x4C, 0x8C
.db 0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 0x46, 0x86, 0x82, 0x42
.db 0x43, 0x83, 0x41, 0x81, 0x80, 0x40
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -