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

MCP2515 Schematic

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.

* 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

'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.0.0"                                                    '
  '                                                                            '
  Dim ProgDate$  = "25-Aug-2024"                                               '
  '----------------------------------------------------------------------------'
  '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
'===============================================================================
' Option settings
'===============================================================================
 
  option explicit
  option default NONE
  OPTION BASE 0
  'OPTION AUTORUN ON
  
'===============================================================================
' LCD and Touch Initialisation and Test Commands from command prompt
'===============================================================================
'OPTION LCDPANEL ILI9341,L,6,5,4  ' d/c rst cs  veroboard version that matches ICSP layout
'OPTION TOUCH 15,2
  
'GUI TEST LCDPANEL
'GUI CALIBRATE 
 
'===============================================================================
' MCP2515 SPI Routines
'===============================================================================
'Code for MMBASIC to communicate with a MCP2515 over SPI
'Original Author:
'Ported to MMBasic by Disco4now!, TBS forums
'*******************************************************************************
'
'*******************************************************************************


  
' ILI9488 Display Driver for the Micromite Plus
' Written by Peter Mather (matherp on the Back Shed Forum)
Sub MM.Startup
  'ILI9488 D/C, RESET, CS, OR
 ' ILI9488 6, 5, 4, 3
  'ILI9481 6,5,4,3
End Sub



  

'===============================================================================
'Initialisation scanning of Console and serial ports if required (SETTICK)
'===============================================================================  
    
Dim integer loc0last,loc0now,loc1last,loc1now,loc2last,loc2now,GetCon=0
DIM INTEGER GetCom1=0,GetCom2=0
'Dim integer i,highlow=0
   'settick 100,IsSerialOrConsoleComplete,1 
settick 300,IsSerialOrConsoleComplete,1  'need longer for VT100 ESC sequences

'===============================================================================
' Data Variables
'===============================================================================
DIM Integer buttonstart=0,LoginRefresh=1  ' flag allocation for timers 0-9+10
DIM Integer buttondown=11,buttonup=12, buttonafter=13  ' other flag allocation 
dim integer laststate =1
dim integer buttontimer

   

'===============================================================================
'Initialisation and Setup of timers 0-9 (SETTICK) 
'===============================================================================	
	Dim Integer TMRctr(9),TMRini(9),Flags=0
	SETTICK 100,CoreTMR,4' service timers every 100mS
  
'===============================================================================
' Rotary  Encoder Initialisation Button and Polling via (SETTICK)
'===============================================================================  
  ' KY040 connected to Micromite
  ' CLK 2 ---> 0.1uF ---> Ov
  ' DT 3 ---> 0.1uF ---> Ov
  'SW 4 ---> 0.1uF ---> Ov
  '+ 3V3
  ' Gnd 0V
  
'Rotary Encoder Input pins
DIM integer CLK=10,DT=9
'Configure uMite pins
SETPIN DT, DIN
SETPIN CLK, INTH, REInt
'Rotary Encoder Button Long/Short Press setup
dim integer SwPin = 7' Pin number for the push button input
Dim Integer btnUPctr ' counter to hold the shifts
dim integer buttonstate=0',buttoncount=0
SetPin SwPin,DIN,PULLUP
SETTICK 20,ButtonTest,3' check button status every 20mS

'Variable incremented/decremented by the Interrupt handling
'routine for the Rotary Encoder.Needs to be global so that
'REInt ISR can access it
DIM Value as integer

'Var Display Value Inc/Decremented in Main Loop
'Cleared when Switch is pushed.Needs to be Global so that
'SWInt ISR can access it
DIM DispValue as integer

'Set to 1 to request a refresh of the display.Needs to be Global so that
'SWInt ISR can access it
DIM integer DisplayRefresh
dim integer LastValue,Change


  

'===============================================================================
' 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.

  
  
  '// clock and speed
  
  '#define MCP_8MHz_125kBPS_CFG1 (0x01)
  '#define MCP_8MHz_125kBPS_CFG2 (0xb1)
  '#define MCP_8MHz_125kBPS_CFG3 (0x05)

 
'   1000000, { 0x00, 0x80, 0x00 } },
'    500000, { 0x00, 0x90, 0x02 } },
'    250000, { 0x00, 0xb1, 0x05 } },
 '   200000, { 0x00, 0xb4, 0x06 } },
 '   125000, { 0x01, 0xb1, 0x05 } },
 '   100000, { 0x01, 0xb4, 0x06 } },
 '    80000, { 0x01, 0xbf, 0x07 } },
 '    50000, { 0x03, 0xb4, 0x06 } },
 '    40000, { 0x03, 0xbf, 0x07 } },
 '    20000, { 0x07, 0xbf, 0x07 } },
 '    10000, { 0x0f, 0xbf, 0x07 } },
 '     5000, { 0x1f, 0xbf, 0x07 } },
 
  '=============================================================================
  ' Program Initialization and variables
  '=============================================================================
 
  DIM INTEGER emersonR48=1
  'dim string newmsg
  'dim string lastmsg 
  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
  
  DIM float hextofloat,vreported,ireported,tempreported,vacreported,ilimitreported
  'DIM integer hextofloataddr=PEEK(VARADDR hextofloat)
  
  Print "Starting " + ProgTitle$ + ": " + ProgVer$ + " - " + ProgDate$
  'EVERY 100,LoginRefresh                'multiples of 100ms login each 10Secs

  'LCD Backlight
  'pwm 2,1000,40
  'ShowStartScreen
  'cls
  'BOX 0,0,320,240,,RGB(BLUE)



  '=============================================================================
  ' 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 MCP2515 connections
'===============================================================================
  'THE MCP2515 module needs to be mofified for  3,3V
  'dim integer CANSPEED=125000   'CAN 125KHz 10MHz
  DIM INTEGER CAN_CS
  CAN_CS=17                     'MCP2515 chip select pin17 
  SETPIN CAN_CS,DOUT 
  
  DIM INTEGER sendnow
  DIM INTEGER MCP_MODE_NORMAL=&H0      'Normal mode
  DIM INTEGER MCP_MODE_LOOPBACK=&H40   'Loopback mode
  DIM INTEGER ECHOMSG = 0              'echo messages
  DIM INTEGER NOFILTERS = 0            'Accept Filters Status
  DIM INTEGER ISROLLOVER = 0           'Rollover Status
  DIM integer rts(2)=(&H81,&H82,&H84),tbn=0
  dim integer values(14),req(3),sets(7)
  
  
  

 '==============================================================================
 ' Configure SPIOpen ans SPIClose SUBs to the desired SPI
 ' and settings for the specific MMBASIC platform.
 '==============================================================================
  dim integer SPISPEED=10000000   'SPI 10MHz
  SUB SPIOpen
   SPI OPEN SPISPEED,0,8
   PIN(CAN_CS)=0
  END SUB
  SUB SPIClose
    PIN(CAN_CS)=1
    SPI CLOSE 
  END SUB
 
  '=============================================================================
  ' Setup MMBasic FIFO Transmit Buffer
  '=============================================================================
  
   DIM INTEGER FifoSize=15          'Number of elements in the FiFo Burrer
   DIM INTEGER TXBuffer(FifoSize,1) 'Buffers are 128 bits wide i.e.2 integers wide
   DIM INTEGER FifoStart,FifoEnd




  'DIM INTEGER login(7) = (&H13, &H45, &H71, &H13, &H59, &H72, &H00, &H00)
  'DIM INTEGER readall(7) = (&H00, &H00, &H00, &H00, &H00, &H00, &H00, &H00)
  'DIM INTEGER reqone(7)=(&H01,&HF0,&H00,&H01,&H00,&H00,&H00,&H00)
  '                              
  DIM INTEGER id=&H05004804
  
  
  
  if emersonR48 THEN
    EVERY 100,LoginRefresh '(multiples of 100ms) refresh the login each 10Secs
  ENDIF
  
'===============================================================================
' Initialse the MCP2515 CAN Module
'=============================================================================== 
DIM INTEGER ROLLOVER=1,NOROLLOVER=0 
DIM INTEGER Normal=0,Loopback=1 ,echoall=2
DIM INTEGER Acceptall=1,UseFilters=0
mcp_init(LoopBack ,125000,AcceptAll,Rollover)    'initialise module 
  pause 20
  
  print hex$(mcp_readReg(&H0F),2)
  print "initialised"
 

SUB mcp_init(canmode as integer,CANSPEED as integer,USEFILTERS as integer,ROLLOVER as integer)
  
  mcp_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
  
  '**** UnComment the line below to echo all received  messages *********** 
   If canmode=2 then
     ECHOMSG = 1     'echo all received messages
   else
     ECHOMSG = 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 )
   ' 
   ' If ECCH mode then don't use filters.
  if ECHOMSG=0 THEN
   setRecBufferCTRLS(USEFILTERS,ROLLOVER)
  else
   setRecBufferCTRLS(AcceptAll,ROLLOVER)
  endif
   ' 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)

' *****  Setup the acceptance masks for RBX0 and RBx1 as required ******************
  'setAcceptMask(rbxno,eid ,idmask,datamask ) 'datamask for data(0)+data(1) if eid=0
  'setAcceptMask(0, 1, &H2222222,0);  
  'setAcceptMask(0, 1, &H1FFFFFFF,&H0)
   setAcceptMask(0, 1, &H1FFFFFFF,&H0)
   setAcceptMask(1, 1, &H1FFFFFFF,&H0)
  'setFilterMask(1, 0, &H7FF,&HAA55)

 ' *****  Setup the acceptance Filter for RBX0 and RBX1 as required ****************** 
  setFilter(0, 1, &H0123456,0)                'RBX6  RBX0
  setFilter(1, 1, &H1FFFFFFF,0)         'RBX7  RBX1 
  
  setFilter(2, 0, &H7FF,0)              'RBX2 
  setFilter(3, 1, &H4444444,&H0)       'RBX3  
  setFilter(4, 1, &H2222222,&H0)       'RBX4
  setFilter(5, 0, &H7FF,&H0)            'RBX5
  showFilters() 

  '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,MCP_MODE_LOOPBACK)'loopback mode - oneshot is disabled.
  else
     mcp_modReg(&H0F,&HE0,MCP_MODE_NORMAL)  'Normal  mode - oneshot is disabled.
  END IF  
  print "mcp mode ";
  print hex$(getMode(),2)
    
  'PRINT "Status=" ;
  'print hex$(mcp_readStatus(),2)
  'PRINT "StatusRX=" ;
  'print hex$(mcp_readStatusRX(),2)
  'PRINT "CANSTAT=" ;
  'PRINT hex$(mcp_readReg(&H0E),2)
  'PRINT "CANCTRL=" ;
  'PRINT hex$(mcp_readReg(&H0F),2)
  'PRINT "CANINTE=" ;
  'PRINT hex$(mcp_readReg(&H2B),2)
  'PRINT "CANINTF=" ;
  'PRINT hex$(mcp_readReg(&H2C),2)
    
end sub

  Print "Listening"
  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 "-  ------- - - -    ----------------------    -------------------"  
 
  '=============================================================================
  ' *********************  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
    IF GetCom1=1 then
      ReadSerial1             'If data in COM1 then GOSUB GetSerial1
    END IF
    IF GetCom2=1 then
      ReadSerial2            'If data in COM2 then GOSUB GetSerial2
    END IF
    
    '==============================Check Rotary Encoder=========================      
      'Has there been any movement of the encoder ?
      Change=Value-LastValue
      'We've caught the change so prepare for next time round
      LastValue=Value
      'Was there any movement of the encoder ?
      IF Change<>0 THEN
         'If encoder is turning ANTI-clockwise, Decrement
         IF Change<0 THEN
           DispValue=DispValue-1
         ENDIF
         'If encoder is turning CLOCKwise, Increment
         IF Change>0 THEN
            DispValue=DispValue+1
         ENDIF
         'Request a Display Refresh
         DisplayRefresh=1
      ENDIF
      '==============================Poll for Messages =========================  
      'Check for Message in RX0
       if mcp_readReg(&H2c) AND &H01 then 'test CANINTF B(0)
         mcp_readRegs(&H60,values() ,14)
         mcp_modReg(&H2c,&H01,&H00) 'clear CANINTF B(0)
         actionmsg 0
         
       endif 
       'Check for Message in RX1
       if mcp_readReg(&H2c) AND &H02 then 'test CANINTF B(1)
         mcp_readRegs(&H70,values() ,14)
         mcp_modReg(&H2c,&H02,&H00) 'clear CANINTF B(1)
         actionmsg 1
       endif 
   ''==================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========================= 
    if sendlogin=1 then
       if emersonR48 THEN
         id=&H06000783
         reqone(3)=1
         sendMsg( id,1,0,8,reqone())
       else
          'login 
         id=&H05004804
         sendMsg( id,1,0,8,login())
       endif
         sendlogin=0
    endif  
    if request_warnings=1 then
      id=&H0501BFFC
      req(0)=&H08:req(1)=&H04:req(2)=&H00
      mcp_sendMsg( id,1,3,req())
      request_warnings=0
    endif  
    if request_errors=1 then
      id=&H0501BFFC
      req(0)=&H08:req(1)=&H08:req(2)=&H00
      mcp_sendMsg( id,1,3,req())
      request_errors=0
    endif
    if sendconfig=1 then
         if walkfast=1 then
           id=&H05FF4004   ' 5sec walkin
         else
           id=&H05FF4005   '60sec walkin
         endif
         sets(6)=&H3E:sets(7)=&H17  'OVP set to 59.9 ????
         sets(0)=reqcurrent10x AND &HFF
         sets(1)=(reqcurrent10x>>8) AND &HFF
         sets(2)=reqvoltage100x AND &HFF
         sets(3)=(reqvoltage100x>>8) AND &HFF
         sets(4)=reqvoltage100x AND &HFF
         sets(5)=(reqvoltage100x>>8) AND &HFF
        
         mcp_sendMsg( id,1,8,sets())
        
        sendconfig=0
    end if
 '==========================Transmit next Messages ========================
    'Process the the next meaage in the Transmit Queue
    sendnow=sendnow+1    
    IF sendnow=10 Then
      sendnow=0 
      sendSingleMessage
    endif 

     'Update the Display ?
    IF DisplayRefresh=1 THEN
      'Reset the trigger 
      DisplayRefresh=0
      'Display on the Console
      PRINT STR$(DispValue)
    ENDIF
    If FlagTest(buttondown) Then ' 
       if FlagTest(buttonafter)=0 then  After 2,buttonstart ' 2*100ms
       FlagSet buttonafter
       FlagRes buttonup  
       'FlagRes buttondown
    endif
    If FlagTest(buttonup) Then ' 
      if buttonstate=0 then   'down
      
      elseif buttonstate=1 then  'SHORT PRESS
         ? "Short Press"
      elseif buttonstate=2 then  'LONG PRESS
         ? "Long Press"
      endif  
      FlagRes buttonup 
    endif
 
    If FlagTest(buttonstart) Then 
      FlagRes buttonstart
      FlagRes buttondown 
      FlagRes buttonafter 
    endif 
    'Send a login every 10 seconds
    if FlagTest(LoginRefresh) Then
     
       FlagRes LoginRefresh
       '? "login now"+str$(timer)
       'sendlogin=1
     
    end if
  Loop
 '==============================================================================
 ' *********************  -- END of Main program loop-- ************************
 '============================================================================== 



'===============================================================================
' CAN High Level Functional Routines actionmsg,
'===============================================================================

SUB actionmsg(rxno as integer)
  local integer id,eid ,dat ,dlc,rtr,msg,i,rfx
  Local INTEGER fmi,fminitial(7)=(0,1,2,3,4,5,0,1)
  Local INTEGER fmo,fmoverflow(7)=(6,7,2,3,4,5,0,1)
       
  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)  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
  'Resolve the matched filter
  if NOFILTERS then
    fmi=-1 
    fmo=-1                
  ELSE 
   'Get the matching filter
    if rxno=0 then rfx=mcp_readReg(&H60) AND &H07
    if rxno=1 then rfx=mcp_readReg(&H70) and &H07      
    if ISROLLOVER then
      fmi=fminitial(rfx)
      fmo=fmoverflow(rfx)
    endif
  ENDIF 

  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 
       
  'if rtr Then msg=&H0
  'print id," "; 
  select case  id
    CASE &H05014400  'Login request
        print "login request Eltek"
        CLS
        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
             ? "Got Voltage=",BIN32ToFloat((msg AND &HFFFFFFFF00000000)>>32  )
             '? hex$(msg)
             '? hex$( msg AND &HFFFF000000000000)
            ' ? hex$((msg AND &HFFFF000000000000)>> 32)
             ? "Got Current=",BIN32ToFloat((msg AND     &HFFFFFFFF) )
             '? hex$((msg AND &HFFFFFFFF0000000000000000) >> 16)
         
    CASE &H060F8003 
            '01 = output voltage
            '02 = output current
            '03 = output current limit
            '04 = temperature in C
            '05 = supply voltage
            '06 =
            '07 =
            '08 =
            '09 =
 
        ? "data=" +hex$(values(6),2)+hex$(values(7),2)+hex$(values(8),2)+" "+hex$(values(9),2);
        ? " "+hex$(values(10),2)+hex$(values(11),2)+hex$(values(12),2)+hex$(values(13),2)
              'this works between 42 24 00 00 min 41V and 42 6A 00 00 max 58,5V
           ' ? peek(float )
          
           'POKE WORD vrequestaddr, &H42240000
        POKE WORD hextofloataddr, values(10)<<24 OR values(11)<<16 OR values(12)<<8 OR values(13)
        select case values(9)
          CASE 1
              vreported = hextofloat
              ? "Voltage:",vreported
          CASE 2
              ireported = hextofloat
              ? "Current",ireported
          CASE 3
              ilimitreported = hextofloat
              ? "Current Limit:",ilimitreported
          CASE 4
              tempreported = hextofloat
              ? "Temperature",tempreported
          CASE 5
              vacreported = hextofloat
              ? "AC Voltage",vacreported
          case else
              ?  values(9),hextofloat
        end select 

    CASE ELSE
            
             'Print STR$(rxno)+"  "+SPACE$(4-eid*4)+HEX$(id%,3+eid*4)+" "+HEX$(eid%)+" "+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 ECHOMSG THEN
               'addMessage( id,eid,rtr,dlc,dat)
             'END IF 
    end select 
    Print STR$(rxno)+"  "+SPACE$(4-eid*4)+HEX$(id%,3+eid*4)+" "+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 ECHOMSG THEN
      addMessage( id,eid,rtr,dlc,msg)
    END IF        
        
END SUB 

SUB addMessage(id as Integer,eid as integer,rtr as integer,dlc as integer,dat as integer)
   local integer i 
   FifoEnd=FifoEnd + 1 : If FifoEnd=FifoSize then FifoEnd=0
   TXBuffer(FifoEnd,0)=id OR (eid << 63) OR (rtr << 62) or ((dlc AND &H0F) << 55)
   TXBuffer(FifoEnd,1)=dat
end sub

SUB sendSingleMessage()
    local INTEGER value,id,eid,rtr,dlc,i
    IF FifoEnd<>FifoStart Then
       FifoStart=FifoStart + 1 : If FifoStart=FifoSize then FifoStart=0
       value=TXBuffer(FifoStart,1) 
       id=TXBuffer(FifoStart,0) AND &H7FFFFFFF
       eid=TXBuffer(FifoStart,0)>>63 AND &H1
       rtr=TXBuffer(FifoStart,0)>>62 AND &H1
       dlc=TXBuffer(FifoStart,0)>>55 AND &H0F
       sendMsg(id,eid,rtr,dlc,value)
       'sendMsg(id,eid,rtr,dlc,value)
             
   endif
end sub

SUB sendMsg( id as integer,eid as integer,rtr as integer,dlc as integer,dat 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)=dat >> (56-i*8) AND &HFF
     next i
    endif
    'PRINT "Load regs"
    mcp_setRegs(8+i,buff())

    mcp_send(tbn)
    tbn=tbn+1:if tbn=3 then tbn=0
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 integer ctr1=((IgnoreFilters AND &H1) << 6) OR ((IgnoreFilters AND &H1)<< 5) OR ( (rollover AND &H1) << 2 ) 
   local integer ctr2=((IgnoreFilters AND &H1) << 6) OR ((IgnoreFilters AND &H1)<< 5)
   mcp_modReg(&H60,&H64,ctr1)
   mcp_modReg(&H70,&H60,ctr2)
   NOFILTERS=IgnoreFilters
   ISROLLOVER=rollover

  ? "CTRL",HEX$(ctr1),HEX$(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
  SPI WRITE 3,&H02,reg,dat
  SPICLOSE
end sub

SUB mcp_setRegs(n as integer,dat() as integer)
  SPIOPEN 'speed,0,8
  SPI WRITE n,dat()
  SPICLOSE
end sub
  
SUB mcp_modReg(reg as integer,mask as integer,dat as integer)
  SPIOPEN 'speed,0,8
  SPI WRITE 4,&H05,reg,mask,dat 'MCP_BITMOD=&H05
  SPICLOSE
end sub
  
FUNCTION mcp_readReg(reg as integer) as integer
  SPIOPEN 'speed,0,8
  SPI WRITE 2,&H03,reg
  mcp_readReg=SPI(0)
  SPICLOSE
END FUNCTION

FUNCTION mcp_readStatus() as integer
  SPIOPEN 'speed,0,8
  SPI WRITE 1,&HA0
  mcp_readStatus=SPI(0)
  SPICLOSE
END FUNCTION

FUNCTION mcp_readStatusRX() as integer
  SPIOPEN 'speed,0,8
  SPI WRITE 1,&HB0
  mcp_readStatusRX=SPI(0)
  SPICLOSE
END FUNCTION
  
SUB mcp_readRegs(reg as integer,values() as INTEGER,n as integer)
  SPIOPEN 'speed,0,8
  SPI WRITE 2,&H03,reg
  SPI READ n,values()
  SPICLOSE
END SUB

SUB mcp_readRxBuff(reg as integer,values() as INTEGER,n as integer)
  SPIOPEN 'speed,0,8
  SPI WRITE 2,&H03,reg
  SPI READ n,values()
  SPICLOSE
END SUB

SUB mcp_send(n as integer)
  'Set Request to Send for desited TX Buffer
  SPIOPEN 'speed,0,8
  SPI WRITE 1,rts(n)
  'ret=SPI(&HC0)
   SPICLOSE
end SUB
   
SUB mcp_reset()
  'open the SPI at 10KHz
  SPIOPEN 'speed,0,8
  SPI WRITE 1,&HC0
  SPICLOSE
end SUB
  




'===============================================================================
' Utility functions to convert between Float and and binary BIN32
'===============================================================================


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
     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
     FloatToBIN32=j
  endif
End Function

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
     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
     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
  
  'Check COM1 and set flag if data exists and has stopped coming in
  '    loc1now=LOC(#1)
  '    IF loc1now > 0 THEN
  '     if loc1now=loc1last then 'data finished
  '       GetCom1=1
  '     ELSE
  '      loc1last=loc1now
  '     ENDIF
  '    ENDIF
  '
  'Check COM2 and set flag if data exists and has stopped coming in
  '    loc2now=LOC(#2)
  '    IF loc2now > 0 THEN
  '     if loc2now=loc2last then 'nothin new
  '       GetCom2=1
  '     ELSE
  '      loc2last=loc2now
  '     ENDIF
  '    ENDIF
  
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)
  ok=0
  if char$<>"" then
      IF char$=" " THEN
       '? "-----SPACE BAR--------"
         '? "**************************"
        'CAN SEND id,eid,dlc,msg,ret
         msg%=&H1213141516171820
         'eid%=1:dlc%=8
         
         addMessage(&H111,0,0,8,msg%) 
         addMessage(&H222,0,0,8,msg%) 
         addMessage(&H234,0,0,8,msg%) 
         addMessage(&H555,0,0,8,msg%) 
         addMessage(&H525,0,1,8,&HFFFFFFFFFFFFFFFF) 
         addMessage(&H1111111,1,0,8,&H1113141516171800) 
         addMessage(&H2222222,1,0,8,&H1213141516171820) 
         addMessage(&H3333333,1,0,8,&H1F03141516171820) 
         addMessage(&H4444444,1,0,8,&H1413141516171800) 
         addMessage(&H123456,1,0,4,&H1513141516171820) 
         addMessage(&H123457,1,0,8,&H1613141516171820) 
      end if
      
      IF Char$="0" then
        'id=0
       ' addMessage( 0,id,1,8,login())
         ok=1
      endif  
      IF Char$="1" then
          
          'login invitation
          id=&H1FFFFFFF
          'id=&H06000783 
          'mcp_sendMsg( 2,id,1,8,reqone())
          addMessage( id,1,0,8,&H12345678abcdef11)
          addMessage( id,1,0,8,&Habcdef11abcdef22)
          addMessage( id,1,0,8,&Habcdef22abcdef22) 
          'mcp_sendMsg( 0,id,1,8,login())
          print "add msg ",hex$(id)
         ok=1
      endif 
      IF Char$="2" then
         'login 
          id=&H1FFFFFFE
          addMessage( id,1,0,8,&H1122334455667788)
          print "mcp msg send",hex$(id)
          ok=1
      endif 
      
      IF Char$="3" then
         'login 
          id=&H7FFF
          addMessage( id,1,0,8,&H1122334455667788)
          print "mcp msg send",hex$(id)
          ok=1
      endif 
           
      
      IF Char$="4" then
        id=&H5555555
        msg%=(FloatToBIN32(58.5)<<32 AND &HFFFF000000000000) OR (FloatToBIN32(19.5) << 16 AND &HFFFF00000000)
        addMessage( id,1,0,8,msg%)
        print "Sent voltage=58.5 Current=19.5",hex$(id)
          
        ok=1   
      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) 
          ok=1   
      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) 
          ok=1 
            
      end if  
            
      ''EMERSON R48-2900U
      'IF Char$="6" then 
         '
         'id=&H0607FF83
         'addMessage( id,1,0,8,readall)
         'ok=1   
      'end if   
      'IF Char$="7" then  
          'id=&H0607FF83
          '? "Fan Auto"
          'addMessage( id,1,0,8,req1)
         'ok=1   
      end if
      
      IF Char$="8" then 
          id=&H0607FF83
          ? "fan full"
          addMessage( id,1,0,8,req2)

         ok=1   
      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
         addMessage( id,1,0,8,reqone)
        case 2  
         ? "Read one"
         id=&H06000783
         'reqone(3)=2
         addMessage( id,1,0,8,reqone)
        case 3
         ? "Read one"
         id=&H06000783
         r'eqone(3)=3
         addMessage( id,1,0,8,reqone)
        case 4
        ? "Read one"
         id=&H06000783
         'reqone(3)=4
         addMessage( id,1,0,8,reqone)
        case 5
        ? "Read one"
         id=&H06000783
         reqone(3)=5
         addMessage( id,1,0,8,reqone)
        case 6
        ? "Read one"
         id=&H06000783
         reqone(3)=6
         addMessage( id,1,0,8,reqone)
        case 7
        ? "Read one"
         id=&H06000783
         reqone(3)=7
         addMessage( 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
        
          ok=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"
        ok=1
      endif 
      if char$=chr$(146) or mid$(char$,2)="[12~" then  'F2 VT100
        print "F2"
        ok=1   
      end if
      if char$=chr$(147) or mid$(char$,2)="[13~" then  'F3 VT100
        print "F3"
         ok=1   
      end if
      if char$=chr$(148) or mid$(char$,2)="[14~"  then  'F4 VT100
        ? "F4"
         ok=1   
      end if
      if char$=chr$(149) or mid$(char$,2)="[15~" then  'F5 VT100
         ? "F5"
         ok=1   
      end if
      if char$=chr$(150) or mid$(char$,2)="[17~" then  'F6 VT100
        ? "F6"
         ok=1   
      end if
      if char$=chr$(151) or mid$(char$,2)="[18~" then  'F7 VT100
        ? "F7"
           ok=1   
      end if
      if char$=chr$(152) or mid$(char$,2)="[19~" then  'F8 VT100
        ?  "F8"
        ok=1   
      end if
      if char$=chr$(153) or mid$(char$,2)="[20~" then  'F9 VT100
        ? "F9"
        ok=1 
      end if
      if char$=chr$(154) or mid$(char$,2)="[21~" then  'F10 VT100
        ? "F10"
          ok=1   
      end if
      if char$=chr$(155) or mid$(char$,2)="[23~" then  'F11 VT100
        print "F11"
          ok=1   
      end if
      if char$=chr$(156) or mid$(char$,2)="[24~" then  'F12 VT100
        print "F12"
          ok=1   
      end if
      if char$=chr$(127) or mid$(char$,2)="[3~" then  'del
        walkfast=0
        text 10,200, "SLOW"
          ok=1   
      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)
         ok=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)
        ok=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)
         ok=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)
        ok=1   
      end if
      if char$=chr$(132) or mid$(char$,2)="[2~" then  'INS
         walkfast=1
         text 10,200, "FAST"
         ok=1   
      end if
      if char$=chr$(133) then
        print "133"
        ok=1   
      end if
      if char$=chr$(134) or mid$(char$,2)="[1~" then 'home
        adjvoltage=0
        text 10,220, "adj="+str$(adjvoltage)+"  "
         ok=1   
      end if
      if char$=chr$(135) or mid$(char$,2)="[4~" then  'end
        print reqcurrent10x,reqvoltage100x +adjvoltage,reqvoltage100x      
        sendconfig=1
         ok=1   
      end if
      if char$=chr$(136) or mid$(char$,2)="[5~" then  'PgUp VT100
         adjvoltage=100
         text 10,220, "adj="+str$(adjvoltage)+"  "
        ok=1   
      end if
      if char$=chr$(137) or mid$(char$,2)="[6~" then  'Pgdn VT100
         adjvoltage=-100
         text 10,220, "adj="+str$(adjvoltage)+"  "
         ok=1   
      end if
      if char$=chr$(138) then
        print "138"
        ok=1   
      end if
      if char$=chr$(139) then
        print "ALT"
        ok=1   
      end if
      if char$=chr$(140) then
        print "140"
        ok=1   
      end if

    'else
      '? char$;
     ' ? ASC(left$(char$,1));
    'endif
    IF ASC(Left$(char$,1))=27 and ok=0 then
      ? "ESC"
      ? len(char$) 
      ? mid$(char$,2) 
      ?
    end if
  
   
  end if
End if

End sub

'===============================================================================
' User Application Supporting Routines
'===============================================================================
SUB ShowStartScreen
  CLS
  BOX 0,0,MM.HRES, MM.VRES,,RGB(GREEN)
  TEXT 50, 10, Progtitle$
  TEXT 50, 30, "Software "+progver$
  TEXT 50, 50, "Date "+progdate$
  TEXT 50, 100, "Waiting Login Request!"
  ShowLed(1,RGB(YELLOW))
  ShowLed(2,RGB(YELLOW))
  ShowLed(3,RGB(YELLOW))
  ShowLed(4,RGB(YELLOW))
  ShowLed(5,RGB(YELLOW))
END SUB 
SUB ShowLed(i as integer, c as integer)
  CIRCLE 40*i,205,13,1,1,c,c

END SUB
SUB ShowStatus(errorlevel as integer)
           if tempin<>values(6) then
             tempin=values(6)
             text 10,10, "temp in="+str$(tempin)
           endif 
           if tempout<>values(13) then
             tempout=values(13)
            text 10,30, "temp out="+str$(tempout)
           endif  
           if iout<>values(8)*256+values(7)then
             iout=values(8)*256+values(7)
             text 10,50, "Current Out="+STR$(iout/10,2,1)
           endif  
           if vout<>INT((values(10)*256+values(9))/10) then
             vout=INT((values(10)*256+values(9))/10)
             text 10,70, "Voltage Out="+STR$(vout/10,2,1)
           endif 
           if vin<>values(12)*256+values(11) then
             vin=values(12)*256+values(11)
             text 10,90,"Voltage In="+str$(vin)
           endif
           if errorlevel=0 then 
               text 10,150,"NORMAL  "
              
           ENDIF  
           if errorlevel=1 then 
               text 10,150,"WARNING  "
              request_warnings=1
           ENDIF   
           if errorlevel=2 then 
             text 10,150,"ERROR   "
             request_errors=1 
           END IF  
           if errorlevel=3 then
            text 10,150,"WALK IN   "
           end if             
   

