Sign in to follow this  
ollyb342

Inverted modulo 128 sum of bytes?!

Recommended Posts

Hey guys, I come here as a last resort as I'm ripping my hair out! I've been given an assignment to write a "semi robust text transfer system" to send addressed packets around a Ring-LAN. Now, one of the characters in the packet needs to be a checksum of the other characters:
public int calcCS(char[] packet)
{
            int checksum = 0;
            for (int i = 0; i < 16; i++)
            {
                if (i == 14) continue;
                checksum += packet[i];
            }
            return ~(checksum%128);
}
this is fine, it's the inverse mod 128 sum of all of the other chars in the array. Now, when I invert the checksum it becomes something insane like 65000, which obviously gets corrupted when it's transmitted and the checksum always fails! Do you have any idea what I can do to rectify this please? I'm so confused. This is my code to recieve a new packet:
 port.Read(tempBuff, 0, 16);
                    System.Text.ASCIIEncoding enc = new System.Text.ASCIIEncoding();
                    convString = enc.GetString(tempBuff); //conversion from byte array to string
                    for (int i = 0; i < 16; i++)
                        ptr[i] = convString[i]; //conversion from string to char array
ptr[] being "packet received", in the format of { dest source type 10BytePayload Checksum } This is all written in C#, if that makes a difference. so.. please let me know if you have any ideas guys. Thanks in advance, Ollie.

Share this post


Link to post
Share on other sites
Off the top of my head, it appears that you're treating the checksum as 1 byte (which I presume what skipping index 14 is for?), even though an 'int' is really 4 bytes. So that could be one issue. Also, what is the size of each field in the packet (other than "10BytePayload" since it's fairly self-describing), and how are you sending the data? There's little information for us to go on :/

Share this post


Link to post
Share on other sites
Quote:
Original post by Zipster
Off the top of my head, it appears that you're treating the checksum as 1 byte (which I presume what skipping index 14 is for?), even though an 'int' is really 4 bytes. So that could be one issue. Also, what is the size of each field in the packet (other than "10BytePayload" since it's fairly self-describing), and how are you sending the data? There's little information for us to go on :/


Sorry, I was a bit vague up there! Each position in the array is 1 byte wide.

The array's a character array; but the SerialPort class can only write a byte array (I think) so I have to cast it from a byte array to a char array on the receivers end.

In the Checksum function I skip number index 14 as it's the position which holds the checksum itself, and I can't add an empty array position to the sum of all characters.

