How to work with a incoming Byte

Hello everyone.

This is one of my first project with programming, i'm problably missing a few basics i would need. :blush:

The Hardware looks like this:

Sender:
-Ardunio UNO with EthernetShield and ElectricImp ---> Receive OSC-Message and send a simple String "r", "g" or "b" (only once) over impSerial.write() whenever the color has changed, send the value rot, gruen or blau

Receiver:
-Arduino Uno with ElectricImp, recieve byte and set the color of the rgb strip to all pixels

How do i convert three ascii values (dez) for example 49, 55, 55 to a int that i can use in the rest of the code.

I already read through http://www.gammon.com.au/forum/?id=11425 (that's where my code ist from)

I've tried with atoi, Serial.parseInt() and so on, but it never worked.

void processIncomingByte (const byte c)
{

if (isdigit (c))
{
.....
.....

Code of the Sender:

#include <SoftwareSerial.h>
#include <SPI.h>
#include <Ethernet.h>
#include <ArdOSC.h>

SoftwareSerial impSerial(8, 9); // RX on 8, TX on 9

byte myMac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
byte myIp[]  = { 10, 0, 0, 88 };
int  serverPort  = 8000;
int destPort=12000;
int lastState = 0;
int currentState = 0;
int rot = 0;
int gruen = 0;
int blau = 0;

OSCServer server;
OSCClient client;

String stringR, stringG, stringB;


void setup(){ 

stringR = String("r");
stringG = String("g");
stringB = String("b");

 
 impSerial.begin(19200);
 Serial.begin(19200);
 Ethernet.begin(myMac ,myIp); 
 server.begin(serverPort);
 
 server.addCallback("/knbr",&OSCrot);
 server.addCallback("/knbg",&OSCgruen);
 server.addCallback("/knbb",&OSCblau);
 
}

  
void loop(){

  if(server.aviableCheck()>0){}
  

}

void   OSCrot(OSCMessage *_mes){
       rot = int( _mes->getArgFloat(0)*255.f);
       currentState= 1;
       if (lastState != currentState) // send the string r whenever color changed
       {
         impSerial.print(stringR);
         Serial.println("StateChanged"); // just for debugging
       }
       
       impSerial.print(rot);  // send the value of red
       lastState = currentState; // store the current state
  } // end of void OSCrot

  void OSCgruen(OSCMessage *_mes){
       gruen= int( _mes->getArgFloat(0)*255.f);
        currentState= 2;
        if (lastState != currentState) // send the string g whenever color changed
       {
         impSerial.print(stringG);
         Serial.println("StateChanged"); // just for debugging
       }
      
       impSerial.print(gruen);   // send the value of green
       lastState = currentState; // store the current state
      
 } // end of void OSCgruen
  
  void OSCblau(OSCMessage *_mes){
       blau= int( _mes->getArgFloat(0)*255.f);
       currentState= 3;
   if (lastState != currentState) // send the string b whenever color changed
       {
         impSerial.print(stringB);
         Serial.println("StateChanged"); // just for debugging
       }
       
     impSerial.print(blau); // send the value of blue
     lastState = currentState; // store the current state
     
     } // end of void OSCblau

Code of the Receiver:

// Most of the Code ist from http://www.gammon.com.au/forum/?id=11425

#include <SoftwareSerial.h>
#include "SPI.h"
#include "WS2801.h"
#include <stdlib.h>

SoftwareSerial impSerial(8, 9); // RX on 8, TX on 9
 

// the possible states of the state-machine
typedef enum {  NONE, GOT_R, GOT_G, GOT_B } states;


// current state-machine state

states state = NONE;
// current partial number

int receivedNumber  = 0;
int r = 0;
int g = 0;
int b = 0;
int dataPin = 2; // for the WS2802 strip
int clockPin = 3; // for the WS2802 strip
WS2801 strip = WS2801(25, dataPin, clockPin);

boolean gotR = LOW;
boolean gotG = LOW;
boolean gotB = LOW;


String stringR, stringG, stringB; 


void setup ()
{ 
  
stringR = String('r');
stringG = String('g');
stringB = String('b');

strip.begin();

impSerial.begin(19200); // Serial for receiving from the electric Imp
Serial.begin (19200); // Serial for debugging
  
}  // end of setup

   

void processIncomingByte (const byte c)
{

  
  if (isdigit (c))
  {
    
//**************************The part i cant figure out************************
    
    // Serial.println(receivedNumber);
   
    switch (state)
    {
      case GOT_R:
    r = receivedNumber;
   Serial.println(r);
    break;
  case GOT_G:
    g = receivedNumber;
   Serial.println(g);
    break;
  case GOT_B:
    b = receivedNumber;
   Serial.println(b);
    break;
  }  // end of switch state    
  }  // end of digit
  else 
  {
  
   // set the new state, if we recognize it
    switch (c)
    {
    case 'r':
      state = GOT_R;
      Serial.println(" Received an r ");
      break;
    case 'g':
      state = GOT_G;
      Serial.println(" Received an g ");
      break;
    case 'b':
      state = GOT_B;
      Serial.println(" Received an b ");
      break;
    default:
      state = NONE;
      break;
    }  // end of switch on incoming byte
  } // end of not digit  
  
} // end of processIncomingByte

void loop ()
{
  
  if (impSerial.available ())
  processIncomingByte (impSerial.read ());
   
  for ( int i = 0; i <= 10; i++) 
  {
strip.setPixelColor(i, r,g,b); // set Color to all Pixels
  }
strip.show();
  
}  // end of loop

How do i convert three ascii values (dez) for example 49, 55, 55 to a int that i can use in the rest of the code.

Subtract '0' from each value. 49 - '0' = 1. 55 - '0' = 7

If the values are being stored in a NULL-terminated char array, atoi() would do the conversion to 177 from those three values for you.

None of that mess you are doing with String is necessary. Stop it.

boolean gotR = LOW;
boolean gotG = LOW;
boolean gotB = LOW;

Boolean variables are meant to hold true or false. Is LOW true?

Also you can check for digit in a char variable (or element in a char array);

char ch = '0'; // '0' == 48 but it's easier to read '0' quickly

if (( ch >= '0' ) && ( ch <= '9' ))
{
// it's a digit, do the digit thing
}
else
{
// it's not a digit, if it was supposed to be a digit then do error handling
}

Thank you both for your reply.

@ PaulS

I was not successful with the NULL-terminated char array. The "value" i've got in the Serial-Monitor was a newLine.

Watched this video several times: :~
http://classes.mst.edu/compsci53/ntca.htm

Then i tried it with some math, doesn't work either. This looked something like this

int receivedNumber = 0;
int marker = 2;
...
...
void processIncomingByte (const byte c)
{
if (isdigit (c))
{

 int var= 0;

if (marker >= 0)
{ 
  var = (c - '0')*(10^marker);
}

else
{
...
...
}
marker --;
receivedNumber = receivedNumber + var;

@ GoForSmoke

I'm not sure but this is what "(isdigit (c))" does. I replaced it by your code and it worked the same way.

The isdigit() macros returns true if the character represents a numeric character - '0' to '9' - and false if it doesn't.

I was not successful with the NULL-terminated char array. The "value" i've got in the Serial-Monitor was a newLine.

We'll need to see the code, to confirm that the NULL is being added in the right place, and that you are storing and using the stored data correctly.

void processIncomingByte (const byte c)
{
if (isdigit (c))
{

 int var= 0;

This almost assuredly will not work. If processingIncomingByte() is to do anything useful one byte (character) at a time, the variable that the data is accumulated in can not be reset every time the function is called. var needs to be global or static, AND have a meaningful name.

You might be able to use the below in a workaround by capturing the DEC value as characters and then use atoi.

int incomingByte = 0;	// for incoming serial data

void setup() {
	Serial.begin(9600);	// opens serial port, sets data rate to 9600 bps
}

void loop() {

	// send data only when you receive data:
	if (Serial.available() > 0) {
		// read the incoming byte:
		incomingByte = Serial.read();

		// say what you got:
		Serial.print("I received: ");
		Serial.println(incomingByte, DEC);
	}
}

Busi4:
@ GoForSmoke

I'm not sure but this is what "(isdigit (c))" does. I replaced it by your code and it worked the same way.

Yes it should. The code in the isdigit() function does the same thing.

That way you have a black-box that does the trick without you learning more about how or why or what you are dealing with.

What I showed you gives you a chance to see inside what is happening, which is very simple.

I see your confusion from lack of knowing and would like to address that as part of the solution.
That solution will stand by you better, long-term, than relying on the bag-of-magic-tricks approach.

Once you learn the nature of C string arrays the C string functions will be more understandable in a "what does this do to my char array?" way. They will lose all mystery quickly and show for the simple things they really are, including isdigit().
There is nothing you can't do with char array manipulation that any of the string commands can do. When you know that from rolling your own a couple times, you will have no fear of string commands.

I can say the same for C++ String objects but I feel compelled to mention that to really know those inside and out you need to learn at least 3x as much. Add to that how the things copy themselves even to add just ONE character, it is nothing like as simple as C string arrays!

You have 2k total SRAM on an UNO. Why learn wasteful practices suitable for PC's with comparably limitless RAM when you are coding for such limited devices? Portability?? Sure, port pin read/write to my Winblows PC while they're at it! It should be so simple!

Busi4:
I was not successful with the NULL-terminated char array. The "value" i've got in the Serial-Monitor was a newLine.

The NULL terminators usually don't get stored in the files, though they -can- be.

The terminator is used in memory as an end of string marker. In file you have end-of-line which maybe anything but is usually CarriageReturn (13) or NewLine (10) or both. Check the lower-right of Serial Monitor, there are options to have it add those to every line you send from Serial Monitor to the Arduino. All these things are just marks for code to know where different ends are.

Memory --
char buffer[ 12 ] = { "string" };
// starting with address buffer the bytes are
// 115 ('s') 116 ('t') 114 ('r') 105 ('i') 110 ('n') 103 ('g') 0 0 0 0 0 0
// when it reaches 0, the loop processing the characters exits because 0 is FALSE
// the function loop reads and processes while character is TRUE, non-zero

File --
There are more different markers for files but generally it is the function that returns NULL at end of file rather than a data byte.

Busi4:
I already read through Gammon Forum : Electronics : Microprocessors : How to process incoming serial data without blocking (that's where my code ist from)

Code of the Receiver:

// Most of the Code ist from http://www.gammon.com.au/forum/?id=11425

...

String stringR, stringG, stringB;

void setup ()
{
 
stringR = String('r');
stringG = String('g');
stringB = String('b');
...

However, the code in my link does not use the String class. Tempting though it might be to use it, it has some flaws on the Arduino at present.

You've changed my code somewhat haven't you? In my original:

void processIncomingByte (const byte c)
{
  if (isdigit (c))
  {
    currentValue *= 10;
    currentValue += c - '0';
  }  // end of digit
  else 
  {

    // The end of the number signals a state change
    handlePreviousState ();

    // set the new state, if we recognize it
    switch (c)
    {
    case 'R':
      state = GOT_R;
      break;
    case 'S':
      state = GOT_S;
      break;
    case 'G':
      state = GOT_G;
      break;
    default:
      state = NONE;
      break;
    }  // end of switch on incoming byte
  } // end of not digit  
  
} // end of processIncomingByte

The first few lines simply take each digit and collect them into a larger number (currentValue):

  if (isdigit (c))
  {
    currentValue *= 10;
    currentValue += c - '0';
  }  // end of digit

You seem to have omitted that, because your code is:

void processIncomingByte (const byte c)
{

  
  if (isdigit (c))
  {
    
//**************************The part i cant figure out************************
    
    // Serial.println(receivedNumber);
   
    switch (state)
    {
      case GOT_R:
    r = receivedNumber;
   Serial.println(r);
    break;
  case GOT_G:
    g = receivedNumber;
   Serial.println(g);
    break;
  case GOT_B:
    b = receivedNumber;
   Serial.println(b);
    break;
  }  // end of switch state    
  }  // end of digit
  else 
  {
  
   // set the new state, if we recognize it
    switch (c)
    {
    case 'r':
      state = GOT_R;
      Serial.println(" Received an r ");
      break;
    case 'g':
      state = GOT_G;
      Serial.println(" Received an g ");
      break;
    case 'b':
      state = GOT_B;
      Serial.println(" Received an b ");
      break;
    default:
      state = NONE;
      break;
    }  // end of switch on incoming byte
  } // end of not digit  
  
} // end of processIncomingByte

So your code does not do anything with incoming numbers.

It looks like he is printing them as debug info. I take that as a good sign. :smiley: