The SPP Class now inherit from the Arduino Stream library

This commit is contained in:
Kristian Sloth Lauszus 2013-05-07 00:06:49 +02:00
parent 305eeb0820
commit e6a557870b
5 changed files with 83 additions and 379 deletions

200
SPP.cpp
View file

@ -67,6 +67,7 @@ void SPP::Reset() {
l2cap_sdp_state = L2CAP_SDP_WAIT; l2cap_sdp_state = L2CAP_SDP_WAIT;
l2cap_rfcomm_state = L2CAP_RFCOMM_WAIT; l2cap_rfcomm_state = L2CAP_RFCOMM_WAIT;
l2cap_event_flag = 0; l2cap_event_flag = 0;
sppIndex = 0;
} }
void SPP::disconnect() { void SPP::disconnect() {
@ -381,6 +382,7 @@ void SPP::ACLData(uint8_t* l2capinbuf) {
waitForLastCommand = false; waitForLastCommand = false;
creditSent = false; creditSent = false;
connected = true; // The RFCOMM channel is now established connected = true; // The RFCOMM channel is now established
sppIndex = 0;
} }
#ifdef DEBUG #ifdef DEBUG
else if (rfcommChannelType != RFCOMM_DISC) { else if (rfcommChannelType != RFCOMM_DISC) {
@ -413,7 +415,9 @@ void SPP::Run() {
creditSent = false; creditSent = false;
waitForLastCommand = false; waitForLastCommand = false;
connected = true; // The RFCOMM channel is now established connected = true; // The RFCOMM channel is now established
sppIndex = 0;
} }
send(); // Send all bytes currently in the buffer
} }
void SPP::SDP_task() { void SPP::SDP_task() {
@ -725,22 +729,21 @@ uint8_t SPP::calcFcs(uint8_t *data) {
} }
/* Serial commands */ /* Serial commands */
void SPP::print(const String &str) { size_t SPP::write(uint8_t data) {
uint8_t length = str.length(); // Get the length of the string return write(&data,1);
uint8_t buf[length];
for(uint8_t i = 0; i < length; i++)
buf[i] = str[i];
print(buf,length);
} }
void SPP::print(const char* str) { size_t SPP::write(const uint8_t* data, size_t size) {
print((uint8_t*) str, strlen(str)); 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) { void SPP::send() {
if (!connected) if (!connected || !sppIndex)
return; return;
uint8_t length; // This is the length of the string we are sending 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 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[0] = rfcommChannelConnection | 0 | 0 | extendAddress; // RFCOMM Address
l2capoutbuf[1] = RFCOMM_UIH; // RFCOMM Control l2capoutbuf[1] = RFCOMM_UIH; // RFCOMM Control
while (stringLength) { // We will run this while loop until this variable is 0 while (sppIndex) { // 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 if (sppIndex > (sizeof (l2capoutbuf) - 4)) // Check if the string is larger than the outgoing buffer
length = sizeof (l2capoutbuf) - 4; length = sizeof (l2capoutbuf) - 4;
else else
length = stringLength; length = sppIndex;
l2capoutbuf[2] = length << 1 | 1; // Length l2capoutbuf[2] = length << 1 | 1; // Length
uint8_t i = 0; uint8_t i = 0;
for (; i < length; i++) for (; i < length; i++)
l2capoutbuf[i + 3] = array[i + offset]; l2capoutbuf[i + 3] = sppOutputBuffer[i + offset];
l2capoutbuf[i + 3] = calcFcs(l2capoutbuf); // Calculate checksum l2capoutbuf[i + 3] = calcFcs(l2capoutbuf); // Calculate checksum
RFCOMM_Command(l2capoutbuf, length + 4); RFCOMM_Command(l2capoutbuf, length + 4);
stringLength -= length; sppIndex -= length;
offset += length; // Increment the offset offset += length; // Increment the offset
} }
} }
void SPP::println(const String &str) { int SPP::available(void) {
String output = str + "\r\n"; return rfcommAvailable;
print(output); };
void SPP::flush(void) {
rfcommAvailable = 0;
} }
void SPP::println(const char* str) { int SPP::peek(void) {
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() {
if (rfcommAvailable == 0) // Don't read if there is nothing in the buffer 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]; uint8_t output = rfcommDataBuffer[0];
for (uint8_t i = 1; i < rfcommAvailable; i++) for (uint8_t i = 1; i < rfcommAvailable; i++)
rfcommDataBuffer[i - 1] = rfcommDataBuffer[i]; // Shift the buffer one left rfcommDataBuffer[i - 1] = rfcommDataBuffer[i]; // Shift the buffer one left

246
SPP.h
View file

@ -90,7 +90,7 @@
*/ */
/** This BluetoothService class implements the Serial Port Protocol (SPP). */ /** This BluetoothService class implements the Serial Port Protocol (SPP). */
class SPP : public BluetoothService { class SPP : public BluetoothService, public Stream {
public: public:
/** /**
* Constructor for the SPP class. * Constructor for the SPP class.
@ -118,217 +118,51 @@ public:
bool connected; bool connected;
/** @name Serial port profile (SPP) Print functions */ /** @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. * Get number of bytes waiting to be read.
* @return Return the number of bytes ready to be read. * @return Return the number of bytes ready to be read.
*/ */
uint8_t available() { virtual int available(void);
return rfcommAvailable; /** 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. * 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(); virtual int read(void);
/**
/** Discard all the bytes in the buffer. */ * 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.
void flush() { * @param data The byte to write.
rfcommAvailable = 0; * @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: private:
@ -369,6 +203,8 @@ private:
bool creditSent; bool creditSent;
uint8_t rfcommDataBuffer[100]; // Create a 100 sized buffer for incoming data 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; uint8_t rfcommAvailable;
bool firstMessage; // Used to see if it's the first SDP request received bool firstMessage; // Used to see if it's the first SDP request received

View file

@ -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 //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; 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() { void setup() {
Serial.begin(115200); // This wil lprint the debugging from the libraries 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 output.reserve(200); // Reserve 200 bytes for the output string
} }
void loop() { void loop() {
Usb.Task(); Usb.Task(); // The SPP data is actually not send until Usb.Task() is called
if(SerialBT.connected) { if(SerialBT.connected) {
if(firstMessage) { if(firstMessage) {
@ -41,7 +41,7 @@ void loop() {
SerialBT.println(F("Hello from Arduino")); // Send welcome message SerialBT.println(F("Hello from Arduino")); // Send welcome message
} }
if(Serial.available()) if(Serial.available())
SerialBT.print(Serial.read()); SerialBT.write(Serial.read());
if(SerialBT.available()) if(SerialBT.available())
Serial.write(SerialBT.read()); Serial.write(SerialBT.read());
} }

View file

@ -22,14 +22,14 @@ void setup() {
Serial.print(F("\r\nSPP Bluetooth Library Started")); Serial.print(F("\r\nSPP Bluetooth Library Started"));
} }
void loop() { void loop() {
Usb.Task(); Usb.Task(); // The SPP data is actually not send until Usb.Task() is called
if(SerialBT.connected) { if(SerialBT.connected) {
if(firstMessage) { if(firstMessage) {
firstMessage = false; firstMessage = false;
SerialBT.println(F("Hello from Arduino")); // Send welcome message SerialBT.println(F("Hello from Arduino")); // Send welcome message
} }
if(Serial.available()) if(Serial.available())
SerialBT.print(Serial.read()); SerialBT.write(Serial.read());
if(SerialBT.available()) if(SerialBT.available())
Serial.write(SerialBT.read()); Serial.write(SerialBT.read());
} }

View file

@ -34,7 +34,7 @@ void setup() {
Serial.print(F("\r\nSPP Bluetooth Library Started")); Serial.print(F("\r\nSPP Bluetooth Library Started"));
} }
void loop() { void loop() {
Usb.Task(); Usb.Task(); // The SPP data is actually not send until Usb.Task() is called
for(uint8_t i=0;i<length;i++) { for(uint8_t i=0;i<length;i++) {
if(SerialBT[i]->connected) { if(SerialBT[i]->connected) {
if(firstMessage[i]) { if(firstMessage[i]) {
@ -44,7 +44,7 @@ void loop() {
if(SerialBT[i]->available()) if(SerialBT[i]->available())
Serial.write(SerialBT[i]->read()); Serial.write(SerialBT[i]->read());
} }
else else
firstMessage[i] = true; firstMessage[i] = true;
} }
if(Serial.available()) { if(Serial.available()) {
@ -61,7 +61,7 @@ void loop() {
if(SerialBT[id]->connected) { // Check if a device is actually connected 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 for(uint8_t i2 = 0; i2 < i-1; i2++) // Don't include the first character
buffer[i2] = buffer[i2+1]; buffer[i2] = buffer[i2+1];
SerialBT[id]->println(buffer,i-1); // Send the data SerialBT[id]->write(buffer,i-1); // Send the data
} }
} }
} }