I'm having a problem passing data to EEPROM. It seemed to be not accepting a char variable. I'm doing exactly what is told here: https://www.arduino.cc/en/Reference/EEPROMPut
So my this is my Object Structure
struct DeviceDataObject {
bool flag;
char data[20];
char data2[20];
int rate1;
int rate2;
int rate3;
};
So as I test with:
int RATES[3] = {300, 1500, 3600};
DeviceDataObject new_data = {true, "Data1Sample", "Sample2", RATES[0], RATES[1], RATES[2]};
WRITE_Device(new_data);
Here's my writing function
void WRITE_Device(DeviceDataObject data) {
while (!Serial) {
; // wait for serial port to connect. Needed for native USB port only
}
int eeAddress = 0;
float f = 123.456f; //Variable to store in EEPROM.
EEPROM.put(eeAddress, f);
eeAddress += sizeof(float); //Move address to the next byte after float 'f'.
EEPROM.put(eeAddress, data);
//Serial.println("Memory Data Updated");
}
Everything seemed to be OK. But if I replace "Data1Sample" and "Sample2" with a variable, EEPROM's data seemed to be changed in incorrectly.
void ChangeValue(String value) {
int RATES[3] = {300, 1500, 3600};
char charBuf[20];
value.toCharArray(charBuf, 20); //Convert to char
DeviceDataObject new_data = {true, "", {charBuf}, RATES[0], RATES[1], RATES[2]}
WRITE_Device(new_data);
}
What could be the mistake?
Looks like a pointer problem, try this
void ChangeValue(String value) {
int RATES[3] = {300, 1500, 3600};
DeviceDataObject new_data = {true, "", "", RATES[0], RATES[1], RATES[2]}
value.toCharArray(new_data.data2, 20); //Convert to char
WRITE_Device(new_data);
}
(you were creating a string where the first character was the pointer to your stack variable charBuf, rather than copying the string)
A somewhat long-winded approach would be to write each element of the structure to EEPROM individually. The code would look something like this and should allow you to isolate any issues more effectively.
ee_address = 0;
EEPROM.put(ee_address, new_data.flag);
ee_address += sizeof(new_data.flag); // Update address to store next variable
EEPROM.put(ee_address, new_data.data);
ee_address += sizeof(new_data.data);
EEPROM.put(ee_address, new_data.data2);
ee_address += sizeof(rawdata.data2);
EEPROM.put(ee_address, new_data.rate1);
ee_address += sizeof(new_data.rate1);
EEPROM.put(ee_address, new_data.rate2);
ee_address += sizeof(new_data.rate2);
EEPROM.put(ee_address, new_data.rate3);
ee_address += sizeof(rawdata.rate3);
This will make it easier to troubleshoot whether variables are not being written to EEPROM correctly or whether the issue stems from something else.
This is the approach I typically take when storing structures which I have defined to the EEPROM, as it gives more control when retrieving this information from the EEPROM at a later point.
I'll be the first to admit this is perhaps not the most elegant solution, but it should help address your issues.
Related
I want to dump chars from a Lora transmitter using Arduino Nano. With this line I assume it can be store the chars into an array:
char* dump = (char)LoRa.read();
char in[255];
strcpy(in, dump);
char str[] = in;
But unfortunately I get this compiler error:
exit status 1
initializer fails to determine size of 'str'
How I fix it?
UPDATE
I give my entire code. I used shox96 shox96 from siara-cc for my objective to compress the data from Lora.read().
void print_compressed(char *in, int len) {
int l;
byte bit;
//Serial.write("\nCompressed bits:");
for (l=0; l<len*8; l++) {
bit = (in[l/8]>>(7-l%8))&0x01;
//Serial.print((int)bit);
//if (l%8 == 7) Serial.print(" ");
}
}
void loop() {
char* dump = (char)LoRa.read();
char in[255];
strcpy(in, dump);
char str[] = in;
char cbuf[300];
char dbuf[300];
int len = sizeof(str);
if (len > 0) {
memset(cbuf, 0, sizeof(cbuf));
int ctot = shox96_0_2_compress(str, len, cbuf, NULL);
print_compressed(cbuf, ctot);
memset(dbuf, 0, sizeof(dbuf));
int dlen = shox96_0_2_decompress(cbuf, ctot, dbuf, NULL);
dbuf[dlen] = 0;
float perc = (dlen-ctot);
perc /= dlen;
perc *= 100;
Serial.print(ctot);
Serial.write(",");
Serial.println(dlen);
}
delay(1000);
}
The compiler can only supply the size of an array for you on creation if it has a brace enclosed initializer list. Like this:
int array[] = {1, 2, 3, 4, 5};
If you're doing anything other than that then you need to put a number inside those braces. Since you're making a copy of the array in and that array is 255 char then this one needs to be 255 char as well in order to accommodate.
char str[255] = in;
My comment on your question still stands though. This answer clears your compiler error, but I don't think it is really a solution to your larger problem. But without seeing more of your code and knowing more about it I can't tell much about it. You already have two copies of this data by the time you get to that line. I'm not sure why you think you need to have a third.
I have the following Arduino code
#include "SIM900.h"
#include <SoftwareSerial.h>
#include "inetGSM.h"
#include<String.h>
InetGSM inet;
char msg[165];
char store[2];
char a;
char b;
char* disp;
boolean started=false;
void setup()
{
//Serial connection.
Serial.begin(9600);
Serial.println("GSM Shield testing.");
//Start configuration of shield with baudrate.
//For http uses is raccomanded to use 4800 or slower.
if (gsm.begin(2400)) {
Serial.println("\nstatus=READY");
started=true;
} else Serial.println("\nstatus=IDLE");
if(started)
{
//GPRS attach, put in order APN, username and password.
//If no needed auth let them blank.
if (inet.attachGPRS("TATA.DOCOMO.INTERNET", "", ""))
Serial.println("status=ATTACHED");
else Serial.println("status=ERROR");
delay(1000);
//TCP Client GET, send a GET request to the server and
//save the reply.
inet.httpGET("www.boat.esy.es", 80, "/retrieve.php", msg, 165);
//Print the results.
Serial.println("\nData received:");
disp = strstr(msg,"\r\n\r\n");
disp = disp+4;
a = disp[1];
b = disp[2];
}
}
void loop()
{
Serial.println("Begin");
Serial.println(a);
Serial.println("+");
Serial.println(b);
Serial.println("End");
delay(500);
}
The disp variable in my program accepts the value 1 & 1 as string. I want this 1 & 1 to be stored in two separate variables. SO I tried the way mentioned above and this is what I got
Output
Begin
1
+
End
Begin
1
+
End
Begin
1
+
End
If I understand array correctly, char arr[100] is same as char* arr, just that the former one reserves 100 character locations on the memory, then b = disp[2] should give the latter 1 of 11 right?
I am not trying to use the String library because that will occupy a lot of memory. So if there's any way that I'm not aware of that extract both the 1s & store them separately, please let me know.
Thank you for your time!
Your code is almost correct.
The problem is here:
disp = strstr(msg,"\r\n\r\n");
disp = disp+4; // now disp points to the string "11" (correct)
// what follows is wrong
a = disp[1]; // this is the second char element if the disp string
b = disp[2]; // this is the zero terminator of the disp string
You need this because in C arrays indexes start with 0:
a = disp[0];
b = disp[1];
Small test program:
#include <stdio.h>
#include <string.h>
int main()
{
char *disp;
char msg[] = "Fake Header\r\n\r\n12";
char a;
char b;
disp = strstr(msg,"\r\n\r\n");
disp = disp+4;
a = disp[0];
b = disp[1];
printf("a = %c\nb = %c\n", a, b);
return 0;
}
Output:
a = 1
b = 2
There are quite a few problems with your code here...
Firstly, all your variables are un-initialised and you're accessing them after their declaration without initially giving them any value in memory. To solve this set each variable to something before you continue on like so:
char a = ''; // & so on...
Next up, char* disp; is a pointer, not a variable. You dont actually know the physical location of disp, it points to somewhere it memory, maybe a bit of populated memory, maybe nothing at all. So the best way to store something in disp is to turn it into an array and they write to it part by part reading when you need and terminating the variable with the correct formatting.
e.g
char disp[2] = {}; // Declare disp...
disp[0] = '1'; // Write to disp...
disp[1] = '1';
disp[2] = '\0';
& finally the webserver you're connecting too has DynDNS attached to the address, and anybody can access it without a password and anybody can start attacking it, so I would hide it.
I've found a very strange issue with both printf (and printf_s), and also std::cout. I'm not sure if it's some short of "glitch" or error in these functions, or if I'm doing something wrong. Since both functions do the same, I'm assuming I'm not doing it the right way.
I have the following structures in my program (By the way, this is a Visual C++ 2010 project):
#pragma pack(push, 1)
typedef struct nameentry
{
char NAME[17];
char EXT[4];
}NAMEENTRY;
#pragma pack(pop)
#pragma pack(push, 1)
typedef struct fileentry
{
unsigned int ID;
NAMEENTRY FILENAME;
unsigned int GPFID;
unsigned long long int FPOINTER;
size_t FILESIZE;
}FILEENTRY;
#pragma pack(pop)
Now I have the following portion of code:
NAMEENTRY fname = MCreateNameEntry("LONGFILE.JPG");
FILEENTRY* myfile_ = SearchFileByPkgID(0, fname);
printf("%s", myfile_->FILENAME.NAME);
So what this code is supposed to do is, create an instance of NAMEENTRY with NAME=LONGFILE, and EXT=JPG. Both character arrays are null terminated (last byte is a 0). Then create an instance of FILEENTRY with it's corresponding data from a database I'm developing, then print the name of the file from the FILEENTRY's NAMEENTRY structure.
After running the code, what I get instead of the name of the file, is... garbage. The classic garbage you get when trying to print text from a bad pointer. If I try to print any of the other fields, I also get wrong values.
So obviously, my first thought was that one of my functions were not returning the right value. So I started inspecting the code and, to my surprise, they are actually returning the right values and the structure is filled with the right data. I get the proper values in each field, every character array ends with a 0, etc.
So then I said... "What if I copy the entire block into another instance of FILEENTRY?", and I tried this:
NAMEENTRY fname = MCreateNameEntry("LONGFILE.JPG");
FILEENTRY* myfile_ = SearchFileByPkgID(0, fname);
FILEENTRY dMem;
memcpy(&dMem, myfile_, sizeof(FILEENTRY));
printf("%s", dMem.FILENAME.NAME);
And guess what? It works perfectly fine. I get the name of the file, no garbage. So I'm assuming, either the problem is inside of printf (I also tried std::cout with the same results), or I am doing something wrong when using these functions.
Well, that helps. Seems like the problem was trying to return a pointer to a local variable, as Igor Tandetnik suggested.
So as a workaround, I'm not sure if this is a proper way of handling this, instead of define a local variable, I'm using calloc to allocate a memory block for a FILEENTRY pointer, then fill it and return it. And yes, it seems to work this way.
This is the actual code of the function:
FILEENTRY* SearchFileByPkgID(int ID, NAMEENTRY fname)
{
FILEENTRY* myFile = (FILEENTRY*)calloc(sizeof(FILEENTRY),1);
std::vector<int> results;
unsigned int* dptable = GetDPTableByPkgId(ID);
bool found = false;
for(int x = 0; x < 1024; x++)
{
if(dptable[x] > 0)
{
fseek(PDBFILE, dptable[x], SEEK_SET);
fread(myFile, sizeof(FILEENTRY), 1, PDBFILE);
if(strcmp(myFile->FILENAME.EXT, fname.EXT) == 0)
if(myFile->FILENAME.NAME[0] == fname.NAME[0])
results.push_back(dptable[x]);
}
}
for(int y = 0; y < results.size(); y++)
{
fseek(PDBFILE, results[y], SEEK_SET);
fread(myFile, sizeof(FILEENTRY), 1, PDBFILE);
if(strcmp(myFile->FILENAME.NAME, fname.NAME) == 0)
{
found = true;
break;
}
}
results.clear();
if(found)
return myFile;
else
return 0L;
}
Any more suggestions are wellcome.
I am processing a binary file that is built up of events. Each event can have a variable length. Since my read buffer is a fixed size I handle things as follows:
const int bufferSize = 0x500000;
const int readSize = 0x400000;
const int eventLengthMask = 0x7FFE0000;
const int eventLengthShift = 17;
const int headerLengthMask = 0x1F000;
const int headerLengthShift = 12;
const int slotMask = 0xF0;
const int slotShift = 4;
const int channelMask = 0xF;
...
//allocate the buffer we allocate 5 MB even though we read in 4MB chunks
//to deal with unprocessed data from the end of a read
char* allocBuff = new char[bufferSize]; //inFile reads data into here
unsigned int* buff = reinterpret_cast<unsigned int*>(allocBuff); //data is interpretted from here
inFile.open(fileName.c_str(),ios_base::in | ios_base::binary);
int startPos = 0;
while(!inFile.eof())
{
int index = 0;
inFile.read(&(allocBuff[startPos]), readSize);
int size = ((readSize + startPos)>>2);
//loop to process the buffer
while (index<size)
{
unsigned int data = buff[index];
int eventLength = ((data&eventLengthMask)>>eventLengthShift);
int headerLength = ((data&headerLengthMask)>>headerLengthShift);
int slot = ((data&slotMask)>>slotShift);
int channel = data&channelMask;
//now check if the full event is in the buffer
if( (index+eventLength) > size )
{//the full event is not in the buffer
break;
}
++index;
//further processing of the event
}
//move the data at the end of the buffer to the beginning and set start position
//for the next read
for(int i = index; i<size; ++i)
{
buff[i-index] = buff[i];
}
startPos = ((size-index)<<2);
}
My question is this: Is there a better to handle having unprocessed data at the end of the buffer?
You could improve it by using a circular buffer rather than a simple array. That, or a circular iterator over the array. Then you don't need to do all that copying — the "start" of the array moves.
Other than that, no, not really.
When I encountered this problem in the past, I simply copied the
unprocessed data down, and then read from the end of it. This
is a valid solution (and by far the simplest) if the individual
elements are fairly small and the buffer is large. (On a modern
machine, "fairly small" can easily be anything up to a couple of
hundred KB.) Of course, you'll have to keep track of how much
you've copied down, to adjust the pointer and the size of the
next read.
Beyond that:
You'd be better off using std::vector<char> for the buffer.
You can't convert four bytes read from a disk into an
unsigned int just by casting its address; you have to insert
each of the bytes into the unsigned int where it belongs.
And finally: you don't check that the read has succeeded
before processing the data. Using unbuffered input with an
istream is a bit tricky: your loop should probably be
something like
while ( inFile.read( addr, len ) || inFile.gcount() != 0 )....
Let's say I have a class that I don't own: DataBuffer. It provides various get member functions:
get(uint8_t *value);
get(uint16_t *value);
...
When reading from a structure contained in this buffer, I know the order and size of fields, and I want to reduce the chance of future code changes causing an error:
struct Record
{
uint16_t Header;
uint16_t Content;
}
void ReadIntoRecord(Record* r)
{
DataBuffer buf( initialized from the network with bytes )
buf.get(&r->Header); // Good!
buf.get(&r->Content);
}
Then someone checks in a change to do something with the header before writing it:
uint8_t customHeader;
buf.get(&customHeader); // Wrong, stopped reading after only 1 byte
r->Header = customHeader + 1;
buf.get(&r->Content); // now we're reading from the wrong part of the buffer.
Is the following an acceptable way to harden the code against changes? Remember, I can't change the function names to getByte, getUShort, etc. I could inherit from DataBuffer, but that seems like overkill.
buf.get(static_cast<uint16_t*>(&r->Header)); // compiler will catch incorrect variable type
buf.get(static_cast<uint16_t*>(&r->Content))
Updated with not-eye-safe legacy code example:
float dummy_float;
uint32_t dummy32;
uint16_t dummy16;
uint8_t dummy8;
uint16_t headTypeTemp;
buf.get(static_cast<uint16_t*>(&headTypeTemp));
m_headType = HeadType(headTypeTemp);
buf.get(static_cast<uint8_t*>(&hid));
buf.get(m_Name);
buf.get(m_SerialNumber);
float start;
buf.get(static_cast<float*>(&start));
float stop;
buf.get(static_cast<float*>(&stop));
buf.get(static_cast<float*>(&dummy_float));
setStuffA(dummy_float);
buf.get(static_cast<uint16_t*>(&dummy16));
setStuffB(float(dummy16)/1000);
buf.get(static_cast<uint8_t*>(&dummy8)); //reserved
buf.get(static_cast<uint32_t*>(&dummy32));
Entries().setStart( dummy32 );
buf.get(static_cast<uint32_t*>(&dummy32));
Entries().setStop( dummy32 );
buf.get(static_cast<float*>(&dummy_float));
Entries().setMoreStuff( dummy_float );
uint32_t datalength;
buf.get(static_cast<uint32_t*>(&datalength));
Entries().data().setLength(datalength);
RetVal ret = ReturnCode::SUCCESS;
Entry* data_ptr = Entries().data().data();
for (unsigned int i = 0; i < datalength && ret == ReturnCode::SUCCESS; i++)
{
ret = buf.get(static_cast<float*>(&dummy_float));
data_ptr[i].FieldA = dummy_float;
}
for (unsigned int i = 0; i < datalength && ret == ReturnCode::SUCCESS; i++)
{
ret = buf.get(static_cast<float*>(&dummy_float));
data_ptr[i].FieldB = dummy_float;
}
// Read in the normalization vector
Util::SimpleVector<float> norm;
buf.get(static_cast<uint32_t*>(&datalength));
norm.setLength(datalength);
for (unsigned int i=0; i<datalength; i++)
{
norm[i] = buf.getFloat();
}
setNormalization(norm);
return ReturnCode::SUCCESS;
}
Don't use overloading. Why not have get_word and get_dword calls? The interface isn't going to be any uglier but at least the mistake is a lot harder to make.
wouldn't it be better to read the whole struct from the network? Letting the user do all the socket operations seems like a bad idea to me (not encapsulated). Encapsulate the stuff you want to send on the network to operate on file descriptors instead of letting the user put raw buffer data to the file descriptors.
I can imagine something like
void readHeader(int filedes, struct Record * Header);
so you can do something like this
struct Record
{
uint16_t Header;
uint16_t Content;
uint16_t getHeader() const { return Header; }
uint16_t getContent() const { return Content; }
};
/* socket stuff to get filedes */
struct Record x;
readHeader(fd, &x);
x.getContent();
You can't read from buffer with type safety unless the buffer contains information about the content. One simple method is to add length to each structure and check that at least the data being read is still the sane length. You could also use XML or ASN.1 or something similar where type information is provided. Of course I'm assuming that you also write to that buffer.