;ModBus and SPiceX demonstration program

;This program reads and writes the i/o of several expansion boards
;using SPiceX mode. It passes the data through RAM
;and makes is accessible via ModBus. This is a companion to
;the VB6 demo program SPiceX1.VB6

***** CAUTION *******
;When a SPLat switches to ModBus it cannot connect to SPLat/PC.
;The board will not switch in the first 10S after turn-on.

***** NOTE ******
;With SPiceX the input and output byte orders are opposite to each other.
;See http://splatco.com/skb/skbredir.htm?toc.htm?3251.htm

;-----------------------------------------
;Absolute RAM locations for ModBus

;Transfers are done in words, so allocation must be in pairs of bytes.
;I will do all transfers via RAM using functions 3 (read) and 16 (write).
;The first bunch of 16 bytes is for inputs. The second is for outputs

mbInputData	mEQU		200,16	;Modicon ref 40201, Hi byte
mbOutputData	mEQU		216,16	;Modicon ref 40217, Hi byte

;The Hi byte is the first of the pair transmitted (furthest left in Visual Basic strings).
;This means that when data is packed inbinary into a VB string,
;it will map to SPLat RAM bytes in the same sequence. 
;Left to right in VB = Lowest to highest address in SPLat.

;Bus addresses (addresses in ModBus messages) are identical to the 
;SPLat RAM address for the start of each block.

;The program transfers up to 8 bytes of input and output data using SPxTxfrU
****************************************************************
;Set the following constant to reflect the number of bytes of 
;data being shifted in.
;
;	XBIO16		2 bytes
;	MBIO16		2 bytes
;	XIRO16		1 byte
;	HIO16		1 byte
;	FP16		1 byte


ShiftLength	EQU		6	;Bytes ... minimum 5 with standard expansion boards!

**** NOTE ****
;SPiceX mode works only with standard XPice expansion boards when
;there is more than 5 bytes of data. For less than that the
;automatic detection will sense the boards and map them as
;regular I/O. 
;With custom expansion boards it may work with fewer than 5 bytes,
;depending on the design of the board. Please consult the board documentation.
****************************************************************

		SPxMode		6
		SetV		ShiftLength	;Will henceforth control how
						;many bytes get transferred

;Once ModBus has been invoked in a board, the only way to connect SPLat/PC to that board is
;within 10s of the board being powered up. The following splash screen is a reminder.

SPLashCount	defBYTE

		SetMem		SPLashCount,10
				;0123456789012345
		OBLCD_Text	" 10S to connect"
		OBLCD_SetCur	1,0
		OBLCD_Text	"to SPLat/PC"		
Splash1:
		OBLCD_SetCur	0,0
		OBLCD_UDecDispMFW	SPLashCount
		Pause		100
		DMGNZ		SPLashCount,Splash1


;Get ModBus going...
		COMSetCCB	ModBusCCB
		OBLCD_Cls

;Get tasks going
		LaunchTask		TransferIO
		RunTasksForever

;----------------------------------------------
;This task transfers ModBus<==>Hardware I/O
InputBuf	defBYTE		16
TxferCount	defBYTE

TransferIO:
		YieldTask
		LoadX		ShiftLength
		PopV				;set up V for byte count
		MemToUV		mbOutputData,0	;Output data
		SPxTxfrU	0		;Writes the outputs, Reads the inputs
		UVToMem		0,InputBuf	;Copy V input bytes from U to memory

;Input data is inverted. It is initially read to a buffer, InputBuf.
;It must now be transferred to the ModBus buffer and inverted.
		LoadI		0
		SetMem		TxferCount,ShiftLength
TxferLoop:
		iRecall		InputBuf
		NOTM
		iStore		mbInputData
		IncI
		DecMGoIfNZ	TxferCount,TxferLoop
		GoTo		TransferIO	

************************************************************************

               NVEM0           ;
ModBusCCB:
                NV0Byte         1       ;Protocol
                NV0Byte         1       ;Address
                NV0Byte         0       ;Character = 8,1,N
                NV0Byte         7       ;38400
                NV0Byte         1       ;Half duplex, echo suppression
                NV0Byte         0       ;Flags: No RTC writes
                NV0Byte         255     ;RTS: use dedicated line
                NV0Byte         10      ;RTSDelay = 10mS
                NV0Byte         0       ;RTSLeadOut
                NV0Byte         10      ;Message gap 100mS
                NV0Byte         100     ;Query timeout 1S
                NV0Byte         3       ;Query attempts
                NV0Byte         0,250   ;ModBus writable RAM
                NV0Byte         255,0   ;Prevent output writes
                NV0Byte         #65535,#0 ;Prevent NVEM0 writes