Search code examples
luachecksum

Function with Checksum Function Producing nACK Responses


For my current application, I'm writing up a plugin that will allow a device to speak to a slave device. The slave device has two checksums, a header and a data checksum. The header checksum was producing some erratic results which was fine tuned and corrected by members here: Odd Checksum Result(s) - Not Receiving Expected Results

Now I'm unsure if my data checksum is correct. I believe it is because of a thread that I had created here to help understand and build it which I did here: Converting a C Checksum Function to Lua

Now, I do not think that it is the data checksum functions. But I believe it is the way I am trying to implement it. I'm at the point where I'm now just trying to duplicate example code and send it to my slave device in hopes that I receive the appropriate response(s). Problem is that I am receiving nACK's in return. I've tried every permutation and combination I could think of and I'm not receiving an accepted value. The input is a representation of the string I need to send to the function databuild(str) function below.

input = "010032380000000000000000000000000000000000000000"  -- title must be a specific length so it is filled with NUL's to meet that criteria

function CRC(data, length)
    sum = 65535
    local d
    for i = 1, length do
        d = string.byte(data, i)
        sum = ByteCRC(sum, d)
    end
    return sum
end

function ByteCRC(sum, data)
    sum = sum ~ data
    for i = 0, 7 do
        if ((sum & 1) == 0) then
            sum = sum >> 1
        else
            sum = (sum >> 1) ~ 0xA001
        end
    end
    return sum
end

function databuild(str) -- I know I should not be doing what's inside here but don't fully understand why not to and better ways of approaching it.
    local dataSum = ""
    local dataSumReslt = ""
    local dataConv = ""
    for char in str:gmatch("..") do
        dataConv = dataConv..string.char("0x"..char)
    end
    dataSum = string.format("%04X", CRC(dataConv, #dataConv))
    for char in dataSum:gmatch("..") do
        dataSumReslt = dataSumReslt..string.char("0x"..char)
    end
    return dataConv..dataSumReslt
end

print(databuild(input))

I'm supposed to be getting the data checksum based on those byte values in my print statement. I send the entire string to the function databuild(str) function. From there I turn the result to hex format and then concatenate that result (after turning the two-byte value to hex via string.char) and then return the entire hex string.

Right now, as it is, I get the result 170B. Unfortunately, I'm not advanced enough in programming to debug or test out properly whether what I'm receiving is true or not.

  • Should I be turning the data string into hex first prior to doing the function CRC(data, length) or should I leave it the decimal representation first, or does it even matter???

  • Since all 2-byte and 4-byte words within my files are needed to be little-endian, does it mean that my checksum should also be little-endian? Or are checksums left untouched? (the checksum functions were provided in C in the slave device's manual.

  • Finally, what is a better way to approach the function databuild(str) so that I'm not breaking up each byte, translating it, then concatenating it so much? I am very appreciative when my code is corrected. But can someone help me understand exactly why it is just not a good thing to do?

Since I'm fairly new to programming in general, most of the time I'm not trying to work at this low-level (bit manipulation). I haven't reached this point in any of my classes since it has been all higher-level programming (Java and self-taught what I know in Lua). This is my first work project where it is truly "baptism by fire" concerning bytes, hex conversions, etc. Needless to say I'm barely keeping my head above water here. So all the constructive criticism I get is DEFINITELY wanted.


Solution

  • You can replace

    for char in str:gmatch("..") do
        dataConv = dataConv..string.char("0x"..char)
    end
    

    with

    dataConv = str:gsub("..",function (x) return string.char(tonumber(x,16)) end)
    

    You can simplify this to

    dataConv = str:gsub("..",HEX)
    

    after doing

    HEX={}
    for c=0,255 do
        HEX[string.format("%02x",c)] = string.char(c)
    end
    

    This will avoid the concatenations.