end sub   



'===============================================================================
' Timer functions
'===============================================================================
'Usage:
' After 10,1 ' 10 seconds using timer 1
'	Every 1 ,2 ' count 1 second intervals using timer 2
'	Every 2 ,3 ' count 2 second intervals using timer 3
'Variable Descriptions:
'TMRctr() maintains the count for a given timer
'TMRini()holds the timer type and its initialization value.
'- bits 0-61 store the initial value value
'- bits 63&62 store the format of the counter:
'0=disabled
'1=(actually 0x4000000000000000) indicates a one shot "AFTER x" type counter
'2=(actually 0x8000000000000000) indicates a repetitive "EVERY x" type counter

SUB CoreTMR ' needs to run on a ticker at whatever interval is required - this is also the multiple of timer counts
		If FlagTest(10) Then Exit Sub
		Local Integer n,f,v
		For n=0 To 9
			f=TMRini(n) And &hC000000000000000 ' extract the top 2 bits
			Select Case f
				Case 0,&hC000000000000000 'disabled or invalid
					FlagRes(n)
				Case &h4000000000000000' AFTER
					If TMRctr(n)>0 then
						TMRctr(n)=TMRctr(n)-1
						If TMRctr(n)=0 Then FlagSet(n) ' indicate the timer has expired
					EndIf
				Case &h8000000000000000' EVERY
					If TMRctr(n)>0 then
						TMRctr(n)=TMRctr(n)-1
						If TMRctr(n)=0 Then
							FlagSet(n) ' indicate the timer has expired
							TMRctr(n)=TMRini(n) And &h3FFFFFFFFFFFFFFF ' reset the timer
						EndIf
					EndIf
			End Select

		Next
