Splitting and combining between char and int?

This might be a stupid way of doing what I'm doing but I'll try to explain my thought process.

I have 2 nrf24l01 wireless transceivers for a project. The code that the professor gave us uses a char buffer[32] (32 bytes) to send messages over. This code works and everything but I'm trying to alter it to work with what I'm trying to do. I'm trying to send. I'm trying to send numbers that go up to 50,000. Since the program sends the message in characters (1 byte) the max value is 255.

Is there a way to split an integer in 2 chars and then combine them in the other arduino.

For example: Suppose I'm trying to send the value "v[0] = 65535" in binary this would be 11111111 11111111. Can I somehow split it to be "buffer[0] = 255" (in binary 11111111) and "buffer[1] = 255" (in binary 11111111)? And when it reaches the other side, it'll combine buffer[0] and buffer[1] into v[0] again?

If yes, how can I do that? If this is too much to ask, then I'll just down scale and upscale. I was hoping I wouldn't do that because I'd be losing some resolution by doing this.

The first Google hit for "split an int into two bytes":

I'm sorry I'm not knowledgeable enough. I realize this was written for Java. Would it work for Arduino too? Also, can you help me out with combing them again, please?

Suppose I'm trying to send the value v[0] = 65535

Why not just send it rather than messing around splitting it into bytes and putting it back together on the receiving side ?

In fact, if you want to send and receive an entire array then just do it as long as its size does not exceed 32 bytes

UKHeliBob:
Why not just send it rather than messing around splitting it into bytes and putting it back together on the receiving side ?

In fact, if you want to send and receive an entire array then just do it as long as its size does not exceed 32 bytes

I'm trying to send 4 different int values. They're basically the controlling values that the user inputs from the computer. The way the professor did it, is he scaled down and sent them in array form using char. I'm not really sure why he does that. He just sent us the code and didn't bother explaining. He's very hard to reach now with quarantine and uni being closed. So I'm trying to make do with what I have rather than try and mess with something break it. This is a small part of the project, so not worth investing too much time trying and testing.

There must be some logic to what he's trying to do, because the original code between a c++ program and the arduino sent through serial communication was in an int array. So the fact that he took the time, means there is a reason, either something in the code or in the hardware. I can post his code, but I was trying to avoid putting too much information that would confuse people.

Is is forbidden to post the professor's code? We need to know at least what code (e.g. library) is being used to operate the NRF.

aarg:
Is is forbidden to post the professor's code? We need to know at least what code (e.g. library) is being used to operate the NRF.

No not forbidden, just has other stuff in it, so I didn't want to add more confusion. Here's the code.

Arduino (PC)

#include <Arduino.h>
#include <Servo.h>
#include <avr/wdt.h> // for sw reset function

#include <SPI.h>
#include "RF24.h"
#include "printf.h" // for print details function

// set up nRF24L01 radio on SPI bus plus pins 7 and 8
RF24 radio(7,8);

byte addresses[][6] = {"1Node","2Node"};

// note you should pick a special address for each node
// on your network -- avoids interference with other groups
// if they happen to choose the same channel by accident
// byte addresses[][6] = {"1GR01","2GR01"}; // for group #1, etc.

// suggest each group use:
// channel = 95 + 2*k, where k is your group number

void setup_RF24_wireless();

void setup()
{
 int i;
 char buffer[32]; // RF24 wirless module max buffer size = 32 bytes
 int len; // length of input data
 
 // initialize serial port communication (usb, etc.) 
 // note: you have to change the communication rate in the arduino program here, 
 // the VC++ program, and the device driver (with device manager), and
 // the serial port monitor if you use it.
 // it's also a good idea to unplug and plug back in the Arduino usb cable
 // after change the device driver setting to restart the driver.
 Serial.begin(9600);
//  Serial.begin(115200);
//  Serial.begin(500000);

 // set serial timeout to 1000 ms
 // Serial.readBytes(...) will return after this time
 // (with the wrong number of bytes)
 Serial.setTimeout(1000);

 setup_RF24_wireless();
 
 // wait for start messge from PC -- this section is neccessary
 // as readBytes doesn't wait properly
 // -> robot waits until the PC contacts it
 // -> need to turn on arduino first then run PC program
 // because of this
 i = 0;
 while( Serial.available() == 0 ) i++;

 // read start message
 len = 1; // number of bytes for message from PC
 Serial.readBytes(buffer,len);

 delay(100); 
}


void loop()
{ 
 static char buffer[32]; // RF24 wireless module max buffer size = 32 bytes
 int len; // length of input data
 int i,n;
 unsigned char b;
  
 unsigned char start_char = 255; // start character for message 
 // -- don't use this value for anything else
 
 // read data from PC serial connection
  
 // wait until new data is available
 // this code is good for synchronization with
 // completely reliable communication but it will
 // hang here (ie infinite loop) of there if
 // communication is stopped from the PC
// i = 0;
// while( Serial.available() == 0 ) i++;
 
 // reset buffers to make sure data is new
 for(i=0;i<3;i++) buffer[i] = 0;

 // wait for message start byte
 while(1) {
 len = 1; // number of bytes for message from PC
 n = Serial.readBytes(buffer,len);
 
 // check for message start byte
 // note: the purpose of the start byte
 // is to synchronize the message
 // in case communication is interrupted,
 // otherwise the inputs can get out of sync
 // because we assume the inputs are in a certain
 // order in the wireless message.
 b = buffer[0];
 if(b == start_char) break;
 }

 // read the rest of the incoming message
 len = 2; // number of bytes for message from PC
 // use buffer+1 so the data read starts at element [1]
 n = Serial.readBytes(buffer+1,len);
 
 // the previous function will return an error if
 // no message in 1000 ms (1s) as specified by the serial time out
 // parameter in setup.
 
 if(n != len) { 
 Serial.print("\nreadBytes error");
 return; // try again
 }
 
 // send 3 byte message using RF24 wireless module
 len = 3;
 
 // blocking write / send to car arduino wireless module
 // the write function will check if the autoacknowledgment
 // is succesful or not -- if not it will retry a certain
 // number of times -- if that fails then the function returns
 // a zero value
 if ( !radio.write(buffer,len) ) {
 Serial.print("\nwrite failed -- wasn't received / acknowledged");
 } 
 
 // we won't be a dog with a bone here -- let's finish loop
 
 // check for serial time out (ie communication fault)
 // and turn off robot if that happens
 // note: default serial time out on Arduino is 1s
 
 // TODO: optionally receive message from wireless module
 // and send it back to PC via serial communication
 
 // TODO: can power down / power up reset the module ?
    // powerDown();
 // powerUp(); 
 
 // send back the data for error checking
 // this is good for debugging but it will stop the robot
 // when that happens which is not good for the final version
 // which you want "robust" to errors.
// Serial.write(buffer,len);
 
}


void setup_RF24_wireless()
{
// printf_begin(); // for print details function
   
 radio.begin();

 radio.setPALevel(RF24_PA_MAX); 
 // Set Power Amplifier (PA) level to one of four levels:
 // RF24_PA_MIN, RF24_PA_LOW, RF24_PA_HIGH and RF24_PA_MAX
 // The power levels correspond to the following output levels respectively:
 // NRF24L01: -18dBm, -12dBm,-6dBM, and 0dBm
    // Reset value is MAX  

// radio.setDataRate(RF24_250KBPS);  
 // reduce data rate to 250 kbps for longer range better reliability (default = 1 Mbps)
 
 // enable auto acknowledgements on transmit -- re-transmit if errors are encountered
 // as configured below with setRetries
 // false will disable checking -- faster but less chance to catch errors
 radio.setAutoAck(true); 
 
 radio.setRetries(5,3); // total max delay = (5 + 1) * 3 * 250 us = 4.5 ms

 // more than 3 retries doesn't seem to help much
    
 // Set the number and delay of retries upon failed submit
    // first argument -- How long to wait between each retry, in multiples of 250us,
    // max is 15.  0 means 250us, 15 means 4000us.  5 means 1500 us. 5 is min for 250 kbps.
 // second argument -- How many retries before giving up, max 15 
 
 // note 15 was default for 2nd argument instead of 6 but that's a bit too slow IMHO 

 radio.setChannel(107); // valid range 0 to 125
 // can use scanner example to find free channels
 
 // set reading and writing connections / pipes
 radio.openWritingPipe(addresses[0]); 
 radio.openReadingPipe(1,addresses[1]); 
 
 // the first argument is the reading pipe number
 // a wireless module can read / listen to up to 6 pipes
 // to make a star like network topology
  
 // note pipes 0 and 1 will store a full 5-byte address. Pipes 2-5 will technically 
 // only store a single byte, borrowing up to 4 additional bytes from pipe #1 per the
 // assigned address width.  
 // warning pipe 0 is also used by the writing pipe.  So if you open
 // pipe 0 for reading, and then startListening(), it will overwrite the
 // writing pipe, so call openWritingPipe() again before write(). 
  
 // print a large block of debug information
 // -- useful for checking parameters and their defaults
// radio.printDetails(); 

}

I'm limited by 9000 characters. So I'll post the receiving end of the code when I'm allowed to post again.

Arduino (car)

#include <Arduino.h>
#include <Servo.h>
#include <avr/wdt.h> // for sw reset function

#include <SPI.h>
#include "RF24.h"
#include "printf.h" // for print details function

// set up nRF24L01 radio on SPI bus plus pins 7 and 8
RF24 radio(7,8);

byte addresses[][6] = {"1Node","2Node"};

// hall encoder pins
const int ENC_A = 2;
const int ENC_B = 3;

// actuator servos pins
const int SER_1 = 5; // servo1 pin
const int SER_2 = 6; // servo2 pin

// servo library objects
Servo Servo1;
Servo Servo2;

void write_actuators(unsigned char pw1, unsigned char pw2);

// turn off robot and stop the program
void stop_robot();

// software reset function
void sw_reset();

void setup_RF24_wireless();

void setup()
{
 int i;
 char buffer[32]; // RF24 wireless module max buffer size = 32 bytes
 int len; // length of input data

 // encoder
 pinMode(ENC_A,INPUT_PULLUP);
 pinMode(ENC_B,INPUT_PULLUP);

 // servo objects
 Servo1.attach(SER_1);
 Servo2.attach(SER_2); 
 
 // for debugging with serial monitor if needed
 Serial.begin(9600); 
 
 setup_RF24_wireless(); 
 
 // wait for start messge from PC -- this section is neccessary
 // as readBytes doesn't wait properly
 // -> robot waits until the PC contacts it
 // -> need to turn on arduino first then run PC program
 // because of this
 
 // must start listening to read / receive data
 radio.startListening();
 
 // wait for message from RF24 wireless module
 // no timeout here since it's just a start message
 // and the robot hasn't been started
 i = 0;
 while ( ! radio.available() ) i++; 

 len = 3; // number of bytes for message
 
 // read the start message
 // note the read function doesn't block so you need
 // to use available function as above to block
 radio.read(buffer,len);

 delay(100); 
}


void loop()
{ 
 static char buffer[32]; // RF24 wireless module max buffer size = 32 bytes
 int len; // length of input data
 int i,n;
 unsigned char b;
  
 unsigned char start_char = 255; // start character for message 
 // -- don't use this value for anything else
 
 // Arduino inputs sent from PC
   unsigned char pw1, pw2;
 unsigned long start_time;
 
 // read data from RF24 wireless module
  
 // wait until new data is available
 // this code is good for synchronization with
 // completely reliable communication but it will
 // hang here (ie infinite loop) of there if
 // communication is stopped from the PC
 
 // TODO: read 3 byte message and check 1st byte for start byte
 // discard message and flush RX buffer if 1st byte is not start byte
 
 // note that RX does not flush automatically but write will
 // result in nothing in TX FIFO -- either flush on fail
 // or empty on write ack
 
 // must start listening to read / receive data
 radio.startListening();
 
 // wait for message from RF24 wireless module
 start_time = millis();
 while ( ! radio.available() ) {
 if( millis() - start_time > 1000 ) { // check for timeout
 Serial.print("\nwireless timeout error -- stop program");
 stop_robot();
 delay(100);  // give time for printing before stopping program
 exit(0); // stop program
 }
 }

 len = 3; // number of bytes for message
 
 // read the start message
 // note the read function doesn't block so you need
 // to use available function as above to block
 radio.read(buffer,len);
 
 // first character in message is the start character
 b = buffer[0]; 

 // check for message start byte
 // note: the purpose of the start byte
 // is to synchronize the message
 // in case communication is interrupted,
 // otherwise the inputs can get out of sync
 // because we assume the inputs are in a certain
 // order in the wireless message.
 
 // check for start character
 if(b != start_char) { 
 Serial.print("\nstart character missing from message");
 delay(2);
 return; // try again
 }


 
 // get inputs from buffer after the start byte
 pw1 = buffer[1];
 pw2 = buffer[2];
 
 // for testing / debugging 
 Serial.print("\n");
 Serial.print(pw1);
 Serial.print(" ");
 Serial.print(pw2);
 
 // saturation of Arduino inputs -- protect actuators / robot

 // prevent throttle from getting too large
 // 90 should be zero throttle with the ESC
 // once it's been configured properly
 if(pw1 > 120) pw1 = 120;
 if(pw1 < 60)  pw1 = 60; 
 
 // prevent steering angle from getting too large
 if(pw2 > 120) pw2 = 120;
 if(pw2 < 60)  pw2 = 60; 
 
 // send back the data for error checking
 // this is good for debugging but it will stop the robot
 // when that happens which is not good for the final version
 // which you want "robust" to errors.
// Serial.write(buffer,len);

 // repeatedly perform the following:
 // 1. Read sensors / outputs
 // 2. Calculate control input
 // 3. Write actuators / inputs
 
 // write actuators
 write_actuators(pw1,pw2);
 
}


void setup_RF24_wireless()
{
// printf_begin(); // for print details function
   
 radio.begin();

 radio.setPALevel(RF24_PA_MAX); 
 // Set Power Amplifier (PA) level to one of four levels:
 // RF24_PA_MIN, RF24_PA_LOW, RF24_PA_HIGH and RF24_PA_MAX
 // The power levels correspond to the following output levels respectively:
 // NRF24L01: -18dBm, -12dBm,-6dBM, and 0dBm
    // Reset value is MAX  
 
// radio.setDataRate(RF24_250KBPS);  
 // reduce data rate to 250 kbps for longer range better reliability (default = 1 Mbps)
 
 // enable auto acknowledgements on transmit -- re-transmit if errors are encountered
 // as configured below with setRetries
 // false will disable checking -- faster but less chance to catch errors
 radio.setAutoAck(true); 
 
 radio.setRetries(5,3); // total max delay = (5 + 1) * 3 * 250 us = 4.5 ms

 // more than 3 retries doesn't seem to help much
    
 // Set the number and delay of retries upon failed submit
    // first argument -- How long to wait between each retry, in multiples of 250us,
    // max is 15.  0 means 250us, 15 means 4000us.  5 means 1500 us. 5 is min for 250 kbps.
 // second argument -- How many retries before giving up, max 15 
 
 // note 15 was default for 2nd argument instead of 6 but that's a bit too slow IMHO 

 radio.setChannel(107); // valid range 0 to 125
 // can use scanner example to find free channels
 
 // set reading and writing connections / pipes
 radio.openWritingPipe(addresses[1]); // use [0] for other module
 radio.openReadingPipe(1,addresses[0]); // use [1] for other module
  
 // note pipes 0 and 1 will store a full 5-byte address. Pipes 2-5 will technically 
 // only store a single byte, borrowing up to 4 additional bytes from pipe #1 per the
 // assigned address width.  
 // warning pipe 0 is also used by the writing pipe.  So if you open
 // pipe 0 for reading, and then startListening(), it will overwrite the
 // writing pipe, so call openWritingPipe() again before write(). 
  
 // print a large block of debug information
 // -- useful for checking parameters and their defaults
// radio.printDetails(); 

}


void write_actuators(unsigned char pw1, unsigned char pw2)
{
 int th1, th2;
 
 th1 = pw1;
 th2 = pw2;
 
 // set servos
 Servo1.write(th1);
 Servo2.write(th2);
}


// turn off robot and stop the program
void stop_robot()
{ 
   unsigned char pw1, pw2;

 // set inputs to zero / neutral values
 pw1 = 90;
 pw2 = 90;
 
 // write actuators
 write_actuators(pw1,pw2);

 // different options available below
 
// cli(); // disable all interrupts to suspend program
 // and allow uninterrupted turning off of the robot
 
 // stop the program, note exit(0) does the same thing
// cli(); // turn off interrupts / background functions
// while(1); // infinite do nothing loop
// or
// exit(0); // stop program

}


void sw_reset()
// software reset function using watchdog timer
{
  wdt_enable(WDTO_15MS); // sets a "watchdog" timer to 15 ms
  // so the arduino will reset in 15 ms if the timer is not stopped
  while(1); // infinite do nothing loop -- wait for the countdown
}

His code basically takes 2 numbers (each one byte) values from a c++ program through serial communication. Then It sends 3 numbers (each one byte) to the arduino (car). The first one is an initiation character. The other two are values for the car.

What I'd like to do is send 4 numbers overs each one 2 bytes. So I'll change the len 2 to 8 and len 3 to 9.

This obviously isn't the final code for the project. This was just an example for using the nrf24l01. He gave us the specific header and cpp files for the nrf24l01 library. I'm pretty sure he got it from here since it's the same author but might be an older copy. GitHub - nRF24/RF24: OSI Layer 2 driver for nRF24L01 on Arduino & Raspberry Pi/Linux Devices

I'm trying to send 4 different int values.

So put them in an array and send them all at the same time

UKHeliBob:
So put them in an array and send them all at the same time

well since the data type is char. Wouldn't that end up ruining the data as the container won't be able to handle it. For example. If I want to send 300, and char can only hold 255. Would would happen with the rest?

I think I've got what I need, but I'm not sure. Will test it. Basically, I'd do like Java example. Save the into to char, that would save the low byte, shift them 8 steps, then save the new value, that would save the high byte. And on the second arduino, I'd combine both together using this "uint16_t value = (highByte << 8) | lowbyte;" I THINK. I gotta test it out to be sure.

I wonder would this increase the time to transfer the data by much or not. If it does take way longer to transfer, then I might be better off sticking with the low step count (servo steps) over losing time.

krusion:
I wonder would this increase the time to transfer the data by much or not. If it does take way longer to transfer, then I might be better off sticking with the low step count (servo steps) over losing time.

Compared to what? Sending one byte for each value? Have you investigated how fast the data is sent over the radio? It's very fast. The framing and message protocol overhead is probably already much bigger than your 8 byte message.

aarg:
Sending one byte for each value?

Yes. That will be 5 bytes vs 9 bytes. It's supposed to be controlling a car that's running with a 20,000 rpm motor. So timing has to be just right. I guess I just need to finish the code for data transmission then I'll test both scenarios, sending 5 bytes and 9 bytes, and compare if the time difference is big or not.

Thanks!

For example. If I want to send 300, and char can only hold 255.

I think that you are making heavy weather of this

Here is a sketch that will send a byte, 2 ints in an array and 20 chars in an array all in the same message

#include <RF24.h>

const byte CE_PIN = 9;
const byte CSN_PIN = 10;

RF24 radio(CE_PIN, CSN_PIN);

const uint64_t pipe = 123456;
struct dataLayout
{
  byte aByte;
  int someInts[2];
  char someChars[20];
} dataPacket;

void setup()
{
  Serial.begin(115200);
  while (!Serial);
  radio.begin();
  radio.setPALevel(RF24_PA_MAX); //max power
  radio.setDataRate(RF24_250KBPS);  //low data rate
  radio.openWritingPipe(pipe);
  Serial.print("Transmitting at PA level ");
  Serial.println(radio.getPALevel());
}

void loop()
{
  dataPacket.someInts[0]++;
  dataPacket.someInts[1]--;
  sprintf(dataPacket.someChars, "Count : %d", dataPacket.someInts[0]);
  radio.write(&dataPacket, sizeof(dataPacket));
  Serial.println(dataPacket.someChars);
  delay(1000);
}

and here is the sketch to receive it

#include <RF24.h>

const byte CE_PIN = 9;
const byte CSN_PIN = 10;

const byte ledPin = A5;
boolean ledState = false;

RF24 radio(CE_PIN, CSN_PIN);

const uint64_t pipe = 123456;
struct dataLayout
{
  byte aByte;
  int someInts[2];
  char someChars[20];
} dataPacket;

void setup()
{
  Serial.begin(115200);
  while (!Serial);
  pinMode(ledPin, OUTPUT);
  radio.begin();
  radio.setDataRate(RF24_250KBPS);  //low data rate
  radio.openReadingPipe(1, pipe);
  radio.startListening();
  Serial.println("Listening");
}

void loop()
{
  if (radio.available())
  {
    radio.read(&dataPacket, sizeof(dataPacket));
    Serial.print(dataPacket.someInts[0]);
    Serial.print("\t");
    Serial.print(dataPacket.someInts[1]);
    Serial.print("\t");
    Serial.println(dataPacket.someChars);
    ledState = !ledState;
    digitalWrite(ledPin, ledState);
  }
}