I am trying to read the length of some strings in flash memory on my Arduino UNO. The array string_table is giving me problems, if I get the index of it with something the compiler optimises to a constant, then I get the expected value. If I access it with something that is a variable at run time, then I get a different answer each time I do so.
I don't think this is specific to Arduino, as I don't seem to be calling any Arduino specific functionality.
Code:
#include <avr/pgmspace.h>
// Entries stored in flash memory
const char entry_0[] PROGMEM = "12345";
const char entry_1[] PROGMEM = "abc";
const char entry_2[] PROGMEM = "octagons";
const char entry_3[] PROGMEM = "fiver";
// Pointers to flash memory
const char* const string_table[] PROGMEM = {entry_0, entry_1, entry_2, entry_3};
void setup() {
Serial.begin(115200);
randomSeed(analogRead(0));
int r = random(4);
Serial.print("random key (r) : ");
Serial.println(r);
Serial.print("Wrong size for key = ");
Serial.print(r);
Serial.print(" : ");
Serial.println(strlen_P(string_table[r]));
int i = 1;
Serial.print("Correct size for key = ");
Serial.print(i);
Serial.print(" : ");
Serial.println(strlen_P(string_table[i]));
Serial.println("=====");
Serial.println("Expected Sizes: ");
Serial.print("0 is: ");
Serial.println(strlen_P(string_table[0]));
Serial.print("1 is: ");
Serial.println(strlen_P(string_table[1]));
Serial.print("2 is: ");
Serial.println(strlen_P(string_table[2]));
Serial.print("3 is: ");
Serial.println(strlen_P(string_table[3]));
Serial.println("++++++");
Serial.println("Wrong Sizes: ");
for (i = 0; i < 4; i++) {
Serial.print(i);
Serial.print(" is: ");
Serial.println(strlen_P(string_table[i]));
}
Serial.println("------");
delay(500);
}
void loop() {
// put your main code here, to run repeatedly:
}
Results:
random key (r) : 1
Wrong size for key = 1 : 16203
Correct size for key = 1 : 3
=====
Expected Sizes:
0 is: 5
1 is: 3
2 is: 8
3 is: 5
++++++
Wrong Sizes:
0 is: 0
1 is: 11083
2 is: 3
3 is: 3
------
From avr-libc - source code:
strlen_P() is implemented as an inline function in the avr/pgmspace.h
header file, which will check if the length of the string is a
constant and known at compile time. If it is not known at compile
time, the macro will issue a call to __strlen_P() which will then
calculate the length of the string as normal.
That could explain it (although the call to __strlen_P() should have fixed that).
Maybe use the following instead:
strlen_P((char*)pgm_read_word(&(string_table[i])));
Or maybe try using strlen_PF().
Related
I'm currently trying to write to a LTO tape device via C++. My problem is, that subsequent write requests will result in "Invalid argument" errors, while the first call seemingly works just fine.
I have set up the tape drive to use a fixed block size of 64k (Which means, that it can only be written to in chunks of 64k or 64k multiples at a time).
When now trying to write via fwrite() to it, the first call will be successful (or at least return that the requested amount of entries where written), but subsequent calls (with the same parameters) will result in no data being written (fwrite returns 0) and an error of "Invalid argument".
Following is a small sample application thrown together to replicate the issue.
#include <iostream>
#include <unistd.h>
#define BLOCK_SIZE (64 * 1024)
#define DATA_BLOCKS 32
#define byte unsigned char
int main(int argc, char *argv[]) {
if (argc <= 1) {
std::cout << "Missing first parameter: Target file\n";
return 1;
}
// Create file handle to access tape device in RW mode
FILE* handle;
const char* targetFile = argv[1];
if (access(targetFile, R_OK | W_OK) == 0) {
handle = fopen(targetFile, "r+");
printf("Create handle OK: %s\n", targetFile);
} else {
printf("Could not access %s: Missing rad or write permission\n", targetFile);
return 1;
}
// Create an byte array with data for DATA_BLOCKS blocks
byte *data = new byte[BLOCK_SIZE * DATA_BLOCKS];
// Initialize with some data
for (int i = 0; i < BLOCK_SIZE * DATA_BLOCKS; i++) {
data[i] = '5';
}
// Write data in BLOCK_SIZE chunks, blocksToWrite times per fwrite() call, in numberOfWriteCalls fwrite() calls
size_t blocksToWrite = 4;
int numberOfWriteCalls = 5;
size_t written;
for (int i = 0; i < numberOfWriteCalls; i++) {
written = fwrite(data, BLOCK_SIZE, blocksToWrite, handle);
printf("Round %d: Wrote %d entries of expected %d entries\n", i+1, (int) written, (int) blocksToWrite);
// Check if there was an error and if so, print error info to stderr
if (ferror(handle)) {
printf("Error while writing:\n");
perror("");
clearerr(handle);
}
/* Start modification: Added flushing, as pointed out by user7860670 */
fflush(handle);
// Check if there was an error and if so, print error info to stderr
if (ferror(handle)) {
printf("Error while flushing:\n");
perror("");
clearerr(handle);
}
/* End modification: Added flushing, as pointed out by user7860670 */
}
delete[] data;
// Close file handle
fclose(handle);
return 0;
}
This code calls the fwrite function 5 times, each time trying to write 4 blocks of 64k data.
This works fine on normal files, but returns the following output on all of my tape devices:
Create handle OK: /dev/nst0
Round 1: Wrote 4 entries of expected 4 entries
Round 2: Wrote 0 entries of expected 4 entries
Invalid argument
Round 3: Wrote 0 entries of expected 4 entries
Invalid argument
Round 4: Wrote 0 entries of expected 4 entries
Invalid argument
Round 5: Wrote 0 entries of expected 4 entries
Invalid argument
As can be seen, the first call reacts as expected: fwrite return that 4 blocks of data have been written. But all subsequent calls, even while using the same parameters, will return 0 written blocks and an error of "Invalid argument".
Is there any "special sauce" when trying to write to tape files that I'm not aware of, or am I maybe using the fwrite functionality in a wrong way?
I'm using esp8266 with my arduino Mega and controlling it over serial with AT commands( i know that it is not the best way of working with ESP but I didn't know how to do it other way)...So my problem is that I have my POST request formulated and send over to my webpage ....It works fine at first try ,but after that, in every loop try, it fails...Please can someone check my code and see if you can find some error that can cause this?
This is my function for sending data:
void SendData(){
cmd = "AT+CIPSTART=\"TCP\",\"";
cmd+= server;
cmd+="\",80";
Serial1.println(cmd);
Serial.println(cmd);
delay(1000);
if(Serial1.find("OK"))
{
Serial.println("\r\nReady to send data!");
}
String retazec="cz="+cas_zaznamu; ////DATA from sensors etc.
retazec=retazec+"&tep="+t;
retazec=retazec+"&vlhv="+vv;
retazec=retazec+"&vlhp="+vp;
retazec=retazec+"&zav="+za;
retazec=retazec+"&kur="+ku;
retazec=retazec+"&vet="+ve;
retazec=retazec+"&pz="+datum_zavlaha;
int retazec_len=retazec.length();
retazec.toCharArray(retaz,70);
cmd = "POST /arduino.php"; ////POST request
cmd+=" HTTP/1.1\r\n";
cmd+="Host: myhost.com\r\n";
cmd+="Content-Type: application/x-www-form-urlencoded\r\n";
cmd+="Connection:Close\r\n";
cmd+="Content-Length: ";
cmd+=retazec_len;
cmd+="\r\n\r\n";
int size=cmd.length()+retazec_len+2;
Serial1.print("AT+CIPSEND=");
Serial1.println(size);
Serial.print("AT+CIPSEND=");
Serial.println(size);
delay(2000);
if (Serial1.find(">")){
Serial.println("Sending data...");
} else {
Serial1.println("AT+CIPCLOSE");
Serial.println("COnnection closed");
return;
}
Serial.print(cmd);
Serial1.print(cmd);
for(int i=0;i<=retazec_len;i++){
Serial.print(retaz[i]);
Serial1.print(retaz[i]);
}
Serial1.print("\r\n");
if(Serial1.find("OK"))
{
Serial.println("Succesfuly send!");
}
ReadString(); /// emptying the buffer by reading serial1
delay(5000);
Serial.println("-----end");
}
Also I have different function for GET request ,very similar to the one above , and that one worked multiple times in a row(dont want to say every time bcs it was running only for few minutes).
Please please any suggestions will be deeply appreciated. :)
My educated guess:The String class in combination with at commandsTry to get rid of the String class in webbased scenarios. Reason: You want to have a stable environment running for a long time. String class uses heap memory to dynamicly build and destroy the underlying structures it needs for e.g. append strings (... = .. + .. + ..). As there is no so called garbagge collection (and would have not enough memory anyway) the relativeley small memory is cut into small units, in which (at a certain length) the String does not fit anymore -> crash, reset => lost POST or GET request.Use fixed global char array(s) to build your messages, these are compiled into the flash and stop the "memory bleeding". Enclosed an example (although I dont understand - from your language - the name or the content of variables and with no type given I had to guess)
char retazec[256] = {'\0'}; /* Defined globally - Used for retazec functions max 255 chars */
char cmd[512] = {'\0'}; /* Defined globally - Used for POST/GET functions max 511 chars */
char numBuffer[16] = {'\0'}; /* Defined globally - Used for uint32_t or smaller number conversions to char */
unsigned long timeStamp = 0;
unsigned long delayTime = 2000;
setup(){...}
//The parts you gave "translated"into char manuipulation
const char* cmdStart[] = "POST /arduino.php HTTP/1.1\r\n Host: myhost.com\r\nContent-Type: application/x-www-form-urlencoded\r\nConnection:Close\r\nContent-Length: ";
const char* cmdEnd[] = "\r\n\r\n";
strcpy (retazec, "cz=");
itoa(cas_zaznamu, numBuffer, 10); // convert int DATA from sensors etc.
// If its a float use this command
// dtostrf(floatvar, StringLengthIncDecimalPoint, numVarsAfterDecimal, charbuf);
// dtostrf(cas_zaznamu, 3, 2, numBuffer); // -> xx.xx
strcat(retazec, numBuffer);
strcat(retazec, "&tep=");
itoa(t, numBuffer, 10);
// or dtostrf(t, 4, 2, numBuffer); // -> xxx.xx
strcat(retazec, numBuffer);
strcat(retazec, "&vlhv=");
....
// ... till datum_zavlaha;
int retazec_len=strlen(retazec); // gives you the length
// not needed we have a char array allready retazec.toCharArray(retaz,70);
strcpy(cmd, cmdStart);
iota (retazec_len, numBuffer);
strcat(cmd, numBuffer);
strcat(cmd, cmdEnd);
int size=strlen(cmd)+retazec_len+2;
if (millis() - timeStamp > delayTime) {
Serial1.print("AT+CIPSEND=");
Serial1.println(size);
Serial.print("AT+CIPSEND=");
Serial.println(size);
timeStamp = millis();
}
// NO NEVER delay(2000);
if (Serial1.find(">")){
Serial.println("Sending data...");
} else {
Serial1.println("AT+CIPCLOSE");
Serial.println("COnnection closed");
return;
}
The second issue is delay (it stops processing dead in its tracks) So the cpu waits in your case 2 sec before restarting - not a clever idea when using communication protocols. I implemented a non-blocking delay - if you need it somewhere else as I said you only gave fragments of code
EDIT after OPs feedback
String class as a whole should be avoided in dynamic communication scenarios so in all parts of the programm.Should I use one big string (small s = char array) thats just coping what the original code does but instead of String with char array. So imho the structure has just to be adapted to char array without big changes (exept expicitly converting numbers to char) Btw the same takes place when you add a variable to String
uint8_t aNumber = 12;
String myBigString = "A number is " + aNumber;
does internally in the String library the same as
uint8_t aNumber = 12;
char numBuffer [16] = {'\0'} ;
char myBigString [32] = {'\0'} ;
strcpy (myBigString, "A number is ");
iota (aNumber, numBuffer, 10);
strcat (myBigString, numBuffer);
The difference is - you write the lines instead of lazely using a bad library but with full control over memory and the advantage to compile it to flash, saving memory. Const char are actually called via pointer - so for later there are functions to get only certain parts of an array handy to create variable messages out of one big array.After a code analysis on github there is one other big problem: The use of blocking delay():
loop() {
delay(1000);
// lot of code
delay(3000);
}
replace with a non blocking delay
unsigned long timeStamp = 0;
setup(){}
loop() {
if (millis() - timeStamp > 4000) {
// lot of code
timeStamp = millis(); // reset the timer
}
}
and as written before get rid of all Strings (e.g)
///////////PREMENNE PRIJIMANÝCH ÚDAJOV///////
String mode;
String inzavlaha;
String inkurenie;
String invetranie;
String invlhkost_p;
String invlhkost_v;
String incas;
String intrvanie;
String inopakovanie;
String inteplota;
and as a final tio.If you want worldwide help, start to write all of your program in English (variables and comments) it makes it easier to help.
I am writing a code to capture serial readings from the Arduino to C++
Is there a way to capture the readings line by line and then store it into an array? I have read another post similar to mine, but I am still unable to apply it.
Any help is greatly appreciated, thank you.
Environment setup:
Arduino UNO
ADXL 335 accelerometer
Ubuntu 16.04
C++
[Updated] applied solution from Bart
Cpp file
The reason why I added the "for-loop with print and break" is to analyze the array contents.
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <unistd.h>
using namespace std;
char serialPortFilename[] = "/dev/ttyACM0";
int main()
{
char readBuffer[1024];
FILE *serPort = fopen(serialPortFilename, "r");
if (serPort == NULL)
{
printf("ERROR");
return 0;
}
while(1)
{
usleep(1000); //sync up Linux and Arduino
memset(readBuffer, 0, 1024);
fread(readBuffer, sizeof(char),1024,serPort);
for(int i=0; i<1024; i++){
printf("%c",readBuffer[i]);
}
break;
}
return 0;
}
Ino file
Fetching data from the Accelerometer
#include <stdio.h>
const int xPin = A0;
const int yPin = A1;
const int zPin = A2;
void setup() {
Serial.begin(9600);
}
void loop() {
int x = 0, y = 0, z = 0;
x = analogRead(xPin);
y = analogRead(yPin);
z = analogRead(zPin);
char buffer[16];
int n;
n = sprintf(buffer,"<%d,%d,%d>",x,y,z);
Serial.write(buffer);
}
Results
Running the code for three times
Click Here
The ideal outputs should be
<a,b,c><a,b,c><a,b,c>...
but right now, some of the outputs has the values inside "corrupted" (please see the fourth line from the top).
Even if use the start and end markers to determine a correct dataset, the data within the set is still wrong. I suspect the issue lies with the char array from C++, due to it being unsynchronized with Arduino. Else I need to send by Bytes from Arduino (not really sure how)
When dealing with two programs running on different processors they will never start sending/receiving at the same time. What you likely see is not that the results are merged wrong it is more likely the reading program started and stopped half way through the data.
When sending data over a line it is best that you:
On the Arduino:
First frame the data.
Send the frame.
On Linux:
Read in data in a buffer.
Search the buffer for a complete frame and deframe.
1. Framing the data
With framing the data I mean that you need a structure which you can recognize and validate on the receiving side. For example you could add the characters STX and ETX as control characters around your data. When the length of your data varies it is also required to send this.
In the following example we take that the data array is never longer than 255 bytes. This means that you can store the length in a single byte. Below you see pseudo code of how a frame could look like:
STX LENGTH DATA_ARRAY ETX
The total length of the bytes which will be send are thus the length of the data plus three.
2. Sending
Next you do not use println but Serial.write(buf, len) instead.
3. Receiving
On the receiving side you have a buffer in which all data received will be appended.
4. Deframing
Next each time new data has been added search for an STX character, assume the next character is the length. Using the length +1 you should find a ETX. If so you have found a valid frame and you can use the data. Next remove it from the buffer.
for(uint32_t i = 0; i < (buffer.size() - 2); ++i)
{
if(STX == buffer[i])
{
uint8_t length = buffer[i+2];
if(buffer.size() > (i + length + 3) && (ETX == buffer[i + length + 2]))
{
// Do something with the data.
// Clear the buffer from every thing before i + length + 3
buffer.clear(0, i + length + 3);
// Break the loop as by clearing the data the current index becomes invalid.
break;
}
}
}
For an example also using a Cyclic Redundancy Check (CRC) see here
I'm honestly at a loss here. I'm trying to store an SSID and password that the user sends through a post request in the flash EEPROM section. To do that I convert the data sent from the post request to a char array and index it to EEPROM. The SSID runs without any problems, but the password always ends up with junk data before it even gets to EEPROM.
Here is the bit of code in question:
// Recieve data from the HTTP server
void changeConfig(String parameter, String value){
int memoffset = 0;
if(parameter == "ssid")
memoffset = 0;
else if(parameter == "pass")
memoffset = 32;
else
return;
#ifdef DEBUG
Serial.println("Updating Data");
Serial.print("Param: ");
Serial.println(parameter);
Serial.print("Value: ");
Serial.println(value);
#endif
EEPROM.begin(64);
char _data[sizeof(value)];
value.toCharArray(_data, sizeof(value));
for(int i = memoffset; i < memoffset + sizeof(value); i++)
{
#ifdef DEBUG
Serial.print("addr ");
Serial.print(i);
Serial.print(" data ");
Serial.println(_data[i]);
#endif
EEPROM.write(i,_data[i]);
}
EEPROM.end();
}
And the Serial monitor output:
Post parameter: ssid, Value: NetworkName
Updating Data
Param: ssid
Value: NetworkName
addr 0 data N
addr 1 data e
addr 2 data t
addr 3 data w
addr 4 data o
addr 5 data r
addr 6 data k
addr 7 data N
addr 8 data a
addr 9 data m
addr 10 data e
addr 11 data ␀
Post parameter: pass, Value: Networkpass
Updating Data
Param: pass
Value: Networkpass
addr 32 data |
addr 33 data (
addr 34 data �
addr 35 data ?
addr 36 data L
addr 37 data ␛
addr 38 data �
addr 39 data ?
addr 40 data ␁
addr 41 data ␀
addr 42 data ␀
addr 43 data ␀
As you can see, when the name of the POST parameter is ssid, it works alright. With pass on the other hand, the char array is just filled with gibberish. Any insight would be helpful. I'm using platformio in the arduino environment. Generic ESP01 with 1M of flash.
Thanks in advance.
You have two problems with your code.
First, you are using sizeof incorrectly. Sizeof returns the size of the String object, but you are trying to get the length of the contained string. Sizeof is not the right tool for that, instead you should use whatever API String offers to read the size of the string.
The next problem is your usage of offsets. The following code snippet is all wrong:
char _data[sizeof(value)];
value.toCharArray(_data, sizeof(value));
for(int i = memoffset; i < memoffset + sizeof(value); i++)
{
...
EEPROM.write(i,_data[i]);
Your i starts with offset of 32, so you are trying to access element with index 32 in your _data array. But _data stores characters starting from the index 0, and since the length of array is actually 12 (sizeof of String is always 12) by accessing element with index 32 you are going beyond it's bounds, and obviously find garbage there (in C++ parlance, it is called undefined behavior).
Last, but not the least, C++ is an extremely complicated language, which can't be learned by 'trial and error'. Instead, you need to methodically study, preferably using one of the good C++ books. The list of those can be found here: The Definitive C++ Book Guide and List
You're using sizeof() incorrectly.
sizeof() tells you the size of the object, at compile time.
Try this experiment - run this code:
#include <Arduino.h>
void setup() {
String x("");
String y("abc");
String z("abcdef");
Serial.begin(115200);
delay(1000);
Serial.println(sizeof(x));
Serial.println(sizeof(y));
Serial.println(sizeof(z));
}
void loop() {
}
On my ESP8266 this outputs:
12
12
12
That's because it takes 12 bytes using this development environment to represent a String object (it might be different on a different CPU and compiler). The String class dynamically allocates storage, so sizeof can tell you nothing about how long the string itself is, only the compile-time size of the object.
For the String class, you should use its length() method. Your lines:
char _data[sizeof(value)];
value.toCharArray(_data, sizeof(value));
for(int i = memoffset; i < memoffset + sizeof(value); i++)
should be written as
char _data[value.length()];
value.toCharArray(_data, value.length());
for(int i = memoffset; i < memoffset + value.length(); i++)
For more information see the documentation on the String class.
You'll likely still have issues with string terminators. C and C++ terminate char array strings with the null character '\0', adding an extra byte to the length of the strings. So your code should more likely be:
void changeConfig(String parameter, String value){
int memoffset = 0;
if(parameter == "ssid")
memoffset = 0;
else if(parameter == "pass")
memoffset = 33;
else
return;
#ifdef DEBUG
Serial.println("Updating Data");
Serial.print("Param: ");
Serial.println(parameter);
Serial.print("Value: ");
Serial.println(value);
#endif
EEPROM.begin(66);
char _data[value.length() + 1];
value.toCharArray(_data, value.length() + 1);
for(int i = memoffset; i < memoffset + value.length() + 1; i++)
{
#ifdef DEBUG
Serial.print("addr ");
Serial.print(i);
Serial.print(" data ");
Serial.println(_data[i]);
#endif
EEPROM.write(i,_data[i]);
}
EEPROM.end();
}
to allow the string terminators to work correctly for 32 character SSIDs and passwords. But the fundamental issue that's breaking your code is the incorrect use of sizeof.
I am trying to divide two integer values and store as a float.
void setup()
{
lcd.begin(16, 2);
int l1 = 5;
int l2 = 15;
float test = 0;
test = (float)l1 / (float)l2;
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(test);
}
For some reason that I expect is fairly obvious I can't seem to store and display the correct value. 'test' variable is always set to 0.
How do I cast the integer values?
It must be your LCD print routine, and thus the casts you have used are correct.
I tried it out on an Arduino using serial printing instead of an LCD. The expected result appears in the serial monitor (started by menu Tools -> Serial Monitor) for the complete code example below:
Start...
5
15
0.33
0.33333334922790
The last result line confirms it is a 4 byte float with 7-8 significant digits.
Complete code example
/********************************************************************************
* Test out for Stack Overflow question "Divide two integers in Arduino", *
* <http://stackoverflow.com/questions/13792302/divide-two-integers-in-arduino> *
* *
********************************************************************************/
// The setup routine runs once when you press reset:
void setup() {
// Initialize serial communication at 9600 bits per second:
Serial.begin(9600);
//The question part, modified for serial print instead of LCD.
{
int l1 = 5;
int l2 = 15;
float test = 0;
test = (float)l1 / (float)l2;
Serial.println("Start...");
Serial.println("");
Serial.println(l1);
Serial.println(l2);
Serial.println(test);
Serial.println(test, 14);
}
} //setup()
void loop()
{
}
lcd.print doesn't know how to print a float, so you end up printing the integer instead.