I am trying to implement a CRC16 checksum in bash. I'm porting from an existing piece of C++ code. I'm almost there, but I am getting different answers.
I don't quite see why the checksums between the C++ code and the bash script are different.
Another set of eyes would be a big help.
Here is the C++ code:
uint16_t Encoder::checksum(std::string thestring)
{
uint8_t d, e, f;
uint16_t c, r, crccalc;
c = 0xffff;
for (unsigned int i = 0; i < thestring.length(); i++)
{
d = thestring[i];
e = c ^ d;
f = e ^ (e << 4);
r = (c >> 8) ^ (f << 8) ^ (f << 3) ^ (f >> 4);
c = r;
}
c ^= 0xffff;
crccalc = c;
return crccalc;
}
And here is my bash code:
function calc_crc16()
{
string=$1
while read -d "" -n 1 ; do astring+=( "$reply" ) ; done <<< "$string"
cnt=${#astring[@]}
c=0xffff
for ((x=0;x<$cnt;x++)); do
char=${astring[$x]}
e=$(($c ^ $char))
s=$(($e << 4))
f=$(($e ^ $s))
t1=$(($c >> 8))
t2=$(($f << 8))
t3=$(($f << 3))
t4=$(($f >> 4))
r1=$(($t1 ^ $t2 ^ $t3 ^ $t4))
c=$r1
done
c=$c ^ 0xffff
echo "checksum = $c"
}
Is it going to have something to do with the size of the ints? I'm guessing there's not much I can do about that in bash.
I'm getting an actual number, but it doesn't match the C++, which I know works correctly. does anyone see anything where I may be screwing things up?
ok. with Sorpigal's help, i've got a working version.
i suspect this could all be done within an awk script, which may run a lot faster. i may try that next.
thank you all for the help. i don't mean to steal the solution here, but i worked on it, and figure it is worth putting up.
anyway, here is a working version:
function calc_crc16()
{
while read -r -d "" -n 1 ; do astring+=( "$REPLY" ) ; done <<< "$1"
cnt=${#1}
c=65535
for ((x=0;x<$cnt;x++)); do
char=$(printf '%d' \'"${1:$x:1}")
e=$(((c ^ char) & 0x00FF))
s=$(((e << 4) & 0x00FF))
f=$(((e ^ s) & 0x00FF))
r1=$(((c >> 8) ^ (f << 8) ^ (f << 3) ^ (f >> 4)))
c=$r1
done
c=$((c ^ 0xffff))
echo "checksum = $c"
}