Arduino / DigiSpark / ATtiny85 - Receiving and parsing several pieces of data - arduino

i'm trying to make a digispark to work with bluetooth and NeoPixel, while i had success into making it go on and off i would like to expand on it.
I have used the Robin2 example 5 method to reciece, and parse my data in order to get the leds color the way i want.
https://forum.arduino.cc/index.php?topic=396450.msg2727728#msg2727728
this is the code in my case - the original is in the link above
void loop() {
recvWithStartEndMarkers();
if (newData == true) {
strcpy(tempChars, receivedChars);
// this temporary copy is necessary to protect the original data
// because strtok() used in parseData() replaces the commas with \0
parseData();
strip.setBrightness(xB);
controlLed();
newData = false;
}
}
void recvWithStartEndMarkers() {
static boolean recvInProgress = false;
static byte ndx = 0;
char startMarker = '<';
char endMarker = '>';
char rc;
while (bluetooth.available() > 0 && newData == false) {
rc = bluetooth.read();
if (recvInProgress == true) {
if (rc != endMarker) {
receivedChars[ndx] = rc;
ndx++;
if (ndx >= numChars) {
ndx = numChars - 1;
}
} else {
receivedChars[ndx] = '\0'; // terminate the string
recvInProgress = false;
ndx = 0;
newData = true;
}
} else if (rc == startMarker) {
recvInProgress = true;
}
}
}
void parseData() { // split the data into its parts
char * strtokIndx; // this is used by strtok() as an index
strtokIndx = strtok(tempChars, ","); // get the first part - the string
eFx = atoi(strtokIndx); // convert this part to an integer
strtokIndx = strtok(NULL, ","); // get the first part - the string
rC1 = atoi(strtokIndx); // convert this part to an integer
strtokIndx = strtok(NULL, ","); // this continues where the previous call left off
gC1 = atoi(strtokIndx); // convert this part to an integer
strtokIndx = strtok(NULL, ","); // this continues where the previous call left off
bC1 = atoi(strtokIndx); // convert this part to an integer
strtokIndx = strtok(NULL, ",");
xS = atoi(strtokIndx); // convert this part to an integer
strtokIndx = strtok(NULL, ",");
xB = atoi(strtokIndx); // convert this part to an integer
}
void controlLed() {
colorWipe(strip.Color(rC1, gC1, bC1), xS);
colorWipe(strip.Color(20, 50, 100), 50);
}
now i have some issues, as the ATtiny85 memory is not that great i ran into issues when i try to send longer strings, basically i want to send all these:
int eFx = 1;
int rC1 = 100;
int gC1 = 100;
int bC1 = 100;
int xS = 20;
int xB = 100;
int rC2 = 5;
int gC2 = 50;
int bC2 = 200;
but when i try to parse it with the strtokIndx method above the digispark stops working (when i add more to what is already shown in the code ex above) i guess it's due to memory issues.
i understand part of the code,but not well enough to expand it in the direction that i want.
Right now the way it works is that when i send via BTooth info in this format asd<1,24,23,54,...,>qwe the recvWithStartEndMarkers () will grab all there is between < > and store it (?) in receivedChars
then i'm not sure why and how parseData() grabs this string and not something else, is it because of the function in the loop?
strcpy(tempChars, receivedChars);
parseData();
Well, i want to try to make this process go at it again, to recieve another string under [ ] and not < > and parseData2() (maybe) on receivedChars2 to get my last 3 INTs (color values for NeoPixel) parsed and stored in order to use them without having the digispark crash out of memory
The first step would be to change the
void recvWithStartEndMarkers() {
to detect also de diffrence between < and [ and run the proper code in order to store either in receivedChars or receivedChars2
not sure how to do that, also i'm not sure if this would be useful and would solve my memory issues.
any thoughts?
here is the full code i'm running
#include <Adafruit_NeoPixel.h> // NeoPixel Lib
#include <SoftSerial.h> // Serial Lib
#define LED_PIN 2
#define LED_COUNT 30
SoftSerial bluetooth(4, 5); // RX TX
Adafruit_NeoPixel strip(LED_COUNT, LED_PIN, NEO_GRB + NEO_KHZ800);
const byte numChars = 42;
char receivedChars[numChars];
char tempChars[numChars];
boolean newData = false;
int eFx = 1;
int rC1 = 100;
int gC1 = 100;
int bC1 = 100;
int xS = 20;
int xB = 100;
int rC2 = 5;
int gC2 = 50;
int bC2 = 200;
void setup() {
bluetooth.begin (9600);
strip.begin(); // INITIALIZE NeoPixel strip object (REQUIRED)
strip.show(); // Turn OFF all pixels ASAP
}
void loop() {
recvWithStartEndMarkers();
if (newData == true) {
strcpy(tempChars, receivedChars);
// this temporary copy is necessary to protect the original data
// because strtok() used in parseData() replaces the commas with \0
parseData();
strip.setBrightness(xB);
controlLed();
newData = false;
}
}
void recvWithStartEndMarkers() {
static boolean recvInProgress = false;
static byte ndx = 0;
char startMarker = '<';
char endMarker = '>';
char rc;
while (bluetooth.available() > 0 && newData == false) {
rc = bluetooth.read();
if (recvInProgress == true) {
if (rc != endMarker) {
receivedChars[ndx] = rc;
ndx++;
if (ndx >= numChars) {
ndx = numChars - 1;
}
} else {
receivedChars[ndx] = '\0'; // terminate the string
recvInProgress = false;
ndx = 0;
newData = true;
}
} else if (rc == startMarker) {
recvInProgress = true;
}
}
}
void parseData() { // split the data into its parts
char * strtokIndx; // this is used by strtok() as an index
strtokIndx = strtok(tempChars, ","); // get the first part - the string
eFx = atoi(strtokIndx); // convert this part to an integer
strtokIndx = strtok(NULL, ","); // get the first part - the string
rC1 = atoi(strtokIndx); // convert this part to an integer
strtokIndx = strtok(NULL, ","); // this continues where the previous call left off
gC1 = atoi(strtokIndx); // convert this part to an integer
strtokIndx = strtok(NULL, ","); // this continues where the previous call left off
bC1 = atoi(strtokIndx); // convert this part to an integer
strtokIndx = strtok(NULL, ",");
xS = atoi(strtokIndx); // convert this part to an integer
strtokIndx = strtok(NULL, ",");
xB = atoi(strtokIndx); // convert this part to an integer
}
void controlLed() {
colorWipe(strip.Color(rC1, gC1, bC1), xS);
colorWipe(strip.Color(20, 50, 100), 50);
}
void controlLed2() {
colorWipe(strip.Color(rC2, gC2, bC2), xS);
}
void colorWipe(uint32_t color, int wait) {
for(int i=0; i<strip.numPixels(); i++) { // For each pixel in strip...
strip.setPixelColor(i, color); // Set pixel's color (in RAM)
strip.show(); // Update strip to match
delay(wait); // Pause for a moment
}
}

Related

Stuck at solving leetcode Q5 using C [=34==ERROR: AddressSanitizer]

Please excuse for my massy code. This was best I could do.
I have been solving leetcode Q5 for a while; however, I couldn't solve it. This is the closest answer I have got.
I think it's acting correctly in terms of showing outputs. But has a runtime error when
let s = "tscvrnsnnwjzkynzxwcltutcvvhdivtmcvwdiwnbmdyfdvdiseyxyiiurpnhuuufarbwalzysetxbaziuuywugfzzmhoessycogxgujmgvnncwacziyybryxjagesgcmqdryfbofwxhikuauulaqyiztkpgmelnoudvlobdsgharsdkzzuxouezcycsafvpmrzanrixubvojyeuhbcpkuuhkxdvldhdtpkdhpiejshrqpgsoslbkfyraqbmrwiykggdlkgvbvrficmiignctsxeqslhzonlfekxexpvnblrfatvetwasewpglimeqemdgdgmemvdsrzpgacpnrbmomngjpiklqgbbalzxiikacwwzbzapqmatqmexxqhssggsyzpnvvpmzngtljlrhrjbnxgpcjuokgxcbzxqhmitcxlzfehwfiwcmwfliedljghrvrahlcoiescsbupitckjfkrfhhfvdlweeeverrwfkujjdwtcwbbbbwctwdjjukfwrreveeewldvfhhfrkfjkctipubscseioclharvrhgjldeilfwmcwifwhefzlxctimhqxzbcxgkoujcpgxnbjrhrljltgnzmpvvnpzysggsshqxxemqtamqpazbzwwcakiixzlabbgqlkipjgnmombrnpcagpzrsdvmemgdgdmeqemilgpwesawtevtafrlbnvpxexkeflnozhlsqexstcngiimcifrvbvgkldggkyiwrmbqaryfkblsosgpqrhsjeiphdkptdhdlvdxkhuukpcbhueyjovbuxirnazrmpvfascyczeuoxuzzkdsrahgsdbolvduonlemgpktziyqaluuaukihxwfobfyrdqmcgsegajxyrbyyizcawcnnvgmjugxgocysseohmzzfguwyuuizabxtesyzlawbrafuuuhnpruiiyxyesidvdfydmbnwidwvcmtvidhvvctutlcwxznykzjwnnsnrvcst"
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
int is_palindrome(char * s);
void get_substring(const char *str, char *substr, int start, int end);
char * longestPalindrome(char * s){
int strlength = strlen(s);
int end = strlength - 1;
int start = 0;
char substr[1000];
char *longstr = (char *)malloc(1000 * sizeof(char));
strcpy(longstr, "");
while (start <= end)
{
get_substring(s, substr, start, end);
// printf("%s\n", substr);
if (is_palindrome(substr) > strlen(longstr))
{
// printf("UPDATE : %s\n", substr);
strcpy(longstr, substr);
}
if (end == start)
{
start++;
end = strlength - 1;
}
else
{
end--;
}
}
// printf("LONG : %s", longstr);
return longstr;
}
void get_substring(const char *str, char *substr, int start, int end) {
int length = end - start + 1;
strncpy(substr, str + start, length);
substr[length] = '\0';
}
int is_palindrome(char * s){
int length = strlen(s);
int mid = length/2;
if (length % 2 == 0)
{
// printf("EVEN : %d\n", mid);
mid--;
int upperptr = mid+1;
int i = 0;
if (s[mid] != s[upperptr])
{
// printf("Returning FALSE [0]\n");
return 0;
}
while (mid-i >= 0 && upperptr+i <= length)
{
// printf("%c and %c and mid is %c\n", s[mid-i], s[upperptr+i], s[mid]);
if (s[mid-i] != s[upperptr+i])
{
// printf("Returning FALSE [1]\n");
return 0;
}
i++;
}
}
else
{
// printf("ODD: %d\n", mid+1);
int i = 0;
while (mid-i >= 0 && mid+i <= length)
{
// printf("%c and %c and mid is %c\n", s[mid-i], s[mid+i], s[mid]);
if (s[mid-i] != s[mid+i])
{
// printf("Returning FALSE [2]\n");
return 0;
}
i++;
}
}
// printf("Returning TRUE\n");
return length;
}
I had difficulties returning a local string. then found out that local string value can't be returned and has to be dynamically malloced and the pointer has to be returned.
So I fixed it (somehow, if it is right). But I reckon this is causing different - even harder - problems that I can't manage.

why i m getting warning: comparison between pointer and integer

I'm getting warning msg saying:
comparison between pointer and integer
char * replaceWord(const char * str, const char * oldWord, const char * newWord)
{
char * resultString;
int i, count = 0;
int newWordLength = strlen(newWord);
int oldWordLength = strlen(oldWord);
//count the no of occurance of word in string in a file
for (i = 0; str[i] !='\0'; i++)
{
if (strstr(str[i], oldWord) == str[i])//i m getting warning here
{
count++;
i = i + oldWordLength - 1;
}
}
// Making a new string to fit in the replaced words
resultString = (char *)malloc(i + count * (newWordLength - oldWordLength) + 1);
i = 0;
while (*str!='\0')
{
// Compare the substring with result
if(strstr(str, oldWord) == str)//here i used same syantax its working but not above
{
strcpy(&resultString[i], newWord);
i += newWordLength;
str += oldWordLength;
}
else{
resultString[i] = *str;
i += 1;
str +=1;
}
}
resultString[i] = '\0';
return resultString;
}
From the man page for strstr():
#include <string.h>
char *strstr(const char *haystack, const char *needle);
So, strstr() returns the substring's char* pointer as the result, and you are comparing it against a char variable (str[i]), thus the error.

how to tokenize a string in arduino

i am using arduino due. what i am trying to do is to receive a string at serial. like this one:
COMSTEP 789 665 432 END
if the string starts with comstep, then to tokenize the string and get an integer array {789, 665, 432}.
is there anyway to do that?
P.S: im a noob at programming, so any help is appreciated.
I have a function that I wrote long ago to parse strings up in an easy manner. It is in use on several of my Arduino projects.
Sample usage:
char pinStr[3];
char valueStr[7];
int pinNumber, value;
getstrfld (parms_in, 0, 0, (char *)",", pinStr);
getstrfld (parms_in, 1, 0, (char *)",", valueStr);
pinNumber = atoi (pinStr);
value = atoi (valueStr);
The functions:
// My old stand-by to break delimited strings up.
char * getstrfld (char *strbuf, int fldno, int ofset, char *sep, char *retstr)
{
char *offset, *strptr;
int curfld;
offset = strptr = (char *)NULL;
curfld = 0;
strbuf += ofset;
while (*strbuf) {
strptr = !offset ? strbuf : offset;
offset = strpbrk ((!offset ? strbuf : offset), sep);
if (offset) {
offset++;
} else if (curfld != fldno) {
*retstr = 0;
break;
}
if (curfld == fldno) {
strncpy (retstr, strptr,
(int)(!offset ? strlen (strptr)+ 1 :
(int)(offset - strptr)));
if (offset)
retstr[offset - strptr - 1] = 0;
break;
}
curfld++;
}
return retstr;
}
// Included because strpbrk is not in the arduino gcc/g++ libraries
// Or I just could not find it :)
char * strpbrk (const char *s1, const char *s2)
{
const char *c = s2;
if (!*s1) {
return (char *) NULL;
}
while (*s1) {
for (c = s2; *c; c++) {
if (*s1 == *c)
break;
}
if (*c)
break;
s1++;
}
if (*c == '\0')
s1 = NULL;
return (char *) s1;
}
A light-weight approach (no strict checks on valid parses of the integers and ignoring any list elements past a fixed maximum):
char buf[32] = "COMSTEP 789 665 432 END"; // assume this has just been read
int res[8], nres = 0;
bool inlist = false;
for (char *p = strtok(buf, " "); p; p = strtok(0, " "))
if (inlist)
{
if (!strcmp(p, "END"))
{
inlist = false;
break;
}
else if (nres < sizeof(res) / sizeof(*res))
res[nres++] = atoi(p);
}
else if (!strcmp(p, "COMSTEP"))
inlist = true;
if (!inlist)
for (size_t i = 0; i < nres; ++i)
printf("%d%s", res[i], i + 1 < nres ? " " : "\n"); // do whatever

Arduino mega crashes while reading somewhat large .txt from SD

I have an Arduino mega with an SD Shield and a GSM shield. I'm trying to send one sms to 200 numbers from a text file on the SD card, but the Arduino reboots every time I try to send to over 100 numbers. It doesn't crash when I try to send to 70 numbers. I only read one number at a time so I don't understand the problem. I'm pretty new to Arduino programming.
Please help me this is for a tournament. Here's the code:
#include <avr/pgmspace.h>
#include <SPI.h>
#include <SD.h>
#include <GSM.h>
#define PINNUMBER ""
GSM gsmAccess;
GSM_SMS sms;
// GSM
boolean notConnected;
//char input;
//byte input2;
//char txtContent[200];
byte i = 1;
byte f = 0;
boolean sendit;
//char senderNumber[11];
const String stopp PROGMEM = "Stopp";
//SD
char numbers[11];
//char nmbr;
int l = 0;
//Optimizing
const char q PROGMEM = '\xe5'; // å
const char w PROGMEM = '\xe4'; // ä
const char e PROGMEM = '\xf6'; // ö
const char r PROGMEM = '\xc5'; // Å
const char t PROGMEM = '\xc4'; // Ä
const char y PROGMEM = '\xd6'; // Ö
void setup() {
// txtContent[0] = '\0';
i = 0;
pinMode(53, OUTPUT);
Serial.begin(115200);
// Serial.begin(4800);
Serial.println(F("Connecting to GSM..."));
notConnected = true;
while (notConnected) {
if (gsmAccess.begin(PINNUMBER) == GSM_READY) {
notConnected = false;
}
else {
Serial.println(F("Not Connected"));
delay(1000);
}
}
Serial.println(F("GSM Ready"));
if (!SD.begin(4)) {
Serial.println(F("Error with SD card"));
return;
}
Serial.println(F("SD Ready"));
delay(1000);
Serial.println(F("Write your sms and end it with * and press Send"));
Serial.flush();
}
void loop() {
char txtContent[300];
if (Serial.available() > 0 && !sendit) {
byte input2;
input2 = (int)Serial.read();
txtContent[i] = (char)input2;
if (txtContent[i] == '{') {
txtContent[i] = q;
}
else if (txtContent[i] == '}') {
txtContent[i] = w;
}
else if (txtContent[i] == '|') {
txtContent[i] = e;
}
else if (txtContent[i] == '[') {
txtContent[i] = r;
}
else if (txtContent[i] == ']') {
txtContent[i] = t;
}
else if (txtContent[i] == ';') {
txtContent[i] = y;
}
i++;
if (input2 == '*') {
// Remove the * from text.
for (int j = 0; j < sizeof(txtContent); j++) {
if (txtContent[j] == '*') {
txtContent[j] = '\0';
//Serial.println(txtContent);
}
}
sendit = true;
Serial.flush();
}
else {
sendit = false;
Serial.flush();
}
}
else if (sendit && txtContent[0] != '\0') {
int txtCount = 0;
// else if(sendit){
Serial.println(F("Sending please wait..."));
// Serial.flush();
File myFile;
myFile = SD.open("numbers.txt");
char input;
if (myFile) {
// if (myFile.available()) {
while(myFile.available()){
input = (char)myFile.read();
if (input == ',') {
sms.beginSMS(numbers);
sms.print(txtContent);
// sms.beginSMS("0704941025");
// sms.print("yo");
delay(30);
sms.endSMS();
delay(30);
Serial.println(numbers);
Serial.flush();
// Serial.flush();
for (int j = 0; j < sizeof(numbers); j++) {
if (numbers[i] != '\0') {
numbers[j] = '\0';
}
}
f = 0;
}
else {
numbers[f] = input;
f++;
}
}
myFile.close();
Serial.println(F("All texts have been sent."));
Serial.flush();
} else {
Serial.println(F("error opening numbers.txt"));
}
for (int j = 0; j < sizeof(txtContent); j++) { // Clear text
txtContent[j] = '\0';
}
i = 0;
sendit = false;
}
else {
// delay(1000);
if (sms.available()) {
char senderNumber[11];
sms.remoteNumber(senderNumber, 11);
if (sms.peek() == 'S') {
Serial.print(F("Detta nummer har skickat Stopp: "));
Serial.println(senderNumber);
}
sms.flush();
Serial.flush();
// sendit = false;
}
}
}
Arduino is a strange ground for me but if that is anything like C, then i risk saying sizeof(numbers) will likely return 44, because you're asking for the size of an array in bytes, this probably means your for loop will iterate up to numbers[43] when numbers[] length is 11. Consider this instead:
for (int j = 0; j < sizeof(numbers)/sizeof(numbers[0]); j++) {
Same goes for all the other times you check for the size of an array in this code.
Also, do double check your textfile to ensure its really written in your expected format: 11 numbers then a comma, with no exception. You should maybe try to figure out if f went past 11 digits before hitting a comma and "Fail gracefully" with an error message.

rosserial arduino hello world won't verify

Edit: Solved
SOLUTION:
I'm running Arduino 1.0.5
I fixed the problem by changing /Sketchbook/library/ros_lib/ros/node_handle.h line 260 from
}else if (topic_ == TopicInfo::ID_TX_STOP){
to
}else if (topic_ == ID_TX_STOP){
However, this gave me a new error message:
/usr/share/arduino/hardware/arduino/cores/arduino/Print.cpp: In member function 'size_t Print::print(const __FlashStringHelper*)':
/usr/share/arduino/hardware/arduino/cores/arduino/Print.cpp:44:9: error: 'prog_char' does not name a type
/usr/share/arduino/hardware/arduino/cores/arduino/Print.cpp:47:23: error: 'p' was not declared in this scope
So to fix this I edited usr/share/arduino/hardware/arduino/cores/arduino/Print.cpp, line 44 from
const prog_char *p = (const prog_char *)ifsh;
to
const char PROGMEM *p = (const char PROGMEM *)ifsh;
Now it compiles!
Original Problem:
I've been using this tutorial to get everything set up: (http://wiki.ros.org/rosserial_arduino/Tutorials/Arduino%20IDE%20Setup) I can install everything without an issue I think, the ros_lib folder is placed in my sketchbook libraries. But when I do the next tutorial with the helloworld example, the code does not verify correctly. When I try to verify with the checkmark in the Arduino IDE, I get the following set of error codes:
In file included from /home/user/sketchbook/libraries/ros_lib/ros.h:38:0,
from HelloWorld.cpp:6:
/home/user/sketchbook/libraries/ros_lib/ros/node_handle.h: In member function 'virtual int ros::NodeHandle_::spinOnce()':
/home/user/sketchbook/libraries/ros_lib/ros/node_handle.h:260:45: error: expected unqualified-id before numeric constant
/home/user/sketchbook/libraries/ros_lib/ros/node_handle.h:260:45: error: expected ')' before numeric constant
I've reinstalled the ros_lib as well as rosserial and I keep getting this error, so I don't know what the problem is. I looked around line 260 of the node_handle.h file but I didn't notice anything out of place.
Here's node_handle.h: (spacing might be a little off)
/*
* Software License Agreement (BSD License)
*
* Copyright (c) 2011, Willow Garage, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * Neither the name of Willow Garage, Inc. nor the names of its
* contributors may be used to endorse or promote prducts derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef ROS_NODE_HANDLE_H_
#define ROS_NODE_HANDLE_H_
#include "std_msgs/Time.h"
#include "rosserial_msgs/TopicInfo.h"
#include "rosserial_msgs/Log.h"
#include "rosserial_msgs/RequestParam.h"
#define SYNC_SECONDS 5
#define MODE_FIRST_FF 0
/*
* The second sync byte is a protocol version. It's value is 0xff for the first
* version of the rosserial protocol (used up to hydro), 0xfe for the second version
* (introduced in hydro), 0xfd for the next, and so on. Its purpose is to enable
* detection of mismatched protocol versions (e.g. hydro rosserial_python with groovy
* rosserial_arduino. It must be changed in both this file and in
* rosserial_python/src/rosserial_python/SerialClient.py
*/
#define MODE_PROTOCOL_VER 1
#define PROTOCOL_VER1 0xff // through groovy
#define PROTOCOL_VER2 0xfe // in hydro
#define PROTOCOL_VER PROTOCOL_VER2
#define MODE_SIZE_L 2
#define MODE_SIZE_H 3
#define MODE_SIZE_CHECKSUM 4 // checksum for msg size received from size L and H
#define MODE_TOPIC_L 5 // waiting for topic id
#define MODE_TOPIC_H 6
#define MODE_MESSAGE 7
#define MODE_MSG_CHECKSUM 8 // checksum for msg and topic id
#define MSG_TIMEOUT 20 //20 milliseconds to recieve all of message data
#define ID_TX_STOP 11 //hardcode for hydro version
#include "msg.h"
namespace ros {
class NodeHandleBase_{
public:
virtual int publish(int id, const Msg* msg)=0;
virtual int spinOnce()=0;
virtual bool connected()=0;
};
}
#include "publisher.h"
#include "subscriber.h"
#include "service_server.h"
#include "service_client.h"
namespace ros {
using rosserial_msgs::TopicInfo;
/* Node Handle */
template<class Hardware,
int MAX_SUBSCRIBERS=25,
int MAX_PUBLISHERS=25,
int INPUT_SIZE=512,
int OUTPUT_SIZE=512>
class NodeHandle_ : public NodeHandleBase_
{
protected:
Hardware hardware_;
/* time used for syncing */
unsigned long rt_time;
/* used for computing current time */
unsigned long sec_offset, nsec_offset;
unsigned char message_in[INPUT_SIZE];
unsigned char message_out[OUTPUT_SIZE];
Publisher * publishers[MAX_PUBLISHERS];
Subscriber_ * subscribers[MAX_SUBSCRIBERS];
/*
* Setup Functions
*/
public:
NodeHandle_() : configured_(false) {
for(unsigned int i=0; i< MAX_PUBLISHERS; i++)
publishers[i] = 0;
for(unsigned int i=0; i< MAX_SUBSCRIBERS; i++)
subscribers[i] = 0;
for(unsigned int i=0; i< INPUT_SIZE; i++)
message_in[i] = 0;
for(unsigned int i=0; i< OUTPUT_SIZE; i++)
message_out[i] = 0;
req_param_resp.ints_length = 0;
req_param_resp.ints = NULL;
req_param_resp.floats_length = 0;
req_param_resp.floats = NULL;
req_param_resp.ints_length = 0;
req_param_resp.ints = NULL;
}
Hardware* getHardware(){
return &hardware_;
}
/* Start serial, initialize buffers */
void initNode(){
hardware_.init();
mode_ = 0;
bytes_ = 0;
index_ = 0;
topic_ = 0;
};
/* Start a named port, which may be network server IP, initialize buffers */
void initNode(char *portName){
hardware_.init(portName);
mode_ = 0;
bytes_ = 0;
index_ = 0;
topic_ = 0;
};
protected:
//State machine variables for spinOnce
int mode_;
int bytes_;
int topic_;
int index_;
int checksum_;
bool configured_;
/* used for syncing the time */
unsigned long last_sync_time;
unsigned long last_sync_receive_time;
unsigned long last_msg_timeout_time;
public:
/* This function goes in your loop() function, it handles
* serial input and callbacks for subscribers.
*/
virtual int spinOnce(){
/* restart if timed out */
unsigned long c_time = hardware_.time();
if( (c_time - last_sync_receive_time) > (SYNC_SECONDS*2200) ){
configured_ = false;
}
/* reset if message has timed out */
if ( mode_ != MODE_FIRST_FF){
if (c_time > last_msg_timeout_time){
mode_ = MODE_FIRST_FF;
}
}
/* while available buffer, read data */
while( true )
{
int data = hardware_.read();
if( data < 0 )
break;
checksum_ += data;
if( mode_ == MODE_MESSAGE ){ /* message data being recieved */
message_in[index_++] = data;
bytes_--;
if(bytes_ == 0) /* is message complete? if so, checksum */
mode_ = MODE_MSG_CHECKSUM;
}else if( mode_ == MODE_FIRST_FF ){
if(data == 0xff){
mode_++;
last_msg_timeout_time = c_time + MSG_TIMEOUT;
}
}else if( mode_ == MODE_PROTOCOL_VER ){
if(data == PROTOCOL_VER){
mode_++;
}else{
mode_ = MODE_FIRST_FF;
if (configured_ == false)
requestSyncTime(); /* send a msg back showing our protocol version */
}
}else if( mode_ == MODE_SIZE_L ){ /* bottom half of message size */
bytes_ = data;
index_ = 0;
mode_++;
checksum_ = data; /* first byte for calculating size checksum */
}else if( mode_ == MODE_SIZE_H ){ /* top half of message size */
bytes_ += data<<8;
mode_++;
}else if( mode_ == MODE_SIZE_CHECKSUM ){
if( (checksum_%256) == 255)
mode_++;
else
mode_ = MODE_FIRST_FF; /* Abandon the frame if the msg len is wrong */
}else if( mode_ == MODE_TOPIC_L ){ /* bottom half of topic id */
topic_ = data;
mode_++;
checksum_ = data; /* first byte included in checksum */
}else if( mode_ == MODE_TOPIC_H ){ /* top half of topic id */
topic_ += data<<8;
mode_ = MODE_MESSAGE;
if(bytes_ == 0)
mode_ = MODE_MSG_CHECKSUM;
}else if( mode_ == MODE_MSG_CHECKSUM ){ /* do checksum */
mode_ = MODE_FIRST_FF;
if( (checksum_%256) == 255){
if(topic_ == TopicInfo::ID_PUBLISHER){
requestSyncTime();
negotiateTopics();
last_sync_time = c_time;
last_sync_receive_time = c_time;
return -1;
}else if(topic_ == TopicInfo::ID_TIME){
syncTime(message_in);
}else if (topic_ == TopicInfo::ID_PARAMETER_REQUEST){
req_param_resp.deserialize(message_in);
param_recieved= true;
}else if(topic_ == TopicInfo::ID_TX_STOP){
configured_ = false;
}else{
if(subscribers[topic_-100])
subscribers[topic_-100]->callback( message_in );
}
}
}
}
/* occasionally sync time */
if( configured_ && ((c_time-last_sync_time) > (SYNC_SECONDS*500) )){
requestSyncTime();
last_sync_time = c_time;
}
return 0;
}
/* Are we connected to the PC? */
virtual bool connected() {
return configured_;
};
/********************************************************************
* Time functions
*/
void requestSyncTime()
{
std_msgs::Time t;
publish(TopicInfo::ID_TIME, &t);
rt_time = hardware_.time();
}
void syncTime( unsigned char * data )
{
std_msgs::Time t;
unsigned long offset = hardware_.time() - rt_time;
t.deserialize(data);
t.data.sec += offset/1000;
t.data.nsec += (offset%1000)*1000000UL;
this->setNow(t.data);
last_sync_receive_time = hardware_.time();
}
Time now(){
unsigned long ms = hardware_.time();
Time current_time;
current_time.sec = ms/1000 + sec_offset;
current_time.nsec = (ms%1000)*1000000UL + nsec_offset;
normalizeSecNSec(current_time.sec, current_time.nsec);
return current_time;
}
void setNow( Time & new_now )
{
unsigned long ms = hardware_.time();
sec_offset = new_now.sec - ms/1000 - 1;
nsec_offset = new_now.nsec - (ms%1000)*1000000UL + 1000000000UL;
normalizeSecNSec(sec_offset, nsec_offset);
}
/********************************************************************
* Topic Management
*/
/* Register a new publisher */
bool advertise(Publisher & p)
{
for(int i = 0; i < MAX_PUBLISHERS; i++){
if(publishers[i] == 0){ // empty slot
publishers[i] = &p;
p.id_ = i+100+MAX_SUBSCRIBERS;
p.nh_ = this;
return true;
}
}
return false;
}
/* Register a new subscriber */
template<typename MsgT>
bool subscribe(Subscriber< MsgT> & s){
for(int i = 0; i < MAX_SUBSCRIBERS; i++){
if(subscribers[i] == 0){ // empty slot
subscribers[i] = (Subscriber_*) &s;
s.id_ = i+100;
return true;
}
}
return false;
}
/* Register a new Service Server */
template<typename MReq, typename MRes>
bool advertiseService(ServiceServer<MReq,MRes>& srv){
bool v = advertise(srv.pub);
for(int i = 0; i < MAX_SUBSCRIBERS; i++){
if(subscribers[i] == 0){ // empty slot
subscribers[i] = (Subscriber_*) &srv;
srv.id_ = i+100;
return v;
}
}
return false;
}
/* Register a new Service Client */
template<typename MReq, typename MRes>
bool serviceClient(ServiceClient<MReq, MRes>& srv){
bool v = advertise(srv.pub);
for(int i = 0; i < MAX_SUBSCRIBERS; i++){
if(subscribers[i] == 0){ // empty slot
subscribers[i] = (Subscriber_*) &srv;
srv.id_ = i+100;
return v;
}
}
return false;
}
void negotiateTopics()
{
rosserial_msgs::TopicInfo ti;
int i;
for(i = 0; i < MAX_PUBLISHERS; i++)
{
if(publishers[i] != 0) // non-empty slot
{
ti.topic_id = publishers[i]->id_;
ti.topic_name = (char *) publishers[i]->topic_;
ti.message_type = (char *) publishers[i]->msg_->getType();
ti.md5sum = (char *) publishers[i]->msg_->getMD5();
ti.buffer_size = OUTPUT_SIZE;
publish( publishers[i]->getEndpointType(), &ti );
}
}
for(i = 0; i < MAX_SUBSCRIBERS; i++)
{
if(subscribers[i] != 0) // non-empty slot
{
ti.topic_id = subscribers[i]->id_;
ti.topic_name = (char *) subscribers[i]->topic_;
ti.message_type = (char *) subscribers[i]->getMsgType();
ti.md5sum = (char *) subscribers[i]->getMsgMD5();
ti.buffer_size = INPUT_SIZE;
publish( subscribers[i]->getEndpointType(), &ti );
}
}
configured_ = true;
}
virtual int publish(int id, const Msg * msg)
{
if(id >= 100 && !configured_)
return 0;
/* serialize message */
unsigned int l = msg->serialize(message_out+7);
/* setup the header */
message_out[0] = 0xff;
message_out[1] = PROTOCOL_VER;
message_out[2] = (unsigned char) ((unsigned int)l&255);
message_out[3] = (unsigned char) ((unsigned int)l>>8);
message_out[4] = 255 - ((message_out[2] + message_out[3])%256);
message_out[5] = (unsigned char) ((int)id&255);
message_out[6] = (unsigned char) ((int)id>>8);
/* calculate checksum */
int chk = 0;
for(int i =5; i<l+7; i++)
chk += message_out[i];
l += 7;
message_out[l++] = 255 - (chk%256);
if( l <= OUTPUT_SIZE ){
hardware_.write(message_out, l);
return l;
}else{
logerror("Message from device dropped: message larger than buffer.");
return -1;
}
}
/********************************************************************
* Logging
*/
private:
void log(char byte, const char * msg){
rosserial_msgs::Log l;
l.level= byte;
l.msg = (char*)msg;
publish(rosserial_msgs::TopicInfo::ID_LOG, &l);
}
public:
void logdebug(const char* msg){
log(rosserial_msgs::Log::ROSDEBUG, msg);
}
void loginfo(const char * msg){
log(rosserial_msgs::Log::INFO, msg);
}
void logwarn(const char *msg){
log(rosserial_msgs::Log::WARN, msg);
}
void logerror(const char*msg){
log(rosserial_msgs::Log::ERROR, msg);
}
void logfatal(const char*msg){
log(rosserial_msgs::Log::FATAL, msg);
}
/********************************************************************
* Parameters
*/
private:
bool param_recieved;
rosserial_msgs::RequestParamResponse req_param_resp;
bool requestParam(const char * name, int time_out = 1000){
param_recieved = false;
rosserial_msgs::RequestParamRequest req;
req.name = (char*)name;
publish(TopicInfo::ID_PARAMETER_REQUEST, &req);
unsigned int end_time = hardware_.time() + time_out;
while(!param_recieved ){
spinOnce();
if (hardware_.time() > end_time) return false;
}
return true;
}
public:
bool getParam(const char* name, int* param, int length =1){
if (requestParam(name) ){
if (length == req_param_resp.ints_length){
//copy it over
for(int i=0; i<length; i++)
param[i] = req_param_resp.ints[i];
return true;
}
}
return false;
}
bool getParam(const char* name, float* param, int length=1){
if (requestParam(name) ){
if (length == req_param_resp.floats_length){
//copy it over
for(int i=0; i<length; i++)
param[i] = req_param_resp.floats[i];
return true;
}
}
return false;
}
bool getParam(const char* name, char** param, int length=1){
if (requestParam(name) ){
if (length == req_param_resp.strings_length){
//copy it over
for(int i=0; i<length; i++)
strcpy(param[i],req_param_resp.strings[i]);
return true;
}
}
return false;
}
};
}
#endif
I tried commenting out line 160 and 161:
//}else if (topic_ == TopicInfo::ID_TX_STOP){
//configured_ = false;
This gave me a different error message:
/usr/share/arduino/hardware/arduino/cores/arduino/Print.cpp: In member function 'size_t Print::print(const __FlashStringHelper*)':
/usr/share/arduino/hardware/arduino/cores/arduino/Print.cpp:44:9: error: 'prog_char' does not name a type
/usr/share/arduino/hardware/arduino/cores/arduino/Print.cpp:47:23: error: 'p' was not declared in this scope
So here's Print.cpp
/*
Print.cpp - Base class that provides print() and println()
Copyright (c) 2008 David A. Mellis. All right reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Modified 23 November 2006 by David A. Mellis
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include "Arduino.h"
#include "Print.h"
// Public Methods //////////////////////////////////////////////////////////////
/* default implementation: may be overridden */
size_t Print::write(const uint8_t *buffer, size_t size)
{
size_t n = 0;
while (size--) {
n += write(*buffer++);
}
return n;
}
size_t Print::print(const __FlashStringHelper *ifsh)
{
const prog_char *p = (const prog_char *)ifsh;
size_t n = 0;
while (1) {
unsigned char c = pgm_read_byte(p++);
if (c == 0) break;
n += write(c);
}
return n;
}
size_t Print::print(const String &s)
{
size_t n = 0;
for (uint16_t i = 0; i < s.length(); i++) {
n += write(s[i]);
}
return n;
}
size_t Print::print(const char str[])
{
return write(str);
}
size_t Print::print(char c)
{
return write(c);
}
size_t Print::print(unsigned char b, int base)
{
return print((unsigned long) b, base);
}
size_t Print::print(int n, int base)
{
return print((long) n, base);
}
size_t Print::print(unsigned int n, int base)
{
return print((unsigned long) n, base);
}
size_t Print::print(long n, int base)
{
if (base == 0) {
return write(n);
} else if (base == 10) {
if (n < 0) {
int t = print('-');
n = -n;
return printNumber(n, 10) + t;
}
return printNumber(n, 10);
} else {
return printNumber(n, base);
}
}
size_t Print::print(unsigned long n, int base)
{
if (base == 0) return write(n);
else return printNumber(n, base);
}
size_t Print::print(double n, int digits)
{
return printFloat(n, digits);
}
size_t Print::println(const __FlashStringHelper *ifsh)
{
size_t n = print(ifsh);
n += println();
return n;
}
size_t Print::print(const Printable& x)
{
return x.printTo(*this);
}
size_t Print::println(void)
{
size_t n = print('\r');
n += print('\n');
return n;
}
size_t Print::println(const String &s)
{
size_t n = print(s);
n += println();
return n;
}
size_t Print::println(const char c[])
{
size_t n = print(c);
n += println();
return n;
}
size_t Print::println(char c)
{
size_t n = print(c);
n += println();
return n;
}
size_t Print::println(unsigned char b, int base)
{
size_t n = print(b, base);
n += println();
return n;
}
size_t Print::println(int num, int base)
{
size_t n = print(num, base);
n += println();
return n;
}
size_t Print::println(unsigned int num, int base)
{
size_t n = print(num, base);
n += println();
return n;
}
size_t Print::println(long num, int base)
{
size_t n = print(num, base);
n += println();
return n;
}
size_t Print::println(unsigned long num, int base)
{
size_t n = print(num, base);
n += println();
return n;
}
size_t Print::println(double num, int digits)
{
size_t n = print(num, digits);
n += println();
return n;
}
size_t Print::println(const Printable& x)
{
size_t n = print(x);
n += println();
return n;
}
// Private Methods /////////////////////////////////////////////////////////////
size_t Print::printNumber(unsigned long n, uint8_t base) {
char buf[8 * sizeof(long) + 1]; // Assumes 8-bit chars plus zero byte.
char *str = &buf[sizeof(buf) - 1];
*str = '\0';
// prevent crash if called with base == 1
if (base < 2) base = 10;
do {
unsigned long m = n;
n /= base;
char c = m - base * n;
*--str = c < 10 ? c + '0' : c + 'A' - 10;
} while(n);
return write(str);
}
size_t Print::printFloat(double number, uint8_t digits)
{
size_t n = 0;
// Handle negative numbers
if (number < 0.0)
{
n += print('-');
number = -number;
}
// Round correctly so that print(1.999, 2) prints as "2.00"
double rounding = 0.5;
for (uint8_t i=0; i<digits; ++i)
rounding /= 10.0;
number += rounding;
// Extract the integer part of the number and print it
unsigned long int_part = (unsigned long)number;
double remainder = number - (double)int_part;
n += print(int_part);
// Print the decimal point, but only if there are digits beyond
if (digits > 0) {
n += print(".");
}
// Extract digits from the remainder one at a time
while (digits-- > 0)
{
remainder *= 10.0;
int toPrint = int(remainder);
n += print(toPrint);
remainder -= toPrint;
}
return n;
}

Resources