;*************************************************************************************************
;********  Demonstration of interaction with 4D Systems ViSi-Genie display **********************
;************************************************************************************************
;[...]
;- Object types -
;
k4D_Dipswitch       EQU 0   
k4D_Knob            EQU 1       
k4D_Rockerswitch    EQU 2 
k4D_Rotaryswitch    EQU 3 
k4D_Slider          EQU 4       
k4D_Trackbar        EQU 5   
k4D_Winbutton       EQU 6   
k4D_Angularmeter    EQU 7 
k4D_Coolgauge       EQU 8
k4D_Customdigits    EQU 9 
k4D_Form            EQU 10          
k4D_Gauge           EQU 11
k4D_Image           EQU 12
k4D_Keyboard        EQU 13
k4D_Led             EQU 14
k4D_Leddigits       EQU 15  
k4D_Meter           EQU 16
k4D_Strings         EQU 17  
k4D_Thermometer     EQU 18 
k4D_Userled         EQU 19  
k4D_Video           EQU 20
k4D_Statictext      EQU 21   
k4D_Sound           EQU 22
k4D_Timer           EQU 23

o4D_Reset       EQU     10

;[...]
;Serial port definitions
HMI_Port          EQU  251 
k4D_Port:           EQU  252  

;[...]
;Set the 4D's reset pin high (= not resetting). For the EC1 this is the ON state   
;This is needed only if you have connected the display to the EC1 with the full 5-wire cable
;which includes the Rest line.
        On              o4D_Reset

;[...]
;Turn on both EC1 LEDs then wait for a button press.
;This provides a trap for any crashes, and makes it easy to detect a crash and connect to SPLat/PC
        On              1
        On              0
        WaitOnK         0 
        Off             0
        Off             1



;[...]
;Open the two serial ports
# Open_Serial   Port(k4D_Port)   User(9600, 8, N)        ;4D BigSPLatDemo defaults to 9600 out of the box
# Open_Serial   Port(HMI_Port)  User(38400, 8, N)       ;Goes to SimpleHMI in the PC (inside SPLat/PC)



;[...]
# 4D_ViSi Port(k4D_Port)                                 ;Associates the 4D display with the port         
# HMI     Port(HMI_Port)                                ;Actually redundant, as this is the default



;[...]
;******************* Declare event handlers for 4D objects *******************************************
# 4D_ViSi  4D_ObjEvent(k4D_Winbutton, 0, ev4DMom)       ;The momentary button. Value always 0
# 4D_ViSi  4D_ObjEvent(k4D_Winbutton, 1, ev4DTgl)       ;Toggle button. Data = 1|0 for on/off state
# 4D_ViSi  4D_ObjEvent(k4D_Winbutton, 2, evRBtop)       ;Radio button top.    Data = 1|0
# 4D_ViSi  4D_ObjEvent(k4D_Winbutton, 3, evRBmdl)       ;Radio button Middle. Data = 1|0 
# 4D_ViSi  4D_ObjEvent(k4D_Winbutton, 4, evRBbtm)       ;Radio button Bottom. Data = 1|0 
# 4D_ViSi  4D_ObjEvent(k4D_Knob, 0, evKnob)             ;Knob. Data reported as 0 - 100
# 4D_ViSi  4D_ObjEvent(k4D_Rotaryswitch, 0, evRsw)      ;Rotary switch. Data reported as 0 through 4
# 4D_ViSi  4D_ObjEvent(k4D_Slider, 0, evSldr)           ;Slider. Data reported as 0 - 100
# 4D_ViSi  4D_ObjEvent(k4D_Trackbar, 0, evTrkbr)        ;Trackbar. Data reported as 0 - 100
# 4D_ViSi  4D_ObjEvent(k4D_Dipswitch, 0, evDIPsw)       ;Dipswitch. Data = 1|0 for on/off state
# 4D_ViSi  4D_ObjEvent(k4D_Rockerswitch, 0, evRkr)      ;Rockerswitch. Data = 1|0 for on/off state
# 4D_ViSi  4D_ObjEvent(k4D_Keyboard, 1, evKpd)                  ;Numeric Keypad. Data = ASCII code
# 4D_ViSi  4D_ObjEvent(k4D_Keyboard, 0, evQWERTY)           ;QWERTY. Data = ASCII code         
                                                                       
