Convert from a string of 0 and 1 to ASCII character

Hello everyone,

I have the following question.Im working on a project about a wireless RF communication between 2 arduino's and on the reciever part i recieve a string of 1 and 0 that is stored in a string like this:

uint8_t buf[8] = "01001000";

Those bits of 0 and 1 are the equivalent of ASCII character "H" in binary.

My question is how can i convert from the binary string into the character H?

Your buf is too small. A c-string is terminated with a nul-character so you need one extra character.

You can use strtoul

void setup()
{
  Serial.begin(57600);

  uint8_t buf[] = "01001000";
  char *endptr;

  uint8_t value = strtoul((char*)buf, &endptr, 2);

  if (endptr == (char*)buf)
  {
    Serial.println("No digits found");
  }
  else if (*endptr != '\0')
  {
    Serial.println("Non-digit found after digits");
  }
  else
  {
    Serial.write(value);
  }
}


void loop()
{
}

Why is the sender transmitting data like this? Is that something you can fix?

Danois90:
Why is the sender transmitting data like this? Is that something you can fix?

I cant fix it . I try to implement a DSSS communication and i have to convert a text intro binary values and after that i have to take every bit of every character and make a XOR with a sequence of 0s and 1s.

sterretje:
Your buf is too small. A c-string is terminated with a nul-character so you need one extra character.

You can use strtoul

void setup()

{
  Serial.begin(57600);

uint8_t buf[] = "01001000";
  char *endptr;

uint8_t value = strtoul((char*)buf, &endptr, 2);

if (endptr == (char*)buf)
  {
    Serial.println("No digits found");
  }
  else if (*endptr != '\0')
  {
    Serial.println("Non-digit found after digits");
  }
  else
  {
    Serial.write(value);
  }
}

void loop()
{
}

I dont think de buffer is too small. If you want to see exactly what i have to do i let my code for tx and rx below:

tx:

// Include RadioHead Amplitude Shift Keying Library
#include <RH_ASK.h>
// Include dependant SPI Library 
#include <SPI.h> 
 
// Create Amplitude Shift Keying Object
RH_ASK rf_driver;
 
void setup()
{
    // Initialize ASK Object
    rf_driver.init();
    Serial.begin(9600);
}

char * strToBinStr(char const * const src, char * const dest, size_t const size)
{
  char const * p = src;
  char c = '\0';
  size_t i = 0;
 
  if (size > 8)
  {
    while ((c = *p++) != '\0' && i < size-8)
    {
      for (int8_t j = 7; j >= 0; j--)
      {
        dest[i++] = ((c >> j) & 1) + '0';
      }
    }
  }
 
  dest[i] = '\0';
 
  return dest;
}

void loop()
{   
    char msg[] = "Hi"; 
    for(int j=0 ; j< strlen(msg) ; j++ )
    {
      char temp[1];
      temp[0] = msg[j];
      Serial.println(temp);
      char dest[strlen(temp)*8+1];  
      strToBinStr(temp, dest, sizeof(dest));
    
   
    
      rf_driver.send((uint8_t *)dest, strlen(dest));
      rf_driver.waitPacketSent();
      Serial.println(dest);
      delay(1000);
    }
}

rx:

// Include RadioHead Amplitude Shift Keying Library
#include <RH_ASK.h>
// Include dependant SPI Library 
#include <SPI.h> 

// Create Amplitude Shift Keying Object
RH_ASK rf_driver;

void setup()
{
    // Initialize ASK Object
    rf_driver.init();
    // Setup Serial Monitor
    Serial.begin(9600);
}

void loop()
{
    // Set buffer to size of expected message
    uint8_t buf[8];
    uint8_t buflen = sizeof(buf);
    // Check if received packet is correct size
    if (rf_driver.recv(buf, &buflen))
    {
      
      // Message received with valid checksum
      Serial.print("Character in binary: "
      Serial.println((char*)buf);
               
    }
}

guturobert:
I cant fix it . I try to implement a DSSS communication and i have to convert a text intro binary values and after that i have to take every bit of every character and make a XOR with a sequence of 0s and 1s.

Not this again but in a new thread. :frowning:
Sorry, but it’s frustrating to keep dealing with the same misunderstanding over and over, and watching a forum member go further down the rabbit hole.

You’ve already been told there is absolutely NO need to covert to a string to XOR bits. You can XOR bits in a byte or char in place using...

char c1 = 'H';
char c2 = 0xA5;
char result = c1 ^ c2;

Now you have XORed all 8 bits at once. Far more efficient, and no need for conversion.

If your stream of bits to XOR with are provided one bit at a time (say by some algorithm), assemble them into a single byte or char and use the code above.

There is absolutely no need to convert to a binary string to XOR, even less reason to do so purely for transmission. Indeed in many ways it is totally counterproductive (bandwidth use for one).

I dont think de buffer is too small

Think harder.

Think about what comes at the end of a string.

is an ascii '0' or '1' actually being transmitted?

even if transmitted as ascii, why not do a quick compare and shift the data into a byte buffer

this string of ascii characters

000000010000001000000011000001000000010100000110

resulted in

 01
 02
 03
 04
 05
 06
#define BUF_SIZE 100
byte buf [BUF_SIZE];
int  idx = 0;
int  bit = 0;

char s [80];

void dump()
{
    for (int i = 0; i < idx; i++)  {
        sprintf (s, " %02x", buf [i]);
        Serial.println (s);
    }
}

void loop()
{
    if (Serial.available ())  {
        byte  c = Serial.read ();

        if ('\n' == c)  {
            dump ();
            idx = bit = 0;
            return;
        }


        buf [idx] <<= 1;
        if ('1' == c)
            buf [idx] |= 1;

        if (8 == ++bit)  {
            bit = 0;
            if (BUF_SIZE == ++idx)
                idx = 0;
        }
    }
}


void setup()
{
    Serial.begin (115200);
}

Original thread where the OP was provided with many many examples of how to convert to/from binary.

And yes OP - YOUR BUFFER IS TOO SMALL. It requires an extra byte for the null terminator.

Edit: Having watched the video you provided on DSSS on the above thread it is more clear than ever to me you are totally confused about data types and their representation.

There is absolutely no need to convert to ASCII for this. The ‘1’s and ‘0’s they are talking about on the video are individual bits, not ASCII characters which are 8 bits each. 0x30 for 0 or 0x31 for 1.

pcbbc:
Not this again but in a new thread. :frowning:
Sorry, but it’s frustrating to keep dealing with the same misunderstanding over and over, and watching a forum member go further down the rabbit hole.

You’ve already been told there is absolutely NO need to covert to a string to XOR bits. You can XOR bits in a byte or char in place using...

char c1 = 'H';

char c2 = 0xA5;
char result = c1 ^ c2;



Now you have XORed all 8 bits at once. Far more efficient, and no need for conversion.

If your stream of bits to XOR with are provided one bit at a time (say by some algorithm), assemble them into a single byte or char and use the code above.

There is absolutely no need to convert to a binary string to XOR, even less reason to do so purely for transmission. Indeed in many ways it is totally counterproductive (bandwidth use for one).

I understand that you can make XOR between 2 chars because the are stored binary , but if i make a XOR between , for example , 'H' and 0xA5 will be like this :
01001000 (H) XOR 10100101 (0xA5= 11101101 .
But what i have to do is to multiplicate each bit of H and make a XOR with 0xA5 like this
000000001111111100000000000000001111111100000000000000000000000 XOR
1110110111101101111011011110110111101101111011011110110111101101

Here is a clear picture of what i need to implement in software before sending data.
https://imgur.com/a/HSDySLd

I hope you understand better what i want to do.

pcbbc:
Original thread where the OP was provided with many many examples of how to convert to/from binary.

And yes OP - YOUR BUFFER IS TOO SMALL. It requires an extra byte for the null terminator.

Edit: Having watched the video you provided on DSSS on the above thread it is more clear than ever to me you are totally confused about data types and their representation.

There is absolutely no need to convert to ASCII for this. The ‘1’s and ‘0’s they are talking about on the video are individual bits, not ASCII characters which are 8 bits each. 0x30 for 0 or 0x31 for 1.

There is a very high chance that i misunderstand data types .
But my question is how can i implement that DSSS for transfering text or data from a sensor. I dont think i get it.And im sorry for my wrong afirmations but its my first time working with arduino and i dont really know how can i implement that DSSS

guturobert:
I hope you understand better what i want to do.

Yes, I understand exactly what you want to do and it still has nothing to do with the ASCII characters '0' and '1''.

Here is an example...

uint8_t iRN = 0;
uint8_t RN[] = { 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0x00 };

uint8_t GetRNByte()
{
  uint8_t rn = RN[iRN++];
  if (iRN >= sizeof(RN)) iRN = 0;
  return rn;
}

void Encode(uint8_t* msg, uint8_t len, uint8_t* buf)
{
  while (len--)
  {
    uint8_t b = *msg++;
    for (uint8_t i = 0; i < 8; i++)
    {
      uint8_t rn = GetRNByte();
      if (b & 0x80) rn ^= 0xFF;
      *buf++ = rn;
      b <<= 1;
    }    
  }
}

void Decode(uint8_t* buf, uint8_t len, uint8_t* msg)
{
  while (len--)
  {
    uint8_t b = 0;
    for (uint8_t i = 0; i < 8; i++)
    {
      uint8_t rn = GetRNByte();
      b <<= 1;
      if (*buf++ != rn) b |= 1;
    }
    *msg++ = b;  
  }
}

void setup() {
  uint8_t source[] = "Hi";
  uint8_t encoded[16];
  uint8_t result[3];
  
  Serial.begin(115200);
  
  Serial.print("Source:");
  Serial.println((char*)source);
  
  iRN = 0;
  Encode(source, 2, encoded);
  
  iRN = 0;
  Decode(encoded, 2, result);  
  result[2] = 0; // null terminator
  
  Serial.print("Result:");
  Serial.println((char*)result);
}



void loop() {
}

Edit:
I've no idea how you are generating your pseudo random noise. I have hard coded an array of (not very) random numbers for testing.

I've no idea how you are decoding the incoming DSSS bytes back into bits. What if there is not an exact match with the PRN? I assumed an exact match is a zero bit in, anything else a 1. Almost certainly this is not correct, but it will do for an example.

What sensor, what wireless link? Or is this just a coding exercise/simulation?

pcbbc:
Yes, I understand exactly what you want to do and it still has nothing to do with the ASCII characters '0' and '1''.

Here is an example...

uint8_t iRN = 0;

uint8_t RN[] = { 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0x00 };

uint8_t GetRNByte()
{
  uint8_t rn = RN[iRN++];
  if (iRN >= sizeof(RN)) iRN = 0;
  return rn;
}

void Encode(uint8_t* msg, uint8_t len, uint8_t* buf)
{
  while (len--)
  {
    uint8_t b = *msg++;
    for (uint8_t i = 0; i < 8; i++)
    {
      uint8_t rn = GetRNByte();
      if (b & 0x80) rn ^= 0xFF;
      *buf++ = rn;
      b <<= 1;
    }   
  }
}

void Decode(uint8_t* buf, uint8_t len, uint8_t* msg)
{
  while (len--)
  {
    uint8_t b = 0;
    for (uint8_t i = 0; i < 8; i++)
    {
      uint8_t rn = GetRNByte();
      b <<= 1;
      if (*buf++ != rn) b |= 1;
    }
    *msg++ = b; 
  }
}

void setup() {
  uint8_t source[] = "Hi";
  uint8_t encoded[16];
  uint8_t result[3];
 
  Serial.begin(115200);
 
  Serial.print("Source:");
  Serial.println((char*)source);
 
  iRN = 0;
  Encode(source, 2, encoded);
 
  iRN = 0;
  Decode(encoded, 2, result); 
  result[2] = 0; // null terminator
 
  Serial.print("Result:");
  Serial.println((char*)result);
}

void loop() {
}



Edit:
I've no idea how you are generating your pseudo random noise. I have hard coded an array of (not very) random numbers for testing.

I've no idea how you are decoding the incoming DSSS bytes back into bits. What if there is not an exact match with the PRN? I assumed an exact match is a zero bit in, anything else a 1. Almost certainly this is not correct, but it will do for an example.

What sensor, what wireless link? Or is this just a coding exercise/simulation?

This is a project. For wireless comunication i,m using some cheap RF transmitter and reciever working on 433MHZ(they are called Aurel TX SAW MID 3V and Aurel RX MID 3V) and for the sensor im using DTH22 temperature and umidity sensor.
About the pseudonoise , its not going to be a real PN code , but a n bits long code(ex n=8) that is gonna be known on the transmitter and reciever part too.

guturobert:
About the pseudonoise , its not going to be a real PN code , but a n bits long code(ex n=8) that is gonna be known on the transmitter and reciever part too.

Even easier then.

#define RANDOM_NOISE 0xAA

void Encode(uint8_t* msg, uint8_t len, uint8_t* buf)
{
  while (len--)
  {
    uint8_t b = *msg++;
    for (uint8_t i = 0; i < 8; i++)
    {
      uint8_t rn = RANDOM_NOISE;
      if (b & 0x80) rn ^= 0xFF;
      *buf++ = rn;
      b <<= 1;
    }    
  }
}

void Decode(uint8_t* buf, uint8_t len, uint8_t* msg)
{
  while (len--)
  {
    uint8_t b = 0;
    for (uint8_t i = 0; i < 8; i++)
    {
      uint8_t rn = RANDOM_NOISE;
      b <<= 1;
      if (*buf++ != rn) b |= 1;
    }
    *msg++ = b;  
  }
}

void setup() {
  uint8_t source[] = "Hi";
  uint8_t encoded[16];
  uint8_t result[3];
  
  Serial.begin(115200);
  
  Serial.print("Source:");
  Serial.println((char*)source);
  
  Encode(source, 2, encoded);
  
  Decode(encoded, 2, result);  
  result[2] = 0; // null terminator
  
  Serial.print("Result:");
  Serial.println((char*)result);
}



void loop() {
}

You still haven't said how reception should work. Say the random noise byte is 0xAA (as above). Then for a 0 we transmit 0xAA and for a 1 we transmit 0x55. What happens at the receiver if we receive any value other than 0xAA or 0x55?

pcbbc:
Even easier then.

#define RANDOM_NOISE 0xAA

void Encode(uint8_t* msg, uint8_t len, uint8_t* buf)
{
  while (len--)
  {
    uint8_t b = *msg++;
    for (uint8_t i = 0; i < 8; i++)
    {
      uint8_t rn = RANDOM_NOISE;
      if (b & 0x80) rn ^= 0xFF;
      *buf++ = rn;
      b <<= 1;
    }   
  }
}

void Decode(uint8_t* buf, uint8_t len, uint8_t* msg)
{
  while (len--)
  {
    uint8_t b = 0;
    for (uint8_t i = 0; i < 8; i++)
    {
      uint8_t rn = RANDOM_NOISE;
      b <<= 1;
      if (*buf++ != rn) b |= 1;
    }
    *msg++ = b; 
  }
}

void setup() {
  uint8_t source[] = "Hi";
  uint8_t encoded[16];
  uint8_t result[3];
 
  Serial.begin(115200);
 
  Serial.print("Source:");
  Serial.println((char*)source);
 
  Encode(source, 2, encoded);
 
  Decode(encoded, 2, result); 
  result[2] = 0; // null terminator
 
  Serial.print("Result:");
  Serial.println((char*)result);
}

void loop() {
}



You still haven't said how reception should work. Say the random noise byte is 0xAA (as above). Then for a 0 we transmit 0xAA and for a 1 we transmit 0x55. What happens at the receiver if we receive any value other than 0xAA or 0x55?

Theoretically , if you recieve a byte different than xAA or x55 , i think you need to check every bit and see if it matches more bits of 0xAA or 0x55

I think what you are doing might work, but it isn't practical. My guess is that your message is encoded in the spreading code with an 1:8 ratio, this is why you are using one bit message per one byte spreading code. However, at the end of the day, the radios you chose have a maximum data rate of 10kHz. In practical experience, it is more wisely run at the "typical" rate of 5 kHz. That means that your message rate will now be limited to 625 bits per second, and most of the benefits of spreading will be squandered. In fact, it is not permitted to broadcast continuously on those radio's frequency in most countries. 433 MHz devices are supposed to transmit with a very low duty cycle so not to interfere with other devices. Since, instead of increasing your bandwidth with spreading (which would normally be done with a spread code of a much higher bandwidth than the message) because it is not possible with the radios, your continuous low bandwidth carrier will definitely interfere with other devices. It is not possible to achieve practical DSSS with those radios, you need something with IQ mod and demods. Unless, this is a purely academic exercise, but as that, it's not going very well.

It is completely nonsense to convert the bits of a byte to a string in order to use the characters from that string to XOR another range of bytes. You where given a very simple example on how to do what your want but it seems like that did not work for you? You should probably try to learn how bytes and bits relate and how numbers are stored in memory because a byte IS essentially a string of 8 bits.

Danois90:
a byte IS essentially a string of 8 bits.

...but without the trailing zero :smiley:

guturobert:
Theoretically , if you recieve a byte different than xAA or x55 , i think you need to check every bit and see if it matches more bits of 0xAA or 0x55

uint8_t count_bits(uint8_t v)
{
  uint8_t c = 0;
  for (uint8_t i = 0; i < 8; i++)
  {
    if (v & 0x80) c++;
    v <<= 1;
  }
  return c;
}

And if you get 4 bits correct, 4 bits wrong?  But anyway...
void Decode(uint8_t* buf, uint8_t len, uint8_t* msg)
{
  while (len--)
  {
    uint8_t b = 0;
    for (uint8_t i = 0; i < 8; i++)
    {
      uint8_t rn = RANDOM_NOISE;
      rn ^= *buf++;      
      b <<= 1;
      if (count_bits(rn) > 4) b |= 1;
    }
    *msg++ = b;  
  }
}

aarg:
I think what you are doing might work, but it isn't practical.

I totally agree.

Having produced a semi-commercial product (which I successfully rent out privately as part of a home business) which uses just this type of OOK radio.

I can say Manchester Encoding plus a CRC of suitable length would be a far better use of available bandwidth, and works perfectly adequately.

Unless of course, as you say, this is being used a learning exercise. Still it is a particularly poor one given the hardware provided.