Segmentation fault (core dumped) with pulseaudio lib on c - c

I'm new to Stackoverflow and c and pulseaudio. Thanks for all help.
I get a the Segmentation fault (core dumped) error in the mainloop of a custom pulseaudiolib code. It it takes 1 to 30s to apear.
I am trying to get the audio data of a custom sink
pacmd load-module module-null-sink sink_name=MySink
pacmd update-sink-proplist MySink device.description=MySink
pacmd load-module module-loopback sink=MySink
use its data and pip it back to the speaker.
I'm pretty new at C and pulseaudio so I used the doc and https://menno.io/posts/pulseaudio_monitoring/
This is my code:
#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>
#include <pulse/context.h>
#include <pulse/def.h>
#include <pulse/format.h>
#include <pulse/introspect.h>
#include <pulse/stream.h>
#include <pulse/thread-mainloop.h>
const char * SINKNAME = "MySink";
const char * SPEAKNAME = "alsa_output.pci-0000_05_00.6.analog-stereo";
char found = 0;
const uint32_t RATE = 344;
pa_stream * gStream = NULL;
void stream_read_cb(pa_stream *stream, size_t length, void *index_incr){
printf("in read\n");
const void * samples[length];
size_t * leng;
(*leng) = length;
printf("length : %d, %d\n",length,(*leng));
int res = pa_stream_peek(stream, samples, leng);
pa_stream_drop(stream);
if(gStream != NULL){
int result = pa_stream_write( gStream, samples,length, NULL,0, PA_SEEK_RELATIVE);
}
printf("[");
if (res == 0){
for(int i = 0 ; i< length; i++){
printf("%d,",samples[i]);
}
}
printf("]\n");
}
void sink_info_cb(pa_context* context, const pa_sink_info *sink_info_p, int eol, void *userdata){
printf( "in sinkinfo\n");
const pa_sink_info* sink_info = sink_info_p;
if(found !=1){
printf( "index: %d\n", (*sink_info).index);
printf("help\n");
printf( "name: %s\n", (*sink_info).name);
printf( "description: %s\n", (*sink_info).description);
printf("searchName: %s\n",SINKNAME);
if (strcmp((*sink_info).name, SINKNAME) == 0){
found = 1;
// Found the sink we want to monitor for peak levels.
// Tell PA to call stream_read_cb with peak samples.
printf( "setting up peak recording using: %s\n ", (*sink_info).monitor_source_name);
pa_sample_spec *samplespec;
(*samplespec).channels = 1;
(*samplespec).format = PA_SAMPLE_U8;
(*samplespec).rate = RATE;
pa_stream * stream = pa_stream_new(context, "peak detect demo", samplespec, NULL);
pa_stream_set_read_callback(stream,
stream_read_cb,
( *sink_info).index);
pa_stream_connect_record(stream,
(*sink_info).monitor_source_name,
NULL,
PA_STREAM_PEAK_DETECT);
printf("settetd \n");
}/*
if((*sink_info).name[0] == 'a'){
//printf( "setting up peak recording using: %s\n ", (*sink_info).monitor_source_name);
//pa_sample_spec *samplespec;
// (*samplespec).channels = 1;
// (*samplespec).format = PA_SAMPLE_U8;
// (*samplespec).rate = RATE;
printf("set gStream");
//gStream = pa_stream_new(context, "peak detect demo", samplespec, NULL);
//printf("gSteam setted\n");
}*/
printf("out sink\n");
}
}
void context_notify_cb(pa_context *context, void *userdata){
printf("in context\n");
pa_context_state_t state = pa_context_get_state(context);
if( state == PA_CONTEXT_READY){
printf( "Pulseaudio connection ready...");
// Connected to Pulseaudio. Now request that sink_info_cb
// be called with information about the available sinks.
pa_operation * o = pa_context_get_sink_info_list(context, sink_info_cb, userdata);
pa_operation_unref(o);
}
else if( state == PA_CONTEXT_FAILED){
printf( "Connection failed");
}
else if( state == PA_CONTEXT_TERMINATED){
printf( "Connection terminated");
}
printf("out context\n");
}
void init(){
// Wrap callback methods in appropriate ctypefunc instances so
// that the Pulseaudio C API can call them
printf("in init\n");
pa_context_notify_cb_t _context_notify_cb;
//context_notify_cb(context_notify_cb void ** userdata);
pa_sink_info_cb_t(sink_info_cb);
pa_stream_request_cb_t(stream_read_cb);
// Create the mainloop thread and set our context_notify_cb
// method to be called when there's updates relating to the
// connection to Pulseaudio
pa_threaded_mainloop* _mainloop = pa_threaded_mainloop_new();
pa_mainloop_api* _mainloop_api = pa_threaded_mainloop_get_api(_mainloop);
pa_context *context = pa_context_new(_mainloop_api, "peak_demo");
pa_context_set_state_callback(context, context_notify_cb,NULL);
pa_context_connect(context, NULL, 0, NULL);
pa_threaded_mainloop_start(_mainloop);
printf("out intit\n");
}
int main(int argc, char*argv[]) {
init();
printf("Hello World\n");
while(1){
;
}
printf("end World\n");
return 0;
}
if I try to uncomment
/*
if((*sink_info).name[0] == 'a'){
//printf( "setting up peak recording using: %s\n ", (*sink_info).monitor_source_name);
//pa_sample_spec *samplespec;
// (*samplespec).channels = 1;
// (*samplespec).format = PA_SAMPLE_U8;
// (*samplespec).rate = RATE;
printf("set gStream");
//gStream = pa_stream_new(context, "peak detect demo", samplespec, NULL);
//printf("gSteam setted\n");
}
*/
the error shots like directly.
the output:
...
in read
length : 1, 1
[-1261830080,]
in read
length : 6, 6
[-1246625728,-1017902384,0,0,-1017902304,591610535,]
in read
length : 1, 1
[-1259864000,]
in read
length : 6, 6
[-1227227072,-1017902384,0,0,-1017902304,591610535,]
in read
length : 1, 1
[-1255800768,]
in read
length : 6, 6
[-1234960320,-1017902384,0,0,-1017902304,591610535,]
in read
length : 7, 7
[-1249247168,-939474438,-1017902512,-1017902384,0,0,-1017902304,]
in read
length : 7, 7
[-1242693568,-939474438,-1017902464,-1017902336,0,0,-1017902256,]
Segmentation fault (core dumped)
the uncomment output:
in init
in context
out context
out intit
Hello World
in context
out context
in context
out context
in context
Pulseaudio connection ready...out context
in sinkinfo
index: 0
help
name: alsa_output.pci-0000_05_00.6.analog-stereo
description: Family 17h (Models 10h-1fh) HD Audio Controller Analog Stereo
searchName: MySink
set gStreamout sink
in sinkinfo
index: 1
help
name: MySink
description: MySink
searchName: MySink
setting up peak recording using: MySink.monitor
settetd
Segmentation fault (core dumped)