Our assignment specification says the following: (I deliberately left this bit til last as I knew it'd be the toughest part!!)

Quote:

CS - the single byte checksum should be the inverted modulo-128 sum of all the other bytes in the packet. This is a 7
bit number but to avoid confusion with other ASCII chars, set the ms bit during transmission. If a packet is received with
a good checksum, an ACK packet is retur ned, otherwise a NAK packet. ACK & NAK packets themselves are never
acknowledged. The implementation of this facility may be left until the end.


I have no idea why it's a 7 bit number.. I didn't really understand that part, but I think that my checksum function sums up what he's asking for.

Any ideas on how to solve this?
Thanks again,

Ollie.

Share this post


Link to post
Share on other sites
In C# the size of the char datatype is 2 bytes. All 16 bits in the char are inverted when you apply the inverse operation.

When you only want the 8 least significant bits, cast the result to byte, like so:

return (byte)~(checksum%128);

Share this post


Link to post
Share on other sites
Quote:
Original post by Maarten X
In C# the size of the char datatype is 2 bytes. All 16 bits in the char are inverted when you apply the inverse operation.

When you only want the 8 least significant bits, cast the result to byte, like so:

return (byte)~(checksum%128);


Ok, thanks I'll give that a go then =)

any idea what he meant by:
Quote:

This is a 7
bit number but to avoid confusion with other ASCII chars, set the ms bit during transmission.


I'm guessing "ms bit" means most significant, but I don't really understand what he wants =S

Share this post


Link to post
Share on other sites
A 7-bit integer and an integer modulo 128 are the same thing. If you are still confused about this part, ask and I'll write an explanation.

I would ask for clarification on the word "inverted". The "inverse" of a number x is normally another number y such that x*y=1. There is no natural operation on 7-bit integers for which the inverse would make sense.

It is possible he meant "opposite", since that would give you a sequence of bits whose sum is 0 modulo 128, which is something that is very easy to check on the receiving end. The interpretation in your code is that "inverse" means "bit-wise negated", which only differs from my previous interpretation in being off by 1. This would also be easy to check because the sum of all the bytes would be 127 modulo 128.

Notice that this checksum completely ignores the most significant bit of every byte, which is a pretty bad property to have.

Share this post


Link to post
Share on other sites
Interestingly, I just put a breakpoint after the packet is recieved;

The 14th item in the array is 63, '?'.. so does this mean that there's some problem when recieving the checksum?

Sorry if I'm being dim and there's a really simple solution to this guys.

currently I have


public byte calcCS(char[] packet)
{
int checksum = 0;
for (int i = 0; i < 16; i++)
{
if (i == 14) continue;
checksum += packet[i];
}
return (byte)~(checksum%128);
}


and then I cast the result of this to a char before I send it, there's no other modifications made to the packet then.

But when it's received it comes out as '?' in the debugger.. do you think it's some kind of bug when I try to convert the byte array to a char array at the receiver end?

As I convert from a byte to an ascii string, to a char array.. maybe the problem is that I'm trying to turn the checksum into an ascii char or something?

Thanks again,
Ollie.

Share this post


Link to post
Share on other sites
Quote:
Original post by ollyb342
Ok, thanks I'll give that a go then =)

any idea what he meant by:
Quote:

This is a 7
bit number but to avoid confusion with other ASCII chars, set the ms bit during transmission.


I'm guessing "ms bit" means most significant, but I don't really understand what he wants =S


Apparently you are still confused about this part. Let's assume the "inverse" of x does mean ~x (which I am starting to believe is actually what your teacher meant). Let's say x is 5. What is ~x? Well, you'd take the binary representation of 5 and turn all the ones to zeros and all the zeros to ones. OK, 5 is 101 in binary, so ~5 should be 010, which is 2. The problem is that 5 is also 0000101 in binary, so ~5 should be 1111010, which is 122. 5 is also 00000101 in binary, so ~5 should be 11111010, which is 250. In other words, in order to define this operation, we should know how many bits we are using.

"This is a 7-bit number" means that, since we have taken some positive number modulo 128, the result is naturally expressed as a sequence of 7 bits (that's what you need to represent any number from 0 to 127), so naturally the ~ operation would be done on 7 bits (the second of my examples above). The result is then again a 7-bit number, but we are transmitting 8 bits at a time, so the assignment is telling you what to do with the extra bit: set it to 1.

I hope that made sense.

Share this post


Link to post
Share on other sites
Thankyou, that was a very concise answer and it's cleared this up a bit for me.

I hope you don't think that i'm taking the mick by asking this, but how would I go about setting the last bit to one.. I'm not entirely sure how to manipulate the value itself to accomplish this.

Thanks again, sorry if this is becoming tedious!

Ollie.

Share this post


Link to post
Share on other sites
Quote:
Original post by ollyb342
I hope you don't think that i'm taking the mick by asking this, but how would I go about setting the last bit to one.. I'm not entirely sure how to manipulate the value itself to accomplish this.


Oh, you are doing it already. :)

Your language doesn't operate on 7-bit numbers, so when you use the operator ~, you get extra ones to the left of the result. Casting to a byte, as someone recommended, should leave you with the last 8 bits. Since the number you had was less than 128, the most significant bit was 0, so it will be 1 after the ~ operation.

In general, if you want to set that bit to 1 explicitly, you can do `x | 128'.

About the "problem" of getting '?' in the debugger, notice that the debugger will show you the ASCII interpretation of a char, since that's often what chars are used for. In your case, you only care about the interpretation of the char as a number, so ignore the ASCII character associated with it.

Share this post


Link to post
Share on other sites
Ok cool thanks =)

Now, as I've previously stated; between setting the checksum byte in the array and sending it through the serial cable I make no modifications.

When I send the array through the cable the checksum is set to 127 or some such value; when it's received, the checksum is set to 63. I've done this little test 3 times with different payloads to get different checksums, and the result is always the same.. checksum is x value on transmit but 63 on receive!

I'm actually pulling my hair out at the minute trying to work this out!

This is the only code to be executed at the receiver's end when it receives a packet:


if (port.IsOpen)
{
if (port.BytesToRead &gt; 0)
{
port.Read(tempBuff, 0, 16);
System.Text.ASCIIEncoding enc = new System.Text.ASCIIEncoding();
convString = enc.GetString(tempBuff); //conversion from byte array to string
for (int i = 0; i &lt; 16; i++)
ptr[i] = convString[i]; //conversion from string to char array
if (DEBUG) rtfMainText.AppendText("Recieved: " + new String(ptr) + "\r\n");

if (ptr[3] == DATA && (ptr[14] != (char)calcCS(ptr)))
{
//this code always runs as the checksum's always incorrect
}

Share this post


Link to post
Share on other sites
Hey guys,

Cheers for all of your help with this; I've just worked out a solution for it.

it turns out that if the receiver receives anything with an ascii value of anything over 127 it goes pop, so I just sent a byte array instead of a char array, then recasted it at the other side and everything worked out ok =)

Thanks again for all of the help guys, I'd not of gotten this done without it.

Ollie.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this