-
-
Save psallandre/4ca99f4684d9903007a38ed9a5bba7f8 to your computer and use it in GitHub Desktop.
Improved version with CAN mapping in the config string
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
-- 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