Skip to content

Instantly share code, notes, and snippets.

@psallandre
Forked from kosenko-max/racecapture3.lua
Last active May 25, 2016 22:04
Show Gist options
  • Save psallandre/4ca99f4684d9903007a38ed9a5bba7f8 to your computer and use it in GitHub Desktop.
Save psallandre/4ca99f4684d9903007a38ed9a5bba7f8 to your computer and use it in GitHub Desktop.
Improved version with CAN mapping in the config string
-- Copyright 2016 Mash at boostedforums.net
-- Minify before use by https://mothereff.in/lua-minifier
-- Editor https://ace.c9.io/build/kitchen-sink.html
-- don't remove excessive commas or comments - minify will deal with it
function dump(o)
if type(o) == 'table' then
local s = '{ '
for k,v in pairs(o) do
if type(k) ~= 'number' then k = '"'..k..'"' end
s = s .. '['..k..'] = ' .. dump(v) .. ','
end
return s .. '} '
else
return tostring(o)
end
end
function initCAN( channel, baud )
end
function setTickRate(rate)
end
function getUptime()
return 0
end
local chanId = 0
function addChannel(name,sampleRate,precision,minv,maxv,unit)
print("addChannel", name,sampleRate,precision,minv,maxv, unit)
chanId = chanId + 1
return chanId
end
function txCAN(channel, id, isExtended, data, timeout )
print("txCAN", channel, id, isExtended, dump(data), timeout)
end
function rxCAN(channel, timeout )
print("rxCAN", channel, timeout)
end
function collectgarbage()
end
-- ========================= CAN CONFIG =======================================
local canCon ="0x7E0,0x805100;160;8,TPS,0,100,%,100/255;8,APP,0,100,%,1/2,-16@"
local canMap = {}
local sb,sl,sm = string.byte,string.len,string.match
function readOne(pos)
local c = sb(canCon,pos)
if c==nil then return nil,pos+1 end
if (c > 47 and c < 58) or c==45 then -- read number
local nums = sm(canCon,"[-.%xxX]+",pos)
local num = tonumber(nums)
local pos2 = pos+sl(nums)
c=sb(canCon,pos2)
if c==42 or c==47 then -- MULTIPLY or DIVIDE
pos2=pos2+1
local nums2=sm(canCon,"[-.%xxX]+",pos2)
local num2=tonumber(nums2)
pos2 = pos2+sl(nums2)
if c==42 then num=num*num2 else num=num/num2 end
end
return num,pos2
end
-- Read string
local st = sm(canCon,"[^,;@]+",pos)
if st==nil then return nil,pos+1
else return st, pos+sl(st) end
end
function ss(pos)
return string.sub(canCon,pos,pos)
end
function canRDmap()
local cmi,res,pos = 1,nil,1
while pos <= sl(canCon) do
canMap[cmi]=nil -- separator of requests
canMap[cmi+1],pos=readOne(pos) -- address
canMap[cmi+2],pos=readOne(pos+1) -- pid
if ss(pos) =="," then
canMap[cmi+3],pos=readOne(pos+1) -- priority
else canMap[cmi+3]=1 end
--print("REQUEST Address: "..canMap[cmi+1].." PID: "..canMap[cmi+2].." Priority: "..canMap[cmi+3])
local cmi_len = cmi+4
canMap[cmi_len]=0
cmi=cmi+5
while ss(pos)~="@" do
-- Address,PID,Priority (1)
-- ;Bits,Name,Min,Max,Unit,Mult(1),Add(0),Signed(0/1 - default 0)
-- ;Bits - skip number of bits forward
-- @
-- nil, address, pid, priority, length - request
-- bits, nil - skip
-- bits, channelId, mult, add, signed - channel
--print(" start char "..ss(pos))
local name,minv,maxv,precision,unit,mult = "",0,0,0,"",1
canMap[cmi],pos=readOne(pos+1) --bits
--print(" bits: "..canMap[cmi])
canMap[cmi_len]=canMap[cmi_len]+canMap[cmi] -- count length
if ss(pos)~="," then
--print(" skip "..ss(pos))
canMap[cmi+1]=nil -- Skip
cmi=cmi+2
else
name,pos = readOne(pos+1)
minv,pos = readOne(pos+1)
maxv,pos = readOne(pos+1)
if ss(pos)=="," then unit,pos = readOne(pos+1) --unit
else unit = "" end
if ss(pos)=="," then mult,pos = readOne(pos+1) --mult
else mult=1 end
canMap[cmi+2]=mult
if ss(pos)=="," then canMap[cmi+3],pos = readOne(pos+1) --add
else canMap[cmi+3]=0 end
if ss(pos)=="," then canMap[cmi+4],pos = readOne(pos+1) --sign
else canMap[cmi+4]=0 end
while mult < 1 do
precision=precision+1
mult=mult*10
end
canMap[cmi+1]=addChannel(name,1000,precision,minv,maxv,unit)
cmi=cmi+5
end
end
pos=pos+1
end
canCon = nil -- Clean memory from large string we won't use anymore
end
function canRDall(count)
-- nil, address, pid, priority, length - request
-- bits, nil - skip
-- bits, channelId, mult, add, signed - channel
local i = 1
while canMap[i+1]~=nil do
if (count % canMap[i+3]) == 0 then -- Priority implement
local data = canRD(canMap[i+1],canMap[i+2],canMap[i+4])
i=i+5
local bit = 1
while canMap[i]~=nil do -- Set Channels
if canMap[i+1]~=nil then
if data ~= nil then
local val = bitsToN(data,bit,canMap[i],canMap[i+4])
val=val*canMap[i+2]+canMap[i+3]
setChannel(canMap[i+1],val)
end
bit=bit+canMap[i]
i=i+5
else -- skip bits
bit=bit+canMap[i]
i=i+2
end
end
end
end
end
-- =========== UP TO 24 BIT NUMBER EXTRACTION FROM BYTE ARRAY ==================
local band, bxor, bnot = bit.band, bit.bxor, bit.bnot
local lshift, rshift = bit.lshift, bit.rshift
function bitsToN(d,startBit,length,signed)
local shift = (8 - ((startBit+length-1) % 8)) % 8
local startByte = 1 + (startBit - 1 - ((startBit-1) % 8)) / 8--TODO: to //
local bnumb = d[startByte]
if (length+shift) > 8 then
bnumb = d[startByte+1] + lshift(bnumb,8)
if (length+shift) > 16 then
bnumb = d[startByte+2] + lshift(bnumb,8)
end
end
bnumb = rshift(bnumb,shift)
bnumb = band(bnumb,2^length-1)
if signed and bnumb > 0x7FFF then
bnumb = 0 - lshift(band(-bnot(0x1000+rshift(number,8)),0xFF),8)
- band(-bxor(0x1000+band(number,0xFF),0),0xFF) - 1
end
return bnumb
end
--============================ READ CAN DATA AND RETURN DATA BYTE ARRAY ========
function canRD(address,pid,reqLength) -- TODO: Check it works without padding
local req
if pid > 255 then -- MODE 23
req = {5,0x23,rshift(pid,16),rshift(pid,8),band(pid,0xFF),reqLength}
else -- MODE21
req={2,0x21,pid}
end
res = txCAN(0, address, 0, req, 100) -- Send request
if res ~= 1 then return nil end
local data = {}
local id, ext, d1 = rxCAN(0,100) -- Read Response
if id == nil then return nil end
-- for r,d in ipairs(d1) do print(d..",") end
-- println(" ")
local i = 1
local s = 3
if d1[1] == 0x10 then s=s+1 end -- Multimessaging
if pid < 256 then s=s+1 end -- Mode23 has more data
while s<9 do
data[i]=d1[s]
i=i+1
s=s+1
end
if d1[1] ~= 0x10 then return data end -- Not multimessaging, so quit
-- Read multi messages
res = txCAN(0, address, 0, {48,8,0},100)
if res ~= 1 then return nil end
local messages = (d1[2] + 1) / 7
for m=1,messages do
local id, ext, d1 = rxCAN(0,100)
if id == nil then return nil end
-- print(m..": ")
-- for r,d in ipairs(d1) do print(d..",") end
-- println(" ")
local s=2
while s<9 and i<reqLength+1 do
data[i]=d1[s]
i=i+1
s=s+1
end
end
return data
end
-- ========================= MAIN CYCLE =======================================
local fpChan,tgtFP,chCANHz = 3,43.5,addChannel("CAN", 1, 0, 0, 300, "Hz")
initCAN(0, 500000)
setTickRate(1000)
for i=1,10 do rxCAN(0,5) end -- Clear CAN buffer
canRDmap()
collectgarbage()
function onTick()
local started,mc = getUptime(),0
print("START")
canRDall(mc)
collectgarbage()
mc = mc + 1
end
onTick()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment