Author Topic: Convert single integer to char to send, then convert back to int?  (Read 2000 times)

doublec4

  • Jr. Member
  • **
  • Posts: 53
Hi all,

So I'm just writing my first test programs to try and get my regular Moteino (remote) and my Moteino MEGA (receiver) to send / receive a simple message.

My regular Moteino has two push buttons that can single click and double click. For a total of four inputs, call them "1", "2", "3", "4". It also has an LED to be flashed quickly if the ACK was received after the message was sent. Slow single flash for a fail.

My Moteino MEGA is hooked up to a 16x2 LCD screen and I am looking to just display the result of the push button input. It also has some code to flash the onboard LED to show a message has been received.

Here is the code for the remote:

Code: [Select]
#include <OneButton.h>
#include <RFM69.h>
#include <SPI.h>

// Setup a new OneButton on pin A1. 
OneButton button1(3, true);

// Setup a new OneButton on pin A2. 
OneButton button2(5, true);


// Addresses for this node. CHANGE THESE FOR EACH NODE!
#define NETWORKID     0   // Must be the same for all nodes
#define MYNODEID      2   // My node ID
#define TONODEID      1   // Destination node ID

// RFM69 frequency
#define FREQUENCY     RF69_915MHZ

// AES encryption (or not):
#define ENCRYPT       true // Set to "true" to use encryption
#define ENCRYPTKEY    "TOPSECRETPASSWRD" // Use the same 16-byte key on all nodes

// Use ACKnowledge when sending messages (or not):
#define USEACK        true // Request ACKs or not

// Packet sent/received indicator LED (optional):
#define LED           4 // LED positive pin
//#define GND           8 // LED ground pin

// Create a library object for our RFM69HCW module:
RFM69 radio;

int sendlength = 0;
char message;
/*--------------------------------------------------------------------------------------------------------------------------------------------------------------*/


void setup() {

  pinMode(LED,OUTPUT);
  digitalWrite(LED,LOW);
 
  // link the button 1 functions.
  button1.attachClick(click1);
  button1.attachDoubleClick(doubleclick1);


  // link the button 2 functions.
  button2.attachClick(click2);
  button2.attachDoubleClick(doubleclick2);

  //Initialize the RFM69HCW:
  radio.initialize(FREQUENCY, MYNODEID, NETWORKID);
 
  // Turn on encryption if set to true above
  if (ENCRYPT)
    radio.encrypt(ENCRYPTKEY);

}

/*--------------------------------------------------------------------------------------------------------------------------------------------------------------*/

// main code here, to run repeatedly:
void loop() {
  // keep watching the push buttons:
  button1.tick();
  button2.tick();

  // You can implement other code in here or just wait a while
  delay(10);
} // loop

/*--------------------------------------------------------------------------------------------------------------------------------------------------------------*/


// ----- button 1 callback functions

// This function will be called when the button1 was pressed 1 time (and no 2. button press followed).
void click1() {
  message = "1";
  if (radio.sendWithRetry(TONODEID, message, sendlength)){
          digitalWrite(LED,HIGH);
          delay(250);
          digitalWrite(LED,LOW);
          delay(150);
          digitalWrite(LED,HIGH);
          delay(250);
          digitalWrite(LED,LOW);
          }
        else{
          digitalWrite(LED,HIGH);
          delay(1000);
          digitalWrite(LED,LOW);
          }
}

/*--------------------------------------------------------------------------------------------------------------------------------------------------------------*/


// This function will be called when the button1 was pressed 2 times in a short timeframe.
void doubleclick1() {
  message = "2";
  if (radio.sendWithRetry(TONODEID, message, sendlength)){
          digitalWrite(LED,HIGH);
          delay(250);
          digitalWrite(LED,LOW);
          delay(150);
          digitalWrite(LED,HIGH);
          delay(250);
          digitalWrite(LED,LOW);
          }
        else{
          digitalWrite(LED,HIGH);
          delay(1000);
          digitalWrite(LED,LOW);
          }
}
 // doubleclick1

/*--------------------------------------------------------------------------------------------------------------------------------------------------------------*/

void click2() {
  message = "3";
  if (radio.sendWithRetry(TONODEID, message, sendlength)){
          digitalWrite(LED,HIGH);
          delay(250);
          digitalWrite(LED,LOW);
          delay(150);
          digitalWrite(LED,HIGH);
          delay(250);
          digitalWrite(LED,LOW);
          }
        else{
          digitalWrite(LED,HIGH);
          delay(1000);
          digitalWrite(LED,LOW);
          }
}
 // click2

/*--------------------------------------------------------------------------------------------------------------------------------------------------------------*/

void doubleclick2() {
  message = "4";
  if (radio.sendWithRetry(TONODEID, message, sendlength)){
          digitalWrite(LED,HIGH);
          delay(250);
          digitalWrite(LED,LOW);
          delay(150);
          digitalWrite(LED,HIGH);
          delay(250);
          digitalWrite(LED,LOW);
          }
        else{
          digitalWrite(LED,HIGH);
          delay(1000);
          digitalWrite(LED,LOW);
          }
}
 // doubleclick2

/*--------------------------------------------------------------------------------------------------------------------------------------------------------------*/


And here is the code for the receiver:

Code: [Select]
#include <LiquidCrystal.h>
#include <RFM69.h>
#include <SPI.h>


// These constants won't change. They're used to give names to the pins used:
//const int analogInPin = A0;  // Analog input pin that the potentiometer is attached to
//int sensorValue = 0;

const int limitswitch = 25;


// initialize the library with the numbers of the interface pins
//Pin D16 is connected and was intended to somehow control back lighting but does not seem to be used.
LiquidCrystal lcd(18, 17, 22, 21, 20, 19); /*LCD connections*/

// Addresses for this node. CHANGE THESE FOR EACH NODE!

#define NETWORKID     0   // Must be the same for all nodes
#define MYNODEID      1   // My node ID
#define TONODEID      2   // Destination node ID

// RFM69 frequency, uncomment the frequency of your module:

//#define FREQUENCY   RF69_433MHZ
#define FREQUENCY     RF69_915MHZ

// AES encryption (or not):

#define ENCRYPT       true // Set to "true" to use encryption
#define ENCRYPTKEY    "TOPSECRETPASSWRD" // Use the same 16-byte key on all nodes

// Use ACKnowledge when sending messages (or not):

#define USEACK        true // Request ACKs or not

// Packet sent/received indicator LED (optional):

#define LED           15 // LED positive pin

// Create a library object for our RFM69HCW module:

RFM69 radio;

/*--------------------------------------------------------------------------------------------------------------------------------------------------------------*/

void setup() {
    lcd.begin(16, 2);             
    lcd.setCursor(0,0);
    lcd.print("START"); // Intro Display
    delay(1000);
 
    pinMode(limitswitch, INPUT);
    pinMode(LED,OUTPUT);
    digitalWrite(LED,LOW);
 
    radio.initialize(FREQUENCY, MYNODEID, NETWORKID);

// Turn on encryption if set to true above
    if (ENCRYPT)
    radio.encrypt(ENCRYPTKEY); 
}

/*--------------------------------------------------------------------------------------------------------------------------------------------------------------*/

void loop() {
  // read the analog in value:
  //sensorValue = analogRead(analogInPin);
   
    if (radio.receiveDone()) // Got one!
  {
    // Print out the information:
    lcd.clear();
    lcd.setCursor(0,0);
    lcd.print("node:");
    lcd.print(radio.SENDERID, DEC);
    lcd.print(", val:");
    lcd.print((char)radio.DATA[0], DEC);

    // Send an ACK if requested.

    if (radio.ACKRequested())
    {
      radio.sendACK();
      //Serial.println("ACK sent");
    }
    digitalWrite(LED,HIGH);
    delay(250);
    digitalWrite(LED,LOW);
    delay(150);
    digitalWrite(LED,HIGH);
    delay(250);
    digitalWrite(LED,LOW);
  }
   
  if (digitalRead(limitswitch) == 1){
    lcd.setCursor(0,1);
    lcd.print("UP");
  }
   else{
    lcd.setCursor(0,1);
    lcd.print("DOWN");
  }
  delay(100);
}

The flashing LEDs on the remote and the receiver would indicate that the message has been successfully sent and received... but the print out on the LCD screen is just showing the value to be '0' every time. So the LCD output looks like "node: 2, val:0"

I think I am somehow not using the right data type, or something is going on when I try to read/write the char values.

Any guidance on how to properly put messages into the right data type before sending and also processing them after receiving would be really helpful!

The basis of my code was found here:
https://learn.sparkfun.com/tutorials/rfm69hcw-hookup-guide

Thanks!
« Last Edit: April 03, 2018, 11:58:45 AM by doublec4 »

TomWS

  • Hero Member
  • *****
  • Posts: 1930
Re: Some simple coding help please
« Reply #1 on: April 02, 2018, 11:54:06 PM »
Without looking at your receiver code, I suspect your problem may begin somewhere around this line...
Code: [Select]
int sendlength = 0;

