0

I want to send integer greater than 255 using uint8 array from mobile to Arduino over bluetooth.

Since BLE module that I'm using does not accept Uint16Array, I'm restricted to use Uint8 array only.

My App code :

var data = new Uint8Array(3);
data[0]= 1;
data[1]= 123;
data[2]= 555;

ble.writeWithoutResponse(app.connectedPeripheral.id, SERVICE_UUID, WRITE_UUID, data.buffer, success, failure);

My Device Specific Code :

void SimbleeBLE_onReceive(char *data, int len) {
    Serial.print(data[0]); // prints 1
    Serial.print(data[1]); // prints 123
    Serial.print(data[2]); // failed to print 555
}

Since uint8 only allows integer upto 255, How do I send greater values than that ?

MANnDAaR
  • 2,546
  • 7
  • 45
  • 64

2 Answers2

0

Use some form of scaling on the data at sending and receiving ends to keep it within the 0 to 255 range. for example dividing and multiplying so the data is sent below 255 and then scale it up at the receiving end.

Another way, if you know the hi and low range of the data would be to use the Arduino mapping function.

y = map(mapped value, actual lo, actual hi, mapped lo, mapped hi)

If you don't know the full range, you could use the constrain() function.

Jay Black
  • 107
  • 2
  • 12
0

You have to split it. You already know (or you should) that an int16 has, well, 16 bits (so it takes two bytes to store it).

Now very small digression about endianness. With endianness you mean the order of the bytes when stored. For instance, if you have the value 0x1234, you can either store it as 0x12 0x34 (big endian) or as 0x34 0x12 (little endian).

I don't know what language you use, so... Normally in C++ you do something like this:

const int datalen = 3;
uint16_t data[datalen];
data[0]= 1;
data[1]= 123;
data[2]= 555;

uint8_t sendingData[] = new uint8_t[datalen * sizeof(uint16_t)];
for (int i = 0; i < datalen; i++)
{
    sendingData[i * 2] = (data[i] >> 8) & 0xFF;
    sendingData[i * 2 + 1] = data[i] & 0xFF;
}

functionToSendData(sendingData, datalen * sizeof(uint16_t));

This sends in big endian format. If you prefer the little endian one, write

    sendingData[i * 2] = data[i] & 0xFF;
    sendingData[i * 2 + 1] = (data[i] >> 8) & 0xFF;

A simpler version can be

const int datalen = 3;
uint16_t data[datalen];
data[0]= 1;
data[1]= 123;
data[2]= 555;

functionToSendData((uint8_t*)data, datalen * sizeof(uint16_t));

In the first case you know the endianness of the transmission (it is little or big according to how you code), in the second it depends on the architecture and/or the compiler.

In JavaScript you can use this:

var sendingData = new Uint8Array(data.buffer)

and then send this new array. Credits go to this answer

When you receive it, you will have to do one of these three things to convert it

// Data is big endian
void SimbleeBLE_onReceive(char *receivedData, int len) {
    uint16_t data[] = new uint16_t[len/2];

    for (int i = 0; i < len/2; i++)
        data = (((uint16_t)receivedData[i * 2]) << 8) + receivedData[i * 2 + 1];

    Serial.print(data[0]);
    Serial.print(data[1]);
    Serial.print(data[2]);
}

// Data is little endian
void SimbleeBLE_onReceive(char *receivedData, int len) {
    uint16_t data[] = new uint16_t[len/2];

    for (int i = 0; i < len/2; i++)
        data = receivedData[i * 2] + (((uint16_t)receivedData[i * 2 + 1]) << 8);

    Serial.print(data[0]);
    Serial.print(data[1]);
    Serial.print(data[2]);
}

// Trust the compiler
void SimbleeBLE_onReceive(char *receivedData, int len) {
    uint16_t *data = receivedData;

    Serial.print(data[0]);
    Serial.print(data[1]);
    Serial.print(data[2]);
}

The last method is the most error-prone, since you have to know what endianness uses the compiler and it has to match the sendong one.

If the endianness mismatches you will receive what you think are "random" numbers. It is really easily debugged, though. For instance, you send the value 156 (hexadecimal 0x9C), and receive the 39936 (hexadecimal 0x9C00). See? The bytes are inverted. Another example: sending 8942 (hex 0x22EE) and receiving 60962 (hex 0xEE22).

Just to finish, I think you are going to have problems with this, because sometimes you will not receive the bytes "in one block", but separated. For instance, when you send 1 123 555 (in hex and, for instance, big endian this will be six bytes, particularly 00 01 00 7B 02 2B) you may get a call to SimbleeBLE_onReceive with just 3 or 4 bytes, then receive the others. So you will have to define a sort of protocol to mark the start and/or end of the packet, and accumulate the bytes in a buffer until ready to process them all.

Community
  • 1
  • 1
frarugi87
  • 2,826
  • 1
  • 20
  • 41