ShiftX3

Introduction

Parts in the Kit

In the kit you will receive:

  • ShiftX2 module
  • 2 M2x5mm screws for enclosure assembly
  • 2 #6 screws for surface mounting


ShiftX3 board and enclosure.jpg

(3D printed enclosure not included)

Dimensions

  • ShiftX3 bare board: 114 x 27mm (4.48 x 1.06 inches)
  • ShiftX3 with enclosure 136 x 32 x 9.46 mm (5.35 x 1.26 x .37 inches)

Installation

ShiftX3 is designed to be surface mounted with the companion enclosure, or it can be embedded into your dashboard in a custom installation.

Printing the enclosure

The enclosure can be 3D printed by downloading the printer files.

File:Shiftx3 enclosure rev A.zip

The enclosure consists of the following parts:

  • shiftx3.stl : Main housing for ShiftX3 - Qty 1 needed
  • shiftx3_back_3dprint: Back cover for housing - Qty 1 needed
  • shiftx3_light_pipe.stl: Light pipe for LEDs - Qty 9 needed
  • shiftx3_light_pipe_photosensor.stl: Light pipe for photosensor - Qty 1 needed

Printing the enclosure

Color and material are not critical for the enclosure; however we recommend ABS.

Printing light pipes

Print the 9 LED light pipes and 1 photosensor light pipe in clear filament. PETG is recommended for optical clarity.

Enclosure clean up

Ensure extra filament is completely removed from the inside of the enclosure and is completely clean, so ShiftX3 board can fit flush and level inside the enclosure.

3D printing notes

  • Print extra light pipes and print with a brim to purge heat-scorched / darkened filament from the extruder.
  • Avoid printing just one light pipe at a time - printing just one will cause the part to sag and deform due to concentrated heat in the small part. We recommend you print at least 4 at a time to ensure heat is distributed across the parts and retain dimensional accuracy.

Assembling the enclosure

Install light pipes

Press the LED light pipes into the enclosure from the back side, ensuring they are flush with the front.

  • Note -The LED light pipes have a small lip that locks into the back surface.

Press the photo sensor light pipe into the front of the enclosure. There should be a tight interference fit; if there is not, use a tiny drop of super glue from the back side of the enclosure to secure it.

Install ShiftX3

Install ShiftX3 into the back of the enclosure, guiding the switches into their respective hole.

ShiftX3 white enclosure back.jpg

  • Note - Take care to not torque the switch handles sideways to prevent damage.

Gently press the back of ShiftX3 board so that it is fully seated into the enclosure. There should be a 0.5mm lip around the back of the enclosure where the back plate will lock into place.

ShiftX3 white enclosure front.jpg


Install the back panel of ShiftX3 so the shallow lip of the back panel sits within the recess of the ShiftX3 enclosure.

When pressed together, there should be no gap between the enclosure and the back plate. If there is, check the inside of the enclosure to clean up any additional 3D printed filament.

Secure the back plate using the two M2x5mm screws. Do not over-torque.

Connection and Installation

Mounting ShiftX3

Attach ShiftX2 with the mounting screws and tighten until snug.

Integration with RaceCapture / PodiumConnect

Suggested parts:

  • RJ45 Splitter "Hub" shaped
  • RJ45 network cable Flat style round style
    • Note Any standard CAT5 or CAT6 patch cable should work, so long as it is not a cross-over cable.
Patching the RJ45 cable to ShiftX2

You will need to splice ShiftX2 to the conductors of the patch cable. Start by snipping the RJ45 connector off the end of a patch cable, and then expose the individual wires.

Rj45labeled.jpg

RJ45 power and CAN connection pinout
ShiftX2 connection RaceCapture Connection CAT5 EIA-T568B RJ45 cable
Red +12v Brown
White Ground Orange/White
No Connection CAN 1 High Orange
No Connection CAN 1 Low Green/White
Black CAN 2 High Blue
Yellow CAN 2 Low Blue/White

Note: These color codes assume EIA-T568B RJ45 cable (check printing on the cable to confirm)

CAN Termination

CAN termination is enabled by default. To disable termination, cut the CAN Term jumper on the bottom of ShiftX3.

Powering and Connecting to RaceCapture

Scripts

