Pages: [1]   Go Down
Author Topic: New peek function for HardwareSerial  (Read 981 times)
0 Members and 2 Guests are viewing this topic.
Queens, New York
Offline Offline
Faraday Member
**
Karma: 98
Posts: 3576
"Of all the things I've ever lost, I miss my mind the most" -Ozzy Osbourne
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I was trying to help out a new user with his project, but the solution I though would work turned out to only work once.

Users post
The user wanted to send a string from his phone to control a RGB led(s), and the code I gave him was:

Code:
char * strings[3] = {
  "RED", "GREEN", "BLUE"};
byte i = 0;

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

void loop()
{
  if(Serial.available())
  {
    while(i < 3)
    {
      if(Serial.find(strings[i]))
      {
        Serial.print("Found ");
        Serial.println(strings[i]);
        i = 0;
        break;
      }
      Serial.println(i);
      i++;
    }
    if( i >= 3)
    {
      Serial.println("not found");
      i = 0;
    }
  }
}

This code should check the buffer and see if a string is found, and if not increment the index and check again.

It will find RED if typed in because it is in the first index of the strings array, but it won't find anything else. Upon further investigation, I found out that read() pops the ints (look at the .h and .cpp files for HWS) out of the buffer when it is called so this prevents my code from working. However another function peek() only looks at the first index of the buffer and doesn't move unless read is called.

I would like to add a new peek() function that allows the user to look through the buffer freely without popping anything out, thus allowing my code to work.

I have made an equivalent code that does what I want using the normal HWS library, but it is not very elegant. I'm sure I am not the only person this new function would help, so I am asking if it can be added.

New peek function, simple right?
Code:
int HardwareSerial::peek(uint8_t position)
{
  if (_rx_buffer->head == _rx_buffer->tail) {
    return -1;
  } else {
    return _rx_buffer->buffer[position];
  }
}
« Last Edit: August 16, 2014, 03:58:06 pm by HazardsMind » Logged

Created Libraries:
NPV2 (NewPasswordV2),  TFT_Extension, OneWireKeypad, SerialServo.
Will provide libraries if asked in PM or forum.

UK
Offline Offline
Tesla Member
***
Karma: 121
Posts: 6987
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

A somewhat related thing I have been thinking about (but not yet doing anything about) is the possibility of passing an array reference to HardwareSerial so it writes the data straight into my variable without needing to use Serial.read(). Then a user could have two or three "buffers" and alternate them to receive incoming data. The idea is to avoid the overhead of transferring the data from the HardwareSerial buffer to my buffer. It would also allow me to specify a larger buffer if necessary.

If the data is put directly into my variable I could "peek" to my heart's content with char x = myArray[indx];

...R
« Last Edit: August 16, 2014, 04:12:46 pm by Robin2 » Logged

Queens, New York
Offline Offline
Faraday Member
**
Karma: 98
Posts: 3576
"Of all the things I've ever lost, I miss my mind the most" -Ozzy Osbourne
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Well if you think about, all we need to do is access the buffer. The only problem that I can't seem to figure out is how to access the buffer

From HardwareSerial.cpp file.
Quote
struct ring_buffer
{
  unsigned char buffer[SERIAL_BUFFER_SIZE];
  volatile unsigned int head;
  volatile unsigned int tail;
};

Is there any way to access this struct outside the library?
Logged

Created Libraries:
NPV2 (NewPasswordV2),  TFT_Extension, OneWireKeypad, SerialServo.
Will provide libraries if asked in PM or forum.

Global Moderator
Netherlands
Offline Offline
Shannon Member
*****
Karma: 216
Posts: 13676
In theory there is no difference between theory and practice, however in practice there are many...
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
Is there any way to access this struct outside the library?

this works for version 1.5.6, (structure/permissions have been changed)

Code:
void setup()
{
  Serial.begin(115200);
  Serial.println("Start ");
}

void loop()
{
  int x = Serial._rx_buffer[1];
  Serial.println(x, DEC);
  int h = Serial._rx_buffer_head;
  Serial.println(h, DEC);
  int t = Serial._rx_buffer_tail;
  Serial.println(t, DEC);
  delay(1000);
}
Logged

Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

Queens, New York
Offline Offline
Faraday Member
**
Karma: 98
Posts: 3576
"Of all the things I've ever lost, I miss my mind the most" -Ozzy Osbourne
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

@robtillaart
I just downloaded version 1.5.7, and I guess the permissions were changed back, because your code doesn't work anymore.

Edit:
I downloaded 1.5.6 r2 and it doesn't work either, I got the exact same error message :/

Error message:
Quote
Arduino: 1.5.7 (Windows 8 ), Board: "Arduino Uno"

In file included from C:\Users\Andrew\Documents\arduino-1.5.7\hardware\arduino\avr\cores\arduino/Arduino.h:221:0,
                 from sketch_aug16a.ino:1:
C:\Users\Andrew\Documents\arduino-1.5.7\hardware\arduino\avr\cores\arduino/HardwareSerial.h: In function 'void loop()':
C:\Users\Andrew\Documents\arduino-1.5.7\hardware\arduino\avr\cores\arduino/HardwareSerial.h:101:51: error: 'unsigned char HardwareSerial::_rx_buffer [64]' is protected
     unsigned char _rx_buffer[SERIAL_RX_BUFFER_SIZE];
                                                   ^
sketch_aug16a.ino:9:18: error: within this context
In file included from C:\Users\Andrew\Documents\arduino-1.5.7\hardware\arduino\avr\cores\arduino/Arduino.h:221:0,
                 from sketch_aug16a.ino:1:
C:\Users\Andrew\Documents\arduino-1.5.7\hardware\arduino\avr\cores\arduino/HardwareSerial.h:93:32: error: 'volatile rx_buffer_index_t HardwareSerial::_rx_buffer_head' is protected
     volatile rx_buffer_index_t _rx_buffer_head;
                                ^
sketch_aug16a.ino:11:18: error: within this context
In file included from C:\Users\Andrew\Documents\arduino-1.5.7\hardware\arduino\avr\cores\arduino/Arduino.h:221:0,
                 from sketch_aug16a.ino:1:
C:\Users\Andrew\Documents\arduino-1.5.7\hardware\arduino\avr\cores\arduino/HardwareSerial.h:94:32: error: 'volatile rx_buffer_index_t HardwareSerial::_rx_buffer_tail' is protected
     volatile rx_buffer_index_t _rx_buffer_tail;
                                ^
sketch_aug16a.ino:13:18: error: within this context

  This report would have more information with
  "Show verbose output during compilation"
  enabled in File > Preferences.
« Last Edit: August 16, 2014, 05:24:05 pm by HazardsMind » Logged

Created Libraries:
NPV2 (NewPasswordV2),  TFT_Extension, OneWireKeypad, SerialServo.
Will provide libraries if asked in PM or forum.

Global Moderator
Netherlands
Offline Offline
Shannon Member
*****
Karma: 216
Posts: 13676
In theory there is no difference between theory and practice, however in practice there are many...
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Sorry,
then the only way seems to be to mod the libs...  smiley-sad

Logged

Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

North Queensland, Australia
Offline Offline
Edison Member
*
Karma: 69
Posts: 2167
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Sorry,
then the only way seems to be to mod the libs...  smiley-sad

There is always a way. I'll have a crack and see what I can come up with.

« Last Edit: August 17, 2014, 08:51:07 am by pYro_65 » Logged


North Queensland, Australia
Offline Offline
Edison Member
*
Karma: 69
Posts: 2167
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Here is a solution. And you can access RX and TX buffers. Sorry for any headaches it may cause, and feel free to ask if you have questions.

Code:
template< typename Tag, typename Tag::type M >
  struct AccessMember{
    friend typename Tag::type get( Tag ){ return M; }
};

template< bool _RX >
struct HardwareSerial_Buffer{
  typedef uint8_t arr_t[ _RX ? SERIAL_RX_BUFFER_SIZE : SERIAL_TX_BUFFER_SIZE ];
  typedef arr_t HardwareSerial::*type;
  friend type get( HardwareSerial_Buffer );
};

template struct AccessMember< HardwareSerial_Buffer< true >, &HardwareSerial::_rx_buffer >;
template struct AccessMember< HardwareSerial_Buffer< false >, &HardwareSerial::_tx_buffer >;

uint8_t *GetRX( HardwareSerial &instance ){ return instance.*get( HardwareSerial_Buffer< true >() ); }
uint8_t *GetTX( HardwareSerial &instance ){ return instance.*get( HardwareSerial_Buffer< false >() ); }

And it is used very simply:
Code:
void setup() {
  Serial.begin( 9600 );
  
  uint8_t *rx_start = GetRX( Serial );
  uint8_t *tx_start = GetTX( Serial );
}

void loop() {}
« Last Edit: August 17, 2014, 09:36:40 am by pYro_65 » Logged


SF Bay Area (USA)
Offline Offline
Tesla Member
***
Karma: 132
Posts: 6746
Strongly opinionated, but not official!
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

These are awful.  Typically the buffer used for serial IO at the hardware level would be separate from the buffer used for parsing, even though that is somewhat memory inefficient.  Something like:

Code:
String token = Serial.readStringUntil('\n');
if (token == "RED") {
  // light red
} else if (token == "BLUE") {
  // light blue
} else if (token == "GREEN") {
  // light green
}
(Insert warning about String not being a great idea, given its current state, and maybe using Serial.readBytesUntil() and strcmp() instead.)
Logged

Queens, New York
Offline Offline
Faraday Member
**
Karma: 98
Posts: 3576
"Of all the things I've ever lost, I miss my mind the most" -Ozzy Osbourne
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I made a solution to the guy's problem without any special functions, but it looks like crap.
Code:
char * strings[] = {
  "RED", "GREEN", "BLUE","ORANGE"};
 
byte i = 0, j=0;
unsigned long _startMillis = 0;
char data[20];
int index = 0;
boolean search = false, found = false;
#define arrSize(x) sizeof(x)/sizeof(x[0])

void setup()
{
  Serial.begin(115200);
  clear(20);
  Serial.println(arrSize(strings));
}

void loop()
{
  searchBuff(20);
}

void searchBuff(byte samples)
{
  if(Serial.available() > 0)
  {
    for(int S = 0, tmp; S < samples; S++)
    {
      tmp = Serial.read();
      if(tmp != '\n' || tmp != '\r' || tmp != '\0')
        data[S] = tmp;
      delay(1); // this is needed, otherwise it will not show/store the correct data in the array.
    }
    search = true;
    found = false;
  }
  index = 0;
  if(search)
  {
    j = 0;
    while(j < arrSize(strings))
    {
      for(byte i = 0; i < samples; i++)
      {
        if(data[i] != strings[j][index])
          index = 0; // reset index if any char does not match

        if( data[i] == strings[j][index])
        {
          if(index == strlen(strings[j])-1) // is true if all chars in the target match
          {
            Serial.print("Found ");
            Serial.println(strings[j]);
            index = 0;
            found = true;
            break;
          }
          else
            index++;
        }
      }//end of FOR loop
      if(found)
        search = false;
      j++;
    }// End of WHILE loop
    if(!found)
    {
      Serial.println("not found");
      search = false;
    }
   
    clear(samples);
  }// End of Search
}

void clear(byte samples)
{
  int k = 0;
  while(k < samples)
  {
    data[k] = 0;
    k++;
  }
  search = false;
}

I also modified my HWS library with the peek function I wanted and it does work, but to clear the buffer, I need to use a loop to do multiple Serial.read(). I am going to see if there is a better way to clear the buffer, maybe its something really simple that I am not seeing, Idk.
« Last Edit: August 21, 2014, 08:14:17 am by HazardsMind » Logged

Created Libraries:
NPV2 (NewPasswordV2),  TFT_Extension, OneWireKeypad, SerialServo.
Will provide libraries if asked in PM or forum.

nr Bundaberg, Australia
Offline Offline
Tesla Member
***
Karma: 126
Posts: 8501
Scattered showers my arse -- Noah, 2348BC.
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

I haven't looked at that code for ages but normally to clear a FIFO you just set the head pointer to = the tail pointer and (sometimes) clear a counter.

______
Rob
Logged

Rob Gray aka the GRAYnomad www.robgray.com

Queens, New York
Offline Offline
Faraday Member
**
Karma: 98
Posts: 3576
"Of all the things I've ever lost, I miss my mind the most" -Ozzy Osbourne
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I'll try it when I get home tonight.
Logged

Created Libraries:
NPV2 (NewPasswordV2),  TFT_Extension, OneWireKeypad, SerialServo.
Will provide libraries if asked in PM or forum.

Pages: [1]   Go Up
Jump to: