c programming optimize packet forwarder - c

I have written UDP packet forwarder which opens UDP port and it continuously listen on perticolar socket and when data comes to it, it forwards data to another end point.
Problem I am facing is while running process for longer duration its process eats up almost 50% of system memory and other process suffers from it.
I have use PCRE library for some regex checking but it seems like main cause of problem how can i optimize my code that can run for infinite without any memory issue.
below is my code i have use of PCRE regex and socket forwarder.
int parse(char *str){
pcre *reCompiled;
pcre_extra *pcreExtra;
int pcreExecRet;
int subStrVec[30];
const char *pcreErrorStr;
int pcreErrorOffset;
int returnval;
char *aStrRegex;
char **aLineToMatch;
const char *psubStrMatchStr;
int j;
//*aLineToMatch = str;
aStrRegex = "(.*)(\"ABC\":)(\\d+)+";
//printf("Regex to use: %s\n", aStrRegex);
// First, the regex string must be compiled.
reCompiled = pcre_compile(aStrRegex, 0, &pcreErrorStr, &pcreErrorOffset, NULL);
/* OPTIONS (second argument) (||'ed together) can be:
PCRE_ANCHORED -- Like adding ^ at start of pattern.
PCRE_CASELESS -- Like m//i
PCRE_DOLLAR_ENDONLY -- Make $ match end of string regardless of \n's
No Perl equivalent.
PCRE_DOTALL -- Makes . match newlins too. Like m//s
PCRE_EXTENDED -- Like m//x
PCRE_EXTRA --
PCRE_MULTILINE -- Like m//m
PCRE_UNGREEDY -- Set quantifiers to be ungreedy. Individual quantifiers
may be set to be greedy if they are followed by "?".
PCRE_UTF8 -- Work with UTF8 strings.
*/
// pcre_compile returns NULL on error, and sets pcreErrorOffset & pcreErrorStr
if(reCompiled == NULL) {
printf("ERROR: Could not compile '%s': %s\n", aStrRegex, pcreErrorStr);
exit(1);
} /* end if */
// Optimize the regex
pcreExtra = pcre_study(reCompiled, 0, &pcreErrorStr);
/* pcre_study() returns NULL for both errors and when it can not optimize the regex. The last argument is how one checks for
errors (it is NULL if everything works, and points to an error string otherwise. */
if(pcreErrorStr != NULL) {
printf("ERROR: Could not study '%s': %s\n", aStrRegex, pcreErrorStr);
exit(1);
}
/* Try to find the regex in aLineToMatch, and report results. */
pcreExecRet = pcre_exec(reCompiled,
pcreExtra,
str,
strlen(str), // length of string
0, // Start looking at this point
0, // OPTIONS
subStrVec,
30); // Length of subStrVec
/* pcre_exec OPTIONS (||'ed together) can be:
PCRE_ANCHORED -- can be turned on at this time.
PCRE_NOTBOL
PCRE_NOTEOL
PCRE_NOTEMPTY */
// Report what happened in the pcre_exec call..
//printf("pcre_exec return: %d\n", pcreExecRet);
if(pcreExecRet < 0) { // Something bad happened..
returnval = -1;
switch(pcreExecRet) {
case PCRE_ERROR_NOMATCH : log_message("String did not match the pattern"); break;
case PCRE_ERROR_NULL : log_message("Something was null"); break;
case PCRE_ERROR_BADOPTION : log_message("A bad option was passed"); break;
case PCRE_ERROR_BADMAGIC : log_message("Magic number bad (compiled re corrupt?)"); break;
case PCRE_ERROR_UNKNOWN_NODE : log_message("Something kooky in the compiled re"); break;
case PCRE_ERROR_NOMEMORY : log_message("Ran out of memory"); break;
default : log_message("Unknown error"); break;
} /* end switch */
} else {
//printf("Result: We have a match!\n");
// At this point, rc contains the number of substring matches found...
if(pcreExecRet == 0) {
pcreExecRet = 30 / 3;
} /* end if */
// PCRE contains a handy function to do the above for you:
for(j=0; j<pcreExecRet; j++) {
pcre_get_substring(str, subStrVec, pcreExecRet, j, &(psubStrMatchStr));
} /* end for */
returnval = atoi(psubStrMatchStr);
// Free up the substring
pcre_free_substring(psubStrMatchStr);
} /* end if/else */
// Free up the regular expression.
pcre_free(reCompiled);
// Free up the EXTRA PCRE value (may be NULL at this point)
if(pcreExtra != NULL) {
#ifdef PCRE_CONFIG_JIT
pcre_free_study(pcreExtra);
#else
pcre_free(pcreExtra);
#endif
}
return returnval;
}
-------------------Udp Listener---------------
while (1) {
n = recvfrom(sock_receiver,buf,2048,0,(struct sockaddr *)&from,&sender_length);
if (n < 0) error("recvfrom");
//write(1,"Received a datagram: ",21);
// printf("n = %d\n", n);
// printf("length of buffer = %lu\n", strlen(buf));
// write(1,buf,n);
strncpy(str, buf, n);
str[n] = '\0'; // IMPORTANT!
value = parse(str);
if(curTime != get_hour()){
//sprintf(temp_str,"Counter",minute,get_minute());
log_message("Counter reset");
reset_component_hits(components);
//reset_component_hits(dropped_msg);
curTime = get_hour();
}
if(value >=0 && components[value] < component_limit && value < max_component){
n = sendto(sock_forwarder,buf,n,0,(const struct sockaddr *)&sender,sender_length);
if (n < 0){
error("sendto");
}
components[value] = components[value]+1;
}else{
if(value < 0 ) {
error_msg = "Unable to parse component";
}else if(value >= max_component){
error_msg = "value not found in valid component list";
}else if(components[value] >= component_limit) {
error_msg = "Rate limit exceeded";
}else {
error_msg = "Message dropped for Unknown reason";
}
sprintf(temp_str,"[Component:%d] %s",value,error_msg);
log_message(temp_str);
bzero(temp_str,100);
bzero(error_msg,100);
}
// print_array(components);
// print_array(dropped_msg);
bzero(buf,2048);
bzero(str,2048);
}

Related

ncurses new_item() failure

I am quite new to ncurses and I have been trying to implement a scrolling menu by following the documentation here. My code is as follows:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <ncurses.h>
#include <unistd.h>
#include <sys/wait.h>
#include <stdbool.h>
#include <menu.h>
int NUMBER_OF_TRACKS = 0;
struct Track {
char *title;
char *pathName;
}; typedef struct Track Track;
/*
* playSong is responsible for playing the selected track.
* This function utilizes fork and execvp to accomplish this.
* could maybe use popen again?
*/
void playSong(char *title) {
FILE *fp;
char cmdBuffer[1024];
sprintf(cmdBuffer, "cd ~/Music/iTunes/\"iTunes Media\"/Music/ && afplay %s", title);
fp = popen(cmdBuffer, "r");
if(fp == NULL) {
printf("Unable to play track.\n");
exit(1);
}
// close the pipe
if(pclose(fp) == -1) {
printf("Error while closing pipe.\n");
exit(1);
}
}
/*
* escapeString takes in a path name for a track, and adds escape characters
* to it so that it later be played by the system.
*/
char * escapeString(char *pathName) {
char * escape = (char *)malloc(1024 * sizeof(char));
int index = 0;
for(int i = 0; pathName[i] != '\n'; i++) {
if(pathName[i] == '/') {
if(i == 1) {
// we don't need to doubly pad the first '/' with quotes
escape[index++] = pathName[i];
escape[index++] = '\"';
}
else {
escape[index++] = '\"';
escape[index++] = pathName[i];
escape[index++] = '\"';
}
}
else {
escape[index++] = pathName[i];
}
}
// don't forget to add last quote to end the song
escape[index++] = '\"';
// don't forget null!
escape[index] = '\0';
return escape;
}
/*
* getTrackTitle parses the escaped pathame and returns only the name of the
* song.
*/
char * getTrackTitle(char *pathName) {
char *title = (char *)malloc(1024*sizeof(char));
int slashCount = 0;
int index = 0;
for(int i = 0; pathName[i] != '\0'; i++) {
if(slashCount == 3) {
title[index++] = pathName[i];
}
else if(pathName[i] == '/') {
slashCount++;
}
}
title[index] = '\0';
return title;
}
Track ** getUserTracks() {
FILE *fp;
char pathName[300]; // may need to be longer?
// use fp with popen
char *cmd = "cd ~/Music/iTunes/\"iTunes Media\"/Music/ && find . -name \"*.m4a\"";
fp = popen(cmd, "r");
if(fp == NULL) {
printf("Unable to find your tracks!\n");
exit(1);
}
// create our list
Track **trackList = (Track **)malloc(1024 * sizeof(Track *));
// read the output (i.e) the tracks
while(fgets(pathName, sizeof(pathName), fp) != NULL) {
// allocate memory for track
trackList[NUMBER_OF_TRACKS] = (Track *)malloc(sizeof(Track));
// get the escaped path name
char *escapedPath = escapeString(pathName);
// store values in struct
trackList[NUMBER_OF_TRACKS]->pathName = escapedPath;
trackList[NUMBER_OF_TRACKS]->title = getTrackTitle(escapedPath);
// update number of tracks
NUMBER_OF_TRACKS++;
}
// null terminate list
trackList[NUMBER_OF_TRACKS] = (Track *)NULL;
// close the pipe
if(pclose(fp) == -1) {
printf("Error while closing pipe.\n");
exit(1);
}
// return our list
return trackList;
}
int main(int argc, char **argv) {
/* START NCURSES */
initscr(); // create screen
curs_set(0); // hide cursor
noecho(); // don't show the characters the user is typing
cbreak(); // allow user to quit with ctrl-c; may want to remove this later
// get screen size
int yMax, xMax;
getmaxyx(stdscr, yMax, xMax);
ITEM **userTracks;
MENU *trackMenu;
WINDOW *trackMenuWindow;
// create items for our menu
Track **choices = getUserTracks();
userTracks = (ITEM **)calloc(NUMBER_OF_TRACKS+1, sizeof(ITEM *));
for(int i = 0; i < NUMBER_OF_TRACKS; i++) {
ITEM *trackItem = new_item(choices[i]->title, "");
userTracks[i] = trackItem;
}
userTracks[NUMBER_OF_TRACKS] = (ITEM *)NULL;
/* MENU STUFF */
// create the menu
trackMenu = new_menu((ITEM **)userTracks);
// printf("Item count: %d\n", item_count(trackMenu));
/* create the window associated with the menu */
trackMenuWindow = newwin(yMax, xMax, 0, 0);
box(trackMenuWindow, 0, 0); // adds border to window
keypad(trackMenuWindow, TRUE); // enables keypd use on menu
/* set main window and set sub windows */
set_menu_win(trackMenu, trackMenuWindow);
set_menu_sub(trackMenu, derwin(trackMenuWindow, yMax - 1, xMax - 1, 1, 1));
set_menu_format(trackMenu, 5, 1); // sets number of items to be displayed
/* Set menu mark to the string " * " */
set_menu_mark(trackMenu, NULL);
/* Post the menu */
post_menu(trackMenu);
wrefresh(trackMenuWindow);
int keyPressed;
while((keyPressed = wgetch(trackMenuWindow)) != 'q') {
switch(keyPressed) {
case KEY_DOWN:
menu_driver(trackMenu, REQ_DOWN_ITEM);
break;
case KEY_UP:
menu_driver(trackMenu, REQ_UP_ITEM);
break;
case KEY_NPAGE:
menu_driver(trackMenu, REQ_SCR_DPAGE);
break;
case KEY_PPAGE:
menu_driver(trackMenu, REQ_SCR_UPAGE);
break;
}
wrefresh(trackMenuWindow);
}
unpost_menu(trackMenu);
free_menu(trackMenu);
for(int i = 0; i < NUMBER_OF_TRACKS; i++) {
free_item(userTracks[i]);
}
endwin();
/* END NCURSES */
return 0;
}
Essentially, I am interested in getting a list of all the user's (iTunes) songs on their machine and displaying them in a (scrollable) menu.
I am able to retrieve all the songs and store them in my Track **choices array, however, I am not able to create any menu items from them. I have deduced that my issue lies within the followig snippet:
// create items for our menu
Track **choices = getUserTracks();
userTracks = (ITEM **)calloc(NUMBER_OF_TRACKS+1, sizeof(ITEM *));
for(int i = 0; i < NUMBER_OF_TRACKS; i++) {
ITEM *trackItem = new_item(choices[i]->title, "");
userTracks[i] = trackItem;
}
userTracks[NUMBER_OF_TRACKS] = (ITEM *)NULL;
Specifically the line ITEM *trackItem = new_item(choices[i]->title, "");
It appears as though new_item() is returning NULL in every iteration. Moreover, errno is being set to E_BAD_ARGUMENT implying that choices[i]->title is not a valid string, though I cannot imagine why this would be the case.
Any help would be immensely appreciated!
You may compile the code above as follows: gcc -I/usr/local/opt/ncurses/include -L/usr/local/opt/ncurses/lib <source_file>.c -lmenu -lncurses
You might be able to get away with excluding -I/usr/local/opt/ncurses/include -L/usr/local/opt/ncurses/lib but that unfortunately doesn't work for me.
Fair warning, this program might not work on Windows/Linux environments due to their file structure and iTunes requirement, but I have not tested it.
Turns out the strings in my structure were nonsense. I needed to allocate memory on the heap for them within my getUserTracks() function.

Linux Kernel Module : Problem with kernel_write function

I have a problem using kernel_write function while I am developing LKM for Linux 4.14.73 version.
This is the part of my module where I am facing the issue :
void change_led_state(char *led_path, int led_value)
{
printk("we are in change_led_state\n");
size_t len = sizeof(led_value);
char lpath[64];
ssize_t rk=0;
strncpy(lpath, led_path, sizeof(lpath) - 1);
lpath[sizeof(lpath) - 1] = '\0';
f_led = filp_open(lpath, O_WRONLY , 0);
if (f_led == NULL) {
printk("Unable to access led\n");
return;
}
rk = kernel_write(f_led, led_value, len, &f_led->f_pos);
printk("rk = %d\n", rk);
filp_close(f_led, NULL);
}
rk is usually getting a negative value. I think it must be positive. What's wrong with the function please ? How can I correct it ?
For more informations, I have the same code but in user-space program, and it's working fine, I just want to replace it to kernel space. This is the user space program :
void change_led_state(char *led_path, int led_value)
{
char lpath[64];
FILE *led_fd;
strncpy(lpath, led_path, sizeof(lpath) - 1);
lpath[sizeof(lpath) - 1] = '\0';
led_fd = fopen(lpath, "w");
if (led_fd == NULL) {
fprintf(stderr, "simplekey: unable to access led\n");
return;
}
fprintf(led_fd, "%d\n", led_value);
fclose(led_fd);
}
void reset_leds(void)
{
change_led_state(LED_PATH "/" green "/brightness", 0);
}
void eval_keycode(int code)
{
static int green_state = 0;
switch (code) {
case 260:
printf("BTN pressed\n");
// figure out red state
green_state = green_state ? 0 : 1;
change_led_state(LED_PATH "/" green "/brightness", green_state);
break;
default :
printf("Wrong Button was pressed\n");
break;
}
}
In the main fuction I just call eval_keycode function and it's working. What mistakes I have made ?
In your call:
rk = kernel_write(f_led, led_value, len, &f_led->f_pos);
The second parameter is supposed to be a char *, but you are passing an int.
In addition, when writing to the "/sys/class/leds/[device]/brightness" file, the code that handles this expects a pointer to a string of decimal digits, terminated by some non-digit character (such as a newline) or a null terminator.
You need to "print" your led_value to a char array as a decimal number and write the array contents to the file:
char led_valstr[20]; /* should be large enough */
len = scnprintf(led_valstr, sizeof(led_valstr), "%d\n", led_value);
rk = kernel_write(f_led, led_valstr, len, &f_led->f_pos);
(EDIT: corrected call to scnprintf.)

Why does my program keep getting stuck while running the mandelbrot brainf*** program?

I wanted to improve my C skills, so I search some program's ideas.
Someone propose to create a simple Brainf*** interpreter and then a compiler. So here I am.
I created the interpreter and it works as expected, except with the Mandelbrot program:
A mandelbrot set fractal viewer in brainfuck written by Erik Bosman
+++++++++++++[->++>>>+++++>++>+<<<<<<]>>>>>++++++>--->>>>>>>>>>+++++++++++++++[[
>>>>>>>>>]+[<<<<<<<<<]>>>>>>>>>-]+[>>>>>>>>[-]>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>[-]+
<<<<<<<+++++[-[->>>>>>>>>+<<<<<<<<<]>>>>>>>>>]>>>>>>>+>>>>>>>>>>>>>>>>>>>>>>>>>>
>+<<<<<<<<<<<<<<<<<[<<<<<<<<<]>>>[-]+[>>>>>>[>>>>>>>[-]>>]<<<<<<<<<[<<<<<<<<<]>>
>>>>>[-]+<<<<<<++++[-[->>>>>>>>>+<<<<<<<<<]>>>>>>>>>]>>>>>>+<<<<<<+++++++[-[->>>
>>>>>>+<<<<<<<<<]>>>>>>>>>]>>>>>>+<<<<<<<<<<<<<<<<[<<<<<<<<<]>>>[[-]>>>>>>[>>>>>
>>[-<<<<<<+>>>>>>]<<<<<<[->>>>>>+<<+<<<+<]>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>
[>>>>>>>>[-<<<<<<<+>>>>>>>]<<<<<<<[->>>>>>>+<<+<<<+<<]>>>>>>>>]<<<<<<<<<[<<<<<<<
<<]>>>>>>>[-<<<<<<<+>>>>>>>]<<<<<<<[->>>>>>>+<<+<<<<<]>>>>>>>>>+++++++++++++++[[
>>>>>>>>>]+>[-]>[-]>[-]>[-]>[-]>[-]>[-]>[-]>[-]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>-]+[
>+>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>[>->>>>[-<<<<+>>>>]<<<<[->>>>+<<<<<[->>[
-<<+>>]<<[->>+>>+<<<<]+>>>>>>>>>]<<<<<<<<[<<<<<<<<<]]>>>>>>>>>[>>>>>>>>>]<<<<<<<
<<[>[->>>>>>>>>+<<<<<<<<<]<<<<<<<<<<]>[->>>>>>>>>+<<<<<<<<<]<+>>>>>>>>]<<<<<<<<<
[>[-]<->>>>[-<<<<+>[<->-<<<<<<+>>>>>>]<[->+<]>>>>]<<<[->>>+<<<]<+<<<<<<<<<]>>>>>
>>>>[>+>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>[>->>>>>[-<<<<<+>>>>>]<<<<<[->>>>>+
<<<<<<[->>>[-<<<+>>>]<<<[->>>+>+<<<<]+>>>>>>>>>]<<<<<<<<[<<<<<<<<<]]>>>>>>>>>[>>
>>>>>>>]<<<<<<<<<[>>[->>>>>>>>>+<<<<<<<<<]<<<<<<<<<<<]>>[->>>>>>>>>+<<<<<<<<<]<<
+>>>>>>>>]<<<<<<<<<[>[-]<->>>>[-<<<<+>[<->-<<<<<<+>>>>>>]<[->+<]>>>>]<<<[->>>+<<
<]<+<<<<<<<<<]>>>>>>>>>[>>>>[-<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>]>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>+++++++++++++++[[>>>>
>>>>>]<<<<<<<<<-<<<<<<<<<[<<<<<<<<<]>>>>>>>>>-]+>>>>>>>>>>>>>>>>>>>>>+<<<[<<<<<<
<<<]>>>>>>>>>[>>>[-<<<->>>]+<<<[->>>->[-<<<<+>>>>]<<<<[->>>>+<<<<<<<<<<<<<[<<<<<
<<<<]>>>>[-]+>>>>>[>>>>>>>>>]>+<]]+>>>>[-<<<<->>>>]+<<<<[->>>>-<[-<<<+>>>]<<<[->
>>+<<<<<<<<<<<<[<<<<<<<<<]>>>[-]+>>>>>>[>>>>>>>>>]>[-]+<]]+>[-<[>>>>>>>>>]<<<<<<
<<]>>>>>>>>]<<<<<<<<<[<<<<<<<<<]<<<<<<<[->+>>>-<<<<]>>>>>>>>>+++++++++++++++++++
+++++++>>[-<<<<+>>>>]<<<<[->>>>+<<[-]<<]>>[<<<<<<<+<[-<+>>>>+<<[-]]>[-<<[->+>>>-
<<<<]>>>]>>>>>>>>>>>>>[>>[-]>[-]>[-]>>>>>]<<<<<<<<<[<<<<<<<<<]>>>[-]>>>>>>[>>>>>
[-<<<<+>>>>]<<<<[->>>>+<<<+<]>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>[>>[-<<<<<<<<
<+>>>>>>>>>]>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>+++++++++++++++[[>>>>>>>>>]+>[-
]>[-]>[-]>[-]>[-]>[-]>[-]>[-]>[-]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>-]+[>+>>>>>>>>]<<<
<<<<<<[<<<<<<<<<]>>>>>>>>>[>->>>>>[-<<<<<+>>>>>]<<<<<[->>>>>+<<<<<<[->>[-<<+>>]<
<[->>+>+<<<]+>>>>>>>>>]<<<<<<<<[<<<<<<<<<]]>>>>>>>>>[>>>>>>>>>]<<<<<<<<<[>[->>>>
>>>>>+<<<<<<<<<]<<<<<<<<<<]>[->>>>>>>>>+<<<<<<<<<]<+>>>>>>>>]<<<<<<<<<[>[-]<->>>
[-<<<+>[<->-<<<<<<<+>>>>>>>]<[->+<]>>>]<<[->>+<<]<+<<<<<<<<<]>>>>>>>>>[>>>>>>[-<
<<<<+>>>>>]<<<<<[->>>>>+<<<<+<]>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>[>+>>>>>>>>
]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>[>->>>>>[-<<<<<+>>>>>]<<<<<[->>>>>+<<<<<<[->>[-<<+
>>]<<[->>+>>+<<<<]+>>>>>>>>>]<<<<<<<<[<<<<<<<<<]]>>>>>>>>>[>>>>>>>>>]<<<<<<<<<[>
[->>>>>>>>>+<<<<<<<<<]<<<<<<<<<<]>[->>>>>>>>>+<<<<<<<<<]<+>>>>>>>>]<<<<<<<<<[>[-
]<->>>>[-<<<<+>[<->-<<<<<<+>>>>>>]<[->+<]>>>>]<<<[->>>+<<<]<+<<<<<<<<<]>>>>>>>>>
[>>>>[-<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
]>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>[>>>[-<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>]>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>++++++++
+++++++[[>>>>>>>>>]<<<<<<<<<-<<<<<<<<<[<<<<<<<<<]>>>>>>>>>-]+[>>>>>>>>[-<<<<<<<+
>>>>>>>]<<<<<<<[->>>>>>>+<<<<<<+<]>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>[>>>>>>[
-]>>>]<<<<<<<<<[<<<<<<<<<]>>>>+>[-<-<<<<+>>>>>]>[-<<<<<<[->>>>>+<++<<<<]>>>>>[-<
<<<<+>>>>>]<->+>]<[->+<]<<<<<[->>>>>+<<<<<]>>>>>>[-]<<<<<<+>>>>[-<<<<->>>>]+<<<<
[->>>>->>>>>[>>[-<<->>]+<<[->>->[-<<<+>>>]<<<[->>>+<<<<<<<<<<<<[<<<<<<<<<]>>>[-]
+>>>>>>[>>>>>>>>>]>+<]]+>>>[-<<<->>>]+<<<[->>>-<[-<<+>>]<<[->>+<<<<<<<<<<<[<<<<<
<<<<]>>>>[-]+>>>>>[>>>>>>>>>]>[-]+<]]+>[-<[>>>>>>>>>]<<<<<<<<]>>>>>>>>]<<<<<<<<<
[<<<<<<<<<]>>>>[-<<<<+>>>>]<<<<[->>>>+>>>>>[>+>>[-<<->>]<<[->>+<<]>>>>>>>>]<<<<<
<<<+<[>[->>>>>+<<<<[->>>>-<<<<<<<<<<<<<<+>>>>>>>>>>>[->>>+<<<]<]>[->>>-<<<<<<<<<
<<<<<+>>>>>>>>>>>]<<]>[->>>>+<<<[->>>-<<<<<<<<<<<<<<+>>>>>>>>>>>]<]>[->>>+<<<]<<
<<<<<<<<<<]>>>>[-]<<<<]>>>[-<<<+>>>]<<<[->>>+>>>>>>[>+>[-<->]<[->+<]>>>>>>>>]<<<
<<<<<+<[>[->>>>>+<<<[->>>-<<<<<<<<<<<<<<+>>>>>>>>>>[->>>>+<<<<]>]<[->>>>-<<<<<<<
<<<<<<<+>>>>>>>>>>]<]>>[->>>+<<<<[->>>>-<<<<<<<<<<<<<<+>>>>>>>>>>]>]<[->>>>+<<<<
]<<<<<<<<<<<]>>>>>>+<<<<<<]]>>>>[-<<<<+>>>>]<<<<[->>>>+>>>>>[>>>>>>>>>]<<<<<<<<<
[>[->>>>>+<<<<[->>>>-<<<<<<<<<<<<<<+>>>>>>>>>>>[->>>+<<<]<]>[->>>-<<<<<<<<<<<<<<
+>>>>>>>>>>>]<<]>[->>>>+<<<[->>>-<<<<<<<<<<<<<<+>>>>>>>>>>>]<]>[->>>+<<<]<<<<<<<
<<<<<]]>[-]>>[-]>[-]>>>>>[>>[-]>[-]>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>[>>>>>[-<
<<<+>>>>]<<<<[->>>>+<<<+<]>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>+++++++++++++++[
[>>>>>>>>>]+>[-]>[-]>[-]>[-]>[-]>[-]>[-]>[-]>[-]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>-]+
[>+>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>[>->>>>[-<<<<+>>>>]<<<<[->>>>+<<<<<[->>
[-<<+>>]<<[->>+>+<<<]+>>>>>>>>>]<<<<<<<<[<<<<<<<<<]]>>>>>>>>>[>>>>>>>>>]<<<<<<<<
<[>[->>>>>>>>>+<<<<<<<<<]<<<<<<<<<<]>[->>>>>>>>>+<<<<<<<<<]<+>>>>>>>>]<<<<<<<<<[
>[-]<->>>[-<<<+>[<->-<<<<<<<+>>>>>>>]<[->+<]>>>]<<[->>+<<]<+<<<<<<<<<]>>>>>>>>>[
>>>[-<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>]>
>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>[-]>>>>+++++++++++++++[[>>>>>>>>>]<<<<<<<<<-<<<<<
<<<<[<<<<<<<<<]>>>>>>>>>-]+[>>>[-<<<->>>]+<<<[->>>->[-<<<<+>>>>]<<<<[->>>>+<<<<<
<<<<<<<<[<<<<<<<<<]>>>>[-]+>>>>>[>>>>>>>>>]>+<]]+>>>>[-<<<<->>>>]+<<<<[->>>>-<[-
<<<+>>>]<<<[->>>+<<<<<<<<<<<<[<<<<<<<<<]>>>[-]+>>>>>>[>>>>>>>>>]>[-]+<]]+>[-<[>>
>>>>>>>]<<<<<<<<]>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>[-<<<+>>>]<<<[->>>+>>>>>>[>+>>>
[-<<<->>>]<<<[->>>+<<<]>>>>>>>>]<<<<<<<<+<[>[->+>[-<-<<<<<<<<<<+>>>>>>>>>>>>[-<<
+>>]<]>[-<<-<<<<<<<<<<+>>>>>>>>>>>>]<<<]>>[-<+>>[-<<-<<<<<<<<<<+>>>>>>>>>>>>]<]>
[-<<+>>]<<<<<<<<<<<<<]]>>>>[-<<<<+>>>>]<<<<[->>>>+>>>>>[>+>>[-<<->>]<<[->>+<<]>>
>>>>>>]<<<<<<<<+<[>[->+>>[-<<-<<<<<<<<<<+>>>>>>>>>>>[-<+>]>]<[-<-<<<<<<<<<<+>>>>
>>>>>>>]<<]>>>[-<<+>[-<-<<<<<<<<<<+>>>>>>>>>>>]>]<[-<+>]<<<<<<<<<<<<]>>>>>+<<<<<
]>>>>>>>>>[>>>[-]>[-]>[-]>>>>]<<<<<<<<<[<<<<<<<<<]>>>[-]>[-]>>>>>[>>>>>>>[-<<<<<
<+>>>>>>]<<<<<<[->>>>>>+<<<<+<<]>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>+>[-<-<<<<+>>>>
>]>>[-<<<<<<<[->>>>>+<++<<<<]>>>>>[-<<<<<+>>>>>]<->+>>]<<[->>+<<]<<<<<[->>>>>+<<
<<<]+>>>>[-<<<<->>>>]+<<<<[->>>>->>>>>[>>>[-<<<->>>]+<<<[->>>-<[-<<+>>]<<[->>+<<
<<<<<<<<<[<<<<<<<<<]>>>>[-]+>>>>>[>>>>>>>>>]>+<]]+>>[-<<->>]+<<[->>->[-<<<+>>>]<
<<[->>>+<<<<<<<<<<<<[<<<<<<<<<]>>>[-]+>>>>>>[>>>>>>>>>]>[-]+<]]+>[-<[>>>>>>>>>]<
<<<<<<<]>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>[-<<<+>>>]<<<[->>>+>>>>>>[>+>[-<->]<[->+
<]>>>>>>>>]<<<<<<<<+<[>[->>>>+<<[->>-<<<<<<<<<<<<<+>>>>>>>>>>[->>>+<<<]>]<[->>>-
<<<<<<<<<<<<<+>>>>>>>>>>]<]>>[->>+<<<[->>>-<<<<<<<<<<<<<+>>>>>>>>>>]>]<[->>>+<<<
]<<<<<<<<<<<]>>>>>[-]>>[-<<<<<<<+>>>>>>>]<<<<<<<[->>>>>>>+<<+<<<<<]]>>>>[-<<<<+>
>>>]<<<<[->>>>+>>>>>[>+>>[-<<->>]<<[->>+<<]>>>>>>>>]<<<<<<<<+<[>[->>>>+<<<[->>>-
<<<<<<<<<<<<<+>>>>>>>>>>>[->>+<<]<]>[->>-<<<<<<<<<<<<<+>>>>>>>>>>>]<<]>[->>>+<<[
->>-<<<<<<<<<<<<<+>>>>>>>>>>>]<]>[->>+<<]<<<<<<<<<<<<]]>>>>[-]<<<<]>>>>[-<<<<+>>
>>]<<<<[->>>>+>[-]>>[-<<<<<<<+>>>>>>>]<<<<<<<[->>>>>>>+<<+<<<<<]>>>>>>>>>[>>>>>>
>>>]<<<<<<<<<[>[->>>>+<<<[->>>-<<<<<<<<<<<<<+>>>>>>>>>>>[->>+<<]<]>[->>-<<<<<<<<
<<<<<+>>>>>>>>>>>]<<]>[->>>+<<[->>-<<<<<<<<<<<<<+>>>>>>>>>>>]<]>[->>+<<]<<<<<<<<
<<<<]]>>>>>>>>>[>>[-]>[-]>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>[-]>[-]>>>>>[>>>>>[-<<<<+
>>>>]<<<<[->>>>+<<<+<]>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>[>>>>>>[-<<<<<+>>>>>
]<<<<<[->>>>>+<<<+<<]>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>+++++++++++++++[[>>>>
>>>>>]+>[-]>[-]>[-]>[-]>[-]>[-]>[-]>[-]>[-]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>-]+[>+>>
>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>[>->>>>[-<<<<+>>>>]<<<<[->>>>+<<<<<[->>[-<<+
>>]<<[->>+>>+<<<<]+>>>>>>>>>]<<<<<<<<[<<<<<<<<<]]>>>>>>>>>[>>>>>>>>>]<<<<<<<<<[>
[->>>>>>>>>+<<<<<<<<<]<<<<<<<<<<]>[->>>>>>>>>+<<<<<<<<<]<+>>>>>>>>]<<<<<<<<<[>[-
]<->>>>[-<<<<+>[<->-<<<<<<+>>>>>>]<[->+<]>>>>]<<<[->>>+<<<]<+<<<<<<<<<]>>>>>>>>>
[>+>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>[>->>>>>[-<<<<<+>>>>>]<<<<<[->>>>>+<<<<
<<[->>>[-<<<+>>>]<<<[->>>+>+<<<<]+>>>>>>>>>]<<<<<<<<[<<<<<<<<<]]>>>>>>>>>[>>>>>>
>>>]<<<<<<<<<[>>[->>>>>>>>>+<<<<<<<<<]<<<<<<<<<<<]>>[->>>>>>>>>+<<<<<<<<<]<<+>>>
>>>>>]<<<<<<<<<[>[-]<->>>>[-<<<<+>[<->-<<<<<<+>>>>>>]<[->+<]>>>>]<<<[->>>+<<<]<+
<<<<<<<<<]>>>>>>>>>[>>>>[-<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>]>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>+++++++++++++++[[>>>>>>>>
>]<<<<<<<<<-<<<<<<<<<[<<<<<<<<<]>>>>>>>>>-]+>>>>>>>>>>>>>>>>>>>>>+<<<[<<<<<<<<<]
>>>>>>>>>[>>>[-<<<->>>]+<<<[->>>->[-<<<<+>>>>]<<<<[->>>>+<<<<<<<<<<<<<[<<<<<<<<<
]>>>>[-]+>>>>>[>>>>>>>>>]>+<]]+>>>>[-<<<<->>>>]+<<<<[->>>>-<[-<<<+>>>]<<<[->>>+<
<<<<<<<<<<<[<<<<<<<<<]>>>[-]+>>>>>>[>>>>>>>>>]>[-]+<]]+>[-<[>>>>>>>>>]<<<<<<<<]>
>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>->>[-<<<<+>>>>]<<<<[->>>>+<<[-]<<]>>]<<+>>>>[-<<<<
->>>>]+<<<<[->>>>-<<<<<<.>>]>>>>[-<<<<<<<.>>>>>>>]<<<[-]>[-]>[-]>[-]>[-]>[-]>>>[
>[-]>[-]>[-]>[-]>[-]>[-]>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>[>>>>>[-]>>>>]<<<<<<<<<
[<<<<<<<<<]>+++++++++++[-[->>>>>>>>>+<<<<<<<<<]>>>>>>>>>]>>>>+>>>>>>>>>+<<<<<<<<
<<<<<<[<<<<<<<<<]>>>>>>>[-<<<<<<<+>>>>>>>]<<<<<<<[->>>>>>>+[-]>>[>>>>>>>>>]<<<<<
<<<<[>>>>>>>[-<<<<<<+>>>>>>]<<<<<<[->>>>>>+<<<<<<<[<<<<<<<<<]>>>>>>>[-]+>>>]<<<<
<<<<<<]]>>>>>>>[-<<<<<<<+>>>>>>>]<<<<<<<[->>>>>>>+>>[>+>>>>[-<<<<->>>>]<<<<[->>>
>+<<<<]>>>>>>>>]<<+<<<<<<<[>>>>>[->>+<<]<<<<<<<<<<<<<<]>>>>>>>>>[>>>>>>>>>]<<<<<
<<<<[>[-]<->>>>>>>[-<<<<<<<+>[<->-<<<+>>>]<[->+<]>>>>>>>]<<<<<<[->>>>>>+<<<<<<]<
+<<<<<<<<<]>>>>>>>-<<<<[-]+<<<]+>>>>>>>[-<<<<<<<->>>>>>>]+<<<<<<<[->>>>>>>->>[>>
>>>[->>+<<]>>>>]<<<<<<<<<[>[-]<->>>>>>>[-<<<<<<<+>[<->-<<<+>>>]<[->+<]>>>>>>>]<<
<<<<[->>>>>>+<<<<<<]<+<<<<<<<<<]>+++++[-[->>>>>>>>>+<<<<<<<<<]>>>>>>>>>]>>>>+<<<
<<[<<<<<<<<<]>>>>>>>>>[>>>>>[-<<<<<->>>>>]+<<<<<[->>>>>->>[-<<<<<<<+>>>>>>>]<<<<
<<<[->>>>>>>+<<<<<<<<<<<<<<<<[<<<<<<<<<]>>>>[-]+>>>>>[>>>>>>>>>]>+<]]+>>>>>>>[-<
<<<<<<->>>>>>>]+<<<<<<<[->>>>>>>-<<[-<<<<<+>>>>>]<<<<<[->>>>>+<<<<<<<<<<<<<<[<<<
<<<<<<]>>>[-]+>>>>>>[>>>>>>>>>]>[-]+<]]+>[-<[>>>>>>>>>]<<<<<<<<]>>>>>>>>]<<<<<<<
<<[<<<<<<<<<]>>>>[-]<<<+++++[-[->>>>>>>>>+<<<<<<<<<]>>>>>>>>>]>>>>-<<<<<[<<<<<<<
<<]]>>>]<<<<.>>>>>>>>>>[>>>>>>[-]>>>]<<<<<<<<<[<<<<<<<<<]>++++++++++[-[->>>>>>>>
>+<<<<<<<<<]>>>>>>>>>]>>>>>+>>>>>>>>>+<<<<<<<<<<<<<<<[<<<<<<<<<]>>>>>>>>[-<<<<<<
<<+>>>>>>>>]<<<<<<<<[->>>>>>>>+[-]>[>>>>>>>>>]<<<<<<<<<[>>>>>>>>[-<<<<<<<+>>>>>>
>]<<<<<<<[->>>>>>>+<<<<<<<<[<<<<<<<<<]>>>>>>>>[-]+>>]<<<<<<<<<<]]>>>>>>>>[-<<<<<
<<<+>>>>>>>>]<<<<<<<<[->>>>>>>>+>[>+>>>>>[-<<<<<->>>>>]<<<<<[->>>>>+<<<<<]>>>>>>
>>]<+<<<<<<<<[>>>>>>[->>+<<]<<<<<<<<<<<<<<<]>>>>>>>>>[>>>>>>>>>]<<<<<<<<<[>[-]<-
>>>>>>>>[-<<<<<<<<+>[<->-<<+>>]<[->+<]>>>>>>>>]<<<<<<<[->>>>>>>+<<<<<<<]<+<<<<<<
<<<]>>>>>>>>-<<<<<[-]+<<<]+>>>>>>>>[-<<<<<<<<->>>>>>>>]+<<<<<<<<[->>>>>>>>->[>>>
>>>[->>+<<]>>>]<<<<<<<<<[>[-]<->>>>>>>>[-<<<<<<<<+>[<->-<<+>>]<[->+<]>>>>>>>>]<<
<<<<<[->>>>>>>+<<<<<<<]<+<<<<<<<<<]>+++++[-[->>>>>>>>>+<<<<<<<<<]>>>>>>>>>]>>>>>
+>>>>>>>>>>>>>>>>>>>>>>>>>>>+<<<<<<[<<<<<<<<<]>>>>>>>>>[>>>>>>[-<<<<<<->>>>>>]+<
<<<<<[->>>>>>->>[-<<<<<<<<+>>>>>>>>]<<<<<<<<[->>>>>>>>+<<<<<<<<<<<<<<<<<[<<<<<<<
<<]>>>>[-]+>>>>>[>>>>>>>>>]>+<]]+>>>>>>>>[-<<<<<<<<->>>>>>>>]+<<<<<<<<[->>>>>>>>
-<<[-<<<<<<+>>>>>>]<<<<<<[->>>>>>+<<<<<<<<<<<<<<<[<<<<<<<<<]>>>[-]+>>>>>>[>>>>>>
>>>]>[-]+<]]+>[-<[>>>>>>>>>]<<<<<<<<]>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>[-]<<<++++
+[-[->>>>>>>>>+<<<<<<<<<]>>>>>>>>>]>>>>>->>>>>>>>>>>>>>>>>>>>>>>>>>>-<<<<<<[<<<<
<<<<<]]>>>]
I don't understand why, but my program keeps getting stuck in some sort of endless loop. I try to debug it using gdb but it's hard to find the right breakpoint in order to see why it stuck.
The program is as follows:
#include <stdio.h>
#include <stdlib.h>
// Brainfuck instructions
// > Math stuff
#define INCR '+' // +1 on current MS
#define DECR '-' // -1 on current MS
// > Memory slot stuff
#define FORW '>' // Go to next MS
#define BACK '<' // Go to previous MS
// > Logic stuff
#define SJMP '[' // Loop till current MS value is equal to zero
#define EJMP ']' // Jump to the beginning of the loop
// > I/O stuff
#define PRTC '.' // Print character with MS value as ASCII code
#define GETC ',' // Get an user input ASCII character code
typedef unsigned char byte;
// The brainfuck program struct
typedef struct {
byte *values;
int size;
int index;
byte *loops_starts;
int loop_size;
int loop_index;
} BrainfuckProgram;
void initialize(BrainfuckProgram *bfp) {
bfp->values = malloc(bfp->size * sizeof(*bfp->values));
bfp->loops_starts = malloc(bfp->size * sizeof(*bfp->loops_starts));
}
int allocate_values(BrainfuckProgram *bfp) {
byte *newMem = realloc(bfp->values, bfp->size * sizeof(byte));
if (!newMem) {
return 1;
}
bfp->values = newMem;
return 0;
}
int allocate_new_loop(BrainfuckProgram *bfp) {
byte *newMem = realloc(bfp->loops_starts, bfp->loop_size * sizeof(byte));
if (!newMem) {
return 1;
}
bfp->loops_starts = newMem;
return 0;
}
void set_value(BrainfuckProgram *bfp, byte value) {
int tempValue = value < 0 ? 255: value % 256;
*(bfp->values + bfp->index) = tempValue;
}
int get_value(BrainfuckProgram *bfp) {
return *(bfp->values + bfp->index);
}
// FILE functions
int get_file_name(int argc, char *argv[], char** fname) {
if (argc == 1) {
printf("File name is missing\n");
return 1;
}
*fname = argv[1];
return 0;
}
int get_file_size(FILE *file) {
fseek(file, 0L, SEEK_END);
int size = ftell(file);
rewind(file);
return size;
}
// Main function
int main(int argc, char *argv[]) {
// Vector part
BrainfuckProgram bfp = {
.values = NULL,
.size = 1,
.index = 0,
.loops_starts = NULL,
.loop_index = 0,
.loop_size = 0
};
initialize(&bfp);
// FILE Part
char* fname = NULL;
int error = get_file_name(argc, argv, &fname);
if (error) {
goto exit;
}
// Create file variable
FILE *fin = NULL;
fin = fopen(fname, "r");
int size = get_file_size(fin);
// Create a char array of the right size
byte *prog = NULL;
prog = malloc(size * sizeof(*prog));
// Read 1 byte size times
fread(prog, 1, size, fin);
for (int i = 0; i < size; i++) {
byte current = *(prog+i);
switch (current) {
case INCR:
set_value(&bfp, get_value(&bfp) + 1);
break;
case DECR:
set_value(&bfp, get_value(&bfp) - 1);
break;
case FORW:
// if index+1 == size then we are at the
// last element of the vector cause
// size = index - 1
if (bfp.index+1 == bfp.size) {
bfp.size++;
int error = allocate_values(&bfp);
if (error) {
printf("an error occured while forwarding pointer");
goto close;
}
}
bfp.index++;
break;
case BACK:
// bfp.index == 0 then !bfp.index == true
if (!bfp.index) {
printf("can go back from index 0\n");
goto close;
}
bfp.index--;
break;
case SJMP:
if (bfp.loop_index == bfp.size) {
bfp.loop_size++;
int error = allocate_new_loop(&bfp);
if (error) {
printf("an error occured while forwarding pointer");
goto close;
}
}
bfp.loop_index++;
*(bfp.loops_starts + bfp.loop_index) = i;
break;
case EJMP:
if (bfp.loop_index == -1) {
printf("cannot go back");
goto close;
}
if (get_value(&bfp) != 0) {
i = *(bfp.loops_starts + bfp.loop_index);
} else {
bfp.loop_index--;
}
break;
case PRTC:
printf("%c", get_value(&bfp));
break;
case GETC:
; // Semicolon here because of the label error
byte buf;
scanf("%c", &buf);
set_value(&bfp, buf);
break;
}
}
close:
fclose(fin);
exit:
;
return 0;
}
I'd like to have some C related advice on what I have done wrong too.
The Mandelbrot program takes a decent time to run on a good interpreter. Yours, well, it isn't that good. That's why it "hangs" at the start.
Some good ideas that you had, performance-wise:
precalculating loops
Some bad ideas, performance-wise:
Using abstracted allocation functions instead of calling realloc
using scanf and printf instead of getchar and putchar
Some odd things that you did:
Manually truncating an unsigned char when wraparound is implicit
checking if an unsigned char is less than 0
using *(x + y) syntax instead of array indexing x[y]
I don't think you actually use those precalculated loops, if you do then probably not correctly
You also probably create a new precalculated loop every time you go over the loop again
Using the get_value and set_value functions instead of pointers (this will be a performance issue if you don't compile with optimizations)
A couple suggestions:
Try to avoid calling functions when you don't need to as much as possible.
Write a BrainFuck->C compiler using this reference.
On second thought, maybe you should try to debug this program instead.
You may also use my interpreter as a reference if you're OK with GPLv3. Note that it doesn't precalculate loops.

Parsing code for GPS NMEA string

i am trying to parse the incoming GPGGA NMEA GPS string using Arduino uno and below code.
What i am trying to do is that i am using only GPGGA NMEA string to get the values of Latitude, longitude and altitude.In my below code, i had put certain checks to check if incoming string is GPGGA or not, and then store the further string in a array which can be further parsed suing strtok function and all the 3 GPS coordinates can be easily find out.
But i am unable to figure out how to store only GPGGA string and not the further string.I am using a for loop but it isn't working.
I am not trying to use any library.I had came across certain existing codes like this.
Here is the GPGGA string information link
i am trying to have following functionlity
i) Check if incoming string is GPGGA
ii) If yes, then store the following string upto EOL or upto * (followed by checksum for the array) in a array, array length is variable(i am unable to find out solution for this)
iii) Then parse the stored array(this is done, i tried this with a different array)
#include <SoftwareSerial.h>
SoftwareSerial mySerial(10,11); // 10 RX / 11 TX
void setup()
{
Serial.begin(9600);
mySerial.begin(9600);
}
void loop()
{
uint8_t x;
char gpsdata[65];
if((mySerial.available()))
{
char c = mySerial.read();
if(c == '$')
{char c1 = mySerial.read();
if(c1 == 'G')
{char c2 = mySerial.read();
if(c2 == 'P')
{char c3 = mySerial.read();
if(c3 == 'G')
{char c4 = mySerial.read();
if(c4 == 'G')
{char c5 = mySerial.read();
if(c5 == 'A')
{for(x=0;x<65;x++)
{
gpsdata[x]=mySerial.read();
while (gpsdata[x] == '\r' || gpsdata[x] == '\n')
{
break;
}
}
}
else{
Serial.println("Not a GPGGA string");
}
}
}
}
}
}
}
Serial.println(gpsdata);
}
Edit 1:
Considering Joachim Pileborg, editing the for loop in the code.
I am adding a pic to show the undefined output of the code.
Input for the code:
$GPGGA,092750.000,5321.6802,N,00630.3372,W,1,8,1.03,61.7,M,55.2,M,,*76
$GPGSA,A,3,10,07,05,02,29,04,08,13,,,,,1.72,1.03,1.38*0A
$GPGSV,3,1,11,10,63,137,17,07,61,098,15,05,59,290,20,08,54,157,30*70
$GPGSV,3,2,11,02,39,223,19,13,28,070,17,26,23,252,,04,14,186,14*79
$GPGSV,3,3,11,29,09,301,24,16,09,020,,36,,,*76
$GPRMC,092750.000,A,5321.6802,N,00630.3372,W,0.02,31.66,280511,,,A*43
$GPGGA,092751.000,5321.6802,N,00630.3371,W,1,8,1.03,61.7,M,55.3,M,,*75
$GPGSA,A,3,10,07,05,02,29,04,08,13,,,,,1.72,1.03,1.38*0A
$GPGSV,3,1,11,10,63,137,17,07,61,098,15,05,59,290,20,08,54,157,30*70
$GPGSV,3,2,11,02,39,223,16,13,28,070,17,26,23,252,,04,14,186,15*77
$GPGSV,3,3,11,29,09,301,24,16,09,020,,36,,,*76
$GPRMC,092751.000,A,5321.6802,N,00630.3371,W,0.06,31.66,280511,,,A*45
After a quick check of the linked article on the NMEA 0183 protocol, this jumped out at me:
<CR><LF> ends the message.
This means, that instead of just read indiscriminately from the serial port, you should be looking for that sequence. If found, you should terminate the string, and break out of the loop.
Also, you might want to zero-initialize the data string to begin with, to easily see if there actually is any data in it to print (using e.g. strlen).
You could use some functions from the C library libnmea. Theres functions to split a sentence into values by comma and then parse them.
Offering this as a suggestion in support of what you are doing...
Would it not be useful to replace all of the nested if()s in your loop with something like:
EDIT added global string to copy myString into once captured
char globalString[100];//declare a global sufficiently large to hold you results
void loop()
{
int chars = mySerial.available();
int i;
char *myString;
if (chars>0)
{
myString = calloc(chars+1, sizeof(char));
for(i=0;i<chars;i++)
{
myString[i] = mySerial.read();
//test for EOF
if((myString[i] == '\n') ||(myString[i] == '\r'))
{
//pick this...
myString[i]=0;//strip carriage - return line feed(or skip)
//OR pick this... (one or the other. i.e.,I do not know the requirements for your string)
if(i<chars)
{
myString[i+1] = mySerial.read() //get remaining '\r' or '\n'
myString[i+2]=0;//add null term if necessary
}
break;
}
}
if(strstr(myString, "GPGGA") == NULL)
{
Serial.println("Not a GPGGA string");
//EDIT
strcpy(globalString, "");//if failed, do not want globalString populated
}
else
{ //EDIT
strcpy(globalString, myString);
}
}
//free(myString) //somewhere when you are done with it
}
Now, the return value from mySerial.available() tells you exactly how many bytes to read, you can read the entire buffer, and test for validity all in one.
I have a project that will need to pull the same information out of the same sentence.
I got this out of a log file
import serial
import time
ser = serial.Serial(1)
ser.read(1)
read_val = ("nothing")
gpsfile="gpscord.dat"
l=0
megabuffer=''
def buffThis(s):
global megabuffer
megabuffer +=s
def buffLines():
global megabuffer
megalist=megabuffer.splitlines()
megabuffer=megalist.pop()
return megalist
def readcom():
ser.write("ati")
time.sleep(3)
read_val = ser.read(size=500)
lines=read_val.split('\n')
for l in lines:
if l.startswith("$GPGGA"):
if l[:len(l)-3].endswith("*"):
outfile=open('gps.dat','w')
outfile.write(l.rstrip())
outfile.close()
readcom()
while 1==1:
readcom()
answer=raw_input('not looping , CTRL+C to abort')
The result is this:
gps.dat
$GPGGA,225714.656,5021.0474,N,00412.4420,W,0,00,50.0,0.0,M,18.0,M,0.0,0000*5B
Using "malloc" every single time you read a string is an enormous amount of computational overhead. (And didn't see the corresponding free() function call. Without that, you never get that memory back until program termination or system runs out of memory.) Just pick the size of the longest string you will ever need, add 10 to it, and declare that your string array size. Set once and done.
There are several C functions for getting substrings out of a string, strtok() using the coma is probably the least overhead.
You are on an embedded microcontroller. Keep it small, keep overhead down. :)
#include <stdio.h>
#include <string.h>
#define GNSS_HEADER_LENGTH 5
#define GNSS_PACKET_START '$'
#define GNSS_TOKEN_SEPARATOR ','
#define bool int
#define FALSE 0
#define TRUE 1
//To trim a string contains \r\n
void str_trim(char *str){
while(*str){
if(*str == '\r' || *str == '\n'){
*str = '\0';
}
str++;
}
}
/**
* To parse GNSS data by header and the index separated by comma
*
* $GPGSV,1,1,03,23,39,328,30,18,39,008,27,15,33,035,33,1*5A
* $GNRMC,170412.000,V,,,,,,,240322,,,N,V*2D
* $GNGGA,170412.000,,,,,0,0,,,M,,M,,*57
*
* #data_ptr the pointer points to gps data
* #header the header for parsing GPGSV
* #repeat_index the header may repeat for many lines
* so the header index is for identifying repeated header
* #token_index is the index of the parsing data separated by ","
* the start is 1
* #result to store the result of the parser input
*
* #result bool - parsed successfully
**/
bool parse_gnss_token(char *data_ptr, char *header, int repeat_index, int token_index, char *result) {
bool gnss_parsed_result = FALSE; // To check GNSS data parsing is success
bool on_header = FALSE;
// For header
int header_repeat_counter = 0;
int header_char_index = 0; // each char in header index
// For counting comma
int counted_token_index = 0;
// To hold the result character index
bool data_found = FALSE;
char *result_start = result;
char header_found[10];
while (*data_ptr) {
// 1. Packet start
if (*data_ptr == GNSS_PACKET_START) {
on_header = TRUE;
header_char_index = 0; // to index each character in header
data_found = FALSE; // is data part found
data_ptr++;
}
// 2. For header parsing
if (on_header) {
if (*data_ptr == GNSS_TOKEN_SEPARATOR || header_char_index >= GNSS_HEADER_LENGTH) {
on_header = FALSE;
} else {
header_found[header_char_index] = *data_ptr;
if (header_char_index == GNSS_HEADER_LENGTH - 1) { // Now Header found
header_found[header_char_index + 1] = '\0';
on_header = FALSE;
if (!strcmp(header, header_found)) {
// Some headers may repeat - to identify it set the repeat index
if (header_repeat_counter == repeat_index) {
//printf("Header: %s\r\n", header_found );
data_found = TRUE;
}
header_repeat_counter++;
}
}
header_char_index++;
}
}
// 3. data found
if (data_found) {
// To get the index data separated by comma
if (counted_token_index == token_index && *data_ptr != GNSS_TOKEN_SEPARATOR) {
// the data to parse
*result++ = *data_ptr;
gnss_parsed_result = TRUE;
}
if (*data_ptr == GNSS_TOKEN_SEPARATOR) { // if ,
counted_token_index++; // The comma counter for index
}
// Break if the counted_token_index(token_counter) greater than token_index(search_token)
if (counted_token_index > token_index) {
break;
}
}
// Appending \0 to the end
*result = '\0';
// To trim the data if ends with \r or \n
str_trim(result_start);
// Input data
data_ptr++;
}
return gnss_parsed_result;
}
int main()
{
char res[100];
char *nem = "\
$GNRMC,080817.000,A,0852.089246,N,07636.289920,E,0.00,139.61,270322,,,A,V*04\r\n\\r\n\
$GNGGA,080817.000,0852.089246,N,07636.289920,E,1,5,1.41,11.246,M,-93.835,M,,*5E\r\n\
$GNVTG,139.61,T,,M,0.00,N,0.00,K,A*2F\r\n\
$GNGSA,A,3,30,19,17,14,13,,,,,,,,1.72,1.41,0.98,1*0A\r\n\
$GNGSA,A,3,,,,,,,,,,,,,1.72,1.41,0.98,3*02\r\n\
$GNGSA,A,3,,,,,,,,,,,,,1.72,1.41,0.98,6*07\r\n\
$GPGSV,3,1,12,06,64,177,,30,60,138,15,19,51,322,18,17,42,356,27,1*68\r\n\
$GPGSV,3,2,12,14,36,033,17,07,34,142,17,13,32,267,17,02,21,208,,1*6C\r\n\
$GPGSV,3,3,12,15,05,286,,01,05,037,,03,03,083,,20,02,208,,1*6B\r\n\
$GAGSV,1,1,00,7*73\r\n\
$GIGSV,1,1,00,1*7D\r\n\
$GNGLL,0852.089246,N,07636.289920,E,080817.000,A,A*43\r\n\
$PQTMANTENNASTATUS,1,0,1*4F\r\n";
printf("Parsing GNRMC\r\n");
printf("===============\r\n");
for(int i=1;i<=16;i++){
parse_gnss_token(nem, "GNRMC", 0, i, res);
printf("Index: %d, Result: %s\r\n", i, res);
}
printf("Parsing GNVTG (First Parameter)\r\n");
printf("================================");
// GNVTG - Header, 0 - Repeat Index(if header is repeating), 1 - Value Index,
parse_gnss_token(nem, "GNVTG", 0, 1, res);
printf("\r\nGNVTG: %s\r\n", res);
return 0;
}

transferring from PLC (OPC client server Kepware) to MS Access, C

I am completely new to working with PLCs, but I have a project that need fetch data from an OPC client server, then send it to an Access database table. The bulk of the code minus OPCWriteGroupItems was from someone else. I am just lost on transferring the data that the get from OPCReadGroupItems to the proper variables in my function OPCWriteGroupItems. I just want to get the values that are read into the variables. Thanks.
F.Y.I.
My query statement I know needs to be tweaked so that it will read the variables correctly but that is anouther problem that I am working on. This is the more pressing concern.
Below are the two functions that I spoke of:
//---------------------------------------------------------
// Read items from an OPC Group
//---------------------------------------------------------
OPCStat OPCReadGroupItems (int iGrp, struct Var_Stru v[] )
{
HRESULT r1;
HRESULT *hr;
OPCITEMSTATE *is;
int iItem;
OPCStat RetVal=OPCSuccess;
if (pGRPTagSIO[iGrp]) {
if (bOPCDebug) printf("Reading data .... \n");
r1 = pGRPTagSIO[iGrp]->Read(OPC_DS_CACHE,
OPCDataGroup[iGrp].iNumItems,
OPCDataGroup[iGrp].hItem,
&is,
&hr);
if (FAILED(r1)) {
printf("Error from Read(%lx)\n", r1);
RetVal = OPCError;
} else {
// if the read worked then copy results to the v structure based on type
for (iItem=0;iItem<OPCDataGroup[iGrp].iNumItems;iItem++ ) {
//printf("Read item= %d, hr= %lx, Quality= %2x", iItem, hr[iItem], is[iItem].wQuality);
if(!FAILED(hr[iItem])) {
// printf("%d", is[iItem].vDataValue.vt);
//printf("%d", iGrp);
switch(is[iItem].vDataValue.vt) {
case VT_I2: // 2
v[iItem].iVal = is[iItem].vDataValue.iVal;
break;
case VT_I4: // 3
v[iItem].lVal = is[iItem].vDataValue.lVal;
break;
case VT_R4: // 4
// printf("Z");
v[iItem].fVal = is[iItem].vDataValue.fltVal;
break;
case VT_R8: // 5
v[iItem].dblVal = is[iItem].vDataValue.dblVal;
break;
case VT_BOOL: // 11
v[iItem].bVal = is[iItem].vDataValue.boolVal;
break;
case VT_UI1: // 11
printf("TEST");
sprintf(v[iItem].cVal, "%s", is[iItem].vDataValue.cVal);
printf("%s", v[iItem].cVal);
printf("%c", v[iItem].cVal);
break;
case VT_BSTR: // 8
// printf("TEST");
sprintf(v[iItem].cVal,"%-.*ls", kOPCStringSize,is[iItem].vDataValue.bstrVal );
//printf("\n STRING STRING %s \n", v[iItem].cVal);
break;
default:
break;
}
}
if(iGrp >= 0 && iGrp <=)
{
stuct_double[iGrp-1][iItem] = v[iItem].dblVal;
// printf("group %d ", iGrp);
// printf("Tag %i: %10.2f\n", iItem, root_plc[iItem]);
}
if(iGrp > 0 && iGrp <= 44)
{
struc_floats[iGrp-1][iItem] = v[iItem].fVal;
//printf("GROUP %d ", iGrp);
//printf("Tag %i: %10.2f\n", iItem, struc_floats[iGrp-1][iItem]);
}
else
{
printf("Error reading data item %d\n", iItem);
//RetVal=OPCError; //Make not as severe -- rjf 06/03/02
RetVal=OPCWarning;
//break; //Escape the for-loop -- rjf- 5/13/02
}
*/
pIMalloc->Free(hr);
for (iItem=0;iItem<OPCDataGroup[iGrp].iNumItems;iItem)
{
VariantClear($is[iItem].vdatavalue)
}
pIMalloc->Free(is);
}
}
else{
RetVal=OPCError;
}
return (RetVal);
}
//-----------------------------------------
// Write items contained in an OPC Group
//-----------------------------------------
OPCStat OPCWriteGroupItems (int iGrp, struct Var_Stru vOut[] )
{
/* Data Access Method used in this sample */
const char* DAM = "Direct ODBC";
/* Connection string for Direct ODBC */
char szDSN[256] = "DSN=Gas_Meter_check;";
HRESULT r1,r2;
HRESULT *hr;
VARIANT v[nMaxOPCItems];
int iItem;
OPCStat RetVal=OPCSuccess;
if (pGRPTagSIO[iGrp]) {
for (iItem=0;iItem<OPCDataGroup[iGrp].iNumItems;iItem++) {
v[iItem].vt = OPCDataGroup[iGrp].iType;
switch(OPCDataGroup[iGrp].iType) {
case VT_I2: // 2
v[iItem].iVal = vOut[iItem].iVal;
break;
case VT_I4: // 3
v[iItem].lVal = vOut[iItem].lVal;
break;
case VT_R4: // 4
v[iItem].fltVal = vOut[iItem].fVal;
break;
case VT_R8: // 5
v[iItem].dblVal = vOut[iItem].dblVal;
HENV hEnv; HDBC hDbc;
/* ODBC API return status */ RETCODE rc;
int iConnStrLength2Ptr;
char szConnStrOut[256];
int i= 0;
char datetime[256];
double HMCO=1.0;
double HMR,HMT;
unsigned char* InsertQuery = "INSERT INTO Data ( [Date / Time], [Hot Strip Mill rate], [Hot Strip Mill Comm Okay], [Hot Strip Mill Total] ) SELECT #datetime# AS Expr1, HMR AS Expr2, 1 AS Expr3, HMCO AS Expr4, HMT AS Expr5;";
SQLCHAR chval1[128], chval2[128], colName[128];
int ret1;
int ret2;
/* Number of rows and columns in result set */
SQLINTEGER rowCount = 0;
SQLSMALLINT fieldCount = 0, currentField = 0;
HSTMT hStmt;
/* Allocate an environment handle */
rc = SQLAllocEnv(&hEnv);
/* Allocate a connection handle */
rc = SQLAllocConnect(hEnv, &hDbc);
/* Connect to the TakeCharge database */
rc = SQLDriverConnect(hDbc, NULL, (unsigned char*)szDSN,
SQL_NTS, (unsigned char*)szConnStrOut,
255, (SQLSMALLINT*)&iConnStrLength2Ptr, SQL_DRIVER_NOPROMPT);
if (SQL_SUCCEEDED(rc))
{
printf("%s: Successfully connected to database. Data source name: \n %s\n",
DAM, szConnStrOut);
/* Prepare SQL query */
printf("%s: SQL InsertQuery:\n %s\n", DAM, InsertQuery);
rc = SQLAllocStmt(hDbc,&hStmt);
rc = SQLPrepare(hStmt, InsertQuery, SQL_NTS);
/* Excecute the query and create a record set */
rc = SQLExecute(hStmt);
if (SQL_SUCCEEDED(rc))
{
printf("Executing query...");
printf("\n");
}
while (SQL_SUCCEEDED(rc))
{
printf(" insert passed\n");
rc = SQLFetch(hStmt);
rowCount++;
};
}
else
{
printf("%s: Couldn't connect to %s.\n", DAM, szDSN);
}
/* Disconnect*/
SQLDisconnect(hDbc);
printf("%s: Cleanup. Done.\n", DAM);
break;
case VT_BOOL: // 11
v[iItem].bVal = vOut[iItem].bVal;
break;
case VT_BSTR: // 8
// printf(" In Message value (VT_BSTR) = %s \n",vOut[iItem].cVal );
r2 = LPTSTR_to_BSTR ( &v[iItem].bstrVal , vOut[iItem].cVal);
if ( r2 != S_OK ) {
printf ("error in memory \n");
RetVal = OPCError;
}
// printf(" Write Msg value(VT_BSTR) = %ls \n", v[iItem].bstrVal );
report(0,0,0, "STRINGS data %s",vOut[iItem].cVal);
break;
default:
printf(" value(unknown type:%d) ", OPCDataGroup[iGrp].iType );
RetVal = OPCError;
break;
}
//if (bOPCDebug) DumpVariant(OPCDataGroup[iGrp].cTagNames[iItem], &v[iItem]);
}
r1 = pGRPTagSIO[iGrp]->Write(
OPCDataGroup[iGrp].iNumItems,
OPCDataGroup[iGrp].hItem,
v,
&hr);
if (FAILED(r1))
{
printf("Error from Write(%lx)\n", r1);
RetVal = OPCError;
} else {
//if (bOPCDebug) printf("Successful Write ... \n");
// Clear the Variant
for (iItem=0;iItem<OPCDataGroup[iGrp].iNumItems;iItem++) {
VariantClear(&v[iItem]);
}
pIMalloc->Free(hr);
}
} else {
RetVal = OPCError;
}
return(RetVal);
}
C/C++ is not my first language, and I am not familiar with your specific OPC library (there are so many), but according to my understanding of the code you are reading some kind of a variant variable, and with case statements you determine it's type and store it to proper property of v[iItem]. You repeat that in a loop for all tags in that group. There must be some property that tells you the name of the tag you have just read, and you can use it to solve the problem.
For example, if the current tag you are reading is of single float type, then this case section will be executed:
case VT_R4:
v[iItem].fVal = is[iItem].vDataValue.fltVal;
break;
So v[iItem].fVal contains the 4 bytes single float value of the OPC tag. If the current tag you are reading is of double float type, then this case section will be executed:
case VT_R8:
v[iItem].dblVal = is[iItem].vDataValue.dblVal;
break;
and v[iItem].dblVal contains the 8 bytes double float value of the OPC tag. I think you get the picture.
You should really spend some time with OPC DA tutorials on http://www.opcfoundation.org.

Resources