How to make synchronism between two distinct C programs? - c

First of all, I don't know if I can explain well my problem or you can get it in the appropriate way. But I will try to make it clear for you.
In fact, I have two different C programs.
The first one is a simple loop print of a message on the console :
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
int main ()
{
while(1)
{
printf("WAITING\n");
sleep(1);
}
}
The second one is a blocking program that waits for an event ( press button ) to turn on led in my embedded board.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <sys/select.h>
#include <sys/time.h>
#include <errno.h>
#include <linux/input.h>
#define BTN_FILE_PATH "/dev/input/event0"
#define LED_PATH "/sys/class/leds"
#define green "green"
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);
}
int configure_leds(void)
{
FILE *l_fd;
FILE *r_fd;
char *none_str = "none";
/* Configure leds for hand control */
r_fd = fopen(LED_PATH "/" green "/trigger", "w");
fprintf(r_fd, "%s\n", none_str);
fclose(r_fd);
/* Switch off leds */
reset_leds();
return 0;
}
void eval_keycode(int code)
{
static int green_state = 0;
switch (code) {
case 260:
printf("BTN left pressed\n");
/* figure out red state */
green_state = green_state ? 0 : 1;
change_led_state(LED_PATH "/" green "/brightness", green_state);
break;
}
}
int main(void)
{
int file;
/* how many bytes were read */
size_t rb;
int ret;
int yalv;
/* the events (up to 64 at once) */
struct input_event ev[64];
char *str = BTN_FILE_PATH;
printf("Starting simplekey app\n");
ret = configure_leds();
if (ret < 0)
exit(1);
printf("File Path: %s\n", str);
if((file = open(str, O_RDONLY)) < 0) {
perror("simplekey: File can not open");
exit(1);
}
for (;;) {
/* Blocking read */
rb= read(file, &ev, sizeof(ev));
if (rb < (int) sizeof(struct input_event)) {
perror("simplekey: short read");
exit(1);
}
for (yalv = 0;
yalv < (int) (rb / sizeof(struct input_event));
yalv++) {
if (ev[yalv].type == EV_KEY) {
printf("%ld.%06ld ",
ev[yalv].time.tv_sec,
ev[yalv].time.tv_usec);
printf("type %d code %d value %d\n",
ev[yalv].type,
ev[yalv].code, ev[yalv].value);
/* Change state on button pressed */
if (ev[yalv].value == 0)
eval_keycode(ev[yalv].code);
}
}
}
close(file);
reset_leds();
exit(0);
}
When I execute the second code, the program starts waiting for the event to switch on/off the led.
My question is :
How can I make interaction between the two programs ? I want to execute the firs one --> It starts printing for me " WAITING " until I press the BUTTON --> the LED turn on --> and then it goes back to the first program and re-start printing " WAITING " on the console.
I don't know if I explained well the issue but I hope that you can help me! Thank you.

You need a communication mechanism between your two programs. This is also known als inter-process communication.
Generally, you have several options to achieve this (depending on the operating system you are using, not all of them may be available):
Shared memory / shared files
Message passing (e.g. via sockets)
Pipes
Signals
A helpful introduction can be found here.

Related

Termcaps lines and columns are not changing when I resize the window

I'm trying to get the terminal window size, even when I resize the window, I'm using termcaps for this, the problem is when I resize the window, the values of lines and columns stays the same instead of updating, I also tried using ncurses's LINES and COLS globals, but the same thing happens.
Here is a minimal reproductible example:
#include <ncurses.h>
#include <term.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
int main(void)
{
char * term_type = getenv("TERM");
int ret;
int li_cap;
int co_cap;
if (!term_type)
{
write(2, "TERM env must be set\n", 21);
return (-1);
}
if ((ret = tgetent(NULL, term_type)) == -1)
{
write(2, "Could not access to the termcap database\n", 41);
return (-1);
}
if (!ret)
{
write(2, "This terminal is not supported by termcaps\n", 43);
return (-1);
}
while (1)
{
sleep(1);
li_cap = tgetnum("li");
co_cap = tgetnum("co");
printf("%d %d\n", li_cap, co_cap);
}
return (0);
}
So when I resize the window inside the loop, the values stay the same, I want to get the lines and colums in real time, how could I do this with termcaps?
The termcap data and the environment variables COLUMNS and LINES are unreliable and aren't updated upon terminal resizing, especially during program execution. There is another solution for POSIX systems where you can:
retrieve the size of the terminal window with ioctl(0, TIOCGWINSZ, &ws)
register a signal handler to get notified of terminal size changes.
Here is a demonstration program:
#include <stdio.h>
#include <signal.h>
#include <termios.h>
#include <sys/ioctl.h>
#include <unistd.h>
static volatile unsigned char term_size_updated;
static void term_resize() {
term_size_updated = 1;
}
static void term_get_size(int *cols, int *rows) {
struct winsize ws;
/* get screen dimensions from (pseudo) tty ioctl */
if (ioctl(0, TIOCGWINSZ, &ws) == 0) {
*cols = ws.ws_col;
*rows = ws.ws_row;
} else {
*cols = *rows = -1;
}
}
int main() {
struct sigaction sig;
int cols, rows;
/* set up terminal resize callback */
sig.sa_handler = term_resize;
sigemptyset(&sig.sa_mask);
sig.sa_flags = 0;
sigaction(SIGWINCH, &sig, NULL);
term_size_updated = 1;
for (;;) {
if (term_size_updated) {
term_size_updated = 0;
term_get_size(&cols, &rows);
fprintf(stderr, "term_resize: cols=%d, rows=%d\n", cols, rows);
}
sleep(1);
}
return 0;
}

How to modify my C code in order to not to stay in an infinite loop?

I have developped a C program for my embedded Board. This program make the green LED lights on when I push and release the BUTTON.
The green LED is defined under "/sys/class/leds" and the BUTTON is under "/dev/input/event0".
This is the code :
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <sys/select.h>
#include <sys/time.h>
#include <errno.h>
#include <linux/input.h>
#define BTN_FILE_PATH "/dev/input/event0"
#define LED_PATH "/sys/class/leds"
#define green "green"
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);
}
int configure_leds(void)
{
FILE *l_fd;
FILE *r_fd;
char *none_str = "none";
/* Configure leds for hand control */
r_fd = fopen(LED_PATH "/" green "/trigger", "w");
fprintf(r_fd, "%s\n", none_str);
fclose(r_fd);
/* Switch off leds */
reset_leds();
return 0;
}
void eval_keycode(int code)
{
static int green_state = 0;
switch (code) {
case 260:
printf("BTN pressed\n");
/* figure out green state */
green_state = green_state ? 0 : 1;
change_led_state(LED_PATH "/" green "/brightness", green_state);
break;
}
}
int main(void)
{
int file;
/* how many bytes were read */
size_t rb;
int ret;
int yalv;
/* the events (up to 64 at once) */
struct input_event ev[64];
char *str = BTN_FILE_PATH;
printf("Starting simplekey app\n");
ret = configure_leds();
if (ret < 0)
exit(1);
printf("File Path: %s\n", str);
if((file = open(str, O_RDONLY)) < 0) {
perror("simplekey: File can not open");
exit(1);
}
for (;;) {
/* Blocking read */
rb= read(file, &ev, sizeof(ev));
for (yalv = 0;
yalv < (int) (rb / sizeof(struct input_event));
yalv++) {
if (ev[yalv].type == EV_KEY) {
/* Change state on button pressed */
if (ev[yalv].value == 0)
eval_keycode(ev[yalv].code);
}
}
}
close(file);
reset_leds();
exit(0);
}
The compilation is going well.
When I execute the code it shows me this :
Starting simplekey app
File Path: /dev/input/event0
When I push the BUTTON nothing happens and when I release it the LED changes state and it shows me this in the terminal :
BTN pressed
The problem is that the code continue executing until I press CTRL+C to exit.
I just want it to wait until the event ( pressing BUTTON ) happens then change LED state and finally exit automatically.
My question is how to modify the program for this purpose ? I thought about using Threads and Signals but I don't have any idea about them. Thank you!
I presume you are running all this under a system complying either SVr4, or 4.3BSD ot POSIX.1-2001 (or later versions).
You are missing the the check on the read() return value, which is not size_t but rather ssize_t (that is it is signed).
Your code could then be changed like this:
/* ... */
ssize_t rb; /* !!! */
/* ... */
for (;;) {
/* Blocking read */
rb= read(file, &ev, sizeof(ev));
if (rb <= 0) /* Check for the EOF */
break;
for (yalv = 0;
yalv < (int) (rb / sizeof(struct input_event));
yalv++) {
if (ev[yalv].type == EV_KEY) {
/* Change state on button pressed */
if (ev[yalv].value == 0)
eval_keycode(ev[yalv].code);
}
}
}
Please, refer to the friendly man pages.

Remap a keyboard with ioctl under linux

I am actually trying to write a small program to catch global keyboard inputs from specific USB keyboards under linux.
I am testing with this piece of code :
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <linux/input.h>
#include <string.h>
#include <stdio.h>
static const char *const evval[3] = {
"RELEASED",
"PRESSED ",
"REPEATED"
};
int main(void)
{
const char *dev = "/dev/input/event2";
struct input_event ev;
ssize_t n;
int fd;
char name[256]= "Unknown";
// int codes[2];
// codes[0] = 58; /* M keycap */
// codes[1] = 49; /* assign to N */
fd = open(dev, O_RDONLY);
if (fd == -1) {
fprintf(stderr, "Cannot open %s: %s.\n", dev, strerror(errno));
return EXIT_FAILURE;
}
if(ioctl(fd, EVIOCGNAME(sizeof(name)), name) > 0)
{
printf("The device on %s says its name is '%s'\n", dev, name);
}
/*
int err = ioctl(fd, EVIOCSKEYCODE, codes);
if (err) {
perror("evdev ioctl");
}*/
while (1) {
n = read(fd, &ev, sizeof ev);
if (n == (ssize_t)-1) {
if (errno == EINTR)
continue;
else
break;
} else
if (n != sizeof ev) {
errno = EIO;
break;
}
if (ev.type == EV_KEY && ev.value >= 0 && ev.value <= 2)
printf("%s 0x%04x (%d)\n", evval[ev.value], (int)ev.code, (int)ev.code);
}
fflush(stdout);
fprintf(stderr, "%s.\n", strerror(errno));
return EXIT_FAILURE;
}
Ths point is that I don't know how to change some input key by other. I tried by calling write() on currently red event by changing the event code, sent key was still previous one, and I tried to used ioctl with EVIOCSKEYCODE, but the call failed with an "invalid argument" error (and I'm not sure to call it correctly).
How can I change outputed key correctly ?
Use the EVIOCGRAB ioctl to grab the input device, so that by reading the events you consume them. Normally (not-grabbed) the events are not consumed when you read them. The ioctl takes an additional parameter, (int)1 for grabbing, (int)0 for releasing.
To re-inject any events, just write them to the uinput device. See eg. a mouse example here. (The event structures are the same type, you only need to write a struct uinput_user_dev structure to the uinput device first, to describe your new input device (which provides the mapped events).)
In other words, you don't remap: you consume and forward.

UART compare charts. Beaglebone

I have a problem trying to compare the uart input data (from a GPS) with '$' in order to detect a new package. I am sure that the problem is in how I manipulate the charRead variable. I tried one thousand of things, but probably because of my inexperience I have not figured out what it is the problem.
The code compiles and the data is coming all the time, but once I load the code into the beaglebone, it gets stacked but and it doesn't enter in the "if (charRead =='$')".
Thank you in advance!
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <time.h>
#include <iostream>
#include <termios.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <string.h>
#include <ctype.h>
#include <math.h>
#include <limits.h>
#include "Payload.h"
#define SLOTS "/sys/devices/bone_capemgr.9/slots"
#define CR 0x0d
#define SPACE 0x20
#define COMMA 0x2C
#define MAXSIZE 100
unsigned long time_data;
unsigned int button = 45;
int i,z =0, j=0, value;
int rx_length;
int main()
{
//uart4 configuration using termios
int fd;
//unsigned char *mess;
unsigned int value = 0;
gpio_export(button);
//Wait until the button is pushed
while (value != 1){
if (z==0){
printf("waiting\n");}
z++;
gpio_get_value(button, &value);}
//OPEN THE UART
//open uart4 for tx/rx, not controlling device
if((fd = open("/dev/ttyO4", O_RDONLY | O_NOCTTY|O_NONBLOCK)) < 0){
printf("Unable to open uart4 access.\n");
}
termios uart4;
cfsetospeed(&uart4, B9600); //Set the speed
//set attributes of uart4
uart4.c_iflag = 0;
uart4.c_oflag = 0;
uart4.c_lflag = 0;
tcsetattr(fd, TCSANOW, &uart4);
//----- CHECK FOR ANY RX BYTES -----
// Read up to 100 characters from the port if they are there
unsigned char stringRead[MAXSIZE];
unsigned char charRead;
do{
if (rx_length = read(fd, (void*)charRead, MAXSIZE)>0){
if (charRead =='$'){
i=0;
stringRead[i] = charRead; //Store in the first position of the char --> $
do {
rx_length = read(fd, (void*)charRead, MAXSIZE); //Read the next bit
if( (charRead != '\0') ) {
i++;
stringRead[i] = charRead; //write into stringRead
}
} while(charRead != 'CR'); //ASCII Carriage Return
stringRead[i+1] = charRead;
printf("%s", stringRead);
}}
if (rx_length==0){
//No data
}
gpio_get_value(button, &value);
}while (value!=0);
gpio_unexport(button);
close(fd);
return 0;
}
You're passing a cast of the variable value of charRead rather than a pointer to a memory location as the function read() expects void *.
read(fd, (void*)charRead, MAXSIZE)
You need to either read one character at a time:
read(fd, &charRead, 1)
Or change your reading logic to maximize amount read and data processing. I also recommend adding a bounds check on accessing stringRead.
// The following should handle the reading of a GPS NMEA message and display it
// I have not run the program, but compiling it was successful
// note:
// 1) the handling of the 'i' variable
// 2) the calls to reading the GPS input
// 3) the handling of error conditions
// 4) the simple logic flow
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <time.h>
//#include <iostream> // this is not C++ so this line not needed
#include <termios.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <string.h>
#include <ctype.h>
#include <math.h>
#include <limits.h>
#include "Payload.h"
// #define SLOTS "/sys/devices/bone_capemgr.9/slots" // not used, raises compiler warning
#define CR (0x0D)
// #define SPACE (0x20) // not used, raises compiler warning
// #define COMMA (0x2C) // not used, raises compiler warning
#define MAXSIZE (100)
#define BUTTON_PORT (45)
// unsigned long time_data; // not used, raises compiler warning
// int j=0; // not used, raises compiler warning
// int value = 0; // not used, raises compiler warning about variable masking
int main()
{
int i;
int z = 0; // flag used to control execution flow
int rx_length; // return status value from read()
//uart4 configuration using termios
int fd; // file descriptor number
//unsigned char *mess; // not used, raises compiler warning
unsigned int value = 0;
gpio_export(BUTTON_PORT);
//Wait until the button is pushed
// burn mass CPU cycles, while waiting
while (0 == value)
{
if (z==0)
{
printf("waiting\n");
z++; // to stop re-entry to this 'if' block
}
// suggest using nsleep() to free up CPU
gpio_get_value(BUTTON_PORT, &value);
} // end while
//open uart4 for rx
if((fd = open("/dev/ttyO4", O_RDONLY | O_NOCTTY|O_NONBLOCK)) < 0)
{
perror("open failed for /dev/tty04");
exit(1);
}
// implied else, open successful
termios uart4;
cfsetospeed(&uart4, B9600); //Set the speed to match the GPS output
//set attributes of uart4
// Note: probably better to read the current termois values
// then modify them to the desired states
uart4.c_iflag = 0;
uart4.c_oflag = 0;
uart4.c_lflag = 0;
tcsetattr(fd, TCSANOW, &uart4);
//----- CHECK FOR ANY RX BYTES -----
// Read up to 100 characters from the port if they are there
unsigned char stringRead[MAXSIZE]; // will contain a GPS NMEA message
unsigned char charRead; // input buffer
do{
while(1)
{
rx_length = read(fd, &charRead, 1);
if( 0 == rx_length )
{ // this will execute a lot since fd set to non-blocking
; // do nothing, while hogging CPU cycles
// suggest using nsleep() to free CPU
}
else if( 0 > rx_length )
{
perror( "read failed" );
exit(1);
}
else if (charRead =='$')
{
stringRead[0] = charRead; //Store first char of NMEA GPS message
i=1; // index for second char of NMEA message from GPS
}
else
{
stringRead[i] = charRead; //Store char
i++; // index for next char into stringRead buffer
if( MAXSIZE <= i )
{ // then overrun input buffer
perror( "read- overrun input buffer, GPS message too long");
exit(2);
}
if( CR == charRead ) //ASCII Carriage Return - end of message
{ // then, got complete message
break; // exit read loop, so can process message
}
} // end if
} // end while
stringRead[i] = '\0'; // terminate string so it can be printed
printf("%s", stringRead);
// get button state via BUTTON_PORT(45)
gpio_get_value(BUTTON_PORT, &value);
} while (value!=0); // then read next gps message
gpio_unexport(BUTTON_PORT);
close(fd);
return 0;
}

record using /pulse/simple.h

i am trying to record my voice from the microphone on my laptop using the simple.h pulseaudio header file into an array, but i cant seem to figure it out. Every time i record and i replay my recording , it is a high pitched beep i followed examples, etc but i can't seem to get this down can someone please help me .
I am basically hacking the example "parec-simple.c" given in the doxygen page. I've tried routing the output of buf to stdout, then using libre-office calc to plot a graph to see if the output looks anything like sound but it does not.
here is the code i used
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <pulse/simple.h>
#include <pulse/error.h>
#define BUFSIZE 1024
FILE *output;
/* A simple routine calling UNIX write() in a loop */
void loop_write(uint8_t *data) {
register int size = 1023;
while (size > 0)
{
fprintf(output,"%"SCNu8"\n",data[size] ) ;
size --;
}
}
int main(int argc, char*argv[]) {
output = fopen("/home/donnell/output", "w");
/* The sample type to use */
static const pa_sample_spec ss = {
.format = PA_SAMPLE_S16LE,
.rate = 41000,
.channels = 2
};
pa_simple *s = NULL;
int ret = 1;
int error;
/* Create the recording stream */
if (!(s = pa_simple_new(NULL, argv[0], PA_STREAM_RECORD, NULL, "record", &ss, NULL, NULL, &error))) {
fprintf(stderr, __FILE__": pa_simple_new() failed: %s\n", pa_strerror(error));
goto finish;
}
for (;;) {
uint8_t buf[BUFSIZE];
/* Record some data ... */
if (pa_simple_read(s, buf, sizeof(buf), &error) < 0) {
fprintf(stderr, __FILE__": pa_simple_read() failed: %s\n", pa_strerror(error));
goto finish;
}
/* and write it to fle*/
loop_write(buf);
}
ret = 0;
finish:
if (s)
pa_simple_free(s);
return ret;
}

Resources