[EDIT]I added all my main code and some of the external functions used by this code. The code is quite long, but in summary it sends a message to a device measuring some parameters of the water in a container, and the device responds with the corresponding value measured by the sensor. After that the code uses this value to modify the level and temperature of water. Prints the current status of the container and makes a log.txt file.[/Edit]
I want to do a constructor object-oriented-like function in C, but the address of my structure and its members are not being changed after I malloc() them. I saw this answer Changing address contained by pointer using function and I got an idea of what my problem is, but still can't solve it. Below is my code that is doing the constructor:
udp.c
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include "udp.h"
#define BUF_SIZE 1000
#define HEADER_SIZE
typedef struct{
int socket;
char header[4];
float *send_value;
char *message_buffer;
}message;
void build_message(message **msg, int socket, char header[], float *send_value){
*msg = (message *)malloc(sizeof(message));
(*msg)->socket = socket;
strncpy((*msg)->header, header, 4);
(*msg)->send_value = send_value;
(*msg)->message_buffer = NULL;
(*msg)->message_buffer = malloc(BUF_SIZE);
//(**msg).message_buffer = (char *)(msg+sizeof(int) + sizeof(float *) + sizeof(char *)*3);
}
int prepara_socket_cliente(char *host, char *porta)
{
struct addrinfo hints;
struct addrinfo *result, *rp;
int sfd, s;
/* Obtain address(es) matching host/port */
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_family = AF_UNSPEC; /* Allow IPv4/ or IPv6 */
hints.ai_socktype = SOCK_DGRAM; /* Datagram socket */
hints.ai_flags = 0;
hints.ai_protocol = 0; /* Any protocol */
s = getaddrinfo(host, porta, &hints, &result);
if (s != 0) {
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(s));
exit(EXIT_FAILURE);
}
/* getaddrinfo() returns a list of address structures.
Try each address until we successfully connect(2).
If socket(2) (or connect(2)) fails, we (close the socket
and) try the next address. */
for( rp = result; rp != NULL; rp = rp->ai_next) {
sfd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
if (sfd == -1)
continue;
if (connect(sfd, rp->ai_addr, rp->ai_addrlen) != -1)
break; /* Success */
close(sfd);
}
if (rp == NULL) { /* No address succeeded */
fprintf(stderr, "Could not connect\n");
exit(EXIT_FAILURE);
}
freeaddrinfo(result); /* No longer needed */
return sfd;
}
float receive_message(message *msg){
ssize_t nread;
int len;
//sprintf(msg->message_buffer, "%s0.0", msg->header);
len = strlen(msg->message_buffer)+1;
int rc;
if (len + 1 > BUF_SIZE){
fprintf(stderr, "Ignoring long message in argument\n");
exit(EXIT_FAILURE);
}
if((rc = write(msg->socket, msg->message_buffer, len)) != len){
printf("%d, %d\n", len, rc);
fprintf(stderr, "partial/failed write\n");
exit(EXIT_FAILURE);
}
nread = read(msg->socket, msg->message_buffer, BUF_SIZE);
if (nread == -1){
perror("read");
exit(EXIT_FAILURE);
}
return atof(msg->message_buffer+3);
}
int send_message(message *msg){
ssize_t nread;
int len;
//sprintf(msg->message_buffer, "%s%.1f", msg->header, *msg->send_value);
len = strlen(msg->message_buffer)+1;
int rc;
if (len + 1 > BUF_SIZE){
fprintf(stderr, "Ignoring long message in argument\n");
exit(EXIT_FAILURE);
}
if((rc = write(msg->socket, msg->message_buffer, len)) != len){
printf("%d, %d\n", len, rc);
fprintf(stderr, "partial/failed write\n");
exit(EXIT_FAILURE);
}
nread = read(msg->socket, msg->message_buffer, BUF_SIZE);
if (nread == -1){
perror("read");
exit(EXIT_FAILURE);
}
return 0;
}
main.c
#include<pthread.h>
#include<stdio.h>
#include<errno.h>
#include<stdlib.h>
#include<string.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<netdb.h>
#include<unistd.h>
#include<math.h>
#include<time.h>
#include<termios.h>
#include"controller.h"
#include"screen.h"
#include"myIO.h"
#include"my_time.h"
#include"data_structures.h"
#include"udp.h"
#define NUM_THREADS 5
#define MAX_PARAM_SIZE 20
#define MAX_BUFFER_SIZE 1200
//variables
typedef enum {IDLE, QUIT, CHANGE_LEVEL_REF, CHANGE_TEMP_REF} command_type;
struct timespec t1;
struct timespec t2;
pthread_cond_t screen = PTHREAD_COND_INITIALIZER;
pthread_cond_t cmd = PTHREAD_COND_INITIALIZER;
pthread_cond_t barrier = PTHREAD_COND_INITIALIZER;
int count[2] = {0,0};
command_type command = IDLE;
double_buffer* log_buffer;
char* port = NULL;
char* host = NULL;;
int socket_cliente;
real Ta, Ti, No;
real T=0;
real H=0;
real Q=0;
real Nf=0;
real Ni=0;
real Na=0;
real href = 2.0;
real tref = 25.0;
pthread_mutex_t em_scan;
pthread_mutex_t em;
void init(){
port = (char *)malloc(sizeof(char)*MAX_PARAM_SIZE);
host = (char *)malloc(sizeof(char)*MAX_PARAM_SIZE);
log_buffer = build_double_buffer();
}
//threads
void *LevelControl(void *threadid){
/**********************************************************
*thread responsible for controling the water level
*********************************************************/
controller* levelControl = NULL;
levelControl = build_controller();
levelControl->kp = 10000.0;
levelControl->ki = 0.0;
levelControl->kd = 0.0;
levelControl->error_thresh = 1.0;
levelControl->step_time = 0.7;
levelControl->max_actuator_value = 100.0;
levelControl->min_actuator_value = 0.0;
int intervalo = 90000000;
message *message_H = NULL;
build_message(&message_H, socket_cliente, "sh-", &H);
sprintf(message_H->message_buffer, "%s0.0", message_H->header);
message *message_Nf = NULL;
build_message(&message_Nf, socket_cliente, "anf", &Nf);
message *message_Ni = NULL;
build_message(&message_Ni, socket_cliente, "ani", &Ni);
loop_1:
if(command != QUIT){
pthread_mutex_lock(&em);
H = receive_message(message_H);
levelControl->error = href - H;
if(levelControl->error < 0.0){
levelControl->error = -levelControl->error;
Nf = PID_Update(levelControl);
Ni = 0.0;
}else{
Ni = PID_Update(levelControl);
Nf = 0.0;
}
sprintf(message_Nf->message_buffer, "%s%f", message_Nf->header, *message_Nf->send_value);
send_message(message_Nf);
sprintf(message_Ni->message_buffer, "%s%f", message_Ni->header, *message_Ni->send_value);
send_message(message_Ni);
count[1] = 1;
if((count[0] == 1) & (count[1] == 1)) pthread_cond_signal(&barrier);
next_timer(t1, intervalo);
pthread_mutex_unlock(&em);
goto loop_1;
}else return NULL;
}
void *TempControl(void *threadid){
/**********************************************************
* thread responsible for controling the temperature
*********************************************************/
controller *tempControl = NULL;
tempControl = build_controller();
tempControl->kp = 10000.0;
tempControl->ki = 0.0;
tempControl->kd = 0.0;
tempControl->error_thresh = 20.0;
tempControl->step_time = 0.7;
tempControl->max_actuator_value = 10000.0;
tempControl->min_actuator_value = 0.0;
int intervalo = 70000000;
message *message_T = NULL;
build_message(&message_T, socket_cliente, "st-", &T);
sprintf(message_T->message_buffer, "%s0.0", message_T->header);
message *message_Q = NULL;
build_message(&message_Q, socket_cliente, "aq-", &Q);
message *message_Na = NULL;
build_message(&message_Na, socket_cliente, "ana", &Na);
char *log_string = NULL;
log_string = (char *)malloc(sizeof(char)*MAX_BUFFER_SIZE);
// while(command != QUIT){
loop_2:
if(command != QUIT){
pthread_mutex_lock(&em);
T = receive_message(message_T);
tempControl->error = tref - T;
Q = PID_Update(tempControl);
sprintf(message_Q->message_buffer, "%s%f", message_Q->header, *message_Q->send_value);
send_message(message_Q);
if(Q == tempControl->max_actuator_value){
Na = 10.0;
}else if(Q == tempControl->min_actuator_value){
Na = 0.0;
}
sprintf(message_Na->message_buffer, "%s%f", message_Na->header, *message_Na->send_value);
send_message(message_Na);
count[0] = 1;
if((count[0] == 1) & (count[1] == 1)) pthread_cond_signal(&barrier);
pthread_mutex_unlock(&em);
sprintf(log_string, "Temperura: %f\n", T);
setDoubleBuffer(log_buffer, log_string);
next_timer(t2, intervalo);
goto loop_2;
}else return NULL;
// pthread_exit(NULL);
}
void *Status(void *threadid){
/**********************************************************
*thread responsible for printing the current status on
*the screen and setting tref and href
*********************************************************/
message *message_Ta = NULL;
build_message(&message_Ta, socket_cliente, "sta", &Ta);
sprintf(message_Ta->message_buffer, "%s0.0", message_Ta->header);
message *message_Ti = NULL;
build_message(&message_Ti, socket_cliente, "sti", &Ti);
sprintf(message_Ti->message_buffer, "%s0.0", message_Ti->header);
message *message_No = NULL;
build_message(&message_No, socket_cliente, "sno", &No);
sprintf(message_No->message_buffer, "%s0.0", message_No->header);
pthread_mutex_lock(&em);
while((count[0] != 1) | (count[1] != 1)) pthread_cond_wait(&barrier, &em);
pthread_mutex_unlock(&em);
//while(command != QUIT){
loop_3:
switch(command){
case IDLE:
pthread_mutex_lock(&em);
clearScreen();
Ta = receive_message(message_Ta);
Ti = receive_message(message_Ti);
No = receive_message(message_No);
printf("/********************************************************************************************************\n");
printf("*STATUS\n");
printf("*reference temperature: %f\n", tref);
printf("*reference water level: %f\n", href);
printf("*current temperature: %f\n", T);
printf("*current water level: %f\n", H);
printf("*other sensor value => Ni = %f, No = %f, Na = %f, Nf = %f, Ta = %f, Ti = %f\n", Ni, No, Na, Nf, Ta,Ti);
printf("*\n");
printf("*\n");
printf("*\n");
printf("*(q)uit, change (l)evel reference, change (t)emperature reference\n");
pthread_mutex_unlock(&em);
sleep(1);
break;
case CHANGE_LEVEL_REF:
pthread_mutex_lock(&em_scan);
printf("insert new Level reference\n");
scanf("%f", &href);
pthread_cond_signal(&screen);
while(command != IDLE){
pthread_cond_wait(&cmd, &em_scan);
}
pthread_mutex_unlock(&em_scan);
break;
case CHANGE_TEMP_REF:
pthread_mutex_lock(&em_scan);
printf("insert new Temperature reference\n");
scanf("%f", &tref);
pthread_cond_signal(&screen);
while(command != IDLE){
pthread_cond_wait(&cmd, &em_scan);
}
pthread_mutex_unlock(&em_scan);
case QUIT:
fprintf(stderr, "get saiu\n");
return NULL;
}
goto loop_3;
//return NULL;
}
void *GetReferences(void *threadid){
/**********************************************************
*thread responsible for changing the program mode
*********************************************************/
char temp;
//while(command != QUIT){
loop_4:
temp = getch();
switch(temp){
case 'q':
command = QUIT;
printf("%c\n --------------------------------------------------------\n", temp);
return NULL;
case 'l':
pthread_mutex_lock(&em_scan);
command = CHANGE_LEVEL_REF;
pthread_cond_wait(&screen, &em_scan);
command = IDLE;
pthread_cond_signal(&cmd);
pthread_mutex_unlock(&em_scan);
break;
case 't':
pthread_mutex_lock(&em_scan);
command = CHANGE_TEMP_REF;
pthread_cond_wait(&screen, &em_scan);
command = IDLE;
pthread_cond_signal(&cmd);
pthread_mutex_unlock(&em_scan);
}
goto loop_4;
}
void *Log(void *threadid){
char *receive_buffer = NULL;
receive_buffer = (char *)malloc(sizeof(char)*MAX_BUFFER_SIZE);
//while(command != QUIT){
loop_5:
if(command != QUIT){
get_buffer(receive_buffer, log_buffer);
write_log(receive_buffer);
goto loop_5;
}else return NULL;
}
int main (int argc, char *argv[]){
init();
pthread_mutex_init(&em_scan, NULL);
pthread_mutex_init(&em, NULL);
init_nano_timer(t1);
init_nano_timer(t2);
clearScreen();
printf("Enter the port where to be used in the udp communication\n");
scanf("%s", port);
strcpy(host, "localhost");
socket_cliente = prepara_socket_cliente(host, port);
pthread_t threads[NUM_THREADS];
int rc;
int t;
void *threadName[NUM_THREADS];
threadName[0] = TempControl;
threadName[1] = LevelControl;
threadName[2] = Status;
threadName[3] = GetReferences;
threadName[4] = Log;
for(t=0; t<NUM_THREADS; t++){
rc = pthread_create(&threads[t], NULL, threadName[t], (void *)t);
if(rc){
printf("ERROR; return code from pthread_create() is %d\n", rc);
exit(1);
}
}
for(t=0; t<NUM_THREADS; t++){
rc = pthread_join(threads[t], NULL);
if(rc){
printf("ERROR; return code from pthread_create() is %d\n", rc);
exit(1);
}
}
return 0;
}
Btw, I am using threads in these code, would this code be thread-safe even without mutexes?