+end
+
+---
+-- return bytes 'sstrat' to 'send' from a table
+function dumpTable(tab, header, tstart, tend)
+ res=""
+ for i=tstart, tend do
+ res=res..tab[i].." "
+ end
+ if (string.len(header)==0) then return res
+ else return (header.." #"..(tend-tstart+1).."\n"..res) end
+end
+
+function dump3rdPartyCash1(tag , seg)
+ local uid=tag.MCD..tag.MSN0..tag.MSN1..tag.MSN2
+ local stamp=tag.SEG[seg].data[0].." "..tag.SEG[seg].data[1].." "..tag.SEG[seg].data[2]
+ local datastamp=tag.SEG[seg].data[20].." "..tag.SEG[seg].data[21].." "..tag.SEG[seg].data[22]
+ local balance=tonumber(tag.SEG[seg].data[32]..tag.SEG[seg].data[33] ,16)
+ local balancecrc=utils.Crc8Legic(uid..tag.SEG[seg].data[32]..tag.SEG[seg].data[33])
+ local mirror=tonumber(tag.SEG[seg].data[35]..tag.SEG[seg].data[36] ,16)
+ local mirrorcrc=utils.Crc8Legic(uid..tag.SEG[seg].data[35]..tag.SEG[seg].data[36])
+ local lastbal0=tonumber(tag.SEG[seg].data[39]..tag.SEG[seg].data[40] ,16)
+ local lastbal1=tonumber(tag.SEG[seg].data[41]..tag.SEG[seg].data[42] ,16)
+ local lastbal2=tonumber(tag.SEG[seg].data[43]..tag.SEG[seg].data[44] ,16)
+
+ test=""
+ -- display decoded/known stuff
+ print("\n------------------------------")
+ print("Tag-ID:\t\t "..uid)
+ print("Stamp:\t\t "..stamp)
+ print("UID-Mapping: \t\t"..("%06d"):format(tonumber(tag.SEG[seg].data[46]..tag.SEG[seg].data[47]..tag.SEG[seg].data[48], 16)))
+ print("------------------------------")
+ print("checksum 1:\t\t "..tag.SEG[seg].data[31].." ("..compareCrc(utils.Crc8Legic(uid..dumpTable(tag.SEG[seg].data, "", 19, 30)), tag.SEG[seg].data[31])..")")
+ print("checksum 2:\t\t "..tag.SEG[seg].data[34].." ("..compareCrc(utils.Crc8Legic(uid..dumpTable(tag.SEG[seg].data, "", 32, 33)), tag.SEG[seg].data[34])..")")
+ print("checksum 3:\t\t "..tag.SEG[seg].data[37].." ("..compareCrc(utils.Crc8Legic(uid..dumpTable(tag.SEG[seg].data, "", 35, 36)), tag.SEG[seg].data[37])..")")
+
+ print("checksum 4:\t\t "..tag.SEG[seg].data[55].." ("..compareCrc(utils.Crc8Legic(uid..dumpTable(tag.SEG[seg].data, "", 46, 54)), tag.SEG[seg].data[55])..")")
+ print("checksum 5:\t\t "..tag.SEG[seg].data[62].." ("..compareCrc(utils.Crc8Legic(uid..dumpTable(tag.SEG[seg].data, "", 56, 61)), tag.SEG[seg].data[62])..")")
+ print("checksum 6:\t\t "..tag.SEG[seg].data[73].." ("..compareCrc(utils.Crc8Legic(uid..dumpTable(tag.SEG[seg].data, "", 63, 72)), tag.SEG[seg].data[73])..")")
+ print("checksum 7:\t\t "..tag.SEG[seg].data[89].." ("..compareCrc(utils.Crc8Legic(uid..dumpTable(tag.SEG[seg].data, "", 74, 88)), tag.SEG[seg].data[89])..")")
+ print("------------------------------")
+ print(string.format("Balance:\t\t %3.2f", balance/100).." ".."("..compareCrc(balancecrc, tag.SEG[seg].data[34])..")")
+ print(string.format("Shadow:\t\t\t %3.2f", mirror/100).." ".."("..compareCrc(balancecrc, tag.SEG[seg].data[37])..")")
+ print("------------------------------")
+ print(string.format("History 1:\t\t %3.2f", lastbal0/100))
+ print(string.format("History 2:\t\t %3.2f", lastbal1/100))
+ print(string.format("History 3:\t\t %3.2f", lastbal2/100))
+ print("------------------------------\n")
+end
+---
+-- compare two bytes
+function compareCrc(calc, guess)
+ calc=("%02x"):format(calc)
+ if (calc==guess) then return "valid"
+ else return "error "..calc.."!="..guess end
+end
+
+---
+-- compare 4 bytes
+function compareCrc16(calc, guess)
+ calc=("%04x"):format(calc)
+ if (calc==guess) then return "valid"
+ else return "error "..calc.."!="..guess end
+end
+
+---
+-- repair / fix (yet known) crc's of a '3rd Party Cash-Segment'
+-- not all bytes know until yet !!
+function fix3rdPartyCash1(uid, data)
+ if(#data==95) then
+ -- checksum 1
+ data[31]=("%02x"):format(utils.Crc8Legic(uid..dumpTable(data, "", 19, 30)))
+ -- checksum 2
+ data[34]=("%02x"):format(utils.Crc8Legic(uid..data[32]..data[33]))
+ -- checksum 3
+ data[37]=("%02x"):format(utils.Crc8Legic(uid..data[35]..data[36]))
+ -- checksum 4
+ data[55]=("%02x"):format(utils.Crc8Legic(uid..dumpTable(data, "", 46, 54)))
+ -- checksum 5
+ data[62]=("%02x"):format(utils.Crc8Legic(uid..dumpTable(data, "", 56, 61)))
+ -- checksum 6
+ data[73]=("%02x"):format(utils.Crc8Legic(uid..dumpTable(data, "", 63, 72)))
+ -- checksum 7
+ data[89]=("%02x"):format(utils.Crc8Legic(uid..dumpTable(data, "", 74, 88)))
+ return data
+ end
+end
+
+---
+-- edit uid 3rd party cash
+function edit3rdUid(mapid, uid, data)
+ mapid=("%06x"):format(tonumber(mapid, 10))
+ data[46]=string.sub(mapid, 0 ,2)
+ data[47]=string.sub(mapid, 3 ,4)
+ data[48]=string.sub(mapid, 5 ,6)
+ return fix3rdPartyCash1(uid, data)
+end
+
+---
+-- edit balance 3rd party cash
+function edit3rdCash(new_cash, uid, data)
+ new_cash=("%04x"):format(new_cash)
+ data[32]=string.sub(new_cash, 0,2)
+ data[33]=string.sub(new_cash, 3,4)
+ data[34]=("%02x"):format(utils.Crc8Legic(uid..new_cash))
+ data[35]=string.sub(new_cash, 0,2)
+ data[36]=string.sub(new_cash, 3,4)
+ data[37]=("%02x"):format(utils.Crc8Legic(uid..new_cash))
+ data[39]=string.sub(new_cash, 0,2)
+ data[40]=string.sub(new_cash, 3,4)
+ data[41]='00'
+ data[42]='00'
+ data[43]='00'
+ data[44]='00'
+ return fix3rdPartyCash1(uid, data)
+end
+
+---
+-- repair / fix crc's of a 'Legic-Cash-Segment'
+function fixLegicCash(data)
+ if(#data==32 and data[7]=="01") then
+ local crc1, crc2, crc3
+ crc1=("%04x"):format(utils.Crc16(dumpTable(data, "", 0, 12)))
+ crc2=("%04x"):format(utils.Crc16(dumpTable(data, "", 15, 20)))
+ crc3=("%04x"):format(utils.Crc16(dumpTable(data, "", 23, 29)))
+ data[13]=string.sub(crc1, 0, 2)
+ data[14]=string.sub(crc1, 3, 4)
+ data[21]=string.sub(crc2, 0, 2)
+ data[22]=string.sub(crc2, 3, 4)
+ data[30]=string.sub(crc3, 0, 2)
+ data[31]=string.sub(crc3, 3, 4)
+ return data
+ end
+end
+
+---
+-- chack for signature of a '3rd Party Cash-Segment'
+-- not all bytes know until yet !!
+function check43rdPartyCash1(uid, data)
+ if(#data==95) then
+ -- too explicit checking will avoid fixing ;-)
+ if (compareCrc(utils.Crc8Legic(uid..dumpTable(data, "", 19, 30)), data[31])=="valid") then
+ --if (compareCrc(utils.Crc8Legic(uid..data[32]..data[33]), data[34])=="valid") then
+ --if (compareCrc(utils.Crc8Legic(uid..data[35]..data[36]), data[37])=="valid") then
+ --if (compareCrc(utils.Crc8Legic(uid..dumpTable(data, "", 56, 61)), data[62])=="valid") then
+ --if (compareCrc(utils.Crc8Legic(uid..dumpTable(data, "", 74, 88)), data[89])=="valid") then
+ io.write("3rd Party Cash-Segment detected ")
+ return true
+ --end
+ --end
+ --end
+ --end
+ end
+ end
+ return false
+end
+
+---
+-- chack for signature of a 'Legic-Cash-Segment'
+function check4LegicCash(data)
+ if(#data==32) then
+ local stamp_len=(#data-25)
+ local stamp=""
+ for i=0, stamp_len-1 do
+ stamp=stamp..data[i].." "
+ end
+ if (data[7]=="01") then
+ if (("%04x"):format(utils.Crc16(dumpTable(data, "", 0, 12))) == data[13]..data[14]) then
+ if (("%04x"):format(utils.Crc16(dumpTable(data, "", 15, 20))) == data[21]..data[22]) then
+ if (("%04x"):format(utils.Crc16(dumpTable(data, "", 23, 29))) == data[30]..data[31]) then
+ io.write("Legic-Cash Segment detected ")
+ return true
+ end
+ end
+ end
+ end
+ end
+ return false
+end
+---
+-- calculate Master-Token crc
+function calcMtCrc(bytes)
+ --print(#bytes)
+ local cmd=bytes[1]..bytes[2]..bytes[3]..bytes[4]..bytes[7]..bytes[6]..bytes[8]
+ local len=(tonumber(0xfc ,10)-("%d"):format('0x'..bytes[7]))
+ for i=1, len do
+ cmd=cmd..bytes[8+i]
+ end
+ local res=("%02x"):format(utils.Crc8Legic(cmd))
+ return res
+end
+
+---
+-- check all segmnet-crc
+function checkAllSegCrc(tag)
+ if (istable(tag.SEG[0])) then
+ for i=0, #tag.SEG do
+ crc=calcSegmentCrc(tag, i)
+ tag.SEG[i].crc=crc
+ end
+ else return print("Matser-Token / unsegmented Tag") end
+end
+
+---
+-- check all segmnet-crc
+function checkAllKghCrc(tag)
+ if (istable(tag.SEG[0])) then
+ for i=0, #tag.SEG do
+ crc=calcKghCrc(tag, i)
+ if (tag.SEG[i].kgh) then
+ tag.SEG[i].data[#tag.SEG[i].data-1]=crc
+ end
+ end
+ end
+end
+
+---
+-- build kghCrc credentials
+function kghCrcCredentials(tag, segid)
+ if (istable(tag) and istable(tag.SEG[0])) then
+ local x='00'
+ if (type(segid)=="string") then segid=tonumber(segid,10) end
+ if (segid>0) then x='93' end
+ local cred = tag.MCD..tag.MSN0..tag.MSN1..tag.MSN2..("%02x"):format(tag.SEG[segid].WRP)
+ cred = cred..("%02x"):format(tag.SEG[segid].WRC)..("%02x"):format(tag.SEG[segid].RD)..x
+ for i=0, #tag.SEG[segid].data-2 do
+ cred = cred..tag.SEG[segid].data[i]
+ end
+ return cred
+ end
+end
+
+---
+-- validate kghCRC to segment in tag-table
+function checkKghCrc(tag, segid)
+ if (type(tag.SEG[segid])=='table') then
+ if (tag.data[3]=="11" and tag.raw=="9f" and tag.SSC=="ff") then
+ local data=kghCrcCredentials(tag, segid)
+ if (("%02x"):format(utils.Crc8Legic(data))==tag.SEG[segid].data[tag.SEG[segid].len-5-1]) then return true; end
+ else return false; end
+ else oops("'Kaba Group header' detected but no Segment-Data found") end
+end
+
+---
+-- calcuate kghCRC for a given segment
+function calcKghCrc(tag, segid)
+ if (istable(tag.SEG[0])) then
+ -- check if a 'Kaber Group Header' exists
+ local i
+ local data=kghCrcCredentials(tag, segid)
+ return ("%02x"):format(utils.Crc8Legic(data))
+ end
+end
+
+---
+-- build segmentCrc credentials
+function segmentCrcCredentials(tag, segid)
+ if (istable(tag.SEG[0])) then
+ local cred = tag.MCD..tag.MSN0..tag.MSN1..tag.MSN2
+ cred = cred ..tag.SEG[segid].raw[1]..tag.SEG[segid].raw[2]..tag.SEG[segid].raw[3]..tag.SEG[segid].raw[4]
+ return cred
+ else return print("Master-Token / unsegmented Tag!") end
+end
+
+---
+-- validate segmentCRC for a given segment
+function checkSegmentCrc(tag, segid)
+ local data=segmentCrcCredentials(tag, segid)
+ if (("%02x"):format(utils.Crc8Legic(data))==tag.SEG[segid].crc) then
+ return true
+ end
+ return false
+end
+
+---
+-- calculate segmentCRC for a given segment
+function calcSegmentCrc(tag, segid)
+ if (istable(tag.SEG[0])) then
+ -- check if a 'Kaber Group Header' exists
+ local data=segmentCrcCredentials(tag, segid)
+ return ("%02x"):format(utils.Crc8Legic(data))
+ end
+end