1

I'm trying to port a C function which calculates a GPS checksum over to Python. According to the receiving end I am sometimes miscalculating the checksum, so must still have a bug in there.

C code is

void ComputeAsciiChecksum(unsigned char *data, unsigned int len,
                          unsigned char *p1, unsigned char *p2)
{
    unsigned char c,h,l;

    assert(Stack_Low());

    c = 0;
    while (len--) {
        c ^= *data++;
    }
    h = (c>>4);
    l = c & 0xf;
    h += '0';
    if (h > '9') {
        h += 'A'-'9'-1;
    }
    l += '0';
    if (l > '9') {
        l += 'A'-'9'-1;
    }
    *p1 = h;
    *p2 = l;
}

My attempt at a Python function is

def calcChecksum(line):
    c = 0
    i = 0
    while i < len(line):
        c ^= ord(line[i]) % 256
        i += 1
    return '%02X' % c;
6
  • 1
    Are you sure line doesn't contain a unicode object, but rather a str (assuming you are on Python 2.x)? The fact that you % 256 the result of ord() looks suspicious -- for an ordinary string, ord() should never return anything outside the range 0 to 255. Commented Nov 27, 2011 at 19:54
  • line should just be a plain ascii string, I am on Python 2.7 Commented Nov 27, 2011 at 19:56
  • Can you give an input for which it does not correctly calculate the checksum? Commented Nov 27, 2011 at 19:56
  • """it should be just a plain ascii string""": never mind what it should be, tell us what it actually is. Give examples of input which produce correct and incorrect results. Use print repr(line) and copy/paste the output into an edit of your question. Commented Nov 27, 2011 at 20:10
  • Have you considered creating a simple DIY test harness for the C function and trying that with your "good" and "bad" input and comparing the results with those of your Python function? Are you sure that the problem is not in the subsequent code that sends line and the checksum? Do you have a URL for the message layout/format? Commented Nov 27, 2011 at 20:28

2 Answers 2

4

Here is how you can set up a testing environment to diagnose your problem.

  1. Copy the above C function to a file, remove the assert() line, and compile it to a shared library with

    gcc -shared -o checksum.so checksum.c
    

    (If you are on Windows or whatever, do the equivalent of the above.)

  2. Copy this code to a Python file:

    import ctypes
    import random
    
    c = ctypes.CDLL("./checksum.so")
    c.ComputeAsciiChecksum.rettype = None
    c.ComputeAsciiChecksum.argtypes = [ctypes.c_char_p, ctypes.c_uint,
                                       ctypes.c_char_p, ctypes.c_char_p]
    
    def compute_ascii_checksum_c(line):
        p1 = ctypes.create_string_buffer(1)
        p2 = ctypes.create_string_buffer(1)
        c.ComputeAsciiChecksum(line, len(line), p1, p2)
        return p1.value + p2.value
    
    def compute_ascii_checksum_py(line):
        c = 0
        i = 0
        while i < len(line):
            c ^= ord(line[i]) % 256
            i += 1
        return '%02X' % c;
    

Now you have access to both versions of the checksum function and can compare the results. I wasn't able to find any differences.

(BTW, how are you computing the length of the string in C? If you are using strlen(), this would stop at NUL bytes.)

As a side note, your Python version isn't really idiomatic Python. Here are two more idiomatic versions:

def compute_ascii_checksum_py(line):
    checksum = 0
    for c in line:
        checksum ^= ord(c)
    return "%02X" % checksum

or

def compute_ascii_checksum_py(line):
    return "%02X" % reduce(operator.xor, map(ord, line))

Note that these implementations should do exactly the same as yours.

Sign up to request clarification or add additional context in comments.

Comments

0

Have you checked out this cookbook recipe? It hints at what input you should include in "line", returns a asterisk in front of the checksum, and gives one (input, output) data pair that you can use as test data.

Are you sure that "the receiver" is working correctly? Is the problem due to upper vs lower case hex letters?

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.