The following scripts assume ShiftX2 is connected to the 2nd CAN bus, and is the first ShiftX2 on the bus (ADR1 jumper default setting)

Disco Lights Demo

This is a test script that exercises all of the LEDs on ShiftX2. You can use this as a first time test, as it does not rely on any sensors.

Script

Copy and paste this entire script into the scripting window, replacing any existing script.

sxCan = 1
sxId=0
tickRate=30
sxBright=0

function rndc()
  return math.random(0,255)
end

function sxOnUpdate()
  for i=0,9,1 do
    r = rndc()
    g = rndc()
    b = rndc()
	sxSetLed(i,1,r,g,b,0)
  end
end

function sxOnBut(b)
  println('button: ' ..b)
end

function sxOnInit()
  print('sx onInit')
end

--ShiftX2 library functions--

function sxSetLed(i,l,r,g,b,f)
  sxTx(10,{i,l,r,g,b,f})
end

function sxSetLinearThresh(id,s,th,r,g,b,f)
  sxTx(41,{id,s,spl(th),sph(th),r,g,b,f})
end

function sxSetAlertThresh(id,tid,th,r,g,b,f)
  sxTx(21,{id,tid,spl(th),sph(th),r,g,b,f})
end

function sxSetBaseConfig(bright)
  sxTx(3,{bright})
end

function sxSetAlert(id,r,g,b,f)
  sxTx(20,{id,r,g,b,f})
end

function sxUpdateAlert(id,v)
  if v~=nil then sxTx(22,{id,spl(v),sph(v)}) end
end

function sxCfgLinearGraph(rs,ls,lr,hr) 
  sxTx(40,{rs,ls,spl(lr),sph(lr),spl(hr),sph(hr)})
end

function sxUpdateLinearGraph(v)
  sxTx(42,{spl(v),sph(v)})
end

function sxInit()
  println('config shiftX2')
  sxSetBaseConfig(sxBright)
  if sxOnInit~=nil then sxOnInit() end
end

function sxChkCan()
  id,ext,data=rxCAN(sxCan,0)
  if id==sxCanId then sxInit() end
  if id==sxCanId+60 and sxOnBut~=nil then sxOnBut(data[1]) end
end

function sxProcess()
  sxChkCan()
  if sxOnUpdate~=nil then sxOnUpdate() end
end

function sxTx(offset, data)
  txCAN(sxCan, sxCanId + offset, 1, data)
  sleep(10)
end

function spl(v) return bit.band(v,0xFF) end
function sph(v) return bit.rshift(bit.band(v,0xFF00),8) end

function onTick()
  sxProcess()
end

sxCanId = 0xE3600 + (256 * sxId)
println('shiftx2 base id ' ..sxCanId)

setTickRate(tickRate)
sxInit()

Sequential shift light

This script configures just a sequential shift light.

Script

Copy and paste this entire script, replacing any existing script:

  • Default is reading RPM via OBDII. You can change to direct RPM input in the script.
-- What CAN bus ShiftX2 is connected to. 0=CAN1, 1=CAN2
sxCan = 1

-- 0=first ShiftX2 on bus, 1=second ShiftX2 (if ADR1 jumper is cut)
sxId=0

--how often ShiftX2 is updated
tickRate=30

--Brightness, 0-100. 0=automatic brightness
sxBright=0

function sxOnUpdate()
  --add your code to update ShiftX2 alerts or linear graph during run time.
  --Runs continuously based on tickRate.
  
  --uncomment the below for OBDII RPM PID
  sxUpdateLinearGraph(readOBD2(12))

  --uncomment the below for Direct RPM on input 0
  --sxUpdateLinearGraph(getTimerRpm(0))
end

function sxOnInit()
  --config shift light
  sxCfgLinearGraph(0,0,0,7000) --left to right graph, linear style, 0 - 7000 RPM range

  sxSetLinearThresh(0,0,3000,0,255,0,0) --green at 3000 RPM
  sxSetLinearThresh(1,0,5000,255,255,0,0) --yellow at 5000 RPM
  sxSetLinearThresh(2,0,6000,255,0,0,10) --red+flash at 6500 RPM
end

function sxOnBut(b)
  --called if the button state changes
  println('button: ' ..b)
end

---ShiftX2 functions