END SUB


Sub After(Interval As Integer,Tmr As Integer)' starts a one-shot timer
		TMRini(Tmr)=Interval OR &h4000000000000000:TMRctr(Tmr)=Interval And &h3FFFFFFFFFFFFFFF:FlagRes(Tmr)
End Sub

Sub Every(Interval As Integer,Tmr As Integer)' starts a repetitive timer
		TMRini(Tmr)=Interval OR &h8000000000000000:TMRctr(Tmr)=Interval And &h3FFFFFFFFFFFFFFF:FlagRes(Tmr)
End Sub
'
Sub DI  'Disable interval interupts
	FlagSet 10
End Sub
'
Sub EI  'Enable interval interupts
		FlagRes 10
End Sub
'
'
'


'===============================================================================
' Bit manipulation functions
'===============================================================================
'Set a bit
SUB FlagSet(bit AS INTEGER)
    FLAGS=FLAGS OR (2^bit)
END SUB  

'Clear a bit
SUB FlagRes(bit AS INTEGER)
    FLAGS=(FLAGS OR (2^bit)) XOR (2^bit)
END SUB 

'Set bit equal to value passed  
SUB FlagEq(bit As Integer,v as integer)
    IF v=0 THEN
      FlagRes(bit)
    ELSE
      FlagSet(bit)
    ENDIF
END SUB

'Test if bit is set
FUNCTION FlagTest(bit AS INTEGER) AS INTEGER
    FlagTest=ABS(SGN(FLAGS AND (2^bit)))
END FUNCTION



'===============================================================================
' Rotary Encoder and Button Support Routines
'===============================================================================
'ISR for Rotary Encoder
'Here when the Rotary encoder moves
SUB REInt()
    IF PIN(DT)=0 THEN
      'Clockwise rotation
      Value=Value+1
    ELSE
     'Anti-Clockwise rotation
     Value=Value-1
    ENDIF
END SUB 

'ISR for Push-Switch
'Here when Switch changes state
SUB SWInt()
   'Clear the Displayed Value
   DispValue=0
   'And trigger a DisplayRefresh of DispValue
   DisplayRefresh=1
END SUB 
Sub ButtonTest
   'STATIC integer laststate =1
   'STATIC integer buttontimer
   local integer buttontemp,b
  
		btnUPctr=btnUPctr<<1 Xor Pin(SwPin) And &h01f ' sample the input pin and shift the bit into the counter
 		' If this loop is fast, increase the &h1f so we sample more bits... reduce it if the main loop is slower - tune it for your purposes
		' If we shift enough zeroes in, the button has been pressed. 
		' Any bounce (back to 1) will shift a one in and "spoil" our counter for which will start again.
    'If FlagTest(buttonchange)=0 Then 
		Select Case btnUPctr
			Case 0	   'button down
        If FlagTest(buttondown)=0 Then 
         buttonstate=0
         if laststate<>buttonstate then 
           FlagSet(buttondown)
           laststate=buttonstate 
           buttontimer=timer
         endif 
        endif  
         'After 2,buttonstart ' 20*100ms i.e 2 seconds 
			Case &h01f 'button up
         b = TIMER - buttontimer ' this is how long the button was down
         IF b < 700 THEN ' short press
       	  buttontemp=1
         else
          buttontemp=2
         endif  
         if laststate=0 then 
           FlagSet(buttonup)
           buttonstate=buttontemp
           laststate=buttonstate
         endif 
         'After 2,buttonstart ' 20*100ms i.e 2 seconds  
			Case Else 'neither up nor down
          
       	 'buttonstate=2
		End Select
 
End sub