LukaQ

  • Sr. Member
  • ****
  • Posts: 302
  • Country: si
Re: Some simple coding help please
« Reply #2 on: April 03, 2018, 12:20:14 AM »
He is right, no where do you calculate sendlength of message, in your case you may not even need
Code: [Select]
int sendlength
Code: [Select]
if (radio.sendWithRetry(TONODEID, message, message.length()))
Or if you keep it
Code: [Select]
sendlength = strlen(message);
if (radio.sendWithRetry(TONODEID, message, sendlength))
« Last Edit: April 03, 2018, 12:25:05 AM by LukaQ »

doublec4

  • Jr. Member
  • **
  • Posts: 53
Re: Some simple coding help please
« Reply #3 on: April 03, 2018, 12:53:22 AM »
I thought I didn't need to calculate the length of the message because it was always going to only be one character.

So I set sendlength = 0 which I thought I was representative of 1 byte. The Sparkfun tutorial mentions that packets can be max 62 bytes and in their code they set their array to size 61. Hence, I thought a value of zero would indicate 1 byte, the size of one char.

Since my message variable is only a "char" I cannot use .length() as the Arduino IDE notifies me that this is not available to that data type.

I tried setting:

message = '1';

because I read that a single char should have single quotes and a string would have the double quotes, but this didn't work... it wouldn't compile.

Then I tried:

message = char(1);

and set sendlength = 1;

Now I started to get random numbers popping up on my LCD screen for the value sent. I'm going to have to do a little more reading on the data types and how they are being sent and read. I feel like things are getting lost in translation between data types  :-[

LukaQ

  • Sr. Member
  • ****
  • Posts: 302
  • Country: si
Re: Some simple coding help please
« Reply #4 on: April 03, 2018, 03:53:19 AM »
I thought I didn't need to calculate the length of the message because it was always going to only be one character.

So I set sendlength = 0 which I thought I was representative of 1 byte. The Sparkfun tutorial mentions that packets can be max 62 bytes and in their code they set their array to size 61. Hence, I thought a value of zero would indicate 1 byte, the size of one char.

Since my message variable is only a "char" I cannot use .length() as the Arduino IDE notifies me that this is not available to that data type.

I tried setting:

message = '1';

because I read that a single char should have single quotes and a string would have the double quotes, but this didn't work... it wouldn't compile.

Then I tried:

message = char(1);

and set sendlength = 1;

Now I started to get random numbers popping up on my LCD screen for the value sent. I'm going to have to do a little more reading on the data types and how they are being sent and read. I feel like things are getting lost in translation between data types  :-[
It can't be sendlength = 0, that would mean you don't send anything. 1 is minimum, since you send min. 1 char.
If you use above example, you will send as much as it is needed. May that be 1 or 60+, I don't think calculation will hurt you. At least get it working, than optimize for things like that

Quote
Since my message variable is only a "char" I cannot use .length() as the Arduino IDE notifies me that this is not available to that data type.
I see... from examples, I see you have two options:
1:

Code: [Select]
char input[64];
byte buff[61];
String inputstr;

inputstr = String(input);
inputstr.getBytes(buff, 61);
radio.sendWithRetry(targetId, buff, inputstr.length())
From PiGateway

2:
Code: [Select]
byte sendLen;
char buffer[50];
char Tds1str[10]; // the thing you will send
float Tds1;  //sensor in my case

dtostrf(Tds1, 3, 2, Tds1str);
sprintf(buffer, "Tds1:%s", Tds1str);  //"Tds1:" is added in front of sensor value, %s is sensor value which is now Tds1str (this would be then "Tds1:valueOF(Tds1str)"). This is all put into buffer

sendLen = strlen(buffer); // how long is it?
radio.sendWithRetry(GATEWAYID, buffer, sendLen);
I don't know about whole ' ' vs " ", but you can test this with 2: Serial.print(sendLen);




TomWS

  • Hero Member
  • *****
  • Posts: 1930
Re: Some simple coding help please
« Reply #5 on: April 03, 2018, 07:46:16 AM »
...I'm going to have to do a little more reading on the data types and how they are being sent and read. I feel like things are getting lost in translation between data types  :-[
That is a very good idea.  I suggest that you examine the difference between char, character arrays, and character pointers.   

doublec4

  • Jr. Member
  • **
  • Posts: 53
Re: Convert single integer to char to send, then convert back to int?
« Reply #6 on: April 03, 2018, 09:00:23 PM »
Okay so I had a good read into strings, chars and the like today. Not surprisingly, my prior "rough" understanding was way off.

Good news is that I got my code working.

Remote:

Code: [Select]
#include <OneButton.h>
#include <RFM69.h>
#include <SPI.h>

// Setup a new OneButton on pin A1. 
OneButton button1(3, true);

// Setup a new OneButton on pin A2. 
OneButton button2(5, true);


// Addresses for this node. CHANGE THESE FOR EACH NODE!
#define NETWORKID     0   // Must be the same for all nodes
#define MYNODEID      2   // My node ID
#define TONODEID      1   // Destination node ID

// RFM69 frequency
#define FREQUENCY     RF69_915MHZ

// AES encryption (or not):
#define ENCRYPT       true // Set to "true" to use encryption
#define ENCRYPTKEY    "TOPSECRETPASSWRD" // Use the same 16-byte key on all nodes

// Use ACKnowledge when sending messages (or not):
#define USEACK        true // Request ACKs or not

// Packet sent/received indicator LED (optional):
#define LED           4 // LED positive pin
//#define GND           8 // LED ground pin

// Create a library object for our RFM69HCW module:
RFM69 radio;

int sendlength = 1;
char message[] = "1";
/*--------------------------------------------------------------------------------------------------------------------------------------------------------------*/


void setup() {

  pinMode(LED,OUTPUT);
  digitalWrite(LED,LOW);
 
  // link the button 1 functions.
  button1.attachClick(click1);
  button1.attachDoubleClick(doubleclick1);


  // link the button 2 functions.
  button2.attachClick(click2);
  button2.attachDoubleClick(doubleclick2);

  //Initialize the RFM69HCW:
  radio.initialize(FREQUENCY, MYNODEID, NETWORKID);
 
  // Turn on encryption if set to true above
  if (ENCRYPT)
    radio.encrypt(ENCRYPTKEY);

}

/*--------------------------------------------------------------------------------------------------------------------------------------------------------------*/

// main code here, to run repeatedly:
void loop() {
  // keep watching the push buttons:
  button1.tick();
  button2.tick();

  // You can implement other code in here or just wait a while
  delay(10);
} // loop

/*--------------------------------------------------------------------------------------------------------------------------------------------------------------*/


// ----- button 1 callback functions

// This function will be called when the button1 was pressed 1 time (and no 2. button press followed).
void click1() {
  message[0] = '1';
  if (radio.sendWithRetry(TONODEID, message, sendlength)){
          digitalWrite(LED,HIGH);
          delay(250);
          digitalWrite(LED,LOW);
          delay(150);
          digitalWrite(LED,HIGH);
          delay(250);
          digitalWrite(LED,LOW);
          }
        else{
          digitalWrite(LED,HIGH);
          delay(1000);
          digitalWrite(LED,LOW);
          }
}

/*--------------------------------------------------------------------------------------------------------------------------------------------------------------*/


// This function will be called when the button1 was pressed 2 times in a short timeframe.
void doubleclick1() {
  message[0] = '2';
  if (radio.sendWithRetry(TONODEID, message, sendlength)){
          digitalWrite(LED,HIGH);
          delay(250);
          digitalWrite(LED,LOW);
          delay(150);
          digitalWrite(LED,HIGH);
          delay(250);
          digitalWrite(LED,LOW);
          }
        else{
          digitalWrite(LED,HIGH);
          delay(1000);
          digitalWrite(LED,LOW);
          }
}
 // doubleclick1

/*--------------------------------------------------------------------------------------------------------------------------------------------------------------*/

void click2() {
  message[0] = '3';
  if (radio.sendWithRetry(TONODEID, message, sendlength)){
          digitalWrite(LED,HIGH);
          delay(250);
          digitalWrite(LED,LOW);
          delay(150);
          digitalWrite(LED,HIGH);
          delay(250);
          digitalWrite(LED,LOW);
          }
        else{
          digitalWrite(LED,HIGH);
          delay(1000);
          digitalWrite(LED,LOW);
          }
}
 // click2

/*--------------------------------------------------------------------------------------------------------------------------------------------------------------*/

void doubleclick2() {
  message[0] = '4';
  if (radio.sendWithRetry(TONODEID, message, sendlength)){
          digitalWrite(LED,HIGH);
          delay(250);
          digitalWrite(LED,LOW);
          delay(150);
          digitalWrite(LED,HIGH);
          delay(250);
          digitalWrite(LED,LOW);
          }
        else{
          digitalWrite(LED,HIGH);
          delay(1000);
          digitalWrite(LED,LOW);
          }
}
 // doubleclick2

/*--------------------------------------------------------------------------------------------------------------------------------------------------------------*/


Receiver:

Code: [Select]
#include <LiquidCrystal.h>
#include <RFM69.h>
#include <SPI.h>


// These constants won't change. They're used to give names to the pins used:
//const int analogInPin = A0;  // Analog input pin that the potentiometer is attached to
//int sensorValue = 0;

const int limitswitch = 25;


// initialize the library with the numbers of the interface pins
//Pin D16 is connected and was intended to somehow control back lighting but does not seem to be used.
LiquidCrystal lcd(18, 17, 22, 21, 20, 19); /*LCD connections*/

// Addresses for this node. CHANGE THESE FOR EACH NODE!

#define NETWORKID     0   // Must be the same for all nodes
#define MYNODEID      1   // My node ID
#define TONODEID      2   // Destination node ID

// RFM69 frequency, uncomment the frequency of your module:

//#define FREQUENCY   RF69_433MHZ
#define FREQUENCY     RF69_915MHZ

// AES encryption (or not):

#define ENCRYPT       true // Set to "true" to use encryption
#define ENCRYPTKEY    "TOPSECRETPASSWRD" // Use the same 16-byte key on all nodes

// Use ACKnowledge when sending messages (or not):

#define USEACK        true // Request ACKs or not

// Packet sent/received indicator LED (optional):

#define LED           15 // LED positive pin

// Create a library object for our RFM69HCW module:

RFM69 radio;

/*--------------------------------------------------------------------------------------------------------------------------------------------------------------*/

void setup() {
    lcd.begin(16, 2);             
    lcd.setCursor(0,0);
    lcd.print("START"); // Intro Display
    delay(1000);
 
    pinMode(limitswitch, INPUT);
    pinMode(LED,OUTPUT);
    digitalWrite(LED,LOW);
 
    radio.initialize(FREQUENCY, MYNODEID, NETWORKID);

// Turn on encryption if set to true above
    if (ENCRYPT)
    radio.encrypt(ENCRYPTKEY); 
}

/*--------------------------------------------------------------------------------------------------------------------------------------------------------------*/

void loop() {
  // read the analog in value:
  //sensorValue = analogRead(analogInPin);
   
    if (radio.receiveDone()) // Got one!
  {
    // Print out the information:
    int x = (char)radio.DATA[0] - '0';
    lcd.clear();
    lcd.setCursor(0,0);
    lcd.print("node:");
    lcd.print(radio.SENDERID, DEC);
    lcd.print(", val:");
    lcd.print(x);

    // Send an ACK if requested.

    if (radio.ACKRequested())
    {
      radio.sendACK();
      //Serial.println("ACK sent");
    }
    digitalWrite(LED,HIGH);
    delay(250);
    digitalWrite(LED,LOW);
    delay(150);
    digitalWrite(LED,HIGH);
    delay(250);
    digitalWrite(LED,LOW);
  }
   
  if (digitalRead(limitswitch) == 1){
    lcd.setCursor(0,1);
    lcd.print("UP");
  }
   else{
    lcd.setCursor(0,1);
    lcd.print("DOWN");
  }
  delay(100);
}

The major changes I made were to declare my char variable like this in the remote:

Code: [Select]
char message[] = "1";

and then assign it single values like this:

Code: [Select]
message[0] = '1';

After doing this, my lcd screen started showing the ASCII values for the integer values I was assigning to the message so I knew I was on the right track. Just a matter of changing the received message from ASCII values back to an integer before printing it on the lcd screen. On the receiver I did this:

Code: [Select]
    int x = (char)radio.DATA[0] - '0';
    lcd.clear();
    lcd.setCursor(0,0);
    lcd.print("node:");
    lcd.print(radio.SENDERID, DEC);
    lcd.print(", val:");
    lcd.print(x);

and that did the trick.

But now that this is done I'm questioning why I'm even going through char variables anyways. My understanding is that the packet being sent is a bunch of bytes... it would probably make more sense to just assign my integer values to a byte variable and send that? I'm going to play around a little more :)

LukaQ

  • Sr. Member
  • ****
  • Posts: 302
  • Country: si
Re: Convert single integer to char to send, then convert back to int?
« Reply #7 on: April 04, 2018, 12:30:18 AM »
In the end there are only 1s and 0s, but that doesn't mean your code had be like that, you have compilers for that. Also depends on what your goal is. Some want speed and minimal as possible approach, you might not. In the end, if it does what you want and you even learned something new, then the code is good enough.