How to retrieve an int array that is stored in a table using PROGMEM? - arduino

I'm new to Arduino and currently learn to use PROGMEM to store variables so that I can save dynamic memory. I have 13 variables including these three below that I store using PROGMEM.
Here are some of example of variables that I store and use it in my functions :-
const unsigned int raw_0[62] PROGMEM = {2600,850,400,500,400,500,450,850,450,850,1350,850,450,450,400,500,400,450,450,400,450,450,450,450,400,450,900,850,900,850,900,450,450,850,900,850,900,850,450,450,900,450,400,450,400,900,450,450,450,400,450,450,450,450,400,450,450,450,450,400,450,};
const unsigned int raw_1[60] PROGMEM = {2600,850,450,450,450,450,450,850,450,850,1350,850,500,400,450,400,450,450,450,450,400,450,450,450,400,450,900,850,900,900,850,450,450,850,850,900,900,900,400,450,900,450,450,400,450,850,450,450,450,450,400,450,450,450,450,400,450,450,850,};
const unsigned int raw_a[100] PROGMEM = {3500,1700,400,450,450,1250,450,400,450,400,450,400,500,400,450,400,450,400,450,400,450,450,400,400,500,400,450,400,450,1300,400,450,450,400,450,400,450,400,450,400,450,400,500,350,500,400,450,400,450,1300,400,400,500,400,450,400,450,400,450,450,400,450,450,400,450,400,450,400,450,400,450,450,400,450,450,400,450,1250,450,400,450,400,500,400,450,400,450,400,450,400,450,400,450,1300,450,400,450,1250,450,};
Here is the table that store the variables. I learn this approach from Arduino website; https://www.arduino.cc/en/Reference/PROGMEM .
const unsigned int* const myTable[13] PROGMEM = {
raw_0,
raw_1,
raw_2,
raw_3,
raw_4,
raw_5,
raw_6,
raw_7,
raw_8,
raw_9,
raw_a,
raw_b,
raw_c};
My problem is, how do I retrieve these variables using PROGMEM such as raw_1 and raw_a ?
This is what I did but it did not work :-
unsigned int * ptr = (unsigned int *) pgm_read_word (&myTable [1]);
irsend.sendRaw(ptr,62,38);
Most of examples that I found, they use String or char datatype but in my case, I use array integer.

The ptr is also pointer to PROGMEM, so you have to read the value (or values in this case) by pgm_read_word. The IR library doesn't support that at all (I hope it's the correct one).
Anyway sendRaw implementation is this:
void IRsend::sendRaw (const unsigned int buf[], unsigned int len, unsigned int hz)
{
// Set IR carrier frequency
enableIROut(hz);
for (unsigned int i = 0; i < len; i++) {
if (i & 1) space(buf[i]) ;
else mark (buf[i]) ;
}
space(0); // Always end with the LED off
}
And all used methods are public, so you can implement your own function to do the same:
void mySendRaw (IRsend & dev, const unsigned int buf[], unsigned int len, unsigned int khz)
{
// Set IR carrier frequency
dev.devenableIROut(khz);
for (unsigned int i = 0; i < len; i++) {
if (i & 1) dev.space(pgm_read_word(buf+i));
else dev.mark (pgm_read_word(buf+i));
}
dev.space(0); // Always end with the LED off
}
// And usage:
mySendRaw(irsend, (const uint16_t*)pgm_read_word(myTable+1), 62, 38);
However the size of arrays should be stored somewhere too, so you can use something like:
byte cmd = 1;
mySendRaw(irsend, (const uint16_t*)pgm_read_word(myTable+cmd), pgm_read_word(myTableLenghts+cmd), 38);

Related

Getting junk data when trying to retrieve elements from a PROGMEM array on Arduino

My code looks something like this:
#define SIZE_OF_ARRAY 1000
const long myArray[SIZE_OF_ARRAY] PROGMEM = {
1610514120L,
1613070480L,
1615630980L,
1618194720L,
1620759660L,
1623322440L,
1625879820L,
1628430600L,
1630975920L,
1633518300L,
1636060500L,
1638603840L,
1641148500L,
1643694540L,
... // All the way to 1000 elements
}
void setup() {
Serial.begin(115200);
for( int i = 0; i < SIZE_OF_ARRAY; i++){
long currentNumber = myArray[i];
// These also do not work:
//long currentNumber = pgm_read_word_near(myArray + i);
//long currentNumber = pgm_read_dword_near(myArray + i);
Serial.println(currentNumber);
}
}
But when I run this code, I get completely random junk data:
0
65536
0
-1195853640
8843185
-566231498
-310626819
-854754529
263210495
-325068311
-159567983
-1770239
-29784074
1054840810
-293611553
-436273185
-566231498
-310626819
-854754529
263210495
... all the way up to 1000
How can I access that array to get the data I put in it? I am not very familiar with C and the difference between variables and pointers, but it works without the PROGMEM flag so I assumed it would work with it as well.
Looks like the answer was to use:
void setup() {
Serial.begin(115200);
for( int i = 0; i < SIZE_OF_ARRAY; i++){
unsigned long currentNumber = pgm_read_dword_near(myArray + i);
Serial.println(currentNumber);
}
}
And to redefine the long array as:
const unsigned long myArray[SIZE_OF_ARRAY] PROGMEM = {
1610514120UL,
1613070480UL,
1615630980UL,
1618194720UL,
1620759660UL,
...
}
Because I was also running into long overflow errors

copying unsigned char array to pointer

I am trying to hash the data string and then copy the result to a pointer in order to use it elsewhere (send it over a URL). Problem is that although hash is correct the pointer does not contain the correct hash.
int main(int argc, char const *argv[])
{
char data[] = "oNOH0hwZ3H6aduK5hnhxl5CI5C9v1EAghfO8maYfHUgKfQGn3NLeJdNEGNZyhqFpvjoIkcOSXUt2BZfvDQAcUeHqRxOZNke9ttHEvmmi7FbzugUXXl0HpxY7UDWyN1x6k5AGhNPfiQECXpqKAgiQE6NpzANcsb9D6AaedPklwOOk35Vtc3aGZOWoezrxBq1xR1CUHM63rLekGZEJSEgIi2XnreLSvCgctJX1mUVDvZO2OjBxOI6XATaSYMBjeImyh9puUaYfZC8ELA2p8YdyHdgvQIFUgRjoRyICzwHpZGUB6MR5BUu9YBvE90pfIytqX2SmoqCeXmFUZmPq79pVAKqzBFFa3YrRQa35rw9eIFYxSEOPE3B4ERu6m07gOoXvpRrGeqKMWzaE3OkxILsdtN9GD7MimAEBiV7mcIZY7Zt1EDpcfHfylf4PcHYp8sQhdNugmj4j9naDRpFWXLk9QeOTMC8KUPSYtc4FmZOldPOU4kGSVQRCVwmxYk8J0QyjTtO5ithm8W636CLSitl4QxsFIrfy7DIRXmM6FTiEFexCG9lPtwK9U2EsjJRhcpY0BBW7l4BR8ZjFYvlhRVgBNKUWjB4mRTcjkZgwTIdSxnnmIytqjASXbCKk4ExLnAUyp1U8AXRYa4aJtuZDUHqVa064vuGIUq69iR8IEPwFKxe4R4yBCPnCFkx1E3zokwosdn1I3odDLiytdWVFB887ivYMoo1yLfRPsJnlXrPzAeTD1E9tD7rLtgoIuf76lOLEoYQcgwCGAl9sP9Li73Uq98ZueWqqB2VPRBRXYjtpvtHasjjpc3Gc2vw7iNoJF9omB69pgsFBLdC4mLkpFRrycOvkrJUWJ98a57qcqWD2Z6XbI7rdOJCRnX2ExMq6Lp7HnoJDadwZaj1IgjMVSeC52uAp7QmJ6kgjzQNzT9pTihspq4b98D50YvgWctv8DCh2iUs2TIL2P4i6Yj5XN0OCmUooeKmHctAkeTcYrOQ6IZ2x9YkNPZf1KufO5rm7LMiP";
unsigned char hash[SHA512_DIGEST_LENGTH];
SHA512(data, sizeof(data) - 1, hash);
for(int i = 0; i < SHA512_DIGEST_LENGTH; ++i) {
printf("%02x", hash[i]);
}
unsigned char* phash = (unsigned char *)malloc(sizeof(hash));
memcpy(phash, hash, (sizeof(hash)));
printf("\nHash is: %p", *phash);
//some other code here
}
OUTPUT:a5274651e4573a7fea8dc1936a26a77a0667f600cad6c0afdd648431fa44b9e1e9128237b8012f103218f743cc422214701af609d22f9cbdf78e7bd5b374b87b (correct hash)
Hash is : 0x564e7a3dc670
What am I missing here?

How does one use qsort to sort a char containing pathnames/files based on their bytes?

I basically wrote a code in which I take two command line arguments one being the type of file that I want to search in my directory and they other being the amount I want(which is not implemented yet, but I can fix that)
The code is like so:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#define sizeFileName 500
#define filesMax 5000
int cmpfunc( const void *a, const void *b) {
return *(char*)a + *(char*)b;
}
int main( int argc, char ** argv) {
FILE * fp = popen( "find . -type f", "r");
char * type = argv[1];
char * extension = ".";
char* tExtension;
tExtension = malloc(strlen(type)+1+4);
strcpy(tExtension, extension);
strcat(tExtension, type);
// printf("%s\n",tExtension);
int amount = atoi(argv[2]);
//printf("%d\n",amount);
char buff[sizeFileName];
int nFiles = 0;
char * files[filesMax];
while(fgets(buff,sizeFileName,fp)) {
int leng = strlen(buff) - 1;
if (strncmp(buff + leng - 4, tExtension, 4) == 0){
files[nFiles] = strndup(buff,leng);
//printf("\t%s\n", files[nFiles]);
nFiles ++;
}
}
fclose(fp);
printf("Found %d files\n", nFiles);
long long totalBytes = 0;
struct stat st;
// sorting based on byte size from greatest to least
qsort(files, (size_t) strlen(files), (size_t) sizeof(char), cmpfunc);
for(int i = 0;i< nFiles; i ++) {
if(0!= stat(files[i],&st)){
perror("stat failed:");
exit(-1);
}
totalBytes += st.st_size;
printf("%s : %ld\n",files[i],st.st_size);
}
printf("Total size: %lld\n", totalBytes);
// clean up
for(int i = 0; i < nFiles ; i ++ ) {
free(files[i]);
}
return 0;
}
So far I have every section set up properly, upon running the code say $./find ini 5, it would print out all the ini files followed by their byte size(it's currently ignore the 5). However, for the qsort(), I'm not exactly sure how I would sort the contents of char * files as while it holds the pathnames, I had to use stat to get the byte sizes, how would I print out a sorted version of my print statements featuring the first statement being the most bytes and finishes at the least bytes?
If we suppose your input is valid, your question could be simplified with:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define filesMax 5000
int cmpfunc(const void const *a, const void *b) { return *(char *)a + *(char *)b; }
int main(void) {
int nFiles = 4;
char *files[filesMax] = {"amazing", "hello", "this is a file", "I'm a bad file"};
qsort(files, strlen(files), sizeof(char), cmpfunc);
for (int i = 0; i < nFiles;; i++) {
printf("%s\n", files[i]);
}
}
If you compile with warning that give you:
source_file.c:11:23: warning: incompatible pointer types passing 'char *[5000]' to parameter of type 'const char *' [-Wincompatible-pointer-types]
qsort(files, strlen(files), sizeof(char), cmpfunc);
^~~~~
qsort() expect the size of your array (or in your case a subsize) and it's also expect the size of one element of your array. In both you wrongly give it to it. Also, your compare function doesn't compare anything, you are currently adding the first bytes of both pointer of char, that doesn't make a lot of sense.
To fix your code you must write:
qsort(files, nFiles, sizeof *files, &cmpfunc);
and also fix your compare function:
int cmpfunc_aux(char * const *a, char * const *b) { return strcmp(*a, *b); }
int cmpfunc(void const *a, void const *b) { return cmpfunc_aux(a, b); }
also size should be of type size_t:
size_t nFiles = 0;
Don't forget that all informations about how to use a function are write in their doc.
how would I print out a sorted version of my print statements featuring the first statement being the most bytes and finishes at the least bytes?
Your code don't show any clue that your are trying to do that, you are currently storing name file and only that. How do you expect sort your file with an information you didn't acquired ?
However, that simple create a struct that contain both file name and size, acquire information needed to sort it and sort it:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <inttypes.h>
struct file {
off_t size;
char *name;
};
int cmpfunc_aux(struct file const *a, struct file const *b) {
if (a->size > b->size) {
return -1;
} else if (a->size < b->size) {
return 1;
} else {
return 0;
}
}
int cmpfunc(void const *a, void const *b) { return cmpfunc_aux(a, b); }
#define filesMax 5000
int main(void) {
size_t nFiles = 4;
struct file files[filesMax] = {{42, "amazing"},
{21, "hello"},
{168, "this is a file"},
{84, "I'm a bad file"}};
qsort(files, nFiles, sizeof *files, &cmpfunc);
for (size_t i = 0; i < nFiles; i++) {
printf("%s, %" PRId64 "\n", files[i].name, (intmax_t)files[i].size);
}
}
The function cmpfunc() provided adds the first character of each string, and that's not a proper comparison function (it should give a opposite sign value when you switch the parameters, e.g. if "a" and "b" are the strings to compare, it adds the first two characters of both strings, giving 97+98 == 195, which is positive on unsigned chars, then calling with "b" and "a" should give a negative number (and it again gives you 98 + 97 == 195), more on, it always gives the same result ---even with signed chars--- so it cannot be used as a sorting comparator)
As you are comparing strings, why not to use the standard library function strcmp(3) which is a valid comparison function? It gives a negative number if first string is less lexicographically than the second, 0 if both are equal, and positive if first is greater lexicographically than the second.
if your function has to check (and sort) by the lenght of the filenames, then you can define it as:
int cmpfunc(char *a, char *b) /* yes, you can define parameters as char * */
{
return strlen(a) - strlen(b);
}
or, first based on file length, then lexicographically:
int cmpfunc(char *a, char *b)
{
int la = strlen(a), lb = strlen(b);
if (la != lb) return la - lb;
/* la == lb, so we must check lexicographycally */
return strcmp(a, b);
}
Now, to continue helping you, I need to know why do you need to sort anything, as you say that you want to search a directory for a file, where does the sorting take place in the problem?

How to create a Queue of unsigned char array in Qt?

I am new in Queue (FIFO) and Qt. I want to create a Queue of unsigned char array in Qt. How to do it? Please help
unsigned char buffer[1024];
If you want to use the Qt API, then you can use the QQueue class -
QQueue<unsigned char> queue;
queue.enqueue(65);
queue.enqueue(66);
queue.enqueue(67);
while (!queue.isEmpty())
cout << queue.dequeue() << endl;
If you want to build the queue on your own, then I guess you can declare a Queue class like this -
class Queue
{
private:
enum{SIZE=1024, EMPTY=0};
unsigned char buffer[SIZE];
int readHead, writeHead;
public:
Queue()
{
readHead = writeHead = EMPTY;
}
void push(unsigned char data);
unsigned char pop();
unsigned char peek();
bool isEmpty();
};
void Queue::push(unsigned char data)
{
if((readHead - writeHead) >= SIZE)
{
// You should handle Queue overflow the way you want here.
return;
}
buffer[writeHead++ % SIZE] = data;
}
unsigned char Queue::pop()
{
unsigned char item = peek();
readHead++;
return item;
}
unsigned char Queue::peek()
{
if(isEmpty())
{
// You should handle Queue underflow the way you want here.
return;
}
return buffer[readHead % SIZE];
}
bool Queue::isEmpty()
{
return (readHead == writeHead);
}
If you want to maintain a Queue of unsigned char array, then you will have to maintain a queue of unsigned char pointers -
QQueue<unsigned char *> queue;
unsigned char *array1 = new unsigned char[10]; // array of 10 items
array1[0] = 65;
array1[1] = 66;
queue.enqueue(array1);
unsigned char *array2 = new unsigned char[20]; // an array of 20 items
queue.enqueue(array2);
unsigned char *arr = queue.dequeue();
qDebug() << arr[0] << ", " << arr[1];
Note: You should take care of the memory cleanup after you are done with this queue. IMHO, you better avoid this type of design though.

QByteArray convert to/from unsigned char *

QByteArray inArray = " ... ";
unsigned char *in = convert1(inArray);
unsigned char *out;
someFunction(in, out);
QByteArray outArray = convert2(out);
the question is how can I correctly make these conversions (convert1 and convert2).
I cannot change someFunction(unsigned char *, unsigned char *), but I have to work with QByteArray here.
Qt has really great docs, you should use them.
If someFunction doesn't modify or store pointer to in data you can use this:
QByteArray inArray = " ... ";
unsigned char *out;
someFunction((unsigned char*)(inArray.data()), out);
QByteArray outArray((char*)out);
Otherwise you have to make a deep copy of the char* returned by QByteArray::data() (see the docs for code snippet).
if someFunction takes a const char* args then just use ConstData() or data() in QByteArray class.
if you need a char*, you can then use strdup(). This method is doing this
char *strdup (const char *s) {
char *d = malloc (strlen (s) + 1); // Space for length plus nul
if (d == NULL) return NULL; // No memory
strcpy (d,s); // Copy the characters
return d; // Return the new string
}
more info here: strdup() - what does it do in C?

Resources