MMBasic Driver For MCP2515 SPI CAN Adaptor
This driver allows sending and receiving CAN Bus message for MMBasic via SPI using the MCP2515 CAN adaptor.
An old but useful CAN primer
CAN Bus Bit Timing Calculator
Datasheet
The MCP2515 CAN Controller chip on the module can operate from 2.7V to 5.5v but the TJA1050 transceiver is a 5V(4.75-5.25V) device so to use the module with a 3.3v micro you will need to convert to use 3.3v by one of these methods:
* Use a level shifter to interface the SPI and CS pins (The nominal 10MHz SPI speed may need to reduced to 5MHz)
* Replace the TJA1050 transceiver chip on the module with the 3.3V SN65HVD230 transceiver chip, which is proven to be a pin for pin direct replacement and power the module from 3.3V
* Some have hacked the module and supplied it with separate 3.3V and 5V to the respective chips. See here for details.
* The MCP2515 module is available with the SN65HVD230 transceiver chip but these seem to be much more expensive than the modules with the TJA1050 chip.
If you want to just play with the module in loopback mode without connecting to the CAN Bus you could just temporarily power it with 3.3V
Picomites
The I/O pins on the RP2350 (Pico 2) series of microcontrollers can withstand 5V (while powered up) so the module
can be directly connected to the 5V supplied by the VSYS pin on the Raspberry Pi Pico 2.
The RP2040 (Pico) must not be subjected to more than 3.6V so to use this module one of the above methods is required to use it on 3.3V.
'FLATPAC 'target port\com10:38400 le\lf s\micromite+
'------------------------------------------------------------------------------'
' Micromite library for MCP2515 CAN Module '
' '
' '
' '
' Author: Disco4now TBS Forum '
' '
dim ProgTitle$ = "CAN MCP2515 Test Suite -Polling" '
' '
Dim ProgVer$ = "v1.1.0" '
' '
Dim ProgDate$ = "09-Aug-2025" '
'----------------------------------------------------------------------------'
'Code for a MMBasic to communicate with a MCP2515 SPI CAN chip.
'The console input is scanned and characters read as they are typed
' 18/01/2021 SPI set to 10K with 3.3v chip
' 19/06/2024 Added values for Emerson R48-2900U and more development.
' 22/07/2024 Filters now working. poll for messages in lieu of interrupts
' 09/08/2025 Updated for Picomites Tidy up as a driver for MCP2525
' 19/08/2025 Added RxBuffer and cleanup iof many things.
'===============================================================================
' Option settings
'===============================================================================
option explicit
option default NONE
OPTION BASE 0
'OPTION AUTORUN ON
'===============================================================================
' MCP2515 SPI Routines
'===============================================================================
'Code for MMBASIC to communicate with a MCP2515 over SPI
'Original Author:
'Ported to MMBasic by Disco4now!, TBS forums
'*******************************************************************************
'===============================================================================
'Initialisation scanning of Console and serial ports if required (SETTICK)
'===============================================================================
Dim integer loc0last,loc0now,loc1last,loc1now,loc2last,loc2now,GetCon=0
settick 100,IsSerialOrConsoleComplete,1
'settick 300,IsSerialOrConsoleComplete,1 'need longer for VT100 ESC sequences
'===============================================================================
' CAN Module Variables
'===============================================================================
'There are 2 receive mask registers and 6 filter registers on the controller
'chip that guarantee you get data from the target device. They are useful,
'especially in a large network consisting of numerous nodes.
'=============================================================================
' Program Initialization and variables
'=============================================================================
dim integer sendlogin=0 , tempin=0,tempout=0,vin=0,request_warnings=0
DIM INTEGER request_errors=0,walkfast=0
dim integer sendconfig=0
dim float reqvoltage100x=4800,reqcurrent10x=200,adjvoltage=0
dim float vout=100,iout=100
Print "Starting " + ProgTitle$ + ": " + ProgVer$ + " - " + ProgDate$
'=============================================================================
' Configure platform specific variables
'=============================================================================
DIM integer doubleprecision
if (MM.DEVICE$="Micromite MkII" OR MM.DEVICE$="Micromite Plus") THEN
doubleprecision=0
else
doubleprecision=1
ENDIF
'===============================================================================
' Setup SPI and MCP2515 CS Pin
'===============================================================================
'THE MCP2515 module needs to be mofified for 3,3V
DIM INTEGER CAN_CS ,SPI_NUMBER
' Set the CAN CS pin The SPI Pins and The SPI_NUMBER
'Set SPI_NUMBER
SPI_NUMBER=2
'Set CS Pin for MCP2515 module
CAN_CS=MM.INFO(PINNO GP22) 'MCP2515 chip select GP22
PIN(CAN_CS)=1
SETPIN CAN_CS,DOUT ' set as DOUT
' Set the SPI Pins
'SETPIN rx, tx, clk, SPI2
IF SPI_NUMBER=1 THEN
SETPIN GPrx, GPtx, GPclk, SPI
ELSE
SETPIN GP28, GP27, GP26, SPI2
END IF
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'===============================================================================
' --- Global Variables used by the Driver----
' These should not be manipulated directly.
' They as set by the high level functions
'===============================================================================
DIM INTEGER NOFILTERS = 0 'Accept Filters Status
DIM INTEGER HASROLLOVER = 0 'Rollover Status
DIM INTEGER CANMODE=0 'CAN Mode
DIM INTEGER EchoAllMsg=0 '
DIM integer rts(2)=(&H81,&H82,&H84),tbn=0
dim integer values(14),req(3),sets(7)
DIM INTEGER id,eid,rtr,dlc,msg,fmi,ret
'==============================================================================
' Configure SPIOpen ans SPIClose SUBs to the desired SPI
' and settings for the specific MMBASIC platform.
'==============================================================================
dim integer SPISPEED=10000000 'SPI 10MHz
'Open the SPI
IF SPI_NUMBER=1 THEN
SPI1 OPEN SPISPEED,0,8
ELSE
SPI2 OPEN SPISPEED,0,8
END IF
SUB SPIOpen
PIN(CAN_CS)=0
END SUB
SUB SPIClose
PIN(CAN_CS)=1
END SUB
'===============================================================================
' Setup MMBasic FIFO Transmit and Receive Buffers
'===============================================================================
'MCP2515 Hardware has only 3 TxBuffers. We can use a queue inside MMBasic to
'ensure we can control the transmissions so as not to overflow the CAN module.
'TxFifoSize sets the size of the buffer. Set to 0 to disable use of the buffer.
DIM INTEGER TxFifoSize=30 'Number of elements in the FiFo Buffer
'MCP2515 Harware has two FIFO Mailboxes. We can use a queue inside MMBasic to
'ensure these are read immediately so thet don't overflow, and process the
'messages from the internal queue.
'RxFifoSize sets the size of the buffer. Set to 0 to disable use of the buffer.
DIM INTEGER RxFifoSize=30 'Number of elements in the FiFo Buffer
'The TX and Rx Buffers are serviced alternately in the main DO:LOOP. The
'Buffer Service Threshold is used to regulate the frequency at which they are
'serviced. BSThreshold is set to 20 by default. i.e. service once every 20 loops.
DIM INTEGER BSThreshold=20
' Supporting variables.
DIM INTEGER BSCount,BSToggle
DIM INTEGER TXBuffer(TxFifoSize+1,1)'Buffer is 128 bits wide (2 integers)
DIM INTEGER TxFifoStart,TxFifoEnd
DIM INTEGER RXBuffer(RxFifoSize+1,1)'Buffer is 128 bits wide (2 integers )
DIM INTEGER RxFifoStart,RxFifoEnd
'===============================================================================
' Initialse and start the MCP2515 CAN Module
'===============================================================================
CONST Normal=0,Loopback=1 ,EchoAll=2
CONST Acceptall=1,UseFilters=0
CONST UseRollover=1,NoRollOver=0
can_init(LoopBack ,125000,UseFilters,UseRollover) 'initialise module
'can_init(LoopBack ,125000,Acceptall,UseRollover) 'initialise module
can_SetFilters
can_Start
'==========================================================================
' Setup the Console
'==========================================================================
OPTION DISPLAY 50,81
vtClr 'clear screen
vtBox(1,1,80,12,1) 'draw a box in "Terminal" font box chars
PRINT At(4,3)+vt100.colour$("RED")+"F8 - Send 1"+vt100.colour$("reset");
PRINT At(5,3)+vt100.colour$("RED")+"F9 read 1 RBX0"+vt100.colour$("reset");
PRINT At(6,3)+vt100.colour$("RED")+"F10 read 1 RBX1"+vt100.colour$("reset");
vtWindow 15,19 ' define window
showheader
vtWindow 19,40 ' define window
'===========================================================================
'print hex$(mcp_readReg(&H0F),2)
'print "initialised"
'===============================================================================
' CAN High Level Functional Routines
'===============================================================================
SUB can_init(cmode as integer,canspeed as integer,filters as integer,rollover as integer)
'SUB mcp_init(mode as integer,CANSPEED as integer,filters as integer,ROLLOVER as integer)
can_reset() ' after reset its in config mode
'set bus speed
If CANSPEED =125000 THEN
mcp_setReg(&H2A, &H01) 'MCP_CNF1 0x01, 0xb1, 0x05
mcp_setReg(&H29, &Hb1) 'MCP_CNF2
mcp_setReg(&H28, &H05) 'MCP_CNF3
else If CANSPEED =250000 THEN
mcp_setReg(&H2A, &H00) 'MCP_CNF1 0x00, 0xb1, 0x05
mcp_setReg(&H29, &Hb1) 'MCP_CNF2
mcp_setReg(&H28, &H05) 'MCP_CNF3
else If CANSPEED =500000 THEN
mcp_setReg(&H2A, &H00) 'MCP_CNF1 0x00, 0x90, 0x02
mcp_setReg(&H29, &H90) 'MCP_CNF2
mcp_setReg(&H28, &H02) 'MCP_CNF3
else If CANSPEED =100000 THEN
mcp_setReg(&H2A, &H00) 'MCP_CNF1 0x00, 0x80, 0x00
mcp_setReg(&H29, &H80) 'MCP_CNF2
mcp_setReg(&H28, &H00) 'MCP_CNF3
else
PRINT "Error: Invalid canspeed. Valid are 125000,50000,100000 "
END
ENDIF
CANMODE=cmode
NoFilters=filters
HasRollover=rollover
'**** If CANMODE=2 the all received messages will be sent back***********
If CANMODE=2 then
EchoAllMsg = 1 'echo all received messages
else
EchoAllMsg = 0
endif
'Initiate the 3 TxBuffers and two RxBuffers.
initBuffers()
'****** Set Interrupt mode if using interrupts.**********
' DONT USE - WE ARE POLLING
' mcp_setReg(&H2B, &H03) 'MCP_CANINTE=&H2B
' ***** setRecBufferCTRLS commands ******************
'setRecBufferCTRLS(IgnoreFilters,rollover )
' Use filters on both receive-buffers to receive accept on only messages passing
' the mask and filter conditions. Dont allow Remote Frames.
'setRecBufferCTRLS(0,0,1,0)'
' If ECHO mode then don't use filters.
if EchoAllMsg=0 THEN
setRecBufferCTRLS(NoFilters,HasRollover)
else
' Override any setting and accept all messages
' with rollover from RBX0 to RBX1
setRecBufferCTRLS(AcceptAll,UseRollover)
endif
END SUB
' ===== Setup the acceptance masks for RBX0 and RBx1 as required ============
' These determine which messages are forward to the Acceptance Filters
' The message is rejected if it does not pass one of the Accptance Masks
' If eid=0 then datamask can be used to filter on Byte(0)+Byte(1) of the data.
' ============================================================================
SUB can_SetFilters
IF NOFILTERS then exit SUB
' setAcceptMask(rbxno,eid ,idmask,datamask )
setAcceptMask(0, 1,&H1FFFFFFF,&H0) 'Uncomment to forward all STDIDs
'setAcceptMask(1, 1,&H1FFFFFFF,&H0) 'Uncomment to forward all EXTIDs
setAcceptMask(0, 1,&H1FFFFFFF,&H0) 'Uncomment to forward all EXTIDs
'--Some examples --------
'setAcceptMask(0, 1,&H2222222,0); 'Forwards ID &H2222222
'setFilterMask(1, 0, &H7FF,&HAA55) 'Forwards all STDIDs matchhing mask AA55
' ===== Setup acceptance Filters for RBX0 and RBX1 as required ==============
' If ROLLOVER is enabled then RFX6 and RFX7 indicate a message originally
' destined for RFX0 or RFX1 but been redirected to because RBX0 or RBX1 contains
' a message that has not been read yet. If ROLLOVER is nor enabled the messages
' are discarded.
setFilter(0, 1, &H0123456,0) 'RFX0 RFX6
setFilter(1, 1, &H0123457,0) 'RFX1 RFX7
setFilter(2, 0, &H7FF,0) 'RFX2
setFilter(3, 1, &H5555555,&H0) 'RFX3
setFilter(4, 1, &H2222222,&H0) 'RFX4
setFilter(5, 0, &H7FF,&H0) 'RBX5
showFilters()
END SUB
SUB can_Start
'Set mode MCP2515 mode ..Select one of .. NORMAL or LOOPBACK
'mcp_modReg(&H0F,&HE0,MCP_MODE_NORMAL) 'Normal mode - oneshot is disabled.
'mcp_modReg(&H0F,&HE0,MCP_MODE_LOOPBACK) 'loopback mode - oneshot is disabled.
IF CANMODE=1 then
mcp_modReg(&H0F,&HE0,&H40)'loopback mode - oneshot is disabled.
else
mcp_modReg(&H0F,&HE0,&H0) 'Normal mode - oneshot is disabled.
END IF
pause 20
end sub
Sub SHOWHEADER
PRINT "R ID E R D --------DATA--------- Filter Match Index "
PRINT "X ID I T L --------DATA--------- Filter Match Index "
PRINT "B ID D R C --------DATA--------- Filter Match Index "
PRINT "- -------- - - - ---------------------- -------------------"
end sub
'===========================================================================
' ********************* Main program loop ***********************************
'===========================================================================
timer=0
do
'Watchdog 40000 'reset after 40 secs on hang
'==========================Check Console and Serial Ports===============
IF GetCon=1 then
ReadConsole 'If data in console1 then GOSUB GetConsole
END IF
'========== Alternately Process Tx and Rx Queues ==========================
BSCount=BSCount+1
IF BSCount=BSThreshold Then
BSCount=0
if BSToggle=0 Then
if TxFifoSize > 0 THEN sendSingleMessage 'from the TxBuffer
BSToggle=1
ELSE
if RxFifoSize > 0 THEN actionSingleMessage(-1) 'from the RxBuffer
BSToggle=0
END IF
ENDIF
'======================Poll for Messages =========================
if RxFifoSize = 0 THEN
'method 1 Read one message from each RX Fifo and action immediately
CAN_READ 0
If ret>0 Then actionSingleMessage(0)
CAN_READ 1
If ret>0 THEN actionSingleMessage(1)
else
'Method 2 Read all messages in each RX Fifo and add to queue
'Read Fifo0
DO
CAN_READ 0
If ret>0 Then addRxMessage(0)
LOOP UNTIL ret=0
'Read Fifo1
DO
CAN_READ 1
If ret>0 THEN addRxMessage(1)
LOOP UNTIL ret=0
END IF
'===============NOT USED WE ARE POLLING ===Check MCP Interrupts==========
'if (pin(CANINT1)=0) THEN
'intno=mcp_readReg(&H0E)
'intno=(intno AND &H0E)>>1
''PRINT intno
'select case intno
'case 7 'message in RX1
'mcp_readRegs(&H70,values() ,14)
'actionmsg 1
'mcp_modReg(&H2c,&H02,&H00) 'clear CANINTF B(1)
'case 6 'message in RX0
''mcp_readRxBuff(&H90,values(),13)
'mcp_readRegs(&H60,values() ,14)
'actionmsg 0
'mcp_modReg(&H2c,&H01,&H00) 'clear CANINTF B(0)
'case 5
'Print "TX2"
'mcp_modReg(&H2c,&H10,&H00) 'clear CANINTF B(4)
'case 4
'Print "TX1"
'mcp_modReg(&H2c,&H08,&H00) 'clear CANINTF B(3)
'case 3
'Print "TX0"
'mcp_modReg(&H2c,&H04,&H00) 'clear CANINTF B(2)
'case 2
'PRINT "WAKI"
'mcp_modReg(&H2c,&H40,&H00) 'clear CANINTF B(6)
'case 1
'PRINT "ERRI"
'mcp_modReg(&H2c,&H20,&H00) 'clear CANINTF B(5)
'case else
'' PRINT "NO INTS !!!!!!!!!!"
'end select
'endif
'=====================Action any Application Requests=====================
Loop
'=========================================================================
' ****************** -- END of Main program loop-- **********************
'==========================================================================
'===============================================================================
' CAN High Level Functional Routines actionmsg,
'===============================================================================
SUB CAN_READ rxno as integer
'Global variables are:id,eid,rtr%dlc,msg,fmi,ret
if rxno=0 then
if mcp_readReg(&H2c) AND &H01 then 'test CANINTF B(0)
mcp_readRegs(&H60,values() ,14) 'read the values from the can
fmi=mcp_readReg(&H60) AND &H07 'read Filter match Index
LoadValues
mcp_modReg(&H2c,&H01,&H00) 'clear CANINTF B(0)
ret=1
else
ret=0
EXIT SUB
end if
else 'rxno=1
if mcp_readReg(&H2c) AND &H02 then 'test CANINTF B(1)
mcp_readRegs(&H70,values() ,14) 'read the values from the can
fmi=mcp_readReg(&H70) AND &H07 'read Filter match Index
LoadValues
mcp_modReg(&H2c,&H02,&H00) 'clear CANINTF B(1)
ret=1
else
ret=0
EXIT SUB
end if
endif
end sub
SUB LoadValues
'Load the register data in to our global variables
eid=(values(2)>>3) and &H1
rtr=(values(5)>>6) and &H1
dlc= values(5) AND &H0F
if eid=1 then
id=(values(1)<<21) OR ((values(2) AND &HE0)<<13)
id=id OR ((values(2) AND &H03)<<16) or (values(3)<<8) or values(4)
else
id =(values(1)<<3) or ((values(2)>>5) AND &H07)
end if
msg=&H0
if rtr=0 then
if dlc > 0 then msg=((values(6) AND &HFF)<<56)
if dlc > 1 then msg=msg OR ((values(7) AND &HFF)<<48)
if dlc > 2 then msg=msg OR ((values(8) AND &HFF)<<40)
if dlc > 3 then msg=msg OR ((values(9) AND &HFF)<<32)
if dlc > 4 then msg=msg OR ((values(10) AND &HFF)<<24)
if dlc > 5 then msg=msg OR ((values(11) AND &HFF)<<16)
if dlc > 6 then msg=msg OR ((values(12) AND &HFF)<<8)
if dlc > 7 then msg=msg OR ((values(13) AND &HFF))
endif
end sub
' Process and action a received CAN message.
' This routine can be called directly when the message is read
' or later to proccess a message from the MMBasic RXBuffer
' if one is being used.
SUB ActionSingleMessage(rxno as integer)
Local INTEGER fminitial(7)=(0,1,2,3,4,5,0,1)
Local INTEGER fmoverflow(7)=(6,7,2,3,4,5,0,1)
Local amsg$
'If we are using an RxBuffer then get the values
IF RxFifoSize>0 and rxno<0 then
IF RxFifoEnd<>RxFifoStart Then
RxFifoStart=RxFifoStart + 1:If RxFifoStart=RxFifoSize then RxFifoStart=0
msg=RXBuffer(RxFifoStart,1)
id=RXBuffer(RxFifoStart,0) AND &H1FFFFFFF
eid=RXBuffer(RxFifoStart,0)>>63 AND &H1
rtr=RXBuffer(RxFifoStart,0)>>62 AND &H1
rxno=RXBuffer(RxFifoStart,0)>>61 AND &H1
dlc=RxBuffer(RxFifoStart,0)>>57 AND &H0F
ret=RXBuffer(RxFifoStart,0)>>53 AND &H3 'number in queue
else
exit sub
endif
endif
'Resolve the matched filter
if NOFILTERS then
fmi=-1
ELSE
if HASROLLOVER and rxno=1 then
fmi=fmoverflow(fmi)
else
fmi=fminitial(fmi)
endif
ENDIF
'Process the id and msg contents
select case id
CASE &H05014400 'Login request
print "login request Eltek"
'login(0)= values(6)
'login(1)= values(7)
'login(2)= values(8)
'login(3)= values(9)
'login(4)= values(10)
'login(5)= values(11)
'sendlogin=1
'EVERY 100,LoginRefresh '(multiples of 100ms) refresh the login each 10Secs
CASE &H05001972 'alt login
'sendlogin=1 'Now done with timer above
CASE &H05014004 'status update normal
ShowStatus 0
CASE &H05014008 'status update with warning
ShowStatus 1
CASE &H0501400C 'status update with error
ShowStatus 2
CASE &H05014010 'status update with walkin
ShowStatus 3
'EMERSON R48-2900U Replrties
CASE &H5555555
amsg$= "Got Voltage="+ str$(BIN32ToFloat((msg AND &HFFFFFFFF00000000)>>32))
amsg$=amsg$+ " Got Current="+str$(BIN32ToFloat((msg AND &HFFFFFFFF) ))
LogAction(amsg$)
CASE ELSE
'PRINT
end select
Print STR$(rxno)+" "+SPACE$(5-eid*5)+HEX$(id,3+eid*5)+" "+HEX$(eid)+" ";
PRINT HEX$(rtr)+" "+HEX$(dlc)+" ";
PRINT FMT$(HEX$(msg,16));
if NOFILTERS then
PRINT " No filters - Accept All"
ELSE
if rxno=0 then print " (RBX0) RFX"+STR$(fmi)
if rxno=1 then print " (RBX1) RFX"+STR$(fmi)
ENDIF
If EchoAllMsg THEN
addTxMessage( id,eid,rtr,dlc,msg)
END IF
END SUB
SUB addRxMessage(rxno as integer)
Local INTEGER i
if RxFifoSize>0 then
RxFifoEnd=RxFifoEnd + 1 : If RxFifoEnd=RxFifoSize then RxFifoEnd=0
i=id OR (eid<<63)OR(rtr<<62)OR(rxno<<61)or((dlc AND &H0F)<<57)OR(ret aND &H0F<<53)
RXBuffer(RxFifoEnd,0)=i
RXBuffer(RxFifoEnd,1)=msg
else
Print "addRxMessage() called but RxFifoSize is 0"
END
END IF
end sub
'Add a message to the TXFifo if it is used, else send directly
SUB addTxMessage(id as Integer,eid as integer,rtr as integer,dlc as integer,msg as integer)
if TxFifoSize>0 then
TxFifoEnd=TxFifoEnd + 1 : If TxFifoEnd=TxFifoSize then TxFifoEnd=0
TXBuffer(TxFifoEnd,0)=id OR (eid << 63)OR(rtr << 62)or((dlc AND &H0F) << 55)
TXBuffer(TxFifoEnd,1)=msg
else
CAN_SEND id,eid,rtr,dlc,msg
end if
end sub
SUB sendSingleMessage()
IF TxFifoEnd<>TxFifoStart Then
TxFifoStart=TxFifoStart + 1:If TxFifoStart=TxFifoSize then TxFifoStart=0
msg=TXBuffer(TxFifoStart,1)
id=TXBuffer(TxFifoStart,0) AND &H1FFFFFFF
eid=TXBuffer(TxFifoStart,0)>>63 AND &H1
rtr=TXBuffer(TxFifoStart,0)>>62 AND &H1
dlc=TXBuffer(TxFifoStart,0)>>55 AND &H0F
CAN_SEND id,eid,rtr,dlc,msg
endif
end sub
SUB CAN_SEND(id as integer,eid as integer,rtr as integer,dlc as integer,msg as integer)
local integer sidh,ctl,buff(15),canid,i
sidh=&H31+16*tbn 'get the SIDH buffer address ie. 31,41,51 for buffers 0,1,2
ctl=&H30+16*tbn 'get the CTL register address ie. 30,40,50 for buffers 0,1,2
'prepare 14 bytes to load to tx buffers
buff(0)=&H02 'the write command
buff(1)=ctl 'the start register
buff(2)=0 'just set the priorit bit 0:1)
' 3=SIDH, 4=SIDL , 5=EID8,6=EID0
if (eid = 1) then
canid = id AND &H1FFFFFFF
buff(6) = canid AND &HFF
buff(5) = canid >> 8 and &HFF
canid = id >> 16
buff(4) = (canid AND 3) or ((canid AND &H1c)<<3)
buff(4)=buff(4) OR 8 'set the EXIDE bit
buff(3) = canid >> 5 AND &HFF
else
canid = id AND &H7FF
buff(3)=canid >> 3
buff(4)=((canid AND &H07) << 5)
buff(5)=0
buff(6)=0
endif
if rtr then
buff(7)=((rtr<<6) AND &H40) '-- RTR -- -- DLC3 DLC2 DLC1 DLC0
else
buff(7)=(dlc AND &H0F) '-- RTR -- -- DLC3 DLC2 DLC1 DLC0
endif
'load data
if rtr=0 then
for i = 0 to dlc-1
buff(8+i)=msg >> (56-i*8) AND &HFF
next i
endif
'Use the 3 TxBuffers in rotation
mcp_setRegs(8+i,buff()) 'load the Txmailbox
mcp_send(tbn) 'send on next Txmailbox
tbn=tbn+1:if tbn=3 then tbn=0 'advance Txmailbox pointer
end sub
Function FMT$(a$) As string
local b$
b$= " "+Mid$(a$,1,2)+" "+Mid$(a$,3,2)+" "+Mid$(a$,5,2)+" "+Mid$(a$,7,2)
FMT$=b$+" "+Mid$(a$,9,2)+" "+Mid$(a$,11,2)+" "+Mid$(a$,13,2)+" "+Mid$(a$,15,2)
End Function
SUB initBuffers()
Local integer i
for i=0 to 13
mcp_setReg(&H30+i,0) 'TXB0CTRL=&H30
mcp_setReg(&H40+i,0) 'TXB1CTRL=&H40
mcp_setReg(&H50+i,0) 'TXB2CTRL=&H50
next i
mcp_setReg(&H60,0) 'RXB0CTRL=&H60
mcp_setReg(&H70,0) 'RXB1CTRL=&H70
END SUB
'Reg 60 RXB0CTRL[6:5]=11 to bypass filter and accept all messages , 00 to enabled filters
'Reg 60 RXB0CTRL[2]=1 to enable rollover to RBX1 if RBX0 is full
'Reg70 RXB1CTRL[6:5]=11 to bypass filter and accept all messages , 00 to enabled filters
'mcp_setFilterCTRLS(0,0,1,0)
SUB setRecBufferCTRLS(IgnoreFilters AS INTEGER,rollover AS INTEGER)
local ctr1%=((IgnoreFilters AND &H1) << 6)OR((IgnoreFilters AND &H1)<< 5)OR((rollover AND &H1) << 2)
local ctr2%=((IgnoreFilters AND &H1) << 6)OR((IgnoreFilters AND &H1)<< 5)
mcp_modReg(&H60,&H64,ctr1%)
mcp_modReg(&H70,&H60,ctr2%)
END SUB
'Regs 20-23 Filter 5 Mask (used for RBX0) STANDARD/EXTENDED
'Regs 24-27 Filter 5 Mask (used for RBX1) STANDARD/EXTENDED
'RBxno is the recieve buffer 0 or 1
'eid is 0 for STANDARD 11 bit IDs , 1 for EXTENDED 29 bit IDs
'id is the id 0-&H7FF for STDIDs , 0-&H1FFFFFFF for EXTIDs
'data01 allows filtering on the first 16 bits of data for STANDARD frames. This is added to the filter.
' is ignored for extended frames so set t0 0
'mcp_setAcceptMask(0, 1, 0x1FFFFFFF,0); Go to regsreg 20-23
SUB setAcceptMask(rbxno as integer,eid as integer,id as integer,data01 as integer)
LOCAL INTEGER buff(10) ,startreg
if RBxno=0 Then startreg=&H20
if RBxno=1 Then startreg=&H24
buff(0)=&H02 'the write command
buff(1)=startreg 'the start register
'Ext id is B28 B27--------B24 B23------B16 B15-----B8 B7-----B0
'Std id B18B17B16 B15-----B8 B7-----B0
if (eid=1) then
if (id >> 29)<>0 THEN PRINT "Error: ID > &H1FFFFFFF when setting filterMask "+str$(RBxno):END
buff(2)=(id >> 21 and &HFF )
buff(3)=((id >> 13 and &HE0 ) OR (id >> 16 AND &H03) )
buff(4)=((id >> 8)and &HFF)
buff(5)=(id and &HFF)
else
if (id >> 11)<>0 THEN PRINT "Error: ID > &H7FF when setting filterMask "+Str$(RBxno):END
buff(2)=((id >> 3 and &HFF ))
buff(3)=(((id AND &H07) << 5) and &HFF )
buff(4)=(data01 >> 8 and &HFF) 'data0 filter for std
buff(5)=(data01 and &HFF) 'data1 filter for std
endif
mcp_setRegs(6,buff())
END SUB
'Set filter mask for RXB0 or RXB1
'Regs 00-03 Filter 0 Mask (used for RBX0) STANDARD/EXTENDED
'Regs 04-07 Filter 1 Mask (used for RBX0) STANDARD/EXTENDED
'Regs 08-0B Filter 2 Mask (used for RBX1) STANDARD/EXTENDED
'Regs 10-13 Filter 3 Mask (used for RBX1) STANDARD/EXTENDED
'Regs 13-17 Filter 4 Mask (used for RBX1) STANDARD/EXTENDED
'Regs 18-1B Filter 5 Mask (used for RBX1) STANDARD/EXTENDED
' STD fills 2 registers, Extend fills 4 registers.
'mcp_setFilter(3,1,&H1A1010B1) go to reg 10-13
SUB setFilter(filterno as integer,eid as integer,id as integer,data01 as integer)
LOCAL INTEGER buff(10) ,startreg
if filterno=0 Then startreg=&H00
if filterno=1 Then startreg=&H04
if filterno=2 Then startreg=&H08
if filterno=3 Then startreg=&H10
if filterno=4 Then startreg=&H14
if filterno=5 Then startreg=&H18
buff(0)=&H02 'the write command
buff(1)=startreg 'the start register
if (eid=1) then
if (id >> 29)<>0 THEN PRINT "Error: ID > &H1FFFFFFF when setting filter "+str$(filterno):END
buff(5)=(id and &HFF)
buff(4)=((id >> 8) and &HFF )
buff(3)=((id >> 13 and &HE0 ) OR (id >> 16 AND &H03) or (1 << 3) )
buff(2)=((id >> 21) and &HFF )
else
if (id >> 11)<>0 THEN PRINT "Error: ID > &H7FF when setting filter "+str$(filterno):END
buff(2)=((id >> 3 and &HFF ))
buff(3)=(((id AND &H07) << 5) and &HFF )
buff(4)=(data01 >> 8 and &HFF) 'data0 filter for std
buff(5)=(data01 and &HFF) 'data1 filter for std
endif
mcp_setRegs(6,buff())
END SUB
function getmode() as integer
getmode=mcp_readReg(&H0E)'&& &HE0)
end function
'Print out the filter and mask configurations
SUB showFilters()
LOCAL integer id1,id2
LOCAL INTEGER mask(3)
LOCAL INTEGER rid
id1=mcp_readReg(&H60)
id2=mcp_readReg(&H70)
PRINT " *********** FILTER and MASK Summary **************"
PRINT "RBX0 Overflows to RBX1 :";
if (id1 AND &H04) THEN Print "YES" ELSE PRINT "NO"
PRINT "RBX0 Uses Mask and Filters :";
if (id1 AND &H60) THEN Print "NO" ELSE PRINT "YES"
PRINT "RBX1 Uses Mask and Filters :";
if (id2 AND &H60) THEN Print "NO" ELSE PRINT "YES"
mcp_readRegs(&H20,mask(),4)
Print "----------------------------"
? HEX$(rid,8)
print "RBX0 Mask -->"+HEX$(mask(0),2)+" "+HEX$(mask(1),2)+" "+HEX$(mask(2),2)+" "+HEX$(mask(3),2)
mcp_readRegs(&H24,mask(),4)
print "RBX1 Mask -->"+HEX$(mask(0),2)+" "+HEX$(mask(1),2)+" "+HEX$(mask(2),2)+" "+HEX$(mask(3),2)
Print "---------------------------"
mcp_readRegs(&H00,mask(),4)
print "RBX0 Flter 0-->"+BIN$(mask(0),8)+" "+BIN$(mask(1),8)+" "+BIN$(mask(2),8)+" "+BIN$(mask(3),8)
mcp_readRegs(&H04,mask(),4)
print "RBX0 Flter 1-->"+BIN$(mask(0),8)+" "+BIN$(mask(1),8)+" "+BIN$(mask(2),8)+" "+BIN$(mask(3),8)
mcp_readRegs(&H08,mask(),4)
print "RBX1 Flter 2-->"+BIN$(mask(0),8)+" "+BIN$(mask(1),8)+" "+BIN$(mask(2),8)+" "+BIN$(mask(3),8)
mcp_readRegs(&H10,mask(),4)
print "RBX1 Flter 3-->"+BIN$(mask(0),8)+" "+BIN$(mask(1),8)+" "+BIN$(mask(2),8)+" "+BIN$(mask(3),8)
'print "RBX1 Filter -->"+HEX$(mask(0),2)+" "+HEX$(mask(1),2)+" "+HEX$(mask(2),2)+" "+HEX$(mask(3),2)
mcp_readRegs(&H14,mask(),4)
print "RBX1 Flter 4-->"+BIN$(mask(0),8)+" "+BIN$(mask(1),8)+" "+BIN$(mask(2),8)+" "+BIN$(mask(3),8)
mcp_readRegs(&H18,mask(),4)
print "RBX1 Flter 5-->"+BIN$(mask(0),8)+" "+BIN$(mask(1),8)+" "+BIN$(mask(2),8)+" "+BIN$(mask(3),8)
PRINT " *********** -------------- **************"
END SUB
'===============================================================================
' Low Level Register Read and Write via SPI to MCP2515 Module
'===============================================================================
SUB mcp_setReg(reg as integer,dat as integer)
SPIOPEN 'speed,0,8
IF SPI_NUMBER=1 THEN
SPI WRITE 3,&H02,reg,dat
ELSE
SPI2 WRITE 3,&H02,reg,dat
END IF
SPICLOSE
end sub
SUB mcp_setRegs(n as integer,dat() as integer)
SPIOPEN 'speed,0,8
IF SPI_NUMBER=1 THEN SPI WRITE n,dat() ELSE SPI2 WRITE n,dat()
SPICLOSE
end sub
SUB mcp_modReg(reg as integer,mask as integer,dat as integer)
SPIOPEN 'speed,0,8
IF SPI_NUMBER=1 THEN
SPI WRITE 4,&H05,reg,mask,dat 'MCP_BITMOD=&H05
else
SPI2 WRITE 4,&H05,reg,mask,dat
ENDIF
SPICLOSE
end sub
FUNCTION mcp_readReg(reg as integer) as integer
SPIOPEN 'speed,0,8
IF SPI_NUMBER=1 THEN
SPI WRITE 2,&H03,reg
mcp_readReg=SPI(0)
else
SPI2 WRITE 2,&H03,reg
mcp_readReg=SPI2(0)
endif
SPICLOSE
END FUNCTION
FUNCTION mcp_readStatus() as integer
SPIOPEN 'speed,0,8
IF SPI_NUMBER=1 THEN
SPI WRITE 1,&HA0
mcp_readStatus=SPI(0)
else
SPI2 WRITE 1,&HA0
mcp_readStatus=SPI2(0)
end if
SPICLOSE
END FUNCTION
FUNCTION mcp_readStatusRX() as integer
SPIOPEN 'speed,0,8
IF SPI_NUMBER=1 THEN
SPI WRITE 1,&HB0
mcp_readStatusRX=SPI(0)
else
SPI2 WRITE 1,&HB0
mcp_readStatusRX=SPI2(0)
end if
SPICLOSE
END FUNCTION
SUB mcp_readRegs(reg as integer,values() as INTEGER,n as integer)
SPIOPEN 'speed,0,8
IF SPI_NUMBER=1 THEN
SPI WRITE 2,&H03,reg
SPI READ n,values()
else
SPI2 WRITE 2,&H03,reg
SPI2 READ n,values()
end if
SPICLOSE
END SUB
SUB mcp_readRxBuff(reg as integer,values() as INTEGER,n as integer)
SPIOPEN 'speed,0,8
IF SPI_NUMBER=1 THEN
SPI WRITE 2,&H03,reg
SPI READ n,values()
else
SPI2 WRITE 2,&H03,reg
SPI2 READ n,values()
END IF
SPICLOSE
END SUB
SUB mcp_send(n as integer)
'Set Request to Send for desired TX Buffer
SPIOPEN 'speed,0,8
IF SPI_NUMBER=1 THEN SPI WRITE 1,rts(n) else SPI2 WRITE 1,rts(n)
'ret=SPI(&HC0)
SPICLOSE
end SUB
SUB can_reset()
'open the SPI at 10KHz
SPIOPEN 'speed,0,8
IF SPI_NUMBER=1 THEN SPI WRITE 1,&HC0 ELSE SPI2 WRITE 1,&HC0
SPICLOSE
end SUB
'===============================================================================
' Utility functions to convert between Float and and binary BIN32
'===============================================================================
'---------------------------------------------------------------------------------
'This function takes a float (single or double precision depending on the platform)
'and returns an integer where the last 32 bits contain binary formatted as for a
'32 bit float.(This could then be sent to a device that expects single precision).
'---------------------------------------------------------------------------------
Function FloatToBIN32(i As FLOAT) As INTEGER
local INTEGER w%,c%,d%,e%,o%
Local INTEGER j
if doubleprecision=0 then
FloatToBIN32=Peek(INTEGER Peek(VARADDR i))
else
if i<>0 then
Poke FLOAT Peek(varaddr w%),i 'store the 64 bits double precision HEX of the floating point to w%
c%=(w% And &H8000000000000000)>>32 'get the sign bit back to Bit32
d%=(w% And &hFFFFFE0000000)>>29 'get the shortened mantissa and move to new position
e%=(((w% And &H7FF0000000000000)>>52)+127-1023)<<23 'get the exponent and convert
o%=(c% Or d% Or e%)
Poke integer Peek(varaddr j),o% 'put the answer into the integer
else
j=0
endif
FloatToBIN32=j
endif
End Function
'---------------------------------------------------------------------------------
'This function takes an integer where the last 32 bits contain binary formatted as
'for a 32 bit float.(This could be from a device that works in single precision).
'It returns a float (single or double precision to match the current platform)
'---------------------------------------------------------------------------------
Function BIN32ToFloat(i As INTEGER) As FLOAT
Local float j
local INTEGER w%,c%,d%,e%,o%
if doubleprecision=0 then
Poke INTEGER Peek(VARADDR j),i
BIN32ToFloat=j
else
Poke word Peek(varaddr w%),i 'store the single precision HEX of the floating point
if (w% XOR &H0000000000000000) then
c%=(w% And &H80000000)<<32 'get the sign bit
d%=(w% And &h7FFFFF)<<29 'get the mantissa
e%=(((w% And &H7f800000)>>23)-127+1023)<<52 'get the exponent and convert
o%=(c% Or d% Or e%)
Poke integer Peek(varaddr j),o% 'put the answer into a double
else
j=0
endif
BIN32ToFloat=j
ENDIF
End Function
'=============================================================================
' Procedures providing program functionality components
'=============================================================================
'Checks console and serial ports for data and sets flag if data has stopped coming in.
'flag triggers read of the data in the main program loop
sub IsSerialOrConsoleComplete
'Check console and set flag if data exists and has stopped coming in
loc0now=LOC(#0)
IF Loc0now>0 then
IF loc0now=loc0last THEN 'data finished
GetCon=1 'If data in CON then set GetConsole flag
else
loc0last=loc0now
ENDIF
END IF
end sub
'Reads data from the console
SUB ReadConsole
local char$
LOCAL INTEGER msg%
LOCAL INTEGER i,j,k,ret,ret1,ret2,ret3,ok=0
STATIC INTEGER x=1
'Fan speed auto?
Local INTEGER req1=&H03F0003300000000
'Fan speed full
Local INTEGER req2=&H03F0003300010000
'read ??
Local INTEGER req3=&H00F0008046A53400
'Fan speed full
Local INTEGER reqall=&H0000000000000000
'Fan speed full
'j=LOC(#0)
'char$= INPUT$(100,#0)
char$=inkey$
if char$<>"" then
IF char$=" " THEN
'? "-----SPACE BAR--------"
'? "**************************"
'CAN SEND id,eid,dlc,msg,ret
msg%=&H1213141516171820
'eid%=1:dlc%=8
LogAction("11 Messages Sent")
addTxMessage(&H111,0,0,8,msg%)
addTxMessage(&H222,0,0,8,msg%)
addTxMessage(&H234,0,0,8,msg%)
addTxMessage(&H555,0,0,8,msg%)
addTxMessage(&H525,0,1,8,&HFFFFFFFFFFFFFFFF)
addTxMessage(&H1111111,1,0,8,&H1113141516171800)
addTxMessage(&H2222222,1,0,8,&H1213141516171820)
addTxMessage(&H3333333,1,0,8,&H1F03141516171820)
addTxMessage(&H4444444,1,0,8,&H1413141516171800)
addTxMessage(&H123457,1,0,8,&H1613141516171820)
addTxMessage(&H123456,1,0,4,&H1513141516171820)
'addMessage (&H123456,1,0,4,&H1513141516171820)
'addMessage (&H123457,1,0,4,&H1513141516171820)
'addMessage (&H123456,1,0,4,&H1513141516171820)
'addMessage (&H123457,1,0,4,&H1513141516171820)
'addMessage (&H123456,1,0,4,&H1513141516171820)
'addMessage (&H123457,1,0,4,&H1513141516171820)
'sendMsg (&H123456,1,0,4,&H1513141516171820)
'sendMsg (&H123457,1,0,4,&H1513141516171820)
'sendMsg (&H123456,1,0,4,&H1513141516171820)
'sendMsg (&H123457,1,0,4,&H1513141516171820)
'sendMsg (&H123456,1,0,4,&H1513141516171820)
'sendMsg (&H123457,1,0,4,&H1513141516171820)
end if
IF Char$="0" then
'id=0
' addMessage( 0,id,1,8,login())
endif
IF Char$="1" then
'login invitation
id=&H1FFFFFFF
'id=&H06000783
'mcp_sendMsg( 2,id,1,8,reqone())
addTxMessage( id,1,0,8,&H12345678abcdef11)
addTxMessage( id,1,0,8,&Habcdef11abcdef22)
addTxMessage( id,1,0,8,&Habcdef22abcdef22)
'mcp_sendMsg( 0,id,1,8,login())
print "add msg ",hex$(id)
endif
IF Char$="2" then
'login
id=&H1FFFFFFE
addTxMessage( id,1,0,8,&H1122334455667788)
print "mcp msg send",hex$(id)
endif
IF Char$="3" then
'login
id=&H7FFF
addTxMessage( id,1,0,8,&H1122334455667788)
print "mcp msg send",hex$(id)
endif
IF Char$="4" then
id=&H5555555
msg%=(FloatToBIN32(58.5)<<32 AND &HFFFFFFFF00000000) OR (FloatToBIN32(19.5) AND &HFFFFFFFF)
addTxMessage( id,1,0,8,msg%)
LogAction( "Sent voltage=58.5 Sent Current=19.5" )
end if
IF Char$="5" then
? "Get voltage 58.56789 From BIN32 of 42 6A 45 85"
'" 42 24 00 00 min 41V and 42 6A 00 00 max 58,5V"
id=&H426A4585
? BIN32ToFloat(id)
end if
IF Char$="6" then
? "Get 42 6A 00 00 from float voltage 58.5 "
'" 42 24 00 00 min 41V and 42 6A 00 00 max 58,5V"
id=&H426A0000
? HEX$(FloatToBIN32(58.5),8)
? HEX$(FloatToBIN32(58.56),8)
? HEX$(FloatToBIN32(1000.5),8)
end if
''EMERSON R48-2900U
'IF Char$="6" then
'
'id=&H0607FF83
'addMessage( id,1,0,8,readall)
'end if
IF Char$="7" then
'id=&H0607FF83
'? "Fan Auto"
'addMessage( id,1,0,8,req1)
end if
IF Char$="8" then
id=&H0607FF83
? "fan full"
addTxMessage( id,1,0,8,req2)
end if
IF Char$="9" then
/*
' ? "Read aa1"
' id=&H060F8007
' mcp_sendMsg( 2,id,1,8,reqall)
' ? "Read aa2"
' id=&H0607FF83
' addMessage( id,1,0,8,reqall)
select case x
case 1
? "Read one"
id=&H06000783
reqone(3)=1
addTxMessage( id,1,0,8,reqone)
case 2
? "Read one"
id=&H06000783
'reqone(3)=2
addTxMessage( id,1,0,8,reqone)
case 3
? "Read one"
id=&H06000783
r'eqone(3)=3
addTxMessage( id,1,0,8,reqone)
case 4
? "Read one"
id=&H06000783
'reqone(3)=4
addTxMessage( id,1,0,8,reqone)
case 5
? "Read one"
id=&H06000783
reqone(3)=5
addTxMessage( id,1,0,8,reqone)
case 6
? "Read one"
id=&H06000783
reqone(3)=6
addTxMessage( id,1,0,8,reqone)
case 7
? "Read one"
id=&H06000783
reqone(3)=7
addTxMessage( id,1,0,8,reqone)
case else
To read from the R48
Send to 06000783 => 01 F0 00 xx 00 00 00 00 xx = measurement No.
Response from 060F8003 <= 41 F0 00 xx yy yy yy yy xx = measurement No. yy yy yy yy = value
EDIT - corrected the response address
xx =
01 = output voltage
02 = output current
03 = output current limit
04 = temperature in C
05 = supply voltage
06 =
07 =
08 =
09 =
end select
x=x+1
if x> 7 then x=1
*/
end if
IF Char$="a" then
'PIN(CANCS)=0
end if
IF Char$="b" then
'PIN(CANCS)=1
end if
IF Char$="b" then id=11
IF Char$="c" then id=12
IF Char$="d" then id=13
IF Char$="e" then id=14
IF Char$="f" then id=15
if char$=chr$(145) or mid$(char$,2)="[11~" then 'F1 VT100
'print "F1"
'vtsc
'vtWindow 13,17 ' define window
'vtClrArea
'PRINT At(17,1)+vt100.colour$("YELLOW")+"DEVICE1"+vt100.colour$("reset")
'PRINT vt100.colour$("YELLOW")+"DEVICE2"+vt100.colour$("reset")
'PRINT vt100.colour$("YELLOW")+"DEVICE3"+vt100.colour$("reset")
'PRINT vt100.colour$("YELLOW")+"DEVICE4"+vt100.colour$("reset")
'PRINT vt100.colour$("YELLOW")+"DEVICE5"+vt100.colour$("reset")
'vtWindow 19,40 ' define window
'vtrc
LogAction("F1 Pressed")
endif
if char$=chr$(146) or mid$(char$,2)="[12~" then 'F2 VT100
'print "F2"
LogAction("F2 Pressed"+time$)
end if
if char$=chr$(147) or mid$(char$,2)="[13~" then 'F3 VT100
print "F3"
end if
if char$=chr$(148) or mid$(char$,2)="[14~" then 'F4 VT100
? "F4"
end if
if char$=chr$(149) or mid$(char$,2)="[15~" then 'F5 VT100
? "F5"
end if
if char$=chr$(150) or mid$(char$,2)="[17~" then 'F6 VT100
? "F6"
end if
if char$=chr$(151) or mid$(char$,2)="[18~" then 'F7 VT100
? "F7"
end if
if char$=chr$(152) or mid$(char$,2)="[19~" then 'F8 VT100
LogAction("Single Messages Sent &H123456")
CAN_SEND(&H123456,1,0,8,&H1413141516171800)
end if
if char$=chr$(153) or mid$(char$,2)="[20~" then 'F9 VT100
LogAction("Single Messages Read RBX0")
'Check for Message in RX0
CAN_READ 0
if ret>0 then
actionmsg 0
else
LogAction("No Messages in RBX0")
endif
end if
if char$=chr$(154) or mid$(char$,2)="[21~" then 'F10 VT100
LogAction("Single Messages Read RBX1")
'Check for Message in RX1
CAN_READ 1
if ret>0 then
actionmsg 1
else
LogAction("No Messages in RBX1")
endif
end if
if char$=chr$(155) or mid$(char$,2)="[23~" then 'F11 VT100
print "F11"
end if
if char$=chr$(156) or mid$(char$,2)="[24~" then 'F12 VT100
print "F12"
end if
if char$=chr$(127) or mid$(char$,2)="[3~" then 'del
text 10,200, "SLOW"
end if
if char$=chr$(128) or mid$(char$,2)="[A" then 'up arrow VT100
reqvoltage100x=reqvoltage100x+10
text 170,70, "Req Voltage="+STR$(reqvoltage100x/100,2,1)
end if
if char$=chr$(129) or mid$(char$,2)="[B" then 'down arrow
reqvoltage100x=reqvoltage100x-10
text 170,70, "Req Voltage="+STR$(reqvoltage100x/100,2,1)
end if
if char$=chr$(131) or char$=chr$(4) or mid$(char$,2)="[C" then 'right arrow VT100 MMEdit
reqcurrent10x=reqcurrent10x+2
text 170,50, "Req Current="+STR$(reqcurrent10x/10,2,1)
end if
if char$=chr$(130) or char$=chr$(19)or mid$(char$,2)="[D" then 'left arrow VT100 VT100 MMEdit
reqcurrent10x=reqcurrent10x-2
text 170,50, "Req Current="+STR$(reqcurrent10x/10,2,1)
end if
if char$=chr$(132) or mid$(char$,2)="[2~" then 'INS
walkfast=1
text 10,200, "FAST"
end if
if char$=chr$(133) then
print "133"
end if
if char$=chr$(134) or mid$(char$,2)="[1~" then 'home
adjvoltage=0
text 10,220, "adj="+str$(adjvoltage)+" "
end if
if char$=chr$(135) or mid$(char$,2)="[4~" then 'end
print reqcurrent10x,reqvoltage100x +adjvoltage,reqvoltage100x
sendconfig=1
end if
if char$=chr$(136) or mid$(char$,2)="[5~" then 'PgUp VT100
adjvoltage=100
text 10,220, "adj="+str$(adjvoltage)+" "
end if
if char$=chr$(137) or mid$(char$,2)="[6~" then 'Pgdn VT100
adjvoltage=-100
text 10,220, "adj="+str$(adjvoltage)+" "
end if
if char$=chr$(138) then
print "138"
end if
if char$=chr$(139) then
print "ALT"
end if
if char$=chr$(140) then
print "140"
end if
end if
End if
End sub
'===============================================================================
' User Application Supporting Routines
'===============================================================================
SUB LogAction(update1$)
vtsc
vtWindow 11,14 ' define window
PRINT At(14,1)+vt100.colour$("YELLOW")+update1$+vt100.colour$("reset")
vtWindow 19,40 ' define window
vtrc
END SUB
Function At(v As Integer,h As Integer) As String
At=Chr$(27)+"["+Str$(v)+";"+Str$(h)+"H"
End Function
Sub vtClr
'Window 1,25' redefine the whole screen
Print Chr$(27);"[2J";
End Sub
Sub vtsc 'save current cursor position
Print Chr$(27);"7";
End Sub
Sub vtrc 'restore cursor position saved with Vsc
Print Chr$(27);"8";
End SUB
Sub vtreset 'reset terminal
Print Chr$(27)+"c";
End Sub
Sub vtWindow(Pt As Integer, Pb As Integer)
'defines a window from line Pt to line Pb and positions the cursor in the start of it
'Clr and At still work on the whole screen. Only when scrolling (or CRLF) enteres the
'window does it capture the cursor. Note 0<Pt<Pb is enforced by the console emulator
Print Chr$(27)+"["+Str$(Pt)+";"+Str$(Pb)+"r"+At(Pt,1);
End Sub
'draw a box in "Terminal" font box chars
Sub vtBox(row as integer,col as integer ,w as integer,h as integer,t as integer)
local integer i
If t=0 Then
Print At( row,col);Chr$(218);String$(w-2,196);Chr$(191);
'Vat row+h,col
Print At(row+h,col);Chr$(192);String$(w-2,196);Chr$(217);
For i=1 To h-1
Print At(row+i,col)+Chr$(179);
PRINT At(row+i,col+w-1)+Chr$(179);
Next
Else
PRINT At( row,col)Chr$(201)+String$(w-2,205)+Chr$(187);
' Vat row+h,col
Print At(row+h,col)+Chr$(200);String$(w-2,205)+Chr$(188);
For i=1 To h-1
Print At(row+i,col)+Chr$(186);
PRINT At(row+i,col+w-1)+Chr$(186);
Next
End If
End Sub
'Erase rectangular area.
'Ps1 Top-line border.
'Ps2 Left-column border.
'Ps3 Bottom-line border.
'Ps4 Right-column border.
SUB vtClrArea
Print Chr$(27)+"[>3;13;1;17;80J"
End sub
Function vt100$(s$)
vt100$ = Chr$(27) + "[" + s$
End Function
Function vt100.colour$(c$)
Select Case LCase$(c$)
Case "black" : vt100.colour$ = vt100$("30m")
Case "red" : vt100.colour$ = vt100$("31m")
Case "green" : vt100.colour$ = vt100$("32m")
Case "yellow" : vt100.colour$ = vt100$("33m")
Case "blue" : vt100.colour$ = vt100$("34m")
Case "magenta", "purple" : vt100.colour$ = vt100$("35m")
Case "cyan" : vt100.colour$ = vt100$("36m")
Case "white" : vt100.colour$ = vt100$("37m")
Case "reset" : vt100.colour$ = vt100$("0m")
Case Else : Error "Unknown VT100 colour: " + c$
End Select
End Function