Related

SDL audio capture callbacks slower than playback

SDL capture audio callbacks seem to be called once for every 12 playback callbacks. Am I doing something wrong? This feels like an SDL or PulseAudio bug.
The program below prints "Reading audio..." once every ~12 "Writing audio..." prints. Tested via running the command directly, through gdb, and through Valgrind.
I've tried this in both C and Golang (using github.com/veandco/go-sdl2/sdl), on the same machine.
C code:
// A test program to copy audio in (microphone) to audio out (speaker) via SDL.
//
// Compile: cc inout.c -o inout -lSDL2
// Run: ./inout
#include <SDL2/SDL.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#define BUF_SIZE 1024
// Stereo float32 samples.
static uint8_t saved[BUF_SIZE*2*sizeof(float)];
// Copies audio callback data into the saved buffer.
void audioReader(void* udata, uint8_t* buf, int len) {
fprintf(stderr, "Reading audio: %d -> %ld bytes\n", len, sizeof(saved));
memcpy(saved, buf, len);
}
// Copies saved audio data into the callback buffer.
void audioWriter(void* udata, uint8_t* buf, int len) {
fprintf(stderr, "Writing audio: %ld -> %d bytes\n", sizeof(saved), len);
memcpy(buf, saved, len);
}
// List all devices of the given type, and return the name of the first or NULL.
// Caller must free the returned pointer.
char* ChooseDevice(int is_capture) {
int dev_cnt = SDL_GetNumAudioDevices(is_capture);
if (dev_cnt < 1) {
fprintf(stderr, "No %s devices: %s\n", is_capture ? "capture" : "playback", SDL_GetError());
return NULL;
}
printf("%s devices:\n", is_capture ? "capture" : "playback");
char* dev_name = NULL;
for (int i = 0; i < dev_cnt; i++) {
printf("%c %s\n", !dev_name ? '*' : ' ', SDL_GetAudioDeviceName(i, is_capture));
if (!dev_name) {
const char* tmp = SDL_GetAudioDeviceName(i, is_capture);
dev_name = malloc(strlen(tmp)+1);
strcpy(dev_name, tmp);
}
}
if (!dev_name) {
fprintf(stderr, "No %s devices\n", is_capture ? "capture" : "playback");
}
return dev_name;
}
// Opens and unpauses the first device of the given type, returning its ID, or
// returns 0.
SDL_AudioDeviceID OpenDevice(int is_capture) {
char* dev_name = ChooseDevice(is_capture);
if (!dev_name) return 0;
SDL_AudioSpec spec;
SDL_memset(&spec, 0, sizeof(spec));
spec.freq = 48000;
spec.format = AUDIO_F32;
spec.channels = 2;
spec.samples = BUF_SIZE;
spec.callback = is_capture ? audioReader : audioWriter;
SDL_AudioDeviceID dev_id = SDL_OpenAudioDevice(dev_name, is_capture, &spec, NULL, 0);
if (dev_id == 0) {
fprintf(stderr, "Failed to open %s device %s: %s\n", is_capture ? "input" : "output", dev_name, SDL_GetError());
return 0;
}
free(dev_name);
SDL_PauseAudioDevice(dev_id, SDL_FALSE);
return dev_id;
}
int main(int argc, char** argv) {
SDL_memset(saved, 0, sizeof(saved));
if (SDL_Init(SDL_INIT_AUDIO) < 0) {
fprintf(stderr, "Failed to initialize SDL audio: %s\n", SDL_GetError());
return 1;
}
SDL_AudioDeviceID in_dev_id = OpenDevice(/* is_capture = */ SDL_TRUE);
if (in_dev_id == 0) return 1;
SDL_AudioDeviceID out_dev_id = OpenDevice(/* is_capture = */ SDL_FALSE);
if (out_dev_id == 0) return 1;
SDL_Delay(10000); // 10 seconds
SDL_CloseAudioDevice(in_dev_id);
SDL_CloseAudioDevice(out_dev_id);
SDL_Quit();
return 0;
}

