Daniel
Daniel

Reputation: 151

byte to int type conversion network application

I'm sending from my android phone integer as byte with the following code(I put only the needed chunks):

private byte[] intToByteArray ( final int i ) throws IOException {      
    ByteArrayOutputStream bos = new ByteArrayOutputStream();
    DataOutputStream dos = new DataOutputStream(bos);
    dos.writeInt(i);
    dos.flush();
    return bos.toByteArray();
}
//thread sender
        data = new byte[16];
        ...
        try {
            temp = intToByteArray((int) (roll*100));
        } catch (IOException e1) {
            // TODO Auto-generated catch block
            e1.printStackTrace();
        }
        data[3] = temp[0];
        data[4] = temp[1];
        data[5] = temp[2];
        data[6] = temp[3];
        ...
        p = new DatagramPacket(data, 16);
        udpSocket.send(p);

The sending code works because I have tried it with a Java received, and the results are correct. The real receiver has to be implemented with an embedded device, Murata SN8200: I receive the packet, but I my integer results (for instance, roll) are not correct. The code that I'm using for converting from byte to int is the following:

void getSubArray(char* dest, char* source, int start, int end){
   uint8_t i, j = 0;
   for(i=start; i<end; i++){
       dest[j] = source[i];
       j++;
   }
}
int byteToInt(char* bytes)
{
  int ch1 = bytes[0];
  int ch2 = bytes[1];
  int ch3 = bytes[2];
  int ch4 = bytes[3];
  if ((ch1 | ch2 | ch3 | ch4) < 0)
      WPRINT_APP_INFO ( ("boh\r\n"));
  return ((ch1 << 24) + (ch2 << 16) + (ch3 << 8) + (ch4 << 0));
}
...
//thread receiver
wiced_packet_get_data(packet, 0, (uint8_t**)&rx_data, &rx_data_length, &available_data_length);
traffic_type = rx_data[0];
        id = rx_data[1];
        takeOffPressed = rx_data[2];
        getSubArray(temp, rx_data, 3, 7);
        roll = byteToInt(temp);
        WPRINT_APP_INFO ( ("Rx: \" Packet Type: %c Id: %c  TakeOffPressed = %c \r\n  roll: %d \r\n ", (unsigned char )traffic_type, (unsigned char )id, (unsigned char)takeOffPressed, roll);

Reading other discussions I have already tried to do: roll = (int*)(temp); as suggested in another post, but it doesn't work for me (aliasing compiler error). Any idea to solve the problem? thanks

Upvotes: 0

Views: 147

Answers (2)

John Bollinger
John Bollinger

Reputation: 180181

You have some possible signedness confusion. Consider your byteToInt() function:

int byteToInt(char* bytes)
{
  int ch1 = bytes[0];
  int ch2 = bytes[1];
  int ch3 = bytes[2];
  int ch4 = bytes[3];
  if ((ch1 | ch2 | ch3 | ch4) < 0)
      WPRINT_APP_INFO ( ("boh\r\n"));
  return ((ch1 << 24) + (ch2 << 16) + (ch3 << 8) + (ch4 << 0));
}

Suppose the 4-byte value that was sent was 511 (decimal). The bytes sent are then 0x00 0x00 0x01 0xff. Now suppose that the receiving system features signed, two's complement chars, which is not uncommon. In that case, on the receiver those chars will be interpreted as values 0 0 1 -1 (decimal). There are now two problems with this:

  1. The behavior of applying a shift operator to a negative left operand (i.e. the value of ch4 in my example) is undefined.
  2. A reasonably likely actual behavior for -1 << 0 would be to yield -1 (a zero-bit shift evaluating to the value of its left operand). In that case, the overall computed value would be 256 + -1 = 255.

Of course, that's just an example, but only one in sixteen 32-bit ints have the high bit of every byte clear.

Both issues could be addressed by performing the computation with the appropriate unsigned quantities. That could be done like this:

int byteToInt(char* bytes)
{
  uint8_t ch1 = bytes[0];
  uint8_t ch2 = bytes[1];
  uint8_t ch3 = bytes[2];
  uint8_t ch4 = bytes[3];
  return ((ch1 << 24) + (ch2 << 16) + (ch3 << 8) + (ch4 << 0));
}

Note, too, that it is wasteful to extract a subarray to pass to byteToInt(). It would be better to just use a bit of pointer arithmetic:

roll = byteToInt(rx_data + 3);

Upvotes: 1

Narcisse Doudieu Siewe
Narcisse Doudieu Siewe

Reputation: 649

#include <sdint.h>
#include <string.h>
#include <netinet/in.h>

uint32_t byteToInt(char* bytes)
{
 uint8_t b[4];
 memcpy(b, bytes, 4);
 if ((b[0] | b[1] | b[2] | b[3]) < 0)WPRINT_APP_INFO ( ("boh\r\n"));
 return ntohl(*((uint32_t *)b));
}
 ...
 //thread receiver
wiced_packet_get_data(packet, 0, (uint8_t**)&rx_data, &rx_data_length, &available_data_length);
traffic_type = rx_data[0];
id = rx_data[1];
takeOffPressed = rx_data[2];
memcpy(temp, rx_data+3, 4);
roll = byteToInt(temp);
WPRINT_APP_INFO ( ("Rx: \" Packet Type: %c Id: %c  TakeOffPressed = %c \r\n  roll: %d \r\n ", (unsigned char )traffic_type, (unsigned char )id, (unsigned char)takeOffPressed, roll);

no need of

void getSubArray(char* dest, char* source, int start, int end)

you can replace it by a

memcpy(void* dest, void* src, size_t t);//from string.h

alse I have modified your byteToInt function to a thing more interessting

Upvotes: 1

Related Questions