Custom Arduino library method does not return to Arduino's loop function.

I'm having difficulty integrating the SoftwareSerial library on my custom library.
https://github.com/arduino/Arduino/tree/master/hardware/arduino/avr/libraries/SoftwareSerial

I was having similar issues previously described on this thread. The previous issue has been resolved.
http://forum.arduino.cc/index.php?topic=486354.0

The issue I'm having now is that the method checkBluetooth() in my library doesn't work.

What happens is that when this function is called, the program does not return to the Arduino's loop function

I tried commenting out code and re-running multiple times and found out that this happens when I call _bluetooth.available() or _bluetooth.read() in checkBluetooth() function.

Thank you for your help.

MobileBLETest.ino

#include <MobileBLE.h>


// PINS
const int BLUETOOTH_TX    = 8;
const int BLUETOOTH_RX    = 7;

int throttle, steering;
char button;

MobileBLE phone(BLUETOOTH_TX, BLUETOOTH_RX);

void setup() {
 Serial.begin(9600);
 Serial.println("setup");
 phone.begin();
}

void loop() {

 // check for any incoming bluetooth signal
 phone.checkBluetooth();

 // this button value is the ASCII character you press on the Command page of the app.
 //button = phone.getButton();

 // TODO: change the range to make it easier
 // throttle and steering value goes from 0 to 99.
 //throttle = phone.getThrottle();
 //steering = phone.getSteering();

 int i = 0;

 Serial.println("test");

 //Serial.println("Throttle: " + throttle);
 //Serial.println("Steering: " + steering);
 //Serial.println("Button: " + button);
}

MobileBLE.h

#ifndef _MobileBLE_h
#define _MobileBLE_h

class SoftwareSerial;

class MobileBLE
{
 public:
 MobileBLE(int TX, int RX); // TODO should I use ref?
 void begin();
 char getButton();
 int getThrottle();
 int getSteering();
 void checkBluetooth();
 private:
 SoftwareSerial &_bluetooth;
 int _signal[10];
 int _signalLength = 0;
 int _TX;
 int _RX;
 int _throttle;
 int _steering;
 char _button;
 void push(int elem);
 void deleteElements();
};

#endif

MobileBLE.cpp

/*
 Name: MobileBLE.cpp
 Created: 6/28/2017 11:00:39 AM
 Author: jaean
 Editor: http://www.visualmicro.com
*/

#include "MobileBLE.h"
#include "Arduino.h"
#include <SoftwareSerial.h>


MobileBLE::MobileBLE(int TX, int RX) {
 _TX = TX;
 _RX = RX;
 _signalLength = 0;
}

void MobileBLE::push(int elem) {
 _signal[_signalLength] = elem;
 _signalLength++;
}

void MobileBLE::deleteElements() {
 for (int i = 0; i < _signalLength; i++) {
 _signal[i] = 0;
 }
 _signalLength = 0;
}

void MobileBLE::begin() {
 _bluetooth = SoftwareSerial(_TX, _RX);
 _bluetooth.begin(9600);  // Start bluetooth serial at 9600
}

void MobileBLE::checkBluetooth() {

 // TODO:
 // returns 0 - if no transmission found for throttle, steering, or button
 // returns 1 - if transmission found for throttle and steering
 // returns 2 - if transmission found for button
 // returns 3 - if both throttle, steering, and button transmission are found.


 for (int i = 0; i < 10; i++) {
 if (_bluetooth.available()) {
 int input = _bluetooth.read();

 push(input);

 if (input == 254) {
 // end of transmission for orientation
 _throttle = _signal[0];
 _steering = _signal[1];
 deleteElements(); // delete all elements in the singal array
 }
 else if (input == 255) {
 // end of transmission for button click
 _button = (char)_signal[0];
 deleteElements();
 }
 }
 }
}

char MobileBLE::getButton() {
 char btn = _button;
 _button = NULL;
 return btn;
}

int MobileBLE::getThrottle() {
 return _throttle;
}

int MobileBLE::getSteering() {
 return _steering;
}

It looks like you have a reference to SoftwareSerial but you never actually create a SoftwareSerial object.

This pattern is used for libraries where you can pass any kind of serial to the library. You might want to run this on a Teensy in the future and you want to put the Bluetooth on hardware Serial3, for example. You would use a Stream reference, since both hardware and software serial are Streams.

On the begin method there is.
_bluetooth = SoftwareSerial(_TX, _RX);

So the SoftwareSerial object should be created.

MorganS is right, you're library would be much more flexible if you don't integrate serial into the library but just pass it a steam object when you create it. :slight_smile:

About this problem, I don't know. SoftSerial is just a bit of a headache which I try to avoid...

Hi,

I have a custom library where ive used software serial in the past for an SL031 tag reader,

See if the attached helps you,

Andy

SL031.cpp (14.2 KB)

SL031.h (746 Bytes)

void MobileBLE::checkBluetooth()
{
  for (int i = 0; i < 10; i++) 
  {
    if (_bluetooth.available()) 
    {
<snippage happens>
    }
  }
}

Why is there a for loop there? If there is no data, do you really need to check that there is no data 10 times?

If there is data, why do you read only one character?

Could use this instead as a timeout to check bluetooth

void MobileBLE::checkBluetooth()
{

      unsigned long timeout=millis();

      while (!_bluetooth.available() && ((millis()-timeout) < 10000)) //10 second timeout
    {

    }
  
}

Blocking functions :frowning: Makes me sadddd

It may be blocking but its not necessarily a bad thing? entirely depends on the context of the application. Just a simple solution.

It depends on the application indeed. But I think it's a bad thing to make a library that can't be used in an application you want to do more then one thing. Aka, no blocking unless you really really really need it. And I don't find that the case here.

I suppose for a generic implementation it would be best to leave it up to the user of the library to decide how to check. i.e:

bool MobileBLE::checkBluetooth()
{

     if(_bluetooth.available()){return true;}
     else{return false;} 
  
}

andyowenwest:
I suppose for a generic implementation it would be best to leave it up to the user of the library to decide how to check.

Libraries are by definition generic.

I'm using SoftwareSerial because I need to use serial communication on non RX TX pins of the Arduino.
Is there a easy way to do that using a Stream object?

I'm a newbie, would anyone mind putting up sample code using stream object in a library?

Thanks. :slight_smile:

It not that it's easier with the Stream object but the Stream calss is the parent of both HardwareSerial and SoftwareSerial. They share the same functionality although the implementation is different.

The great advantage in designing the library in a way you need to pass a Stream object is that the user may choose to do use Serial or Serial1 etc. You give them a choice :slight_smile: All you need to know in your library is that you can call .begin(), print() etc on the object which you can with both HardareSerial and SoftwareSerial because it's part of Stream :slight_smile:

So not fixing any other errors you have (except indentation)

.h

#ifndef _MobileBLE_h
#define _MobileBLE_h
 #include <Arduio.h>

class MobileBLE
{
 public:
   MobileBLE(Stream &output);
   void begin();
   char getButton();
   int getThrottle();
   int getSteering();
   void checkBluetooth();
 private:
   Stream &_bluetooth;
   int _signal[10];
   int _signalLength = 0;
   int _throttle;
   int _steering;
   char _button;
   void push(int elem);
   void deleteElements();
};

#endif

.cpp

/*
  Name: MobileBLE.cpp
  Created: 6/28/2017 11:00:39 AM
  Author: jaean
  Editor: http://www.visualmicro.com
*/

#include "MobileBLE.h"
#include "Arduino.h"


MobileBLE::MobileBLE(Stream &output) :
  _bluetooth(output),
  _signalLength(0)
{
  
}

void MobileBLE::push(int elem) {
  _signal[_signalLength] = elem;
  _signalLength++;
}

void MobileBLE::deleteElements() {
  for (int i = 0; i < _signalLength; i++) {
    _signal[i] = 0;
  }
  _signalLength = 0;
}

void MobileBLE::begin() {
  _bluetooth.begin(9600);  // Start bluetooth serial at 9600
}

void MobileBLE::checkBluetooth() {

  // TODO:
  // returns 0 - if no transmission found for throttle, steering, or button
  // returns 1 - if transmission found for throttle and steering
  // returns 2 - if transmission found for button
  // returns 3 - if both throttle, steering, and button transmission are found.


  for (int i = 0; i < 10; i++) {
    if (_bluetooth.available()) {
      int input = _bluetooth.read();

      push(input);

      if (input == 254) {
        // end of transmission for orientation
        _throttle = _signal[0];
        _steering = _signal[1];
        deleteElements(); // delete all elements in the singal array
      }
      else if (input == 255) {
        // end of transmission for button click
        _button = (char)_signal[0];
        deleteElements();
      }
    }
  }
}

char MobileBLE::getButton() {
  char btn = _button;
  _button = NULL;
  return btn;
}

int MobileBLE::getThrottle() {
  return _throttle;
}

int MobileBLE::getSteering() {
  return _steering;
}

And now use SoftSerial in your sketch and pass the SoftSerial object to the constructor of MobileBLE.

Thank you so much everyone and septillion. The code finally works :slight_smile: