I have a device driver where the access to the wifi-router are hard coded using the #define macros in C. where the code looks like:
#define SSID "XXXX-XXX"
#define AUTH AAAA
#define PSK “YYyy00”
and the function that use these user defined constants is defined as:
router_connect((char *)SSID, sizeof(SSID), AUTH, (char *)PSK, CH_ALL);
I'd like to be change these constants as defined .h file as strings that I can read from a SD card and pass it to the function call rather than as hard coded in the main.h file. I'd like to have the ability to change them rather them as stored as fixed ones coded inside a program. After all they are user defined strings, as long as the values are correctly passed between the devices they don't need to be hard coded in the main code.
So I wrote them in the main.c as:
extern char SSID[] = "XXXX-XXX";
extern uint8 AUTH = AAAA;
extern char PSK[] = "YYyy00";
and in the SD card I have a file setup.txt where I entered the three strings as below in three lines:
XXXX-XXX;
AAAA;
YYyy00;
I wrote a little routine to read each line from the SD card and assign the strings to the variables
SSID, AUTH, PSK
char line[20];
int line_count;
FRESULT my_res;
FIL myfil;
my_res = f_open(&myfil, "setup.txt", FA_READ);
if (my_res != FR_OK) {
printf("file: setup.txt is not found. \n\r");
/* deal with errors */;
}
for (line_count = 1; line_count < 4;) {
f_gets(line, sizeof(line), &myfil);
if (line_count == 1) {
strcpy(SSID, line);
printf("SSID: %s %s \n\r", SSID, line);
}
if (line_count == 2) {
strcpy(AUTH, line);
printf("AUTH: %s %s \n\r", AUTH, line);
}
if (line_count == 3) {
strcpy(PSK, line);
printf("PSK: %s %s \n\r", PSK, line);
}
line_count++;
}
My intent was to read these strings from the SD card before the function "router_connect" is called.
I can do that with no problem, when I print out the stings I read from the SD card they are exactly like when they are hard coded, but I find the "router_connect" function does not like the parameters I'm passing. The device driver works when I hard code the values in the #define statement but for some reason it is not passing the values correctly to the function. Can you please advise if I'm doing it incorrectly for passing parameters to the function call and what will be the right way to achieve it. Thanks.
Firstly, it would be nice to see how exactly the function doesn't like those parameters. Secondly, I see that you read the AUTH value as a char array, and what the function wants is a uint8. How do you pass it? Maybe parsing AUTH into an uint8 would do the trick.
Related
I currently have a string in C that I have coded like this:
#define MESSAGE_STRING "{\"deviceName\":string, \"Telemetry\":{\"voltage\":12,\"current\":0.12}}"
As I am sending it to a cloud service that processes it as a JSON message and receives this:
But I want to do this in an easier way as this could get a lot more complex when I am sending more complicated JSON messages. I was wondering if there was any easy way to create these JSON objects within C easier?
Cheers
Write your JSON in a text file, and replace every parameter with a %d, %f, %s placeholder.
Then read this file, and fill in the values with sprintf()
But pay attention to the order of your parameters.
json.txt:
{
"device_name": "%s",
"Telemetry": {
"voltage": %d,
"current": %f
}
}
main.c
#include <stdio.h>
int main(void)
{
char json_format[4096];
char message_string[4096];
FILE* fp;
// Read in json format
fp = fopen("json.txt", "r");
int len = fread(json_format, 1, 4096, fp);
json_format[len] = '\0';
fclose(fp);
// Fill in parameters
const char* device_name = "string";
int voltage = 12;
float current = 0.12;
sprintf(message_string, json_format, device_name, voltage, current);
printf("%s", message_string);
}
The code is only for understanding the concept.
It works, but don't use it, because it doesn't check for erorrs and the memory management is bad too.
After I enter a string in c and store it in for example char s[100], how can I compare that string to all function names in a math.h? For example, I enter pow and the result will look like this in stored form.
s[0]='p'
s[1]='o'
s[2]='w'
s[3]='\0'
Since my string is the equivalent of pow(), I want my program to recognise that and then call pow() during execution of my program. I know it is not that hard to do string comparison within the code, but that would mean that I would have to do string comparison for every function name in the library. I don't want to do that. How is it possible to compare my string against all names in the library without hard coding every comparison?
Thank you :)
You can't, not without doing work yourself. There are no names of functions present at runtime in general, and certainly not of functions you haven't called.
C is not a dynamic language, names are only used when compiling/linking.
Regular expressions in C
Try parsing the header files using FILE and use aforementioned link as a guide to check whether the function exists or not.
I tried to make a little sample about what I assume the questioner is looking for (eval.c):
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <assert.h>
/* mapping function names to function pointers and number of parameters */
struct Entry {
const char *name; /* function name */
double (*pFunc)(); /* function pointer */
int nArgs; /* number of arguments */
} table[] = {
#define REGISTER(FUNC, N_ARGS) { #FUNC, &FUNC, N_ARGS }
REGISTER(atan2, 2),
REGISTER(pow, 2),
REGISTER(modf, 2),
REGISTER(sin, 1),
REGISTER(cos, 1)
#undef REGISTER
};
/* let compiler count the number of entries */
enum { sizeTable = sizeof table / sizeof *table };
void printUsage(const char *argv0)
{
int i;
printf(
"Usage:\n"
" %s FUNC\n"
" where FUNC must be one of:\n", argv0);
for (i = 0; i < sizeTable; ++i) printf(" - %s\n", table[i].name);
}
int main(int argc, char **argv)
{
int i;
char *func;
struct Entry *pEntry;
/* read command line argument */
if (argc <= 1) {
fprintf(stderr, "ERROR: Missing function argument!\n");
printUsage(argv[0]);
return -1;
}
func = argv[1];
/* find function by name */
for (i = 0; i < sizeTable && strcmp(func, table[i].name) != 0; ++i);
if (i >= sizeTable) {
fprintf(stderr, "ERROR! Unknown function '%s'!\n", func);
printUsage(argv[0]);
return -1;
}
/* perform found function on all (standard) input */
pEntry = table + i;
for (;;) { /* endless loop (bail out at EOF or error) */
switch (pEntry->nArgs) {
case 1: {
double arg1, result;
/* get one argument */
if (scanf("%lf", &arg1) != 1) {
int error;
if (error = !feof(stdin)) fprintf(stderr, "Input ERROR!\n");
return error; /* bail out at EOF or error */
}
/* compute */
result = (*pEntry->pFunc)(arg1);
/* output */
printf("%s(%f): %f\n", pEntry->name, arg1, result);
} break;
case 2: {
double arg1, arg2, result;
/* get two arguments */
if (scanf("%lf %lf", &arg1, &arg2) != 2) {
int error;
if (error = !feof(stdin)) fprintf(stderr, "Input ERROR!\n");
return error; /* bail out at EOF or error */
}
/* compute */
result = (*pEntry->pFunc)(arg1, arg2);
/* output */
printf("%s(%f, %f): %f\n", pEntry->name, arg1, arg2, result);
} break;
default: /* should never happen */
fprintf(stderr,
"ERROR! Functions with %d arguments not yet implemented!\n",
pEntry->nArgs);
assert(0);
return -1; /* bail out at error */
}
}
}
I compiled and tested this with gcc in cygwin on Windows (64 bit):
$ gcc -std=c11 -o eval eval.c
$ ./eval
ERROR: Missing function argument!
Usage:
./eval FUNC
where FUNC must be one of:
- atan2
- pow
- modf
- sin
- cos
$ echo "1 2 3 4 5 6 7 8 9 10" | ./eval pow
pow(1.000000, 2.000000): 1.000000
pow(3.000000, 4.000000): 81.000000
pow(5.000000, 6.000000): 15625.000000
pow(7.000000, 8.000000): 5764801.000000
pow(9.000000, 10.000000): 3486784401.000000
$ echo "1 2 3 4 5 6 7 8 9 10" | ./eval sin
sin(1.000000): 0.841471
sin(2.000000): 0.909297
sin(3.000000): 0.141120
sin(4.000000): -0.756802
sin(5.000000): -0.958924
sin(6.000000): -0.279415
sin(7.000000): 0.656987
sin(8.000000): 0.989358
sin(9.000000): 0.412118
sin(10.000000): -0.544021
The usage of this application: the name of the function to apply is provided as command line argument. The values (to apply function to) are provided via standard input. In the sample session, I used echo and a pipe (|) to redirect the output of echo to the input of eval. (If eval is called stand-alone the numbers may be typed in by keyboard.)
Notes:
The table does the actual mapping of strings to function pointers. To solve that issue about the number of parameters, I considered this in struct Entry also.
The REGISTER macro is a trick to use the identifier as string constant also. The #FUNC is a stringize macro-operation (a typical C trick to prevent errors due to typos).
The sizeTable is another trick to prevent redundant definitions. I let the compiler count the number of entries. Thus, new entries may be added and it still will work without any other editing.
The actual trick is to provide a function pointer where the arguments are "left out". When it is called, the correct number of arguments is used and it works. (assuming, of course, the table initialization has been implemented carefully.) However, it would be a pain to do this in C++ because the functions with distinct number of arguments would need an appropriate function pointer with matching signature - horrible casts would be necessary. (Try to compile this with g++ -std=c++11 -c eval.c to see what I mean.)
For a productive solution, I would sort the entries by names (lexicographically) and apply a binary search (or even use hashing to be faster and more sophisticated). For this sample, I wanted to keep it simple.
math.h provides a lot of functions in "float flavor" also. These may not be added to this sample without additional effort. To support other than double arguments
some type info had to been added to the table entries
the type info has to be considered somehow in the switch statement of evaluation.
...not to mention functions where argument types are distinct to each other (or return type). (I cannot remember whether math.h even provides such functions.)
Btw. this will work for non-math.h functions also...
I'm learning to use libcurl in C. To start, I'm using a randomized list of accession names to search for protein sequence files that may be found hosted here. These follow a set format where the first line is a variable length (but which contains no information I'm trying to query) then a series of capitalized letters with a new line every sixty (60) characters (what I want to pull down, but reformat to eighty (80) characters per line).
I have the call itself in a single function:
//finds and saves the fastas for each protein (assuming on exists)
void pullFasta (proteinEntry *entry, char matchType, FILE *outFile) {
//Local variables
URL_FILE *handle;
char buffer[2] = "", url[32] = "http://www.uniprot.org/uniprot/", sequence[2] = "";
//Build full URL
/*printf ("u:%s\nt:%s\n", url, entry->title); /*This line was used for debugging.*/
strcat (url, entry->title);
strcat (url, ".fasta");
//Open URL
/*printf ("u:%s\n", url); /*This line was used for debugging.*/
handle = url_fopen (url, "r");
//If there is data there
if (handle != NULL) {
//Skip the first line as it's got useless info
do {
url_fread(buffer, 1, 1, handle);
} while (buffer[0] != '\n');
//Grab the fasta data, skipping newline characters
while (!url_feof (handle)) {
url_fread(buffer, 1, 1, handle);
if (buffer[0] != '\n') {
strcat (sequence, buffer);
}
}
//Print it
printFastaEntry (entry->title, sequence, matchType, outFile);
}
url_fclose (handle);
return;
}
With proteinEntry being defined as:
//Entry for fasta formatable data
typedef struct proteinEntry {
char title[7];
struct proteinEntry *next;
} proteinEntry;
And the url_fopen, url_fclose, url_feof, url_read, and URL_FILE code found here, they mimic the file functions for which they are named.
As you can see I've been doing some debugging with the URL generator (uniprot URLs follow the same format for different proteins), I got it working properly and can pull down the data from the site and save it to file in the proper format that I want. I set the read buffer to 1 because I wanted to get a program that was very simplistic but functional (if inelegant) before I start playing with things, so I would have a base to return to as I learned.
I've tested the url_<function> calls and they are giving no errors. So I added incremental printf calls after each line to identify exactly where the bus error is occurring and it is happening at return;.
My understanding of bus errors is that it's a memory access issue wherein I'm trying to get at memory that my program doesn't have control over. My confusion comes from the fact that this is happening at the return of a void function. There's nothing being read, written, or passed to trigger the memory error (as far as I understand it, at least).
Can anyone point me in the right direction to fix my mistake please?
EDIT: As #BLUEPIXY pointed out I had a potential url_fclose (NULL). As #deltheil pointed out I had sequence as a static array. This also made me notice I'm repeating my bad memory allocation for url, so I updated it and it now works. Thanks for your help!
If we look at e.g http://www.uniprot.org/uniprot/Q6GZX1.fasta and skip the first line (as you do) we have:
MNAKYDTDQGVGRMLFLGTIGLAVVVGGLMAYGYYYDGKTPSSGTSFHTASPSFSSRYRY
Which is a 60 characters string.
When you try to read this sequence with:
//Grab the fasta data, skipping newline characters
while (!url_feof (handle)) {
url_fread(buffer, 1, 1, handle);
if (buffer[0] != '\n') {
strcat (sequence, buffer);
}
}
The problem is sequence is not expandable and not large enough (it is a fixed length array of size 2).
So make sure to choose a large enough size to hold any sequence, or implement the ability to expand it on-the-fly.
I have an array of structs and they get saved into a file. Currently there are two lines in the file:
a a 1
b b 2
I am trying to read in the file and have the data saved to the struct:
typedef struct book{
char number[11];//10 numbers
char first[21]; //20 char first/last name
char last[21];
} info;
info info1[500]
into num = 0;
pRead = fopen("phone_book.dat", "r");
if ( pRead == NULL ){
printf("\nFile cannot be opened\n");
}
else{
while ( !feof(pRead) ) {
fscanf(pRead, "%s%s%s", info1[num].first, info1[num].last, info1[num].number);
printf{"%s%s%s",info1[num].first, info1[num].last, info1[num].number); //this prints statement works fine
num++;
}
}
//if I add a print statement after all that I get windows directory and junk code.
This makes me think that the items are not being saved into the struct. Any help would be great. Thanks!
EDIT: Okay so it does save it fine but when I pass it to my function it gives me garbage code.
When I call it:
sho(num, book);
My show function:
void sho (int nume, info* info2){
printf("\n\n\nfirst after passed= %s\n\n\n", info2[0].first); //i put 0 to see the first entry
}
I think you meant int num = 0;, instead of into.
printf{... is a syntax error, printf(... instead.
Check the result of fscanf, if it isn't 3 it hasn't read all 3 strings.
Don't use (f)scanf to read strings, at least not without specifying the maximum length:
fscanf(pRead, "%10s%20s%20s", ...);
But, better yet, use fgets instead:
fgets(info1[num].first, sizeof info1[num].first, pRead);
fgets(info1[num].last, sizeof info1[num].last, pRead);
fgets(info1[num].number, sizeof info1[num].number, pRead);
(and check the result of fgets, of course)
Make sure num doesn't go higher than 499, or you'll overflow info:
while(num < 500 && !feof(pRead)){.
1.-For better error handling, recommend using fgets(), using widths in your sscanf(), validating sscanf() results.
2.-OP usage of feof(pRead) is easy to misuse - suggest fgets().
char buffer[sizeof(info)*2];
while ((n < 500) && (fgets(buffer, sizeof buffer, pRead) != NULL)) {
char sentinel; // look for extra trailing non-whitespace.
if (sscanf(buffer, "%20s%20s%10s %c", info1[num].first,
info1[num].last, info1[num].number, &sentinel) != 3) {
// Handle_Error
printf("Error <%s>\n",buffer);
continue;
}
printf("%s %s %s\n", info1[num].first, info1[num].last, info1[num].number);
num++;
}
BTW: using %s does not work well should a space exists within a first name or within a last name.
I am trying to import a C function into a System verilog test bench. The code for the C function is as shown below. I want to pass files as arguments. The function basically reads from one file and writes to another.
int readmem(int z, FILE *file1, FILE *file2) {
char data;
int x;
int i;
for(i = 0; i<z;i ++) {
data = fgetc(file1);
x = data;
fputc(x,file2);
}
return 0;
}
Kindly advise me on how I could call this function in a System verilog test bench.
You cannot pass file descriptors between SystemVerilog and C via the DPI, so I don't think it's possible to import the function directly as-is.
If all you really need to do is get the functionality in SystemVerilog, it will be easier to just port it to SystemVerilog rather than trying to import it via the DPI.
Something like this should work (not tested!):
function int readmem(int z, int file1, int file2);
reg[8:0] data;
for (int i = 0; i < z; i++) begin
data = $fgetc(file1); // Really should break out of the loop if data == EOF ('h1FF)
$fwrite(file2, "%c", data[7:0]);
end
return 0;
endfunction
Then from somewhere else:
int file1 = $fopen("input_file", "r");
int file2 = $fopen("output_file", "w");
readmem(10, file1, file2)
The reason data is declared as 9 bits is to capture an EOF if the end of file is reached. Your original function could run past the end of file1 since you are not checking for EOF.
SystemVerilog includes DPI (Direct Programming Interface) which lets your SystemVerilog call C functions and can even let your C call SystemVerilog tasks/functions. Check out IEEE std 1800-2009 Section 35 and Annex H & I. There are limitations with data types so check out Annex H.7.4 that for basic SV/C type mapping.
To call C functions in SystemVerilog, simply import it into the desired scope (e.g. module or package)
import "DPI-C" context function C_function_name(/* args */);
To call SystemVerilog from C requires one extra step.
In SV :
export "DPI-C" function SV_function_name; /*no args */
In C :
extern return_type SV_function_name( /* args */);
Depending on your simulator you may need to compile the C code first and reference the object file, or just include the source file in your file list. You make need to add options to your simulator to, so check the manual.
Here are some resources that can help you get started:
http://en.wikipedia.org/wiki/SystemVerilog_DPI
http://www.doulos.com/knowhow/sysverilog/tutorial/dpi/
http://www.asic-world.com/examples/systemverilog/dpi.html
Revision:
Use a translate wrapper since FILE does does not translate across DPI. C's const char* maps to SystemVerilog's string.
C:
#include <stdlib.h>
#include <stdio.h>
// include for DPI
#include "svdpi.h"
// wrapper
int C2SV_readmem(int z, const char *filename1, const char *filename2) {
FILE *file1;
FILE *file2;
int rtn;
file1 = fopen(filename1, "r");
file2 = fopen(filename2, "w");
if (file1 == NULL) {
printf("failed to open '%s' for read\n", filename1);
return 1;
}
if (file2 == NULL) {
printf("failed to open '%s' for write\n", filename2);
return 1;
}
return readmem(z, file1, file2); // call original readmem function
}
/* ... */
SystemVerilog:
module test;
import "DPI-C" context function int C2SV_readmem(input int z, input string filename1, input string filename2);
int value;
initial begin
value = C2SV_readmem( 25, "FileIn.txt", "FileOut.txt");
end
endmodule