Segmentation fault multithreading with file open

I created a program to get all files in a directory, find the individual checksums and then find the total checksums using multithreading.
I am receiving a segmentation fault so I ran gdb and saw that the error is on line 60 where open() is. After researching the seg fault on SO, and on other forums, I attempted to implement a few different approaches such as changing open() to fopen() with a FILE *handle rather than an int. That change proved incorrect.
After hours of debugging and searching, I am clueless and would greatly appreciate any insight.
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <stdarg.h>
#include <fcntl.h>
#include <time.h>
#include <sys/types.h>
#include <dirent.h>
#include <pthread.h> ///Compile with -pthread or -lpthread
#include <sys/stat.h>
#define BUFFER_SIZE (1<<16)
void cleanup();
void get_filenames();
void* get_checksum();
char **filenames;
int file_cnt;
DIR *dir;
//int handle;
FILE *handle;
unsigned int checksum;
unsigned char* ptr;
int length;
int count;
unsigned char* buffer;
int* sum;
unsigned int total = 0;
int main(int argc, char *argv[]){
int i;
pthread_t* file;
atexit(cleanup);
get_filenames();
printf("There are %d files:\n", file_cnt);
file = calloc(sizeof(pthread_t), file_cnt);
sum = calloc(sizeof(int), file_cnt);
for(i=0; i<file_cnt; i++){
printf("%s\n", filenames[i]);
pthread_create(&(file[i]), NULL, get_checksum, (void*)&filenames[i]);
}
for(i=0; i<file_cnt; i++){
total += sum[i];
}
printf("total is: %u\n", total);
return EXIT_SUCCESS;
}
void* get_checksum(void* a){
int b = *((int *)a);
//handle = open(filenames[b], O_RDONLY); //SEG FAULT HERE
handle = fopen(filenames[b], "r"); //SEG FAULT HERE
if( handle == NULL ){
printf( "Can't open file: %s\n", filenames[b]);
exit(1);
}
buffer = malloc(BUFFER_SIZE);
if( buffer == NULL ){
printf( "Can't get enough memory\n" );
exit(1);
}
checksum = 0;
do{
//length = read( handle, buffer, BUFFER_SIZE );
length = read( handle, buffer, (sizeof(char)));
if( length == -1 ){
printf( "Error reading file: %s\n", filenames[b]);
//return NULL;
exit(1);
}
ptr = buffer;
count = length;
while( count-- ){
checksum = checksum + (unsigned int)( *ptr++ );
sum[b] = checksum;
}
} while( length );
printf("Checksum= %d\nTimes at: %d\n", checksum, (int)clock());
}
void cleanup() {
if(filenames && file_cnt > 0) {
while(file_cnt-- > 0) {
if(filenames[file_cnt]) {
free(filenames[file_cnt]);
}
}
free(filenames);
}
if(dir) {
closedir(dir);
}
return;
}
void get_filenames() {
struct dirent *dir_entry;
if((dir = opendir(".")) == NULL) {
fprintf(stderr, "Couldn't open the directory entry for reading\n");
exit(1);
}
errno = 0;
file_cnt = 0;
while((dir_entry = readdir(dir)) != NULL) {
char **new_filenames = filenames;
static int realative_dirs = 0;
if(realative_dirs < 2 &&
(strcmp(".", dir_entry->d_name) == 0 || strcmp("..", dir_entry->d_name) == 0)
) {
realative_dirs++;
continue;
}
new_filenames = (char **)realloc(filenames, sizeof(char **) * (file_cnt + 1));
if(new_filenames == NULL) {
free(filenames[file_cnt]);
fprintf(stderr, "Could not allocate reference for filename[%d]\n", file_cnt);
exit(1);
}
filenames = new_filenames;
filenames[file_cnt] = (char *)calloc(strlen(dir_entry->d_name) + 1, sizeof(char));
if(filenames[file_cnt] == NULL) {
fprintf(stderr, "Could not allocate memory for filename[%d]'s string: \"%s\"\n",
file_cnt, dir_entry->d_name);
exit(1);
}
strcpy(filenames[file_cnt], dir_entry->d_name);
file_cnt++;
}
if(errno != 0) {
fprintf(stderr, "An error occured getting the filenam list\n");
exit(1);
}
return;
}
Below is the output and gdb debugging:
There are 24 files:
.windows
.xscreensaver
.alias
.cshrc
Segmentation fault
(gdb) run
Starting program: /home/nolooking/a.out
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib64/libthread_db.so.1".
There are 24 files:
.windows
[New Thread 0x7ffff781e700 (LWP 15957)]
.xscreensaver
[New Thread 0x7ffff701d700 (LWP 15958)]
Program received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0x7ffff781e700 (LWP 15957)]
0x0000000000400d53 in get_checksum (a=0x60b610) at checksum.c:60
60 handle = open(filenames[b], O_RDONLY);
(gdb) backtrace
#0 0x0000000000400d53 in get_checksum (a=0x60b610) at checksum.c:60
#1 0x00007ffff7bc6374 in start_thread () from /lib64/libpthread.so.0
#2 0x00007ffff7907c3d in clone () from /lib64/libc.so.6
(gdb) quit
A debugging session is active.
UPDATE:
I took the advice of one user in the comments who suggested that I use:
handle=fopen((char*)a, "r");. I can successfully print out the file names when the if statement if(handle==NULL) is commented out. When I include that if statement I receive the following output:
There are 24 files:
.windows
.xscreensaver
.alias
.cshrc
Can't open file: p▒`
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <stdarg.h>
#include <fcntl.h>
#include <time.h>
#include <sys/types.h>
#include <dirent.h>
#include <pthread.h>
#include <sys/stat.h>
#define BUFFER_SIZE (1<<16)
void cleanup();
void get_filenames();
void* get_checksum();
char **filenames;
int file_cnt;
DIR *dir;
//int handle;
FILE *handle;
unsigned int checksum;
unsigned char* ptr;
int length;
int count;
unsigned char* buffer;
int* sum;
unsigned int total = 0;
int main(int argc, char *argv[]){
int i;
pthread_t* file;
atexit(cleanup);
get_filenames();
printf("There are %d files:\n", file_cnt);
file = calloc(sizeof(pthread_t), file_cnt);
sum = calloc(sizeof(int), file_cnt);
for(i=0; i<file_cnt; i++){
printf("%s\n", filenames[i]);
pthread_create(&(file[i]), NULL, get_checksum, (void*)&filenames[i]);
}
for(i=0; i<file_cnt; i++){
total += sum[i];
}
printf("total is: %u\n", total);
return EXIT_SUCCESS;
}
void* get_checksum(void* a){
int b = *((int *)a);
handle = fopen(((char*)a), "r");
if( handle == NULL ){
printf( "Can't open file: %s\n", ((char*)a));
exit(1);
}
buffer = malloc(BUFFER_SIZE);
if( buffer == NULL ){
printf( "Can't get enough memory\n" );
exit(1);
}
checksum = 0;
do{
length = read( handle, buffer, BUFFER_SIZE );
if( length == -1 ){
printf( "Error reading file: %s\n", ((char*)a));
//return NULL;
exit(1);
}
ptr = buffer;
count = length;
while( count-- ){
checksum = checksum + (unsigned int)( *ptr++ );
//sum[a] = checksum;
}
} while( length );
printf("Checksum= %d\nTimes at: %d\n", checksum, (int)clock());
}
void cleanup() {
if(filenames && file_cnt > 0) {
while(file_cnt-- > 0) {
if(filenames[file_cnt]) {
free(filenames[file_cnt]);
}
}
free(filenames);
}
if(dir) {
closedir(dir);
}
return;
}
void get_filenames() {
struct dirent *dir_entry;
if((dir = opendir(".")) == NULL) {
fprintf(stderr, "Couldn't open the directory entry for reading\n");
exit(1);
}
errno = 0;
file_cnt = 0;
while((dir_entry = readdir(dir)) != NULL) {
char **new_filenames = filenames;
static int realative_dirs = 0;
if(realative_dirs < 2 &&
(strcmp(".", dir_entry->d_name) == 0 || strcmp("..", dir_entry->d_name) == 0)
) {
realative_dirs++;
continue;
}
new_filenames = (char **)realloc(filenames, sizeof(char **) * (file_cnt + 1));
if(new_filenames == NULL) {
free(filenames[file_cnt]);
fprintf(stderr, "Could not allocate reference for filename[%d]\n", file_cnt);
exit(1);
}
filenames = new_filenames;
filenames[file_cnt] = (char *)calloc(strlen(dir_entry->d_name) + 1, sizeof(char));
if(filenames[file_cnt] == NULL) {
fprintf(stderr, "Could not allocate memory for filename[%d]'s string: \"%s\"\n",
file_cnt, dir_entry->d_name);
exit(1);
}
strcpy(filenames[file_cnt], dir_entry->d_name);
file_cnt++;
}
if(errno != 0) {
fprintf(stderr, "An error occured getting the filenam list\n");
exit(1);
}
return;
}
Why I am receiving that output once I uncomment the if statement?
Change this
pthread_create(&(file[i]), NULL, get_checksum, (void*)&filenames[i]);
to be
pthread_create(&(file[i]), NULL, get_checksum, (void*)i);
and this
int b = *((int *)a);
to be
int b = (int)a;
Also you cannot call read() on a FILE* as it is returned by fopen(). Use fread() instead.
Don't use &i. I'll explain in a bit. The argument you're passing to the thread is wrong a is not an integer. It's meant to be a pointer to a string...
Change the thread create to this...
pthread_create(&(file[i]), NULL, get_checksum, filenames[i]);
then print the string as follows...
void* get_checksum(void *a){
char *file_name = (char *)a;
printf("filename=%s\n", file_name);
You're passing the string as a pointer to the called function. In your code you're trying to use this as an index into the array.
If you want to pass the index as an integer beware... this won't work..
pthread_create(&(file[i]), NULL, get_checksum, &i);
This is multithreaded and the value pointed to by &i is changing as the loop runs. Pass the pointer to the string and do not under any circumstances change filenames as the threads run.
I think your problem is simply because you are passing &filenames[i] instead of simply &i.
Then in void* get_checksum(void* a) you are trying to use a char* as an int.
The code would be more like :
for(i=0; i<file_cnt; i++){
printf("%s\n", filenames[i]);
pthread_create(&(file[i]), NULL, get_checksum, (void*)&i);
}
and in void* get_checksum(void* a) :
int b = *((int *)a);
handle = fopen(filenames[b], "r");
if( handle == NULL ){
printf( "Can't open file: %s\n", filenames[b]);
exit(1);
}

Mysterious Redis C core dump

I am currently running a C program calling a Redis Server instance. After the 1020th iteration, it always bombs with:
Redis Connect 1021 Error: System error Segmentation fault (core
dumped)
Ugh. Something tells me one of the pointers decided to go wild. Can anyone help here? I am using the current version of Ubuntu Linux
//codingsteps.com/installing-using-hiredis-c-client-library-for-redis/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "hiredis.h"
void redisTest(void) {
redisReply *reply;
long int i;
// Start measuring time
clock_t start = clock();
// For local connections:
//redisContext *c = redisConnect("127.0.0.1", 6379);
redisContext *c = redisConnect("localhost", 6379);
// For connections to a remote Redis server:
//redisContext *c = redisConnect
// ("ec2-**-**-***-**.compute-1.amazonaws.com", 6379);
if (c->err) {
printf("Error: %s\n", c->errstr);
}else{
printf("Connection Made! \n");
}
// Get all keys for testing
//reply = redisCommand(c, "keys %s", "*");
reply = redisCommand(c, "lrange EUR 0 10", "*");
if ( reply->type == REDIS_REPLY_ERROR )
printf( "Error: %s\n", reply->str );
else if ( reply->type != REDIS_REPLY_ARRAY )
printf( "Unexpected type: %d\n", reply->type );
else {
for ( i=0; i<reply->elements; ++i ){
printf( "Result:%lu: %s\n", i,
reply->element[i]->str );
}
}
printf( "Total Number of Results: %lu\n", i );
// Output Elapsed time
printf ( "%f Seconds\n", ( (double)clock() - start ) /
CLOCKS_PER_SEC );
redisFree(c);
freeReplyObject(reply);
}
int main(void) {
int i = 0;
for(;;) {
printf("\n\nRedis Connect %d\n",i++);
redisTest();
}
}
Update: I added redisFree() as suggested by others (thanks for that). This still core dumps but after 28233 iterations.

System-calls with c

Hi I'm trying to make a couple pipes in c for communication between a 'server' and an 'interface'. I'm getting a weird error though that I'm having trouble debugging. I've been looking at this for a while and I'm afraid that I'm looking past it at this point. Any help will be greatly appreciated.
//server file
// include needed libraries
#include <errno.h> // system error numbers
#include <stdio.h> // Standard Input and Output Library
#include <stdlib.h> // Standard General Utilities Library
#include <string.h> // strings and arrays
#include <sys/types.h> // needed for pipes to work
#include <sys/wait.h> // for waitpid
#include <unistd.h> // sleep
#define BUFLENMES 65
#define BUFLEN2 1024
typedef struct {
char id[8];
int odometer;
float gallons;
} gasData;
// function prototype for comparing ID values
// using void in order to use built-in sort function
int compareID(const void *, const void *);
/**************** Main function *******************/
int main (int argc, char *argv[]) {
// initialize values for file reading
int iter = 0,
value = 0,
command,
outputFD;
// set up based on spaces used for delimtation
char id[8],
odometer[6],
gallons[8],
err,
buffer[BUFLEN2+1];
// get input and output file descriptors for pipes
err = sscanf (argv[1], "%d", &command);
if (err == 0) {
printf("Parameter must be an integer.\n");
exit(2);
}
err = sscanf (argv[2], "%d", &outputFD);
if (err == 0) {
printf("Parameter must be an integer.\n");
exit(2);
}
// initialize struct
gasData gasRecords[20];
// open file that contains the gas data
FILE *iFile;
iFile = fopen ("./gasData.txt", "r");
//read file for records
do {
value = fscanf (iFile, "%8s", id);
value = fscanf (iFile, "%6s", odometer);
value = fscanf (iFile, "%8s", gallons);
//store values in gasRecords struct
strcpy(gasRecords[iter].id, id);
sscanf (odometer, "%d", &gasRecords[iter].odometer);
sscanf (gallons, "%f", &gasRecords[iter].gallons);
// move to next record
iter++;
} while (value != EOF);
fclose(iFile);
// use iter to print records stored into struct
printf("\nRecords Stored\n");
for(int i = 0; i < (iter -1) ; i++) {
printf("element = %d: ", i);
printf("id = %s, ", gasRecords[i].id);
printf("odometer = %d, ", gasRecords[i].odometer);
printf("gallons = %f\n", gasRecords[i].gallons);
}
printf("\n");
/***************** act as server ****************/
int odom[iter-1],
count;
float averageMPG;
// checking commands
do {
char subString[8],
finalMessage[BUFLEN2+1],
message[BUFLENMES+1],
temp[20];
err = read (command, buffer, BUFLEN2);
if (err == -1 ) {
printf ("Error on read from pipe [server]: %d\n", errno);
exit (3);
}
buffer[BUFLEN2] = '\0';
if(strstr(buffer, "list,")) {
count = 0;
// get second part of command after the firs 5 chars
for(int i =0; i < 10; i++) {
subString[i] = buffer[i + 5];
}
// loop through structure for other IDs
for(int i =0; i < (iter-1); i++) {
if(!strcmp(gasRecords[i].id, subString)) {
odom[i] = gasRecords[i].odometer;
}
}
// sort using compareID below and qsort
qsort(odom, (iter-1), sizeof(int), compareID);
while(count < (iter-1)) {
// for each element in odom, check gasRecords
for(int i=0; i < (iter-1); i++) {
// if both the ID and the odometer match, send back to interface
if(!strcmp(gasRecords[i].id, subString) &&
odom[count] == gasRecords[i].odometer) {
char message2[65],
temp2[20];
sprintf(temp2, "element %d: ", i);
strcpy(message2, temp2);
sprintf(temp2, "id = %s, ", gasRecords[i].id);
strcat(message2, temp2);
sprintf(temp2, "odometer = %d, ", gasRecords[i].odometer);
strcat(message2, temp2);
sprintf(temp2, "gallons %f\n", gasRecords[i].gallons);
strcat(message2, temp2);
strcat(finalMessage, message2);
}
}
count++;
}
strcat(finalMessage, '\0');
err = write (outputFD, finalMessage, strlen(finalMessage)+1);
if (err == -1 ) {
printf ("Error on write to interface: %d\n", errno);
exit (3);
}
}
else if(strstr(buffer, "mpg,")) {
averageMPG = 0.0;
count = 0;
// get ID into subString
for(int i = 0; i < 10; i++) {
subString[i] = buffer[i + 4];
}
// search for mpg data for id and add it up
for(int i = 0; i < (iter-1); i++) {
if(!strcmp(gasRecords[i].id, subString)) {
averageMPG += gasRecords[i].gallons;
count++;
}
}
sprintf(temp, "Average MPG = %f\n", (averageMPG/count));
strcpy(message, temp);
message[BUFLENMES] = '\0';
err = write (outputFD, message, strlen(message)+1);
if (err == -1 ) {
printf ("Error on write to interface: %d\n", errno);
exit (3);
}
}
// if exit is entered print "response: Server complete."
else if(!strcmp(buffer, "exit")) {
strcpy(message, "Server complete");
message[BUFLENMES] = '\0';
err = write (outputFD, message, strlen(message)+1);
if (err == -1 ) {
printf ("Error on write to interface: %d\n", errno);
exit (3);
}
}
// check for invalid command
else {
strcpy(message, "Invalid command");
message[BUFLENMES] = '\0';
err = write (outputFD, message, strlen(message)+1);
if (err == -1 ) {
printf ("Error on write to interface: %d\n", errno);
exit (3);
}
}
} while(strcmp(buffer, "exit"));
return 0;
}
/****************** Function *********************/
int compareID(const void *first, const void *second) {
int f = *((int*)first);
int s = *((int*)second);
if (f > s)
return 1;
else if (s > f)
return -1;
else
return 0;
}
Here's my interface file
// interface file
#include <errno.h> // system error numbers
#include <stdio.h> // Standard Input and Output Library
#include <stdlib.h> // Standard General Utilities Library
#include <string.h> // strings and arrays
#include <sys/types.h> // needed for pipes to work
#include <sys/wait.h> // for waitpid
#include <unistd.h> // sleep
// define buffer length
#define BUFLEN 1024
int main (int argc, char *argv[])
{
int err,
i,
id,
status,
pError;
char buffer[BUFLEN+1],
command[20],
tochild[2],
toparent[2];
int toChild[2]; // if toChild[1], then writting to child
int toParent[2]; // if toParent[1], then writting to parent
// turning tochild into a pipe and checking for an error
err = pipe(toChild);
if ( err == -1) {
printf ("Error on pipe creation: %d\n", errno);
exit (1);
}
err = pipe(toParent);
if ( err == -1) {
printf ("Error on pipe creation: %d\n", errno);
exit (1);
}
// create child process
id = fork ();
// if id = 0, in child process
if ( id == 0 ) {
// set up pipes for passing into server
close (toChild[1]);
close (toParent[0]);
sprintf(tochild, "%d", toChild[0]);
sprintf(toparent, "%d", toParent[1]);
tochild[1] = '\0';
toparent[1] = '\0';
// exec into server, print records, and wait for instructions
err = execl("server", "server", tochild, toparent, 0);
if ( err == -1) {
printf ("Error on execl: %d\n", errno);
exit (1);
}
}
// if id > 0, in parent process
else if ( id > 0 ) {
close (toChild[0]);
close (toParent[1]);
sleep(1);
do {
printf("Input command: ");
scanf("%s", command);
command[19] = '\0';
err = write (toChild[1], command, strlen(command)+1);
if (err == -1 ) {
printf ("Error on write to pipe: %d\n", errno);
exit (3);
}
// parent reads back reponse from server read toParent[0]
err = read (toParent[0], buffer, BUFLEN);
if (err == -1 ) {
printf ("Error on read from pipe: %d\n", errno);
exit (3);
}
buffer[BUFLEN] = '\0';
printf ("Response: %s", buffer);
printf("\n");
} while(strcmp(command, "exit") != 0);
pError = waitpid(-1, &status, 0);
printf("Interface: child process (%d) completed.\n", id);
printf("Interface: child process exit status = %d.\n", status);
printf("Interface: Complete.\n");
exit (0);
}
else{
printf("Error creating forked process");
exit (4);
}
}
// compilation and error
csci2>g++ -o server Server.c
csci2>g++ Interface3.c
csci2>a.out
Records Stored
element = 0: id = red, odometer = 90229, gallons = 13.500000
element = 1: id = red, odometer = 90345, gallons = 14.500000
element = 2: id = red, odometer = 90453, gallons = 14.200000
element = 3: id = green, odometer = 23000, gallons = 32.000000
element = 4: id = green, odometer = 23300, gallons = 31.500000
element = 5: id = green, odometer = 23546, gallons = 37.799999
element = 6: id = , odometer = 120000, gallons = 23.700001
element = 7: id = , odometer = 120200, gallons = 24.670000
element = 8: id = , odometer = 120423, gallons = 26.799999
element = 9: id = 9045, odometer = 67321, gallons = 30.100000
element = 10: id = 9045, odometer = 67412, gallons = 15.900000
element = 11: id = 9045, odometer = 67689, gallons = 18.900000
Input command: mpg,red
Response: Average MPG = 14.066667
Input command: mgp,green
Response: Invalid command
Input command: mpg,green
Response: Average MPG = 33.766668
Input command: mpg,9045
Response: Average MPG = 21.633334
Input command: list,red
Response: Average MPG = 21.633334
Input command: list,red
Broken pipe
/* end */
its worth noting that the middle id isn't being transferred correctly either.
I have a .txt file with this info in it:
red 90229 13.5
red 90345 14.5
red 90453 14.2
green 23000 32.0
green 23300 31.5
green 23546 37.8
1489 120000 23.7
1489 120200 24.67
1489 120423 26.8
9045 67321 30.1
9045 67412 15.9
9045 67689 18.9
I think I know what is wrong, it's this
buffer[BUFLEN] = '\0';
if the recieved message is smaller than that, then you are not nul terminating the string correctly, you should
buffer[err] = '\0';
because read() returns the number of bytes successfuly read.
And of course, the same applies to this buffer[BUFLEN2] = '\0';.

Serial communication not working. Readfile goes wrong

After hours of browsing and reading, I still can't figure out why my code isn't working. I saw similar code snippets on different websites, but I can't seem to get it to work. The writing part is working, but the reading goes wrong. Every 'real character' is followed by three null terminators. Writing a string of 19 characters works and the FPGA I am using gives the correct data on the display. The FPGA should reverse the input and send this pack to the serial port. In the Hyperterminal this is working without any problem.
Can someone maybe point me on my mistake and tell me what I am doing wrong?
Thanks in advance =)
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <time.h>
#include <commdlg.h>
//#include <windef.h>
#define BUFFERLENGTH 19
void writeToSerial(char *line, HANDLE hSerial, DWORD dwBytesWritten);
void printBuffer(char * buffRead, DWORD dwBytesRead);
int main(){
HANDLE hSerial;
COMMTIMEOUTS timeouts;
COMMCONFIG dcbSerialParams;
char *line, *buffWrite, *buffRead;
DWORD dwBytesWritten, dwBytesRead;
/* Create a handle to the serial port */
hSerial = CreateFile("COM3",
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
/* Check if the handle is valid */
if(hSerial == INVALID_HANDLE_VALUE){
if(GetLastError() == ERROR_FILE_NOT_FOUND){
printf("Serial port does not exist \n");
}else{
printf("Port occupied. Please close terminals!\n");
}
}else{
printf("Handle created\n");
/* Check the state of the comm port */
if(!GetCommState(hSerial, &dcbSerialParams.dcb)){
printf("Error getting state \n");
}else{
printf("Port available\n");
/* Configure the settings of the port */
dcbSerialParams.dcb.DCBlength = sizeof(dcbSerialParams.dcb);
/* Basic settings */
dcbSerialParams.dcb.BaudRate = CBR_57600;
dcbSerialParams.dcb.ByteSize = 8;
dcbSerialParams.dcb.StopBits = ONESTOPBIT;
dcbSerialParams.dcb.Parity = NOPARITY;
/* Misc settings */
dcbSerialParams.dcb.fBinary = TRUE;
dcbSerialParams.dcb.fDtrControl = DTR_CONTROL_DISABLE;
dcbSerialParams.dcb.fRtsControl = RTS_CONTROL_DISABLE;
dcbSerialParams.dcb.fOutxCtsFlow = FALSE;
dcbSerialParams.dcb.fOutxDsrFlow = FALSE;
dcbSerialParams.dcb.fDsrSensitivity= FALSE;
dcbSerialParams.dcb.fAbortOnError = TRUE;
/* Apply the settings */
if(!SetCommState(hSerial, &dcbSerialParams.dcb)){
printf("Error setting serial port state \n");
}else{
printf("Settings applied\n");
GetCommTimeouts(hSerial,&timeouts);
//COMMTIMEOUTS timeouts = {0};
timeouts.ReadIntervalTimeout = 50;
timeouts.ReadTotalTimeoutConstant = 50;
timeouts.ReadTotalTimeoutMultiplier = 10;
timeouts.WriteTotalTimeoutConstant = 50;
timeouts.WriteTotalTimeoutMultiplier= 10;
if(!SetCommTimeouts(hSerial, &timeouts)){
printf("Error setting port state \n");
}else{
/* Ready for communication */
line = "Something else\r";
//****************Write Operation*********************//
writeToSerial(line, hSerial, dwBytesWritten);
//***************Read Operation******************//
if(ReadFile(hSerial, buffRead, BUFFERLENGTH, &dwBytesRead, NULL)){
printBuffer(buffRead, dwBytesRead);
}
}
}
}
}
CloseHandle(hSerial);
system("PAUSE");
return 0;
}
void printBuffer(char * buffRead, DWORD dwBytesRead){
int j;
for(j = 0; j < dwBytesRead; j++){
if(buffRead[j] != '\0'){
printf("%d: %c\n", j, buffRead[j]);
}
}
}
void writeToSerial(char *line, HANDLE hSerial, DWORD dwBytesWritten){
WriteFile(hSerial, line, 19, &dwBytesWritten,NULL);
if(dwBytesWritten){
printf("Writing success, you wrote '%s'\n", line);
}else{
printf("Writing went wrong =[\n");
}
}
In this line:
if(ReadFile(hSerial, buffRead, BUFFERLENGTH, &dwBytesRead, NULL))
the buffRead parameter is an uninitialised pointer. Change the declaration to:
char *line, *buffWrite, buffRead [BUFFERLENGTH+1];
Hyper terminal probably doesn't display null characters so it's possible that your fpga is actually sending them.
You could try testing it with Br#y Terminal in hex mode, or looking at the line with an oscilloscope.

Resources