;[...]
# 4D_ViSi  4D_NackEvent(ev4DNack)               ;Handler for when 4D sends us a NACK 



;[...](Don't yet know what MultiTrack is? See 32 processes for the price of one)
                LaunchTask      tskBumpForm                               
                LaunchTask      tskHeartBeat  
                LaunchTask      tskMoveMeter
                LaunchTask      tskMoveThermometer 
                LaunchTask      tskMoveGauge  
                LaunchTask      tskMoveAngularmeter 
                LaunchTask      tskMoveCoolgauge 
                GoSub           evHMI_Connect   ;Initialise the SimpleHMI display                
                RunTasksForever






;[...]
;=========== Task to monitor the EC1 push button and switch forms on the 4D ==============  
;Includes a killswitch function
bFormNumber     defByte        ;Allocate 1 byte of RAM to the form number
tskBumpForm:
                WaitOnK         0                ;Wait for the EC1 button to be pressed
                GoIfMLE         bFormNumber,11,Loop2 ;Go to Loop2 if bFormNumber <= 11
                SetMem          bFormNumber,0    ;Reset bFormNumber to 0
Loop2:                
                Recall          bFormNumber      ;Retrieve the form number
# 4D_ViSi 4D_SetFormX()                          ;Select that form in the 4D display
                IncM            bFormNumber      ;Increment the number for next time
;[...]
                WaitOffT        0,200            ;long press is killswitch               
                GoIfT           tskBumpForm      ;g/short press
                On              1                ;Red LED
                Pause           20        
Die:            GoSub           Die



;[...]
;================= Heartbeat task =========================
tskHeartBeat
                On              0
                Pause           10
                Off             0
                Pause           90
                GoTo            tskHeartBeat            

;[...]
;***********   Generate a bunch of output data to various 4D objects **********
; These demonstrate different ways of supplying data to the 4D display        *
; The 4D demo contains several more objects that can receive and display data *
; Have a go at making your own drivers for them!                              *
;******************************************************************************
;[...]
;========================================================================================
;Move the meter using constant values 
;This is the most simplistic way of doing it.
tskMoveMeter:
# 4D_Visi 4D_WriteObj(k4D_Meter, 0, 0)
# 4D_Visi 4D_WriteObj(k4D_Meter, 0, 10)
# 4D_Visi 4D_WriteObj(k4D_Meter, 0, 20)
# 4D_Visi 4D_WriteObj(k4D_Meter, 0, 30)
# 4D_Visi 4D_WriteObj(k4D_Meter, 0, 40)
# 4D_Visi 4D_WriteObj(k4D_Meter, 0, 50)
# 4D_Visi 4D_WriteObj(k4D_Meter, 0, 60)
# 4D_Visi 4D_WriteObj(k4D_Meter, 0, 70)
# 4D_Visi 4D_WriteObj(k4D_Meter, 0, 80)
# 4D_Visi 4D_WriteObj(k4D_Meter, 0, 90)
# 4D_Visi 4D_WriteObj(k4D_Meter, 0, 100)
                GoTo           tskMoveMeter                

;[...]
;=================================================
;Move the thermometer using a byte variable   
bThermometerValue       defBYTE
tskMoveThermometer:
               LoadX           0
MoveThermometer1:
               Store           bThermometerValue
# 4D_Visi 4D_bWriteObj(k4D_Thermometer, 0, bThermometerValue)
               Recall           bThermometerValue
               IncX 
               Push 
               GoIfXgt          100,tskMoveThermometer
               GoTo             MoveThermometer1

;[...]
;=================================================
;Move the gauge using a floating point variable   
fGaugeValue    defFloat
tskMoveGauge: 
               fLoadW          0
MoveGauge1:
               fStore           fGaugeValue
# 4D_Visi 4D_fWriteObj(k4D_Gauge, 0, fGaugeValue)
               fRecallW         fGaugeValue
               fLoadQ           1  
               fAdd
               fLoadQ           100  
               fGoIfWGTQ        tskMoveGauge
               GoTo             MoveGauge1

;[...]
;======================================================================
;Move the CoolGauge using W alone
;(Also shows how newer boards preserve registers across a yield).
tskMoveCoolgauge:
               fLoadW           0
               fLoadQ           99
MoveCoolgauge1:
# 4D_Visi 4D_fWriteObjW(k4D_Coolgauge, 0)
               fInc 
               fGoIfWgtQ        tskMoveCoolgauge
               GoTo             MoveCoolgauge1

;[...]
;=================================================
;Move the Angular meter using X alone
;(Also shows how newer boards preserve registers across a yield).
tskMoveAngularmeter:
               LoadX            0
MoveAngularmeter1:
               Push 
# 4D_Visi 4D_WriteObjX(k4D_Angularmeter, 0)
               IncX 
               Push 
               GoIfXgt          100,tskMoveAngularmeter
               GoTo             MoveAngularmeter1

;[...]
;*****************************************************************
;************* Event handlers for 4D object events *************** 
*               Any data reported by 4D is in W                  *
;*****************************************************************
ev4DMom:        ;The momentary button. Value always 0
# HMI_Trace Text("Momentary button ")   NL()
        Return



;-----------------------------------
ev4DTgl:        ;Toggle button. Data = 1|0 for on/off state
# HMI_Trace Text("Toggle button ")  
                fGoIfNZ         TglOn
# HMI_Trace Text("off")   NL()    
                Return   
TglOn:                
# HMI_Trace Text("on")   NL()    
                Return



;-----------------------------------
evRBtop:        ;Radio button top.    Data = 1  - For a radio group last reported is "it"
                Return
;-----------------------------------
evRBmdl:        ;Radio button Middle. Data = 1
                Return
;-----------------------------------
evRBbtm:        ;Radio button Bottom. Data = 1
                Return



;-----------------------------------
evKnob:         ;Knob. Data reported as 0 - 100
# HMI_Trace Text("Knob:")  fDispW(5, 0) NL()
                Return



;-----------------------------------
evRsw:          ;Rotary switch. Data reported as position 0 through 4   
                Fix                     ;Move the data to X
# HMI_Trace Text("Rotary switch: ")  HexDispX() NL()  ;Just to give HexX() a workout
                Return
;-----------------------------------
evSldr:         ;Slider. Data reported as 0 - 100
                Fix                     ;Move the data to X
# HMI_Trace Text("Slider:")  uDispXVW() NL()  ;Just to give uDispXVW() a workout
        Return



;-----------------------------------
evTrkbr:        ;Trackbar. Data reported as 0 - 100
                Fix                     ;Move the data to X
# HMI_Trace Text("Trackbar:")  uDispXFW() NL()  ;Just to give uDispXFW() a workout
                Return



;-----------------------------------
evDIPsw:        ;Dipswitch. Data = 1|0 for on/off state
                Return
;-----------------------------------
evRkr:          ;Rockerswitch. Data = 1|0 for on/off state
                Return
;-----------------------------------
evKpd:          ;Numeric Keypad. Data = ASCII code
                Return



;-----------------------------------
evQWERTY:       ;QWERTY. Data = ASCII code
                Return



;[...]
;---- Event handler for 4D protocol NACK ---------------- 
;You can fill in your own stuff here.
ev4DNack:
                ON      1    
                Pause   20
                Off     1
                LoadX   T
# HMI_Trace Text("N") 
                Return            
                



;[...]
 ;**********************************************************************************
;        SimpleHMI screen 
;I am using the SimpleHMI client in SPLat/PC to manually control the 4D contrast setting
;Declare event handlers for SimpleHMI
# HMI ConnectEvent(evHMI_Connect)
     
bContrast       defByte



;Event handler for SimpleHMI connect event. Also: Paint the SimpleHMI screen at startup
evHMI_Connect:
# HMI HideAllButtons()  Cls()
# HMI ButtonEvent(, 5, C-15, 3, 10, "Contrast -", R, evContrastDn)   ;The Down button
# HMI ButtonEvent(, 5, C+5, 3, 10, "Contrast +", R, evContrastUp)    ;The Up button
                SetMem          bContrast,10                         ;Initial value
                GoTo            SendContrast2                       



;Handle Contrast+ button 
evContrastUp:
                GoIfMGE         bContrast,15,GenRet    ;Don't let contrast number get > 15
                IncM            bContrast
SendContrast:
                Recall          bContrast
# 4D_Visi 4D_WriteContrastX()  



SendContrast2:
# HMI Cursor(6, C-1)  HexVar(bContrast)                       
GenRet:         Return



;Handle Contrast- button 
evContrastDn:
                RetIfMZ         bContrast       ;r/ can't decrement further
                DecM            bContrast
                GoTo            SendContrast