Memcpy_p issues, how to resolve? - c++

I'm puzzled by my own code :-) I'm trying to read data from PROGMEM. This works ok when I only have this array in PROGMEM. When adding an extra seperate array in PROGMEM it goes wrong. That is, when it's defined in a different piece of code and #included. When put together in 1 code it's fine. But I want these to arrays to live apart in different pieces of code.
I believe I have an error in the last function which I have include here (callMenuItemParaName).
It has to do with the way I'm reading out PROGMEM. I think it's best to use memcpy_P but cannot find any online explanation on how to use this exactly.
The code I have now works, but as long as I don't put another array in PROGMEM. (this routine is working correctly, with the memcpy_P function. But how do I implement memcpy_P in the function callMenuItemParaName?
Thanks for any advice you can give! (ofcourse pgmspace.h is included)
Working on AVR GCC, IDE is Eclipse, mcu = atmega644 # 20MHz
unsigned char (*adresParaName);
const uint8_t TEXT0[] PROGMEM = "TEXT0";
const uint8_t paraNameAtk[] PROGMEM = "Atk ";
const uint8_t paraNameDcy[] PROGMEM = "Dcy ";
...
const uint8_t paraNameTru[] PROGMEM = "Tru ";
const uint8_t paraNameLight[] PROGMEM = "Light";
typedef void (*pMenu)(void);
typedef struct
{
void (*pointer2MenuNumber)(void);
char VALUE;
const unsigned char *adresParaName;
} sel_item;
const sel_item menuNumber2ItemDbase[] PROGMEM=
{
{ itemA , 0x00 , TEXT0 },
{ itemB , 0x01 , paraNameAtk },
{ itemC , 0x02 , paraNameDcy },
...
{ itemM , 0x05 , paraNameTru },
{ itemN , 0x05 , paraNameLight }
};
//prototypes
void callMenuItem(const sel_item *item);
void callMenuItemValue(const sel_item *item);
void callMenuItemParaName(const sel_item *item);
// *************************************************
// callMenu
// Description:
//
// *************************************************
void callMenuItem(const sel_item *item)
{
pMenu function = (pMenu)pgm_read_word(&item->pointer2MenuNumber);
function();
}
void callMenuItemValue(const sel_item *item)
{
setCursor(1,4);
char VAL = (char)pgm_read_byte(&item->VALUE);
char2LCD('0'+VAL);
}
void callMenuItemParaName(const sel_item *item)
{
char tempText[5];
char *data = (char*)pgm_read_word(&item->adresParaName);
strcpy_P (tempText, data);
for (uint8_t x=0;x<5;x++)
{
char2LCD(tempText[x]);
}
}
I've tried adding this:
char* pstr = 0;
memcpy_P (&pstr, data, sizeof(char*));
But no luck. (can't find a good tutorial on memcpy_P either, btw)

Your strings are 6 bytes long (remember the terminating 0), which means that you're overflowing tempText when you strcpy_P into it. Use memcpy_P instead.
memcpy_P(tempText, data, sizeof tempText);
The way you use pgm_read_word is just fine.

Related

Pointer to pointer comparision breaks when while(1) removed - why?

Trying to build a menu system but running into some issues with pointers - which I don't have much experience with.
I don't understand why removing the while(1) makes the comparison fail between mainmenu_table[1][i] == &option6 but for some reason it does.
What am I doing wrong? Using visual studio and an atmega328p. Thanks
Serial output with original code:
Serial begins
MeNu6
MeNu6
Starting compare loop
it worked
Serial output with while(1) removed.
Serial begins
MeNu6
MeNu6
Starting compare loop
the end
Original code (with while(1) included)
const char option1[] PROGMEM = "Menu1";
const char option2[] PROGMEM = "MEnu2";
const char option3[] PROGMEM = "MeNu3";
const char option4[] PROGMEM = "Menu4";
const char option5[] PROGMEM = "MEnu5";
const char option6[] PROGMEM = "MeNu6";
const char option7[] PROGMEM = "menu7";
const char* const submenu1_table[] PROGMEM = { option1, option2, option3 }; // array of pointers to chars stored in flash
const char* const submenu2_table[] PROGMEM = { option4, option5, option6, option7 };
const char** const mainmenu_table[] PROGMEM = { submenu1_table, submenu2_table }; //array of pointers to pointers to chars in flash
// The setup() function runs once each time the micro-controller starts
void setup()
{
Serial.begin(9600);
delay(100);
Serial.println("Serial begins");
Serial.println((const __FlashStringHelper*)(mainmenu_table[1][2])); // prints "Menu6" as expected
Serial.println((const __FlashStringHelper*)option6); // also prints "Menu6"
Serial.println("Starting compare loop");
for (int i = 0; i < 4; i++) {
if ( mainmenu_table[1][i] == &option6 ) { //
Serial.println("it worked");
while (1); // COMMENTING THIS OUT MEANS DOESN'T COMPARE SUCCESSFULLY.
}
}
Serial.println("the end");
}
// Add the main program code into the continuous loop() function
void loop()
{
}
According to Arduino description of PROGMEM, you cannot access the data through pointers to it directly as with plain pointers. You need to use the proper macros/functions to access the data.
In your code, the pointer tables themselves are located in the PROGMEM, so, to extract the individual pointers, you are supposed to do something like:
const char** submenu = (const char**)pgm_read_word(&(mainmenu_table[1]));
const char* option = (const char*)pgm_read_word(&(submenu[i]));
if (option == option6) {
//...
This code is based on the string table example from the first link.

Traverse an raw video more efficiently

I have a raw video file , and i make in qt , an app that reads frame by frame from this file .At large raw files when i press an button that goes to the next frame there is a big delay almost one sec .
Here is my code that returns an frame from raw file :
void RawVideoReader::getFrame(int offset)
{
std::cout<<"getFrame"<<std::endl;
file.seek((unsigned long long int)(((unsigned long long int)width * (unsigned long long int)height) * (unsigned long long int)offset));
QByteArray array = file.read(width * height);
const std::size_t count = array.size();
hex = std::unique_ptr<unsigned char>(new unsigned char[count]);
std::memcpy(hex.get(), array.constData(), count);
}
You can read directly into the buffer you desire - the question is: why do you want to manage this memory buffer using unique_ptr? QByteArray already does that job. Furthermore, you probably want to keep the same buffer, and not reallocate it over and over.
class RawVideoReader : ... {
QByteArray frame;
uint8_t *frameData() const { return frame.size() ? static_cast<uint8_t*>(frame.constData()) : nullptr; }
size_t frameSize() const { return static_cast<size_t>(frame.size()); }
...
};
bool RawVideoReader::getFrame(int frameNo) {
qDebug() << __FUNCTION__;
frame.resize(width * height * 1);
file.seek(qint64(frame.size()) * qint64(frameNo));
auto const hadRead = file.read(frame.data(), frame.size());
return hadRead == frame.size();
}

VS2017: cannot add strings/wstrings

I have trouble understanding why the following code does not do what it should, VS2017 does not show an error and the solution is created, but the string is never what it should be:
void COrion::AddJournalMessage(CTextData *msg, const string &name)
{
WISPFUN_DEBUG("c194_f101");
CTextData *jmsg = new CTextData(msg);
jmsg->Text = name + jmsg->Text;
}
jmsg->Text is std::string.
now at runtime let's say 'name' is "Player:" and 'jmsg->Text' is "Hello World", I would expect the text after the code to be "Player:Hello World", but it is not. It's only "Player:" and I don't understand why.
I found a workaround in a way:
jmsg->Text = name.c_str() + jmsg->Text;
with this change it is "Player:Hello World".
Problem is, I still don't understand why the first one does not work.
Can someone explain where the problem is?
Is it specific to VS or something?
to make it clear: this is from an open source project I want to use, not code I wrote myself, but the problem has been the source of many bugs, since it is used in this way alot.
edit
CTextData class:
class CTextData : public CRenderTextObject
{
public:
bool Unicode = false;
TEXT_TYPE Type = TT_CLIENT;
uchar Font = 0;
uint Timer = 0;
uint MoveTimer = 0;
string Text = "";
wstring UnicodeText = L"";
uchar Alpha = 0xFF;
CRenderWorldObject *Owner = NULL;
CTextData();
CTextData(CTextData *obj);
virtual ~CTextData();
virtual bool IsText() { return true; }
bool CanBeDrawedInJournalGump();
CGLTextTexture m_Texture;
void GenerateTexture(
int maxWidth,
ushort flags = 0,
TEXT_ALIGN_TYPE align = TS_LEFT,
uchar cell = 30,
int font = -1);
};

AT command list as char * array

,,I need to provide an AT command to a modem which looks like this: AT^SRPN=1,99991,"Download_URL","Image";^SMSO
How can I insert the variable download_url and the variable image into the commands string array? Is the right way to declare the commands array not as const and to use strcpy() to insert the two variables into the commands list?
The function at_send_commands() needs the commands list as const.
Function proto: at_resp_t at_send_commands(TickType ticks_to_wait, const char *commands[]);
at_resp_t at_send_download_url_and_image(const char *download_url, const char *image)
{
static const char *commands[] =
{
"AT^SRPN=1,99991,",
download_url,
",",
image,
";^SMSO\r",
NULL
};
at_resp_t err = at_send_commands(AT_TIMEOUT, commands);
if (err)
return err;
}
Try this:
at_resp_t at_send_download_url_and_image(const char *download_url, const char *image)
{
std::string str("AT^SRPN=1,99991,");
str += download_url;
str += ",";
str += image;
str += ";^SMSO\r";
const char* command = str.c_str();
const char* commands[] =
{
command,
NULL
};
at_resp_t err = at_send_commands(AT_TIMEOUT, commands);
if (err)
return err;
}
In C the simplest way is IMO
void send_command(const char *download_url, const char *image) {
char buf[1000];
sprintf(buf, "AT^SRPN=1,99991,\"%s\",\"%s\";^SMSO",
download_url, image);
...
}
in buf you will end up having the final command to send to the modem.
If this code can be used in an hostile environment then you should also pay attention that no overflow can happen when passed large strings as url/image (e.g. add a check on strlen first or use snprintf instead).

Saving changes to LLVM BasicBlock Pass

I successfully added some Metadata to a Basic Block in LLVM. Then I used Mod->dump() to display it on the screen.
The data is added successfully to my byte code, i.e. metadata is displayed on the screen.
My problem is that these changes are not updated in my original file.
How can I solve this problem?
class BasicBlock1 : public BasicBlockPass {
public:
BasicBlock1()
: BasicBlockPass(ID)
{}
virtual bool runOnBasicBlock(BasicBlock &BB) {
Value *A[] = {MDString::get(getGlobalContext(), "mymetadata")};
MDNode *Node = MDNode::get(getGlobalContext(), A);
for (BasicBlock::iterator ii = BB.begin(), ii_e = BB.end();
ii != ii_e; ++ii) {
ii->setMetadata("XXX", Node);
}
return true;
}
static char ID;
};
char FunctionPrint::ID = 0;
char BasicBlock1::ID =0;
int main(int argc, char **argv) {
Module *Mod = ParseIRFile(argv[1], Err, getGlobalContext());
PM.add(new BasicBlock1());
PM.run(*Mod);
Mod->dump();
return 0;
}
You write:
The data is added successfully to my byte code, i.e. metadata is displayed on the screen.
My problem is that these changes are not updated in my original file.
In your code snippet, you do not write your modified module anywhere, you just print it to the output. You can write it using:
std::string ErrorInfo;
raw_fd_ostream OS(argv[1], ErrorInfo, sys::fs::F_Binary);
if (ErrorInfo.empty()) WriteBitcodeToFile(*Mod, OS);