diff --git a/SPP.cpp b/SPP.cpp index 80b5a8f6..a3b4401d 100644 --- a/SPP.cpp +++ b/SPP.cpp @@ -67,6 +67,7 @@ void SPP::Reset() { l2cap_sdp_state = L2CAP_SDP_WAIT; l2cap_rfcomm_state = L2CAP_RFCOMM_WAIT; l2cap_event_flag = 0; + sppIndex = 0; } void SPP::disconnect() { @@ -381,6 +382,7 @@ void SPP::ACLData(uint8_t* l2capinbuf) { waitForLastCommand = false; creditSent = false; connected = true; // The RFCOMM channel is now established + sppIndex = 0; } #ifdef DEBUG else if (rfcommChannelType != RFCOMM_DISC) { @@ -413,7 +415,9 @@ void SPP::Run() { creditSent = false; waitForLastCommand = false; connected = true; // The RFCOMM channel is now established + sppIndex = 0; } + send(); // Send all bytes currently in the buffer } void SPP::SDP_task() { @@ -725,22 +729,21 @@ uint8_t SPP::calcFcs(uint8_t *data) { } /* Serial commands */ -void SPP::print(const String &str) { - uint8_t length = str.length(); // Get the length of the string - uint8_t buf[length]; - - for(uint8_t i = 0; i < length; i++) - buf[i] = str[i]; - - print(buf,length); +size_t SPP::write(uint8_t data) { + return write(&data,1); } -void SPP::print(const char* str) { - print((uint8_t*) str, strlen(str)); +size_t SPP::write(const uint8_t* data, size_t size) { + for(uint8_t i = 0; i < size; i++) { + if(sppIndex >= sizeof(sppOutputBuffer)/sizeof(sppOutputBuffer[0])) + return i; // Don't send any more if buffer is already full + sppOutputBuffer[sppIndex++] = data[i]; // All the bytes are put into a buffer and then send using the send() function + } + return size; } -void SPP::print(uint8_t* array, uint8_t stringLength) { - if (!connected) +void SPP::send() { + if (!connected || !sppIndex) return; uint8_t length; // This is the length of the string we are sending uint8_t offset = 0; // This is used to keep track of where we are in the string @@ -748,177 +751,42 @@ void SPP::print(uint8_t* array, uint8_t stringLength) { l2capoutbuf[0] = rfcommChannelConnection | 0 | 0 | extendAddress; // RFCOMM Address l2capoutbuf[1] = RFCOMM_UIH; // RFCOMM Control - while (stringLength) { // We will run this while loop until this variable is 0 - if (stringLength > (sizeof (l2capoutbuf) - 4)) // Check if the string is larger that the outgoing buffer + while (sppIndex) { // We will run this while loop until this variable is 0 + if (sppIndex > (sizeof (l2capoutbuf) - 4)) // Check if the string is larger than the outgoing buffer length = sizeof (l2capoutbuf) - 4; else - length = stringLength; + length = sppIndex; l2capoutbuf[2] = length << 1 | 1; // Length uint8_t i = 0; for (; i < length; i++) - l2capoutbuf[i + 3] = array[i + offset]; + l2capoutbuf[i + 3] = sppOutputBuffer[i + offset]; l2capoutbuf[i + 3] = calcFcs(l2capoutbuf); // Calculate checksum RFCOMM_Command(l2capoutbuf, length + 4); - stringLength -= length; + sppIndex -= length; offset += length; // Increment the offset } } -void SPP::println(const String &str) { - String output = str + "\r\n"; - print(output); +int SPP::available(void) { + return rfcommAvailable; +}; + +void SPP::flush(void) { + rfcommAvailable = 0; } -void SPP::println(const char* str) { - char output[strlen(str) + 3]; - strcpy(output, str); - strcat(output, "\r\n"); - print(output); -} - -void SPP::println(uint8_t data) { - uint8_t buf[3] = {data, '\r', '\n'}; - print(buf, 3); -} - -void SPP::println(uint8_t* array, uint8_t length) { - uint8_t buf[length + 2]; - memcpy(buf, array, length); - buf[length] = '\r'; - buf[length + 1] = '\n'; - print(buf, length + 2); -} - -void SPP::printFlashString(const __FlashStringHelper *ifsh, bool newline) { - const char PROGMEM *p = (const char PROGMEM *)ifsh; - uint8_t size = 0; - while (1) { // Calculate the size of the string - uint8_t c = pgm_read_byte(p + size); - if (c == 0) - break; - size++; - } - uint8_t buf[size + 2]; // Add two extra in case it needs to print a newline and carriage return - - for (uint8_t i = 0; i < size; i++) - buf[i] = pgm_read_byte(p++); - - if (newline) { - buf[size] = '\r'; - buf[size + 1] = '\n'; - print(buf, size + 2); - } else - print(buf, size); -} - -void SPP::println(void) { - uint8_t buf[2] = {'\r', '\n'}; - print(buf, 2); -} - -/* These must be used to print numbers */ -void SPP::printNumber(uint32_t n) { - char output[11]; - intToString(n, output); - print(output); -} - -void SPP::printNumberln(uint32_t n) { - char output[13]; - intToString(n, output); - strcat(output, "\r\n"); - print(output); -} - -void SPP::printNumber(int32_t n) { - char output[12]; - intToString(n, output); - print(output); -} - -void SPP::printNumberln(int32_t n) { - char output[14]; - intToString(n, output); - strcat(output, "\r\n"); - print(output); -} - -void SPP::intToString(int32_t input, char* output) { - if (input < 0) { - char buf[11]; - intToString((uint32_t)(input*-1), buf); - strcpy(output, "-"); - strcat(output, buf); - } else - intToString((uint32_t)input, output); -} - -void SPP::intToString(uint32_t input, char* output) { - uint32_t temp = input; - uint8_t digits = 0; - while (temp) { - temp /= 10; - digits++; - } - if (digits == 0) - strcpy(output, "0"); - else { - for (uint8_t i = 1; i <= digits; i++) { - output[digits - i] = input % 10 + '0'; // Get number and convert to ASCII Character - input /= 10; - } - output[digits] = '\0'; // Add null character - } -} - -void SPP::printNumber(double n, uint8_t digits) { - char output[13 + digits]; - doubleToString(n, output, digits); - print(output); -} - -void SPP::printNumberln(double n, uint8_t digits) { - char output[15 + digits]; - doubleToString(n, output, digits); - strcat(output, "\r\n"); - print(output); -} - -void SPP::doubleToString(double input, char* output, uint8_t digits) { - char buffer[13 + digits]; - if (input < 0) { - strcpy(output, "-"); - input = -input; - } else - strcpy(output, ""); - - // Round correctly - double rounding = 0.5; - for (uint8_t i = 0; i < digits; i++) - rounding /= 10.0; - input += rounding; - - uint32_t intpart = (uint32_t)input; - intToString(intpart, buffer); // Convert to string - strcat(output, buffer); - strcat(output, "."); - double fractpart = (input - (double)intpart); - fractpart *= pow(10, digits); - for (uint8_t i = 1; i < digits; i++) { // Put zeros in front of number - if (fractpart < pow(10, digits - i)) { - strcat(output, "0"); - } - } - intToString((uint32_t)fractpart, buffer); // Convert to string - strcat(output, buffer); -} - -uint8_t SPP::read() { +int SPP::peek(void) { if (rfcommAvailable == 0) // Don't read if there is nothing in the buffer - return 0; + return -1; + return rfcommDataBuffer[0]; +} + +int SPP::read(void) { + if (rfcommAvailable == 0) // Don't read if there is nothing in the buffer + return -1; uint8_t output = rfcommDataBuffer[0]; for (uint8_t i = 1; i < rfcommAvailable; i++) rfcommDataBuffer[i - 1] = rfcommDataBuffer[i]; // Shift the buffer one left diff --git a/SPP.h b/SPP.h index 92cb51b0..20ab8f0a 100644 --- a/SPP.h +++ b/SPP.h @@ -90,7 +90,7 @@ */ /** This BluetoothService class implements the Serial Port Protocol (SPP). */ -class SPP : public BluetoothService { +class SPP : public BluetoothService, public Stream { public: /** * Constructor for the SPP class. @@ -118,217 +118,51 @@ public: bool connected; /** @name Serial port profile (SPP) Print functions */ - /** - * Used to send Arduino String data type. - * @param str String to send. - */ - void print(const String &str); - /** - * Same as print(const String &str), but will include newline and carriage return. - * @param str String to send. - */ - void println(const String &str); - - /** - * Used to send standard strings. - * @param str String to send. - */ - void print(const char* str); - /** - * Same as print(const char* str), but will include newline and carriage return. - * @param str String to send. - */ - void println(const char* str); - - /** - * Used to send single bytes. - * @param data Data to send. - */ - void print(uint8_t data) { - print(&data, 1); - }; - /** - * Same as print(uint8_t data), but will include newline and carriage return. - * @param data Data to send. - */ - void println(uint8_t data); - - /** - * Used to send arrays. - * @param array Array to send. - * @param length Number of bytes to send. - */ - void print(uint8_t* array, uint8_t length); - /** - * Same as print(uint8_t* array, uint8_t length), but will include newline and carriage return. - * @param array Array to send. - * @param length Number of bytes to send. - */ - void println(uint8_t* array, uint8_t length); - - /** - * Used to print strings stored in flash. - * Use "SerialBT.print(F("String"));" to print a string stored in flash. - * @param ifsh String to send - see: http://playground.arduino.cc/Learning/Memory. - */ - void print(const __FlashStringHelper *ifsh) { - printFlashString(ifsh, false); - }; - - /** - * Same as print(const __FlashStringHelper *ifsh), but will include newline and carriage return. - * @param ifsh String to send - see: http://playground.arduino.cc/Learning/Memory. - */ - void println(const __FlashStringHelper *ifsh) { - printFlashString(ifsh, true); - }; - /** - * Helper function to print a string stored in flash. - * @param ifsh String stored in flash you want to print. - * @param newline Set this to true to include newline and carriage return. - */ - void printFlashString(const __FlashStringHelper *ifsh, bool newline); - - - /** Use this to print newline and carriage return. */ - void println(void); - - /** - * Used to print unsigned integers. - * @param n Unsigned integer to send. - */ - void printNumber(uint8_t n) { - printNumber((uint32_t) n); - }; - - /** - * Same as printNumber(uint8_t n), but will include newline and carriage return. - * @param n Unsigned integer to send. - */ - void printNumberln(uint8_t n) { - printNumberln((uint32_t) n); - }; - - /** - * Used to print signed integers. - * @param n Signed integer to send. - */ - void printNumber(int8_t n) { - printNumber((int32_t) n); - }; - - /** - * Same as printNumber(int8_t n), but will include newline and carriage return. - * @param n Signed integer to send. - */ - void printNumberln(int8_t n) { - printNumberln((int32_t) n); - }; - - /** - * Used to print unsigned integers. - * @param n Unsigned integer to send. - */ - void printNumber(uint16_t n) { - printNumber((uint32_t) n); - }; - - /** - * Same as printNumber(uint16_t n), but will include newline and carriage return. - * @param n Unsigned integer to send. - */ - void printNumberln(uint16_t n) { - printNumberln((uint32_t) n); - }; - - /** - * Used to print signed integers. - * @param n Signed integer to send. - */ - void printNumber(int16_t n) { - printNumber((int32_t) n); - }; - - /** - * Same as printNumber(int16_t n), but will include newline and carriage return. - * @param n Signed integer to send. - */ - void printNumberln(int16_t n) { - printNumberln((int32_t) n); - }; - - /** - * Used to print unsigned integers. - * @param n Unsigned integer to send. - */ - void printNumber(uint32_t n); - /** - * Same as printNumber(uint32_t n), but will include newline and carriage return. - * @param n Unsigned integer to send. - */ - void printNumberln(uint32_t n); - - /** - * Used to print signed integers. - * @param n Signed integer to send. - */ - void printNumber(int32_t n); - /** - * Same as printNumber(int32_t n), but will include newline and carriage return. - * @param n Signed integer to send. - */ - void printNumberln(int32_t n); - - /** - * Helper function to convert from an unsigned integer to a string. - * @param input Unsigned integer to convert. - * @param output Output buffer. - */ - void intToString(int32_t input, char* output); - /** - * Helper function to convert from a signed integer to a string. - * @param input Signed integer to convert. - * @param output Output buffer. - */ - void intToString(uint32_t input, char* output); - - /** - * Used to print floating-point numbers. - * @param n Floating-point number to print. - * @param digits Number of digits to send. If argument is omitted, then 2 digits will be used. - */ - void printNumber(double n, uint8_t digits = 2); - /** - * Same as printNumber(double n, uint8_t digits), but will include newline and carriage return. - * @param n Floating-point number to print. - * @param digits Number of digits to send. If argument is omitted, then 2 digits will be used. - */ - void printNumberln(double n, uint8_t digits = 2); - /** - * Helper function to convert from a double to a string. - * @param input Floating-point number to convert. - * @param output Output buffer. - * @param digits Number of digits to convert. If argument is omitted, then 2 digits will be used. - */ - void doubleToString(double input, char* output, uint8_t digits = 2); - /** * Get number of bytes waiting to be read. * @return Return the number of bytes ready to be read. */ - uint8_t available() { - return rfcommAvailable; - }; + virtual int available(void); + /** Discard all the bytes in the buffer. */ + virtual void flush(void); + /** + * Used to read the next value in the buffer without advancing to the next one. + * @return Return the byte. Will return -1 if no byte is available. + */ + virtual int peek(void); /** * Used to read the buffer. - * @return Return the byte. Will return 0 if no byte is available. + * @return Return the byte. Will return -1 if no byte is available. */ - uint8_t read(); - - /** Discard all the bytes in the buffer. */ - void flush() { - rfcommAvailable = 0; - }; + virtual int read(void); + /** + * Writes the byte to send to a buffer. The message is send when either send(const uint8_t* data, size_t size) or after Usb.Task() is called. + * @param data The byte to write. + * @return Return the number of bytes written. + */ + virtual size_t write(uint8_t data); + /** + * Writes the bytes to send to a buffer. The message is send when either send(const uint8_t* data, size_t size) or after Usb.Task() is called. + * @param data The data array to send. + * @param size Size of the data. + * @return Return the number of bytes written. + */ + virtual size_t write(const uint8_t* data, size_t size); + /** Pull in write(const char *str) from Print */ + using Print::write; + /** + * This will send all the bytes in the buffer. + * This is called whenever Usb.Task() is called, + * but can also be called via this function. + */ + void send(void); + /** + * Used to provide Boolean tests for the class. + * @return Return true if SPP communication is connected. + */ + operator bool() { + return connected; + } /**@}*/ private: @@ -369,6 +203,8 @@ private: bool creditSent; uint8_t rfcommDataBuffer[100]; // Create a 100 sized buffer for incoming data + uint8_t sppOutputBuffer[100]; // Create a 100 sized buffer for outgoing SPP data + uint8_t sppIndex; uint8_t rfcommAvailable; bool firstMessage; // Used to see if it's the first SDP request received diff --git a/examples/Bluetooth/PS3SPP/PS3SPP.ino b/examples/Bluetooth/PS3SPP/PS3SPP.ino index d07b51dd..098b4278 100644 --- a/examples/Bluetooth/PS3SPP/PS3SPP.ino +++ b/examples/Bluetooth/PS3SPP/PS3SPP.ino @@ -21,7 +21,7 @@ PS3BT PS3(&Btd); // This will just create the instance //PS3BT PS3(&Btd,0x00,0x15,0x83,0x3D,0x0A,0x57); // This will also store the bluetooth address - this can be obtained from the dongle when running the sketch boolean firstMessage = true; -String output = ""; // We will store the data in this string so we doesn't overflow the dongle +String output = ""; // We will store the data in this string void setup() { Serial.begin(115200); // This wil lprint the debugging from the libraries @@ -33,7 +33,7 @@ void setup() { output.reserve(200); // Reserve 200 bytes for the output string } void loop() { - Usb.Task(); + Usb.Task(); // The SPP data is actually not send until Usb.Task() is called if(SerialBT.connected) { if(firstMessage) { @@ -41,7 +41,7 @@ void loop() { SerialBT.println(F("Hello from Arduino")); // Send welcome message } if(Serial.available()) - SerialBT.print(Serial.read()); + SerialBT.write(Serial.read()); if(SerialBT.available()) Serial.write(SerialBT.read()); } diff --git a/examples/Bluetooth/SPP/SPP.ino b/examples/Bluetooth/SPP/SPP.ino index e3d13ec0..d488a7a4 100644 --- a/examples/Bluetooth/SPP/SPP.ino +++ b/examples/Bluetooth/SPP/SPP.ino @@ -22,14 +22,14 @@ void setup() { Serial.print(F("\r\nSPP Bluetooth Library Started")); } void loop() { - Usb.Task(); + Usb.Task(); // The SPP data is actually not send until Usb.Task() is called if(SerialBT.connected) { if(firstMessage) { firstMessage = false; SerialBT.println(F("Hello from Arduino")); // Send welcome message } if(Serial.available()) - SerialBT.print(Serial.read()); + SerialBT.write(Serial.read()); if(SerialBT.available()) Serial.write(SerialBT.read()); } diff --git a/examples/Bluetooth/SPPMulti/SPPMulti.ino b/examples/Bluetooth/SPPMulti/SPPMulti.ino index 4cf6f66f..00a4d7b3 100644 --- a/examples/Bluetooth/SPPMulti/SPPMulti.ino +++ b/examples/Bluetooth/SPPMulti/SPPMulti.ino @@ -34,7 +34,7 @@ void setup() { Serial.print(F("\r\nSPP Bluetooth Library Started")); } void loop() { - Usb.Task(); + Usb.Task(); // The SPP data is actually not send until Usb.Task() is called for(uint8_t i=0;iconnected) { if(firstMessage[i]) { @@ -44,7 +44,7 @@ void loop() { if(SerialBT[i]->available()) Serial.write(SerialBT[i]->read()); } - else + else firstMessage[i] = true; } if(Serial.available()) { @@ -61,7 +61,7 @@ void loop() { if(SerialBT[id]->connected) { // Check if a device is actually connected for(uint8_t i2 = 0; i2 < i-1; i2++) // Don't include the first character buffer[i2] = buffer[i2+1]; - SerialBT[id]->println(buffer,i-1); // Send the data + SerialBT[id]->write(buffer,i-1); // Send the data } } }