function sxSetLed(i,l,r,g,b,f)
  sxTx(10,{i,l,r,g,b,f})
end

function sxSetLinearThresh(id,s,th,r,g,b,f)
  sxTx(41,{id,s,spl(th),sph(th),r,g,b,f})
end

function sxSetAlertThresh(id,tid,th,r,g,b,f)
  sxTx(21,{id,tid,spl(th),sph(th),r,g,b,f})
end

function setBaseConfig(bright)
  sxTx(3,{bright})
end

function sxSetAlert(id,r,g,b,f)
  sxTx(20,{id,r,g,b,f})
end

function sxUpdateAlert(id,v)
  if v~=nil then sxTx(22,{id,spl(v),sph(v)}) end
end

function sxCfgLinearGraph(rs,ls,lr,hr) 
  sxTx(40,{rs,ls,spl(lr),sph(lr),spl(hr),sph(hr)})
end

function sxUpdateLinearGraph(v)
  if v ~= nil then sxTx(42,{spl(v),sph(v)}) end
end

function sxInit()
  println('config shiftX2')
  setBaseConfig(sxBright)
  if sxOnInit~=nil then sxOnInit() end
end

function sxChkCan()
  id,ext,data=rxCAN(sxCan,0)
  if id==sxCanId then sxInit() end
  if id==sxCanId+60 and sxOnBut~=nil then sxOnBut(data[1]) end
end

function sxProcess()
  sxChkCan()
  if sxOnUpdate~=nil then sxOnUpdate() end
end

function sxTx(offset, data)
  txCAN(sxCan, sxCanId + offset, 1, data)
  sleep(10)
end

function spl(v) return bit.band(v,0xFF) end
function sph(v) return bit.rshift(bit.band(v,0xFF00),8) end

function onTick()
  sxProcess()
end

sxCanId = 0xE3600 + (256 * sxId)
println('shiftx2 base id ' ..sxCanId)

setTickRate(tickRate)
sxInit()

Shift Light + Twin Alert Example

This script shows a more complete example that demos a sequential shift light + two alerts.

Assumptions:

  • Engine Temperature on the 1st alert LED, connected to first analog channel
  • Oil Pressure on the 2nd alert LED, connected to second analog channel

Edit the script to change the analog channels you want to monitor.

Script

Copy and paste this entire script into the scripting window, replacing any existing script.

-- What CAN bus ShiftX2 is connected to. 0=CAN1, 1=CAN2
sxCan = 1

-- 0=first ShiftX2 on bus, 1=second ShiftX2 (if ADR1 jumper is cut)
sxId=0

--how often ShiftX2 is updated
tickRate=30

--Brightness, 0-100. 0=automatic brightness
sxBright=0

function sxOnUpdate()
  --add your code to update ShiftX2 alerts or linear graph during run time.
  --Runs continuously based on tickRate.
  
  --uncomment the below for OBDII RPM PID
  sxUpdateLinearGraph(readOBD2(12))

  --uncomment the below for Direct RPM on input 0
  --sxUpdateLinearGraph(getTimerRpm(0))

  --update engine temp alert
  sxUpdateAlert(0, getAnalog(0))

  --update oil pressure alert
  sxUpdateAlert(1, getAnalog(1))
end

function sxOnInit()
  --config shift light
  sxCfgLinearGraph(0,0,0,7000) --left to right graph, linear style, 0 - 7000 RPM range

  sxSetLinearThresh(0,0,3000,0,255,0,0) --green at 3000 RPM
  sxSetLinearThresh(1,0,5000,255,255,0,0) --yellow at 5000 RPM
  sxSetLinearThresh(2,0,6000,255,0,0,10) --red+flash at 6500 RPM

  --configure first alert (right LED) as engine temperature (F)
  sxSetAlertThresh(0,0,205,255,255,0,0) --yellow warning at 205F
  sxSetAlertThresh(0,1,225,255,0,0,10) -- red flash at 225F

  --configure second alert (left LED) as oil pressure (PSI)
  sxSetAlertThresh(1,0,0,255,0,0,10) --red flash below 15 psi
  sxSetAlertThresh(1,1,15,255,255,0,5) --yellow flash 15-20 PSI
  sxSetAlertThresh(1,2,20,0,0,0,0) --above 20, no alert
end

function sxOnBut(b)
  --called if the button state changes
  println('button: ' ..b)
end

---ShiftX2 functions

function sxSetLed(i,l,r,g,b,f)
  sxTx(10,{i,l,r,g,b,f})
end

function sxSetLinearThresh(id,s,th,r,g,b,f)
  sxTx(41,{id,s,spl(th),sph(th),r,g,b,f})
end

function sxSetAlertThresh(id,tid,th,r,g,b,f)
  sxTx(21,{id,tid,spl(th),sph(th),r,g,b,f})
end

function setBaseConfig(bright)
  sxTx(3,{bright})
end

function sxSetAlert(id,r,g,b,f)
  sxTx(20,{id,r,g,b,f})
end

function sxUpdateAlert(id,v)
  if v~=nil then sxTx(22,{id,spl(v),sph(v)}) end
end

function sxCfgLinearGraph(rs,ls,lr,hr) 
  sxTx(40,{rs,ls,spl(lr),sph(lr),spl(hr),sph(hr)})
end

function sxUpdateLinearGraph(v)
  if v ~= nil then sxTx(42,{spl(v),sph(v)}) end
end

function sxInit()
  println('config shiftX2')
  setBaseConfig(sxBright)
  if sxOnInit~=nil then sxOnInit() end
end

function sxChkCan()
  id,ext,data=rxCAN(sxCan,0)
  if id==sxCanId then sxInit() end
  if id==sxCanId+60 and sxOnBut~=nil then sxOnBut(data[1]) end
end

function sxProcess()
  sxChkCan()
  if sxOnUpdate~=nil then sxOnUpdate() end
end

function sxTx(offset, data)
  txCAN(sxCan, sxCanId + offset, 1, data)
  sleep(10)
end

function spl(v) return bit.band(v,0xFF) end
function sph(v) return bit.rshift(bit.band(v,0xFF00),8) end

function onTick()
  sxProcess()
end

sxCanId = 0xE3600 + (256 * sxId)
println('shiftx2 base id ' ..sxCanId)

setTickRate(tickRate)
sxInit()

Predictive Lap Timer Indicator

This script enables predictive lap time visualization.

How it works

A bar extends left or right from the center of the linear graph:

  • Green bar extending to the right indicates you're beating the best time
  • Red bar extending to the left means you're falling behind.
  • When you're close to the best time, the center blue LED illuminates.


Notes:

  • The script is designed for a +/- 10 second maximum delta - so if you're ahead or behind by 10 seconds, the linear graph will be fully illuminated center-right, or center-left.
  • You will need to complete a a full lap to train the predictive timer before the graph will update.

Script

Copy and paste this entire script into the scripting window, replacing any existing script.


-- Predictive time visualizer

-- What CAN bus ShiftX2 is connected to. 0=CAN1, 1=CAN2
sxCan = 1

-- 0=first ShiftX2 on bus, 1=second ShiftX2 (if ADR1 jumper is cut)
sxId=1

--how often ShiftX2 is updated
tickRate=30

--Brightness, 0-100. 0=automatic brightness
sxBright=0

--save best lap time
bestTime = 0

function sxOnUpdate()
  local predTime = getPredTime()

  local timeDiff = (bestTime - predTime) * 60
  -- rail values 
  timeDiff = math.max(timeDiff, -10)
  timeDiff = math.min(timeDiff, 10)
  --scale values from +/- 10 sec to a 0-200 scale
  timeDiff = (timeDiff + 10) * 10

  sxUpdateLinearGraph(timeDiff)

  --update best lap time if an updated lap time is available
  local lastLapTime = getLapTime()
  if lastLapTime < bestTime or bestTime == 0 then bestTime = lastLapTime end
end

function sxOnInit()
  --config shift light
  sxCfgLinearGraph(1,0,0,200) --center-out graph, linear style, +/- 10.0 seconds in 0.1 sec resolution

  sxSetLinearThresh(0,0,0,255,0,0,0) --red if you're falling behind best lap
  sxSetLinearThresh(1,0,80,0,0,255,0) --blue if you're close to best lap
  sxSetLinearThresh(2,0,110,0,255,0,0) --green if you're beating best lap
end

function sxOnBut(b)
  --if button is pressed, reset the best lap time
  bestTime = 0
end

---ShiftX2 functions

function sxSetLed(i,l,r,g,b,f)
  sxTx(10,{i,l,r,g,b,f})
end

function sxSetLinearThresh(id,s,th,r,g,b,f)
  sxTx(41,{id,s,spl(th),sph(th),r,g,b,f})
end

function sxSetAlertThresh(id,tid,th,r,g,b,f)
  sxTx(21,{id,tid,spl(th),sph(th),r,g,b,f})
end

function setBaseConfig(bright)
  sxTx(3,{bright})
end

function sxSetAlert(id,r,g,b,f)
  sxTx(20,{id,r,g,b,f})
end

function sxUpdateAlert(id,v)
  if v~=nil then sxTx(22,{id,spl(v),sph(v)}) end
end

function sxCfgLinearGraph(rs,ls,lr,hr) 
  sxTx(40,{rs,ls,spl(lr),sph(lr),spl(hr),sph(hr)})
end

function sxUpdateLinearGraph(v)
  if v ~= nil then sxTx(42,{spl(v),sph(v)}) end
end

function sxInit()
  println('config shiftX2')
  setBaseConfig(sxBright)
  if sxOnInit~=nil then sxOnInit() end
end

function sxChkCan()
  id,ext,data=rxCAN(sxCan,0)
  if id==sxCanId then sxInit() end
  if id==sxCanId+60 and sxOnBut~=nil then sxOnBut(data[1]) end
end

function sxProcess()
  sxChkCan()
  if sxOnUpdate~=nil then sxOnUpdate() end
end

function sxTx(offset, data)
  txCAN(sxCan, sxCanId + offset, 1, data)
  sleep(10)
end

function spl(v) return bit.band(v,0xFF) end
function sph(v) return bit.rshift(bit.band(v,0xFF00),8) end

function onTick()
  sxProcess()
end

sxCanId = 0xE3600 + (256 * sxId)

setTickRate(tickRate)
sxInit()

Boost Gauge

This script visualizes a single analog input channel on the linear graph.

How it works

The script configures the linear graph, then reads an analog channel and updates the graph with the current value. In this case, the value represents boost level measured from a MAP sensor.

Assumptions

  • MAP sensor channel is on the first Analog channel, and reads in KPa - typically 0-255. You can also connect this to the MAP reading on OBDII (PID 11)

Script

Copy and paste this entire script into the scripting window, replacing any existing script.

-- What CAN bus ShiftX2 is connected to. 0=CAN1, 1=CAN2
sxCan = 1

-- 0=first ShiftX2 on bus, 1=second ShiftX2 (if ADR1 jumper is cut)
sxId=1

--how often ShiftX2 is updated
tickRate=30

--Brightness, 0-100. 0=automatic brightness
sxBright=0

function sxOnUpdate()
  local map = getAnalog(0) --MAP sensor in KPa
  --convert to PSI boost
  local boost = math.max(map - 100, 0) * .145038
  sxUpdateLinearGraph(boost)
  println(map ..' ' ..boost)
end

function sxOnInit()
  --config shift light
  sxCfgLinearGraph(0,0,0, 20) --left to right graph, linear style, 0 - 20 PSI boost

  sxSetLinearThresh(0,0,0,0,255,0,0) --green starting at no boost
  sxSetLinearThresh(1,0,10,255,255,0,0) --yellow starting at 10 PSI boost
  sxSetLinearThresh(2,0,15,255,0,0,10) --red+flash at 15 PSI boost
end

function sxOnBut(b)
  --called if the button state changes
  println('button: ' ..b)
end

---ShiftX2 functions

function sxSetLed(i,l,r,g,b,f)
  sxTx(10,{i,l,r,g,b,f})
end

function sxSetLinearThresh(id,s,th,r,g,b,f)
  sxTx(41,{id,s,spl(th),sph(th),r,g,b,f})
end

function sxSetAlertThresh(id,tid,th,r,g,b,f)
  sxTx(21,{id,tid,spl(th),sph(th),r,g,b,f})
end

function setBaseConfig(bright)
  sxTx(3,{bright})
end

function sxSetAlert(id,r,g,b,f)
  sxTx(20,{id,r,g,b,f})
end

function sxUpdateAlert(id,v)
  if v~=nil then sxTx(22,{id,spl(v),sph(v)}) end
end

function sxCfgLinearGraph(rs,ls,lr,hr) 
  sxTx(40,{rs,ls,spl(lr),sph(lr),spl(hr),sph(hr)})
end

function sxUpdateLinearGraph(v)
  if v ~= nil then sxTx(42,{spl(v),sph(v)}) end
end

function sxInit()
  println('config shiftX2')
  setBaseConfig(sxBright)
  if sxOnInit~=nil then sxOnInit() end
end

function sxChkCan()
  id,ext,data=rxCAN(sxCan,0)
  if id==sxCanId then sxInit() end
  if id==sxCanId+60 and sxOnBut~=nil then sxOnBut(data[1]) end
end

function sxProcess()
  sxChkCan()
  if sxOnUpdate~=nil then sxOnUpdate() end
end

function sxTx(offset, data)
  txCAN(sxCan, sxCanId + offset, 1, data)
  sleep(10)
end

function spl(v) return bit.band(v,0xFF) end
function sph(v) return bit.rshift(bit.band(v,0xFF00),8) end

function onTick()
  sxProcess()
end

sxCanId = 0xE3600 + (256 * sxId)
println('shiftx2 base id ' ..sxCanId)

setTickRate(tickRate)
sxInit()

Only Alerts

This script enables 3 alert channels:

  • Left alert for oil pressure
  • Right alert for engine temperature
  • Center alert for Air/Fuel ratio

How it works

The script configures the left and right alert indicators, then configures the center graph to visualize safe and dangerous AFR ranges. During operation, the analog channels for oil pressure and engine temperature are read and updates the alert indicators. The AFR channel is read and updates the linear graph.

Script

Copy and paste this entire script into the scripting window, replacing any existing script.

function onTick()
--implement me
end

ShiftX2 starter script

Use this as a starter for your own custom script

-- What CAN bus ShiftX2 is connected to. 0=CAN1, 1=CAN2
sxCan = 0

-- 0=first ShiftX2 on bus, 1=second ShiftX2 (if ADR1 jumper is cut)
sxId=0

--how often ShiftX2 is updated
tickRate=30

--Brightness, 0-100. 0=automatic brightness
sxBright=0

function sxOnUpdate()
  --add your code to update ShiftX2 alerts or linear graph during run time.
  --Runs continuously based on tickRate.

end

function sxOnInit()
  --add your code for configuring ShiftX2. Runs once during startup

end

function sxOnBut(b)
  --called if the button state changes
  println('button: ' ..b)
end

---ShiftX2 functions
--===============
--Reference. Delete me to save space
--===============

--function sxSetLed(index,length,red,green,blue,flash)
--Set an individual LED
--index: LED index, starting at 0
--length: number of LEDs to set at once
--red: Red value (0-255)
--green: Green value (0-255)
--blue: Blue value(0-255)
--flashHz: Flash rate, in Hz; 0=no flash

--sxSetLinearThresh(thresholdId,segmentLength,thresholdValue,red,green,blue,flashHz)
--Setup a threshold for the linear graph
--thresholdId: Threshold ID to set. from 0-4. define in ascending order.
--segmentLength: Length of the segment when in stepped graph mode. ignored for smooth mode.
--thresholdValue: Value for this threshold.
--red: Red value (0-255)
--green: Green value (0-255)
--blue: Blue value (0-255)
--flashHz: Flash rate, in Hz; 0=no flash

--sxSetAlertThresh(alertId,thresholdId,thresholdValue,red,green,blue,flashHz)
--Setup a threshold for an alert indicator
--alertId: Id of the alert to configure
--thresholdId: Threshold ID to set. from 0-4. define in ascending order.
--thresholdValue: Value for this threshold.
--red: Red value (0-255)
--green: Green value (0-255)
--blue: Blue value (0-255)
--flashHz: Flash rate, in Hz; 0=no flash

--sxSetAlert(alertId,red,green,blue,flashHz)
--Directly sets an alert indicator
--alertId: Alert Id to set
--red: Red value (0-255)
--green: Green value (0-255)
--blue: Blue value (0-255)
--flashHz: Flash rate, in Hz; 0=no flash

--sxUpdateAlert(alertId,currentValue)
--Updates Current alert value, using the previously configured thresholds
--alertId: Alert Id to set 
--currentValue: Updated value

--sxCfgLinearGraph(renderStyle,linearStyle,lowRange,highRange)
--Configures the linear graph
--renderStyle: 0=left->right, 1=center,2=right->left
--linearStyle: 0=smooth/interpolated, 1=stepped
--lowRange: low range of the graph
--highRange: high range of the graph (ignored if stepped linear style)

--sxUpdateLinearGraph(currentValue)
--Updates the linear graph value, using the previously configured thresholds
--currentValue: Updated value
--===============
--End reference
--===============

function sxSetLed(i,l,r,g,b,f)
  sxTx(10,{i,l,r,g,b,f})
end

function sxSetLinearThresh(id,s,th,r,g,b,f)
  sxTx(41,{id,s,spl(th),sph(th),r,g,b,f})
end

function sxSetAlertThresh(id,tid,th,r,g,b,f)
  sxTx(21,{id,tid,spl(th),sph(th),r,g,b,f})
end

function setBaseConfig(bright)
  sxTx(3,{bright})
end

function sxSetAlert(id,r,g,b,f)
  sxTx(20,{id,r,g,b,f})
end

function sxUpdateAlert(id,v)
  if v~=nil then sxTx(22,{id,spl(v),sph(v)}) end
end

function sxCfgLinearGraph(rs,ls,lr,hr) 
  sxTx(40,{rs,ls,spl(lr),sph(lr),spl(hr),sph(hr)})
end

function sxUpdateLinearGraph(v)
  sxTx(42,{spl(v),sph(v)})
end

function sxInit()
  println('config shiftX2')
  setBaseConfig(sxBright)
  if sxOnInit~=nil then sxOnInit() end
end

function sxChkCan()
  id,ext,data=rxCAN(sxCan,0)
  if id==sxCanId then sxInit() end
  if id==sxCanId+60 and sxOnBut~=nil then sxOnBut(data[1]) end
end

function sxProcess()
  sxChkCan()
  if sxOnUpdate~=nil then sxOnUpdate() end
end

function sxTx(offset, data)
  txCAN(sxCan, sxCanId + offset, 1, data)
  sleep(10)
end

function spl(v) return bit.band(v,0xFF) end
function sph(v) return bit.rshift(bit.band(v,0xFF00),8) end

function onTick()
  sxProcess()
end

sxCanId = 0xE3600 + (256 * sxId)
println('shiftx2 base id ' ..sxCanId)

setTickRate(tickRate)
sxInit()

ShiftX2 CAN bus API

Overview

The CAN bus API provides the configuration and control interface for ShiftX2.

Two styles of control are available:

  • Low level control of LEDs - the ability to discretely set LED color and flash behavior
  • High level control - configuring alert thresholds and linear graph up front, and then providing simple value updates

CAN Messages

CAN base ID

CAN base ID is 0xE3600 (931328)

Cutting the jumper ADR1 will add 256 to the base ID, allowing up to two ShiftX2 displays on the same CAN bus.

CAN Baud rate

500K and 1MB rates are supported.

500K is enabled by default; cut the jumper ADR2 on the bottom of ShiftX2 to enable 1MB.

Configuration / Runtime Options

Announcement

Broadcast by the device upon power up

CAN ID: Base + 0

Offset What Value
0 Total LEDs Total number of LEDs on the device
1 Alert Indicators Number of logical alert indicators
2 Linear Bar Graph Length Number of LEDs in linear graph
3 Major Version Firmware major version number
4 Minor Version Firmware minor version number
5 Patch Version Firmware patch version number

Statistics

Statistics information, broadcast periodically by device

CAN ID: Base + 2

Offset What Value
0 Major Version Firmware major version number
1 Minor Version Firmware minor version number
2 Patch Version Firmware patch version number

Set Configuration Parameters Group 1

Sets various configuration options.

CAN ID: Base + 3

Offset What Value
0 Brightness 0 - 100; 1 = dimmest; 100 = brightest; 0 = automatic brightness control using built-in light sensor.
1 Automatic brightness scaling (Optional) 0-255; default=51. adjust this value to adjust the relative gain of the built-in light sensor when in automatic brightness mode.

Set Discrete LED

A low level function to directly set any LED on the device.

CAN ID: Base + 10

Offset What Value
0 LED index 0 -> # of LEDs on device
1 Number of LEDs to set 0 -> # of LEDs on device (0 = set all remaining)
2 Red 0 - 255
3 Green 0 - 255
4 Blue 0 - 255
5 Flash 0-10Hz (0 = full on)

Alert Indicators

Alert Indicators are typically single LEDs or a group of LEDs treated as one logical unit. This is defined by the hardware configuration of the device.

Set Alert

Directly set an alert indicator

CAN ID: Base + 20

Offset What Value
0 Alert ID 0 -> # of Alert indicators
1 Red 0 - 255
2 Green 0 - 255
3 Blue 0 - 255
4 Flash 0-10Hz (0 = full on)

Set Alert Threshold

Configures an alert threshold. Up to 5 thresholds can be configured per alert indicator.

Notes:

  • If the current value is greater than the last threshold, then the last threshold is selected.
  • The first threshold may have a threshold value >= 0; remaining thresholds must be > 0

CAN ID: Base + 21

Offset What Value
0 Alert ID 0 -> # of Alert indicators
1 Threshold ID 0 - 4
2 Threshold (low byte)
3 Threshold (high byte)
4 Red 0 - 255
5 Green 0 - 255
6 Blue 0 - 255
7 Flash Hz 0 - 10 (0 = full on)

Update Current Alert Value

Updates the current value for an alert indicator. The configured alert thresholds will be applied to the current value.

CAN ID: Base + 22

Offset What Value
0 Alert ID 0 -> # of Alert indicators
1 Value (low byte)
2 Value (high byte)

Linear Graph

The linear graph mode provides visualizations for common scenarios:

  • Sequential RPM shift light where the progression is stepped
  • Linear bar graph to linearly indicate a sensor value
  • Center left/right graph to indicate +/- performance against a reference - such as visualizing current predictive time vs best time

Power up default configuration

Upon power up the linear graph is configured:

  • Rendering style: left->right
  • Linear style: stepped
  • Low Range: 0
  • High Range: N/A
  • Threshold :
    • Threshold value: 3000 / segment length: 3 / color RGB: (0, 255, 0) / flash: 0
    • Threshold value: 5000 / segment length: 5 / color RGB: (0, 255, 255) / flash: 0
    • Threshold value: 7000 / segment length: 7 / color RGB: (255, 0, 0) / flash: 5

Configure Linear Graph

Configures the options for the linear graph portion of the device.

Rendering style:

  • If left->right, linear graph illuminates left to right
  • If centered, values below the mid-point in the range extend from the center to the left, and values above the mid-point extend from the center to the right.
  • If right->left, linear graph illuminates right to left

Linear style:

  • if smooth, graph length is updated smoothly by interpolating the current value in-between LEDs
  • If stepped, creates the visual effect of stepped progressions by setting the segment length of the threshold configuration. High Range of configuration is ignored.


CAN ID: Base + 40

Offset What Value
0 Rendering Style 0 = left->right, 1=center, 2=right->left
1 Linear Style 0 = Smooth / interpolated, 1 = stepped
2 Low Range (low byte)
3 Low Range (high byte)
4 High Range (low byte) (ignored if linear style = stepped)
5 High Range (high byte) (ignored if linear style = stepped)

Set Linear Graph Threshold

Configures a linear threshold. Up to 5 thresholds can be configured

Notes:

  • If the current value is greater than the last threshold, then the last threshold is selected.
  • The first threshold may have a threshold value >= 0; remaining thresholds must be > 0

CAN ID: Base + 41

Offset What Value
0 Threshold ID 0 - 4
1 Segment Length 0 -> # of LEDs on device (ignored if linear style is ‘smooth’)
2 Threshold (low byte)
3 Threshold (high byte)
4 Red 0 - 255
5 Green 0 - 255
6 Blue 0 - 255
7 Flash Hz 0 - 10 (0 = full on)

Update Current Linear Graph Value

Updates the current value for the linear graph

CAN ID: Base + 42

Offset What Value
0 Value (low byte)
1 Value (high byte)

Notifications

Notifications related to events broadcasted from ShiftX2

Button State

Indicates a change in the button state

CAN ID: Base + 60

Offset What Value
0 Button state 1 = button is pressed; 0 = button