Example of structured xqueue freeRTOS - multithreading

I'm coming to you because I'm desperate about my problem. I've already made a previous post (xQueue ESP32 can't send two command) but I've tried but I don't have the expected result.
Result :
len : -1184515756
data :
I also tried these two tutorials but still nothing works...
https://freertos.org/a00018.html
https://controllerstech.com/freertos-tutorial-5-using-queue/
After several tries without really understanding how I got something almost working except I end up with a Guru Err Load Prohibited.
Code :
void app_main() {
/* Create the queue used to send complete struct message structures. */
uart_queue = xQueueCreate(20, sizeof(struct message));
xMutexUart = xSemaphoreCreateMutex();
....
struct message *ptx_msg =pvPortMalloc(sizeof (struct message));
//Set Channel
sprintf(ptx_msg->cmd,"%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c\n",0x01, 0x02, 0x10, 0x21, 0x02, 0x10, 0x02, 0x14, 0x2D, 0x02, 0x10, 0x02, 0x10, 0x02, 0x18, 0x02, 0x10, 0x03);
ptx_msg->len = strlen(ptx_msg->cmd);
printf("len : %d\n", ptx_msg->len);
for(int i=0;i<ptx_msg->len;i++){
printf("%02x ",ptx_msg->cmd[i]);
}
xSemaphoreTake(xMutexUart, portMAX_DELAY);
xQueueSend(uart_queue, (void*)&ptx_msg, portMAX_DELAY);
xSemaphoreGive(xMutexUart);
//repeat X time
....
}
void vTaskSend( void * pvParameters )
{
struct message *rx_msg;
int err;
while(1){
xSemaphoreTake(xMutexUart, portMAX_DELAY);
if (xQueueReceive(uart_queue, &rx_msg, portMAX_DELAY) == pdPASS){
printf("len : %d\n", rx_msg->len);
for(int i=0;i<rx_msg->len;i++){
printf("%02x ",rx_msg->cmd[i]);
}
printf("\n");
err = uart_write_bytes(uart_num, (const char *)rx_msg->cmd, rx_msg->len); // Write data to UART.
ESP_ERROR_CHECK(uart_wait_tx_done(uart_num, 5000)); // wait timeout is 5000 RTOS ticks (TickType_t)
if(err != rx_msg->len){
printf("Err, not all bytes send : %d/%d\n",err,rx_msg->len);
}
vPortFree(rx_msg); // free the structure memory*/
vTaskDelay(100 / portTICK_RATE_MS);
//taskYIELD();
}
xSemaphoreGive(xMutexUart);
vTaskDelay(100 / portTICK_RATE_MS);
}
}
Result :
len : 19
data : 01 02 10 21 02 10 02 14 2d 02 10 02 10 02 18 02 10 03 0a
I would like to correct my problem please!
EDIT :
Here is the code that I have and the result is :
len : 54516257561
data :
#include <stdio.h>
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
#include <freertos/queue.h>
#include <esp_system.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
#include <driver/uart.h>
#define COMMAND_DEVICE_LIST 0x15
#define COMMAND_STATUS 0x00
#define COMMAND_DESCRIPTION 0x43
#define COMMAND_UNRECOGNIZED 0x11
#define COMMAND_ADDGROUP 0x60
#define COMMAND_BIND 0x30
#define SIZE_TYPE_DEVICE 2
#define SIZE_CLUSTER 2
#define SIZE_SHORT_ADD 2
#define SIZE_IEEE_ADD 8
#define START_DATA 7
#define SIZE_MIN_NB_DEVICE 2
#define CHAR_END_FRAME 0x03
#define CHAR_CONFIG_FRAME 0x02
#define CHAR_VAL_MAX_CONFIG_FRAME 0x10
#define STACK_SIZE 2048
//storage info
struct device{
char type_id[SIZE_TYPE_DEVICE];
char manufacturer[32]; //attribute 4
char name[32]; // attribute 5
char short_add[SIZE_SHORT_ADD];
char ieee_add[SIZE_IEEE_ADD];
char cluster_input[32][SIZE_CLUSTER];
char cluster_output[32][SIZE_CLUSTER];
};
struct get_device_list{
int len;
struct device device[];
}dev_list;
//list device type
char list_device_type[2][SIZE_TYPE_DEVICE]={{0x01,0x0C},{0x08,0x20}};
// Setup UART buffered IO with event queue
const int uart_buffer_size = 2048;
// Queue used to send and receive complete struct message structures.
QueueHandle_t uart_queue = NULL;
const int uart_num = UART_NUM_2;
struct message{
char cmd[128];
int len;
};
SemaphoreHandle_t xMutexUart;
/************************************************CONFIG***********************************************/
/**
* #brief Configuraiton of UART and set pin that uart use.
*
* #return [int] 0 if is successed
*/
int uart_setup()
{
uart_config_t uart_config = {
.baud_rate = 115200,
.data_bits = UART_DATA_8_BITS,
.parity = UART_PARITY_DISABLE,
.stop_bits = UART_STOP_BITS_1,
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE
};
// Configure UART parameters
ESP_ERROR_CHECK(uart_param_config(uart_num, &uart_config));
ESP_ERROR_CHECK(uart_set_pin(UART_NUM_2, 18, 19, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE));
// Install UART driver using an event queue here
ESP_ERROR_CHECK(uart_driver_install(UART_NUM_2, uart_buffer_size, \
uart_buffer_size, 20, &uart_queue, 0));
return 0;
}
/************************************************UTILS***********************************************/
int cmdlen(char* cmd){
int i = 0;
while(cmd[i]!='\n'){
i++;
}
return i+1;
}
int device_shortadd_compare(char* search_add){
int res=-1,val=0;
for(int i=0;i < dev_list.len;i++){
val = 0;
for(int l=0;l<SIZE_TYPE_DEVICE;l++){
if(search_add[l]==dev_list.device[i].short_add[l]){
val++;
}
}
if(val == 2){
res=i;
}
}
return res;
}
int parse_translate(char* data,int len,char res[][64]){
int i=0,j=0,end=0,index=0;
while(len - j != 0){
if (data[j]==CHAR_CONFIG_FRAME)
{
j++; //skip 02
data[j]^=0x10; //10xor10=00
res[end][i-index]= data[j];
printf("%02x ",res[end][i-index]);
i++;
}else if (data[j]==CHAR_END_FRAME)
{
res[end][i-index]=data[j];
res[end][i+1-index]='\n';
res[end][i+2-index]='\0';
printf("%02x\n",res[end][i-index]);
i=i+2;
index=i;
end++;
}else{
res[end][i-index]= data[j];
printf("%02x ",res[end][i-index]);
i++;
}
j++;
}
return end;
}
/************************************************COMMUNICATION***********************************************/
/**
* #brief [Thread]Send commande to Zigbee module by UART
*
*/
void vTaskSend( void * pvParameters )
{
while(1){
int err;
struct message rx_msg;
if (xQueueReceive(uart_queue, &rx_msg, portMAX_DELAY) == pdPASS){
printf("len : %d\n", rx_msg.len);
for(int i=0;i< rx_msg.len;i++){
printf("%02x ", rx_msg.cmd[i]);
}
printf("\n");
xSemaphoreTake(xMutexUart, portMAX_DELAY);
err = uart_write_bytes(uart_num, (const char *) rx_msg.cmd, rx_msg.len); // Write data to UART.
ESP_ERROR_CHECK(uart_wait_tx_done(uart_num, 5000)); // wait timeout is 5000 RTOS ticks (TickType_t)
xSemaphoreGive(xMutexUart);
if(err != rx_msg.len){
printf("Err, not all bytes send : %d/%d\n",err, rx_msg.len);
}
//vPortFree(rx_msg); // free the structure memory*/
vTaskDelay(100 / portTICK_RATE_MS);
//taskYIELD();
}
xSemaphoreGive(xMutexUart);
vTaskDelay(100 / portTICK_RATE_MS);
}
}
/**
* #brief [Thread]Read response from UART
*
*/
void vTaskRead( void * pvParameters )
{
char data[512];
int length = 0;
while(1){
xSemaphoreTake(xMutexUart, portMAX_DELAY);
ESP_ERROR_CHECK(uart_get_buffered_data_len(uart_num, (size_t*)&length));
length = uart_read_bytes(uart_num, (uint8_t*)data, length, 100);
xSemaphoreGive(xMutexUart);
if(length>0){
printf("[R] message size : %d\n ",length);
char res[8][64];
int nb_cmd=parse_translate(data,length,res);
for(int i=0;i<nb_cmd;i++){
switch(res[i][2]){
case COMMAND_STATUS:
if(res[6]==COMMAND_STATUS){
printf("Command status success\n");
}
break;
case COMMAND_DEVICE_LIST:
dev_list.len=(cmdlen(res[i])-8)/13;
printf("Nb device find : %d\n",dev_list.len);
int start = START_DATA; //start of device info in frame
for(int j=0;j<dev_list.len;j++){
struct device dev;
printf("short: ");
for(int j=0;j<SIZE_SHORT_ADD;j++){
dev.short_add[j] = res[i][start+j];
printf("%02x ",dev.short_add[j]);
}
printf("\n");
printf("ieee: ");
for(int l=0;l<SIZE_IEEE_ADD;l++){
dev.ieee_add[l]=res[i][start+2+l];
printf("%02x ",dev.ieee_add[l]);
}
printf("\n");
dev_list.device[j]=dev;
vTaskDelay(100 / portTICK_RATE_MS);
start=start+SIZE_SHORT_ADD+SIZE_IEEE_ADD+2+1; //info of device 1 not used + id device 2 not used
}
break;
case COMMAND_DESCRIPTION:
printf(" ");
char add[SIZE_TYPE_DEVICE];
for(int j=0;j<SIZE_TYPE_DEVICE;j++){
add[j]=res[i][8+j];
}
int id = device_shortadd_compare(add);
if(id != -1){
printf("type: ");
for(int j=0;j<SIZE_TYPE_DEVICE;j++){
dev_list.device[id].type_id[j]=res[i][14+j];
printf("%02x ",dev_list.device[id].type_id[j]);
}
printf("\n");
if(dev_list.device[id].type_id[0]==0x00 && dev_list.device[id].type_id[1] ==0x00){
printf("Device %d not found, if it's a button press it\n",i);
}
}
break;
case COMMAND_ADDGROUP:
printf("Device add to group!\n");
break;
case COMMAND_BIND:
printf("Press the button, hurry up!!\n");
break;
}
}
}
vTaskDelay(100 / portTICK_RATE_MS);
//taskYIELD();
}
vTaskDelay(1000 / portTICK_RATE_MS);
ESP_ERROR_CHECK(uart_flush(uart_num));
}
/************************************************ZIGBEE***********************************************/
/**
* #brief Configuration of Zigbee module (channel,type) and start network
*
*/
void zigbee_config_with_pemit_join(){
struct message *ptx_msg =pvPortMalloc(sizeof (struct message));
//Set Channel
sprintf(ptx_msg->cmd,"%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c\n",0x01, 0x02, 0x10, 0x21, 0x02, 0x10, 0x02, 0x14, 0x2D, 0x02, 0x10, 0x02, 0x10, 0x02, 0x18, 0x02, 0x10, 0x03);
ptx_msg->len = strlen(ptx_msg->cmd);
printf("len : %d\n", ptx_msg->len);
for(int i=0;i<ptx_msg->len;i++){
printf("%02x ",ptx_msg->cmd[i]);
}
xQueueSend(uart_queue, (void*)ptx_msg, portMAX_DELAY);
printf("[S] Set channel to 11\n");
vTaskDelay(100 / portTICK_RATE_MS);
//Set Type
//ptx_msg = pvPortMalloc(sizeof (struct message));
sprintf(ptx_msg->cmd,"%c%c%c%c%c%c%c%c%c%c%c%c\n",0x01, 0x02, 0x10, 0x23, 0x02, 0x10, 0x02, 0x11, 0x22, 0x02, 0x10, 0x03);
ptx_msg->len =strlen(ptx_msg->cmd);
xQueueSend(uart_queue, (void*)ptx_msg, portMAX_DELAY);
printf("[S] Set as Coordinator\n");
vTaskDelay(100 / portTICK_RATE_MS);
//Start Network
//ptx_msg =pvPortMalloc(sizeof (struct message));
sprintf(ptx_msg->cmd,"%c%c%c%c%c%c%c%c%c%c\n",0x01, 0x02, 0x10, 0x24, 0x02, 0x10, 0x02, 0x10, 0x24, 0x03);
ptx_msg->len =strlen(ptx_msg->cmd);
xQueueSend(uart_queue, (void*)ptx_msg, portMAX_DELAY);
printf("[S] Start Network\n");
//Permit join
//ptx_msg =pvPortMalloc(sizeof (struct message));
sprintf(ptx_msg->cmd,"%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c\n",0x01, 0x02, 0x10, 0x49, 0x02, 0x10, 0x02, 0x14, 0xB0, 0xFF, 0xFC, 0xFF, 0x02, 0x10, 0x03);
ptx_msg->len =strlen(ptx_msg->cmd);
xQueueSend(uart_queue, (void*)ptx_msg, portMAX_DELAY);
printf("[S] Permit join: If you have button press it 2sec.\n");
vTaskDelay(6000 / portTICK_RATE_MS);
}
void vTaskZigbee( void * pvParameters )
{
if (uart_setup() == -1){
printf("Err during uart setup\n");
}
zigbee_config_with_pemit_join();
//taskYIELD();
while(1){
vTaskDelay(100000 / portTICK_RATE_MS);
}
}
/************************************************MAIN***********************************************/
void app_main() {
/* Create the queue used to send complete struct message structures. */
uart_queue = xQueueCreate(20, sizeof(struct message ));
xMutexUart = xSemaphoreCreateMutex();
BaseType_t xReturned;
TaskHandle_t xHandle = NULL;
/* Create the task, storing the handle. */
xReturned = xTaskCreate(
vTaskZigbee, /* Function that implements the task. */
"Zigbee", /* Text name for the task. */
STACK_SIZE, /* Stack size in words, not bytes. */
NULL, /* Parameter passed into the task. */
tskIDLE_PRIORITY,/* Priority at which the task is created. */
&xHandle); /* Used to pass out the created task's handle. */
xReturned = xTaskCreate( vTaskSend, "Send", STACK_SIZE, NULL, tskIDLE_PRIORITY, &xHandle);
xReturned = xTaskCreate( vTaskRead, "Read", STACK_SIZE*2, NULL, tskIDLE_PRIORITY, &xHandle);
}

Related

Time consumption of Linux RS485 serial communication

I'm trying to communicate with several Modbus RTU devices through one usb to RS232 to RS485 port at baudrate 38400, 1 start bit, 8databits, no parity and 1 stop bit.
Communication processes with one Modbus RTU device is as follows:
Send 8 bytes to the device;
wait for replies from the device;
Receive 23 bytes of replies.
According to my calculation and the digital oscilloscope, send 8 bytes costs 2.083ms, receive 23 bytes costs 5.99ms, response time of the Modbus RTU device is about 1.3ms. So time of the communication process costs 9.373ms in total.
But in my test program I found the average communication time is about 15ms (10000 times average). I wonder where does the additional 5 more milliseconds come from and how could I optimize my program to reduce this time.
Thanks in advance!
The test program is as follows:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <time.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <termios.h>
#include <errno.h>
#include <string.h>
#include <signal.h>
void print_hex_buf(unsigned char *buffer, int size)
{
for (int i=0; i<size; i++)
{
printf("%02x ", buffer[i]);
}
printf("\n");
}
void diff_time(struct timeval t1, struct timeval t2, struct timeval *diff)
{
time_t sec;
suseconds_t usec;
//time in two different days
if (t1.tv_sec > t2.tv_sec)
sec = t2.tv_sec + 24*60*60 - t1.tv_sec;
else
sec = t2.tv_sec - t1.tv_sec;
usec = t2.tv_usec - t1.tv_usec;
if (usec < 0)
{
sec -= 1;
usec += 1000000;
}
diff->tv_sec = sec;
diff->tv_usec = usec;
}
int serial_write(int uart_fd, char *buffer, int size)
{
int count = 0;
count = write(uart_fd, buffer, size);
return count;
}
int serial_read(int uart_fd, char *buffer, int size)
{
int count = 0;
int bytes_read = 0;
int read_retry = 0;
fd_set fds_read;
struct timeval timeout;
FD_ZERO(&fds_read);
FD_SET(uart_fd, &fds_read);
timeout.tv_sec = 0;
timeout.tv_usec = 500000; //500ms
int ret = select(uart_fd + 1, &fds_read, NULL, NULL, &timeout);
if (ret > 0 && FD_ISSET(uart_fd, &fds_read))
{
count = read(uart_fd, buffer, size);
bytes_read = (count > 0)?count:0;
while (bytes_read < size && read_retry++ < 500)
{
count = read(uart_fd, buffer+bytes_read, size-bytes_read);
bytes_read += (count > 0)?count:0;
if (bytes_read >= size)
break;
}
}
else
{
printf("Failed to from uart!\n");
return -1;
}
return bytes_read;
}
int main(int argc, char** argv)
{
int fd;
struct termios opt;
int count;
unsigned char send_buf[] = { 0x01, 0x04, 0x00, 0x00, 0x00, 0x09, 0x30, 0x0c};
unsigned char buffer[256];
int iteration = 0;
int delay_ms = 0;
int err_count = 0;
int cycle = 0;
suseconds_t average_time = 0;
setbuf(stdout, NULL);
if (argc != 3)
{
printf("Usage: testuart [uart device] [iteration]\n");
return 0;
}
iteration = atoi(argv[2]);
fd = open(argv[1], O_RDWR | O_NOCTTY | O_NDELAY);
if (fd == -1)
{
printf("Failed to open port: %s\n", argv[1]);
return -1;
}
if (tcgetattr(fd, &opt) != 0)
{
printf("Failed to get uart attribute!\n");
return -1;
}
opt.c_cflag = B38400|CS8|CREAD|CLOCAL;
opt.c_iflag = IGNPAR;
opt.c_cflag &= ~PARENB;
opt.c_cflag &= ~PARODD;
opt.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
opt.c_oflag &= ~OPOST;
opt.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON);
tcflush(fd, TCIFLUSH);
if (tcsetattr(fd, TCSANOW, &opt) != 0)
{
printf("Failed to setup serial port!\n");
close(fd);
return -1;
}
while (cycle++ < iteration)
{
printf("Send hex command:\n");
print_hex_buf(send_buf, 8);
struct timeval tm_start;
struct timeval tm_end;
struct timeval tm_diff;
gettimeofday(&tm_start, NULL);
count = serial_write(fd, send_buf, 8);
if (count != 8)
{
printf("Failed to write 8 bytes!\n");
close(fd);
return -1;
}
count = serial_read(fd, buffer, 23);
if (count <= 0)
{
printf("serial read returns %d\n", count);
close(fd);
return -1;
}
gettimeofday(&tm_end, NULL);
diff_time(tm_start, tm_end, &tm_diff);
print_hex_buf(buffer, count);
printf("serial communication costs %ld.%06ld seconds.\n",
tm_diff.tv_sec, tm_diff.tv_usec);
average_time = ((average_time*(cycle-1))+tm_diff.tv_usec)/cycle;
}
printf("%d times, average time in usec is %ld\n", cycle-1, average_time);
close(fd);
return 0;
}
Thanks to sawdust!
The following link helps! The average time has reduced from 15ms to 10ms.
High delay in RS232 communication on a PXA270

Segmentation Fault Error When Reading Two Serial Port with BeagleBone Black

I am getting Segmentation fault error while reading two diffentent serial communication line with using Debian GNU/Linux 7.4 on Beaglebone Black. One of them is CAN-BUS data. I am using Waveshares RS485/CAN CAPE module for this with using can-utils package. "https://github.com/linux-can/can-utils/blob/master/candump.c"
CAN log file
And the other one is UART data by a GPS module called uBlox GY-NEO6MV2 module. For the GPS I have this code which works perfectly;
#include <stdio.h>
#include <fcntl.h> /* File Control Definitions */
#include <termios.h> /* POSIX Terminal Control Definitions */
#include <unistd.h> /* UNIX Standard Definitions */
#include <errno.h> /* ERROR Number Definitions */
#include <string.h> /* Array to String */
void main(void){
int fd;/*File Descriptor*/
/*------------------------------- Opening the Serial Port -------------------------------*/
/* Change /dev/ttyUSB0 to the one corresponding to your system */
while(1){
fd = open("/dev/ttyO2",O_RDWR | O_NOCTTY); /* ttyUSB0 is the FT232 based USB2SERIAL Converter */
/* O_RDWR - Read/Write access to serial port */
/* O_NOCTTY - No terminal will control the process */
/* Open in blocking mode,read will wait */
if(fd == -1) /* Error Checking */
printf("\n Error! in Opening ttyO2 ");
else
printf("\n ttyO2 Opened Successfully ");
/*---------- Setting the Attributes of the serial port using termios structure --------- */
struct termios SerialPortSettings; /* Create the structure */
tcgetattr(fd, &SerialPortSettings); /* Get the current attributes of the Serial port */
/* Setting the Baud rate */
cfsetispeed(&SerialPortSettings,B9600); /* Set Read Speed as 9600 */
cfsetospeed(&SerialPortSettings,B9600); /* Set Write Speed as 9600 */
/* 8N1 Mode */
SerialPortSettings.c_cflag &= ~PARENB; /* Disables the Parity Enable bit(PARENB),So No Parity */
SerialPortSettings.c_cflag &= ~CSTOPB; /* CSTOPB = 2 Stop bits,here it is cleared so 1 Stop bit */
SerialPortSettings.c_cflag &= ~CSIZE; /* Clears the mask for setting the data size */
SerialPortSettings.c_cflag |= CS8; /* Set the data bits = 8 */
SerialPortSettings.c_cflag &= ~CRTSCTS; /* No Hardware flow Control */
SerialPortSettings.c_cflag |= CREAD | CLOCAL; /* Enable receiver,Ignore Modem Control lines */
SerialPortSettings.c_iflag &= ~(IXON | IXOFF | IXANY); /* Disable XON/XOFF flow control both i/p and o/p */
SerialPortSettings.c_iflag &= ~(ICANON | ECHO | ECHOE | ISIG); /* Non Cannonical mode */
SerialPortSettings.c_oflag &= ~OPOST;/*No Output Processing*/
/* Setting Time outs */
SerialPortSettings.c_cc[VMIN] = 42; /* Read at least 51 characters */
SerialPortSettings.c_cc[VTIME] = 0; /* Wait indefinetly */
if((tcsetattr(fd,TCSANOW,&SerialPortSettings)) != 0) /* Set the attributes to the termios structure*/
printf("\n ERROR ! in Setting attributes");
else
printf("\n BaudRate = 9600 \n StopBits = 1 \n Parity = none \n\n");
/*------------------------------- Read data from serial port -----------------------------*/
tcflush(fd, TCIFLUSH); /* Discards old data in the rx buffer */
char read_buffer[42]; /* Buffer to store the data received */
int bytes_read = 0; /* Number of bytes read by the read() system call */
int ia = 0; int a;
int test = 0;
char new_read[38];
char curr_read[33];
a = 0;
do{
bytes_read = read(fd,&read_buffer,42); /* Read the data */
if(read_buffer[0] == '$')
if(read_buffer[1] == 'G')
if(read_buffer[2] == 'P')
if(read_buffer[3] == 'G')
if(read_buffer[4] == 'G'){
for(ia=7;ia<bytes_read;ia++){ /*printing only the received characters*/
new_read[a] = read_buffer[ia];
printf("%c",read_buffer[ia]);
a = a+1;
test = 1;
}
strcpy(curr_read, new_read);
printf("\n%s \n", curr_read);
}
else
test = 0;
else
test = 0;
else
test = 0;
else
test = 0;
else
test = 0;
}while(test == 0);
close(fd); /* Close the serial port */
}
}
And for the CAN logging I am using the code in the link above. What I try to achive is logging two data in to same log file. I modified the code above a little to get the datas only that I need; which is timestamp and location coordinates.
GPS edited data
GPS module gives data every second so I am triyng to get one data from GPS and attach it to the next 1000 CAN data then write in to a .log file then read a new value from GPS. GPS modules communication bitrate is 9600kbps and CAN bitrate is 125000 kbps. GPS is connected to UART2 pin, CAN to UART1. When I try to combine two code into one I get the Segmentation fault error. I made a little research its UNIX error code while violeting the restiricted memory space. But these two codes works perfectly when working seperatly. This is where I got stucked.
The code I tried to merge is like;
/* for hardware timestamps - since Linux 2.6.30 */
#ifndef SO_TIMESTAMPING
#define SO_TIMESTAMPING 37
#endif
/* from #include <linux/net_tstamp.h> - since Linux 2.6.30 */
#define SOF_TIMESTAMPING_SOFTWARE (1<<4)
#define SOF_TIMESTAMPING_RX_SOFTWARE (1<<3)
#define SOF_TIMESTAMPING_RAW_HARDWARE (1<<6)
#define MAXSOCK 16 /* max. number of CAN interfaces given on the cmdline */
#define MAXIFNAMES 30 /* size of receive name index to omit ioctls */
#define MAXCOL 6 /* number of different colors for colorized output */
#define ANYDEV "any" /* name of interface to receive from any CAN interface */
#define ANL "\r\n" /* newline in ASC mode */
#define SILENT_INI 42 /* detect user setting on commandline */
#define SILENT_OFF 0 /* no silent mode */
#define SILENT_ANI 1 /* silent mode with animation */
#define SILENT_ON 2 /* silent mode (completely silent) */
static char *cmdlinename[MAXSOCK];
static __u32 dropcnt[MAXSOCK];
static __u32 last_dropcnt[MAXSOCK];
static char devname[MAXIFNAMES][IFNAMSIZ+1];
static int dindex[MAXIFNAMES];
static int max_devname_len; /* to prevent frazzled device name output */
const int canfd_on = 1;
#define MAXANI 4
const char anichar[MAXANI] = {'|', '/', '-', '\\'};
const char extra_m_info[4][4] = {"- -", "B -", "- E", "B E"};
extern int optind, opterr, optopt;
static volatile int running = 1;
void sigterm(int signo)
{
running = 0;
}
int idx2dindex(int ifidx, int socket) {
int i;
struct ifreq ifr;
for (i=0; i < MAXIFNAMES; i++) {
if (dindex[i] == ifidx)
return i;
}
/* create new interface index cache entry */
/* remove index cache zombies first */
for (i=0; i < MAXIFNAMES; i++) {
if (dindex[i]) {
ifr.ifr_ifindex = dindex[i];
if (ioctl(socket, SIOCGIFNAME, &ifr) < 0)
dindex[i] = 0;
}
}
for (i=0; i < MAXIFNAMES; i++)
if (!dindex[i]) /* free entry */
break;
if (i == MAXIFNAMES) {
fprintf(stderr, "Interface index cache only supports %d interfaces.\n",
MAXIFNAMES);
exit(1);
}
dindex[i] = ifidx;
ifr.ifr_ifindex = ifidx;
if (ioctl(socket, SIOCGIFNAME, &ifr) < 0)
perror("SIOCGIFNAME");
if (max_devname_len < strlen(ifr.ifr_name))
max_devname_len = strlen(ifr.ifr_name);
strcpy(devname[i], ifr.ifr_name);
#ifdef DEBUG
printf("new index %d (%s)\n", i, devname[i]);
#endif
return i;
}
int main(int argc, char **argv)
{
fd_set rdfs;
int s[MAXSOCK];
int bridge = 0;
useconds_t bridge_delay = 0;
unsigned char timestamp = 0;
unsigned char hwtimestamp = 0;
unsigned char down_causes_exit = 1;
unsigned char dropmonitor = 0;
unsigned char extra_msg_info = 0;
unsigned char silent = SILENT_INI;
unsigned char silentani = 0;
unsigned char color = 0;
unsigned char view = 0;
unsigned char log = 0;
unsigned char logfrmt = 0;
int count = 0;
int rcvbuf_size = 0;
int opt, ret;
int currmax, numfilter;
int join_filter;
char *ptr, *nptr;
struct sockaddr_can addr;
char ctrlmsg[CMSG_SPACE(sizeof(struct timeval) + 3*sizeof(struct timespec) + sizeof(__u32))];
struct iovec iov;
struct msghdr msg;
struct cmsghdr *cmsg;
struct can_filter *rfilter;
can_err_mask_t err_mask;
struct canfd_frame frame;
int nbytes, i, maxdlen;
struct ifreq ifr;
struct timeval tv, last_tv;
struct timeval timeout, timeout_config = { 0, 0 }, *timeout_current = NULL;
FILE *logfile = NULL;
int fd;/*File Descriptor*/
struct termios SerialPortSettings; /* Create the structure */
signal(SIGTERM, sigterm);
signal(SIGHUP, sigterm);
signal(SIGINT, sigterm);
last_tv.tv_sec = 0;
last_tv.tv_usec = 0;
if (optind == argc) {
print_usage(basename(argv[0]));
exit(0);
}
if (logfrmt && view) {
fprintf(stderr, "Log file format selected: Please disable ASCII/BINARY/SWAP options!\n");
exit(0);
}
if (silent == SILENT_INI) {
if (log) {
fprintf(stderr, "Disabled standard output while logging.\n");
silent = SILENT_ON; /* disable output on stdout */
} else
silent = SILENT_OFF; /* default output */
}
currmax = argc - optind; /* find real number of CAN devices */
if (currmax > MAXSOCK) {
fprintf(stderr, "More than %d CAN devices given on commandline!\n", MAXSOCK);
return 1;
}
for (i=0; i < currmax; i++) {
ptr = argv[optind+i];
nptr = strchr(ptr, ',');
#ifdef DEBUG
printf("open %d '%s'.\n", i, ptr);
#endif
s[i] = socket(PF_CAN, SOCK_RAW, CAN_RAW);
if (s[i] < 0) {
perror("socket");
return 1;
}
cmdlinename[i] = ptr; /* save pointer to cmdline name of this socket */
if (nptr)
nbytes = nptr - ptr; /* interface name is up the first ',' */
else
nbytes = strlen(ptr); /* no ',' found => no filter definitions */
if (nbytes >= IFNAMSIZ) {
fprintf(stderr, "name of CAN device '%s' is too long!\n", ptr);
return 1;
}
if (nbytes > max_devname_len)
max_devname_len = nbytes; /* for nice printing */
addr.can_family = AF_CAN;
memset(&ifr.ifr_name, 0, sizeof(ifr.ifr_name));
strncpy(ifr.ifr_name, ptr, nbytes);
#ifdef DEBUG
printf("using interface name '%s'.\n", ifr.ifr_name);
#endif
if (strcmp(ANYDEV, ifr.ifr_name)) {
if (ioctl(s[i], SIOCGIFINDEX, &ifr) < 0) {
perror("SIOCGIFINDEX");
exit(1);
}
addr.can_ifindex = ifr.ifr_ifindex;
} else
addr.can_ifindex = 0; /* any can interface */
if (nptr) {
/* found a ',' after the interface name => check for filters */
/* determine number of filters to alloc the filter space */
numfilter = 0;
ptr = nptr;
while (ptr) {
numfilter++;
ptr++; /* hop behind the ',' */
ptr = strchr(ptr, ','); /* exit condition */
}
rfilter = malloc(sizeof(struct can_filter) * numfilter);
if (!rfilter) {
fprintf(stderr, "Failed to create filter space!\n");
return 1;
}
numfilter = 0;
err_mask = 0;
join_filter = 0;
while (nptr) {
ptr = nptr+1; /* hop behind the ',' */
nptr = strchr(ptr, ','); /* update exit condition */
if (sscanf(ptr, "%x:%x",
&rfilter[numfilter].can_id,
&rfilter[numfilter].can_mask) == 2) {
rfilter[numfilter].can_mask &= ~CAN_ERR_FLAG;
numfilter++;
} else if (sscanf(ptr, "%x~%x",
&rfilter[numfilter].can_id,
&rfilter[numfilter].can_mask) == 2) {
rfilter[numfilter].can_id |= CAN_INV_FILTER;
rfilter[numfilter].can_mask &= ~CAN_ERR_FLAG;
numfilter++;
} else if (*ptr == 'j' || *ptr == 'J') {
join_filter = 1;
} else if (sscanf(ptr, "#%x", &err_mask) != 1) {
fprintf(stderr, "Error in filter option parsing: '%s'\n", ptr);
return 1;
}
}
if (err_mask)
setsockopt(s[i], SOL_CAN_RAW, CAN_RAW_ERR_FILTER,
&err_mask, sizeof(err_mask));
if (join_filter && setsockopt(s[i], SOL_CAN_RAW, CAN_RAW_JOIN_FILTERS,
&join_filter, sizeof(join_filter)) < 0) {
perror("setsockopt CAN_RAW_JOIN_FILTERS not supported by your Linux Kernel");
return 1;
}
if (numfilter)
setsockopt(s[i], SOL_CAN_RAW, CAN_RAW_FILTER,
rfilter, numfilter * sizeof(struct can_filter));
free(rfilter);
} /* if (nptr) */
/* try to switch the socket into CAN FD mode */
setsockopt(s[i], SOL_CAN_RAW, CAN_RAW_FD_FRAMES, &canfd_on, sizeof(canfd_on));
if (rcvbuf_size) {
int curr_rcvbuf_size;
socklen_t curr_rcvbuf_size_len = sizeof(curr_rcvbuf_size);
/* try SO_RCVBUFFORCE first, if we run with CAP_NET_ADMIN */
if (setsockopt(s[i], SOL_SOCKET, SO_RCVBUFFORCE,
&rcvbuf_size, sizeof(rcvbuf_size)) < 0) {
#ifdef DEBUG
printf("SO_RCVBUFFORCE failed so try SO_RCVBUF ...\n");
#endif
if (setsockopt(s[i], SOL_SOCKET, SO_RCVBUF,
&rcvbuf_size, sizeof(rcvbuf_size)) < 0) {
perror("setsockopt SO_RCVBUF");
return 1;
}
if (getsockopt(s[i], SOL_SOCKET, SO_RCVBUF,
&curr_rcvbuf_size, &curr_rcvbuf_size_len) < 0) {
perror("getsockopt SO_RCVBUF");
return 1;
}
/* Only print a warning the first time we detect the adjustment */
/* n.b.: The wanted size is doubled in Linux in net/sore/sock.c */
if (!i && curr_rcvbuf_size < rcvbuf_size*2)
fprintf(stderr, "The socket receive buffer size was "
"adjusted due to /proc/sys/net/core/rmem_max.\n");
}
}
if (timestamp || log || logfrmt) {
if (hwtimestamp) {
const int timestamping_flags = (SOF_TIMESTAMPING_SOFTWARE | \
SOF_TIMESTAMPING_RX_SOFTWARE | \
SOF_TIMESTAMPING_RAW_HARDWARE);
if (setsockopt(s[i], SOL_SOCKET, SO_TIMESTAMPING,
&timestamping_flags, sizeof(timestamping_flags)) < 0) {
perror("setsockopt SO_TIMESTAMPING is not supported by your Linux kernel");
return 1;
}
} else {
const int timestamp_on = 1;
if (setsockopt(s[i], SOL_SOCKET, SO_TIMESTAMP,
&timestamp_on, sizeof(timestamp_on)) < 0) {
perror("setsockopt SO_TIMESTAMP");
return 1;
}
}
}
if (dropmonitor) {
const int dropmonitor_on = 1;
if (setsockopt(s[i], SOL_SOCKET, SO_RXQ_OVFL,
&dropmonitor_on, sizeof(dropmonitor_on)) < 0) {
perror("setsockopt SO_RXQ_OVFL not supported by your Linux Kernel");
return 1;
}
}
if (bind(s[i], (struct sockaddr *)&addr, sizeof(addr)) < 0) {
perror("bind");
return 1;
}
}
if (log) {
time_t currtime;
struct tm now;
char fname[sizeof("candump-2006-11-20_202026.log")+1];
if (time(&currtime) == (time_t)-1) {
perror("time");
return 1;
}
localtime_r(&currtime, &now);
sprintf(fname, "candump-%04d-%02d-%02d_%02d%02d%02d.log",
now.tm_year + 1900,
now.tm_mon + 1,
now.tm_mday,
now.tm_hour,
now.tm_min,
now.tm_sec);
if (silent != SILENT_ON)
printf("\nWarning: console output active while logging!");
fprintf(stderr, "\nEnabling Logfile '%s'\n\n", fname);
logfile = fopen(fname, "w");
if (!logfile) {
perror("logfile");
return 1;
}
}
/* these settings are static and can be held out of the hot path */
iov.iov_base = &frame;
msg.msg_name = &addr;
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
msg.msg_control = &ctrlmsg;
while (running) {
/*------------------------------- Opening the Serial Port -------------------------------*/
/* Change /dev/ttyUSB0 to the one corresponding to your system */
fd = open("/dev/ttyO2",O_RDWR | O_NOCTTY); /* ttyUSB0 is the FT232 based USB2SERIAL Converter */
/* O_RDWR - Read/Write access to serial port */
/* O_NOCTTY - No terminal will control the process */
/* Open in blocking mode,read will wait */
/* Error Checking */
if(fd == -1)
printf("\n Error! in Opening ttyO2 ");
else
printf("\n ttyO2 Opened Successfully ");
/*---------- Setting the Attributes of the serial port using termios structure --------- */
//struct termios SerialPortSettings; /* Create the structure */
tcgetattr(fd, &SerialPortSettings); /* Get the current attributes of the Serial port */
/* Setting the Baud rate */
cfsetispeed(&SerialPortSettings,B9600); /* Set Read Speed as 9600 */
cfsetospeed(&SerialPortSettings,B9600); /* Set Write Speed as 9600 */
/* 8N1 Mode */
SerialPortSettings.c_cflag &= ~PARENB; /* Disables the Parity Enable bit(PARENB),So No Parity */
SerialPortSettings.c_cflag &= ~CSTOPB; /* CSTOPB = 2 Stop bits,here it is cleared so 1 Stop bit */
SerialPortSettings.c_cflag &= ~CSIZE; /* Clears the mask for setting the data size */
SerialPortSettings.c_cflag |= CS8; /* Set the data bits = 8 */
SerialPortSettings.c_cflag &= ~CRTSCTS; /* No Hardware flow Control */
SerialPortSettings.c_cflag |= CREAD | CLOCAL; /* Enable receiver,Ignore Modem Control lines */
SerialPortSettings.c_iflag &= ~(IXON | IXOFF | IXANY); /* Disable XON/XOFF flow control both i/p and o/p */
SerialPortSettings.c_iflag &= ~(ICANON | ECHO | ECHOE | ISIG); /* Non Cannonical mode */
SerialPortSettings.c_oflag &= ~OPOST;/*No Output Processing*/
/* Setting Time outs */
SerialPortSettings.c_cc[VMIN] = 42; /* Read at least 42 characters */
SerialPortSettings.c_cc[VTIME] = 0; /* Wait indefinetly */
if((tcsetattr(fd,TCSANOW,&SerialPortSettings)) != 0) /* Set the attributes to the termios structure*/
printf("\n ERROR ! in Setting attributes");
else
printf("\n BaudRate = 9600 \n StopBits = 1 \n Parity = none \n\n");
/*------------------------------- Read data from serial port -----------------------------*/
tcflush(fd, TCIFLUSH); /* Discards old data in the rx buffer */
char read_buffer[42]; /* Buffer to store the data received */
int bytes_read = 0; /* Number of bytes read by the read() system call */
int ia = 0; int a;
int test = 0;
char new_read[38];
char curr_read[33];
int countc = 0;
a = 0;
do{
bytes_read = read(fd,&read_buffer,42); /* Read the data */
if(read_buffer[0] == '$')
if(read_buffer[1] == 'G')
if(read_buffer[2] == 'P')
if(read_buffer[3] == 'G')
if(read_buffer[4] == 'G'){
for(ia=7;ia<bytes_read;ia++){ /*printing only the received characters*/
new_read[a] = read_buffer[ia];
//printf("%c",read_buffer[ia]);
a = a+1;
test = 1;
}
strcpy(curr_read, new_read);
//printf("\n%s \n", curr_read);
}
else
test = 0;
else
test = 0;
else
test = 0;
else
test = 0;
else
test = 0;
}while(test == 0);
//tcflush(fd, TCIFLUSH); /* Discards old data in the rx buffer */
close(fd); /* Close the serial port */
while(countc < 1000){
FD_ZERO(&rdfs);
for (i=0; i<currmax; i++)
FD_SET(s[i], &rdfs);
if (timeout_current)
*timeout_current = timeout_config;
if ((ret = select(s[currmax-1]+1, &rdfs, NULL, NULL, timeout_current)) <= 0) {
//perror("select");
running = 0;
continue;
}
for (i=0; i<currmax; i++) { /* check all CAN RAW sockets */
if (FD_ISSET(s[i], &rdfs)) {
int idx;
/* these settings may be modified by recvmsg() */
iov.iov_len = sizeof(frame);
msg.msg_namelen = sizeof(addr);
msg.msg_controllen = sizeof(ctrlmsg);
msg.msg_flags = 0;
nbytes = recvmsg(s[i], &msg, 0);
idx = idx2dindex(addr.can_ifindex, s[i]);
if (nbytes < 0) {
if ((errno == ENETDOWN) && !down_causes_exit) {
fprintf(stderr, "%s: interface down\n", devname[idx]);
continue;
}
perror("read");
return 1;
}
if ((size_t)nbytes == CAN_MTU)
maxdlen = CAN_MAX_DLEN;
else if ((size_t)nbytes == CANFD_MTU)
maxdlen = CANFD_MAX_DLEN;
else {
fprintf(stderr, "read: incomplete CAN frame\n");
return 1;
}
if (count && (--count == 0))
running = 0;
if (bridge) {
if (bridge_delay)
usleep(bridge_delay);
nbytes = write(bridge, &frame, nbytes);
if (nbytes < 0) {
perror("bridge write");
return 1;
} else if ((size_t)nbytes != CAN_MTU && (size_t)nbytes != CANFD_MTU) {
fprintf(stderr,"bridge write: incomplete CAN frame\n");
return 1;
}
}
for (cmsg = CMSG_FIRSTHDR(&msg);
cmsg && (cmsg->cmsg_level == SOL_SOCKET);
cmsg = CMSG_NXTHDR(&msg,cmsg)) {
if (cmsg->cmsg_type == SO_TIMESTAMP) {
memcpy(&tv, CMSG_DATA(cmsg), sizeof(tv));
} else if (cmsg->cmsg_type == SO_TIMESTAMPING) {
struct timespec *stamp = (struct timespec *)CMSG_DATA(cmsg);
/*
* stamp[0] is the software timestamp
* stamp[1] is deprecated
* stamp[2] is the raw hardware timestamp
* See chapter 2.1.2 Receive timestamps in
* linux/Documentation/networking/timestamping.txt
*/
tv.tv_sec = stamp[2].tv_sec;
tv.tv_usec = stamp[2].tv_nsec/1000;
} else if (cmsg->cmsg_type == SO_RXQ_OVFL)
memcpy(&dropcnt[i], CMSG_DATA(cmsg), sizeof(__u32));
}
/* check for (unlikely) dropped frames on this specific socket */
if (dropcnt[i] != last_dropcnt[i]) {
__u32 frames = dropcnt[i] - last_dropcnt[i];
if (silent != SILENT_ON)
printf("DROPCOUNT: dropped %d CAN frame%s on '%s' socket (total drops %d)\n",
frames, (frames > 1)?"s":"", devname[idx], dropcnt[i]);
if (log)
fprintf(logfile, "DROPCOUNT: dropped %d CAN frame%s on '%s' socket (total drops %d)\n",
frames, (frames > 1)?"s":"", devname[idx], dropcnt[i]);
last_dropcnt[i] = dropcnt[i];
}
/* once we detected a EFF frame indent SFF frames accordingly */
if (frame.can_id & CAN_EFF_FLAG)
view |= CANLIB_VIEW_INDENT_SFF;
if (log) { /* CODE GETS IN TO THIS PART */
char buf[CL_CFSZ]; /* max length */ /* WHEN PRINTING INTO FILE */
/* */
/* log CAN frame with absolute timestamp & device */ /* */
sprint_canframe(buf, &frame, 0, maxdlen); /* */
fprintf(logfile, "%s %*s %s\n", /* */
curr_read, /* */
max_devname_len, devname[idx], buf); /* */
} /* */
if (logfrmt) {
char buf[CL_CFSZ]; /* max length */
/* print CAN frame in log file style to stdout */
sprint_canframe(buf, &frame, 0, maxdlen);
printf("(%010ld.%06ld) %*s %s\n",
tv.tv_sec, tv.tv_usec,
max_devname_len, devname[idx], buf);
goto out_fflush; /* no other output to stdout */
}
if (silent != SILENT_OFF){
if (silent == SILENT_ANI) {
printf("%c\b", anichar[silentani%=MAXANI]);
silentani++;
}
goto out_fflush; /* no other output to stdout */
}
printf(" %s", (color>2)?col_on[idx%MAXCOL]:"");
switch (timestamp) {
case 'a': /* absolute with timestamp */
printf("(%010ld.%06ld) ", tv.tv_sec, tv.tv_usec);
break;
case 'A': /* absolute with date */
{
struct tm tm;
char timestring[25];
tm = *localtime(&tv.tv_sec);
strftime(timestring, 24, "%Y-%m-%d %H:%M:%S", &tm);
printf("(%s.%06ld) ", timestring, tv.tv_usec);
}
break;
case 'd': /* delta */
case 'z': /* starting with zero */
{
struct timeval diff;
if (last_tv.tv_sec == 0) /* first init */
last_tv = tv;
diff.tv_sec = tv.tv_sec - last_tv.tv_sec;
diff.tv_usec = tv.tv_usec - last_tv.tv_usec;
if (diff.tv_usec < 0)
diff.tv_sec--, diff.tv_usec += 1000000;
if (diff.tv_sec < 0)
diff.tv_sec = diff.tv_usec = 0;
printf("(%03ld.%06ld) ", diff.tv_sec, diff.tv_usec);
if (timestamp == 'd')
last_tv = tv; /* update for delta calculation */
}
break;
default: /* no timestamp output */
break;
}
printf(" %s", (color && (color<3))?col_on[idx%MAXCOL]:"");
printf("%*s", max_devname_len, devname[idx]);
if (extra_msg_info) {
if (msg.msg_flags & MSG_DONTROUTE)
printf (" TX %s", extra_m_info[frame.flags & 3]);
else
printf (" RX %s", extra_m_info[frame.flags & 3]);
}
printf("%s ", (color==1)?col_off:"");
fprint_long_canframe(stdout, &frame, NULL, view, maxdlen);
printf("%s", (color>1)?col_off:"");
printf("\n");
}
out_fflush:
fflush(stdout);
}
countc = countc +1;
}
}
for (i=0; i<currmax; i++)
close(s[i]);
if (bridge)
close(bridge);
if (log)
fclose(logfile);
return 0;
}
Actually everything matters works in while(running) block. Inside this block when I make the bytes_read = read(fd,&read_buffer,42); as comment, it didn't write anything but also doesn't give the Segmentation fault error. Same also happens when I connect the GPS' TX pin in to BBB. So the problem starts to occur when the data is coming from the GPS and read by the BBB.
Segmentation Fault Err
What should I do about it?
Thanks.
Your GPS reading code
char new_read[38];
char curr_read[33];
strcpy(curr_read, new_read);
is copying a 38 char buffer into a 33 char buffer, which can result in bad things.
Strcpy will copy the contents of the source buffer into the destination buffer until it reads NULL from the source buffer. If the NULL char is at the 36th position in new_read, strcpy will be writing in random memory which can cause the segmentation fault.
I am guessing that when you run your GPS reading code as stand-alone, the writing into random memory goes un-noticed, but when you combine it with the CAN bus reading, it writes into allocated space and the error happens.

Reduction in running time of multiple modules due to linking

This question may seem very vague, hence I have included the code snippets for the modules mentioned. I have written a program that collects data from various sensors on an I2C bus and stores the formatted values in a file. This shall run on an ARM cortex A9 processor (single core) in an SoC configuration called Zedboard by Xilinx, and uses the petalinux operating system with the vanilla linux kernel. The time is being measured using clock_gettime(). I have noticed significant reduction in a single sensor access time when all of the sensors are being accessed sequentially within a single process. The comparison of this time was done with that of individual processes that access a single sensor only and do not write the data to a file, but print it to stdout instead.
Sensors used along with modules:
GY521 Module:
#include <linux/i2c-dev-user.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdint.h>
#include <inttypes.h>
#include "GY521.h"
#include <time.h>
#define ADDR 0x68
static int file;
static __s32 res;
static __u8 reg;
static __u8 values[14]; //array to hold all the register values
void set_sleep_gy521(int flag)
{
if(flag==0) //wake up the device
{
//Accessing reg 107
reg = 0x6B;
uint8_t val8 = 0x01; //write 0x00 if you want to set the internal 8MHz oscillator as CLK
res = i2c_smbus_write_byte_data(file, reg, val8);
if(res<0)
perror("Failed to wake it up");
/*else
printf("Device is awake\n");*/
}
else //set it to sleep
{
reg = 0x6B;
uint8_t val8 = 0x41; //write 0x40 if you want to set the internal 8MHz oscillator as CLK
res = i2c_smbus_write_byte_data(file, reg, val8);
if(res<0)
perror("Failed to go to sleep");
/*else
printf("In sleep mode\n");*/
}
}
void init_gy521()
{
char filename[20];
int adapter_no = 0;
snprintf(filename, 19, "/dev/i2c-%d", adapter_no);
file = open(filename, O_RDWR);
if(file<0)
{
perror("File not opened");
exit(1);
}
if(ioctl(file, I2C_SLAVE, ADDR)<0)
{
perror("Not able to access the device");
exit(EXIT_FAILURE);
}
//setting the sensitivity of the gyroscope and accelerometer
res = i2c_smbus_write_byte_data(file, 0x1B, 0x00);
if(res<0)
perror("Failed to set gyro range");
res = i2c_smbus_write_byte_data(file, 0x1C, 0x00);
if(res<0)
perror("Failed to set the accelerometer range");
set_sleep_gy521(0); //this also sets the clock source to X-axis gyro reference which is slightly better than the internal 8MHz oscillator
}
//get_values() stores all the register measurements in the array values
int get_values()
{
//reading all the values needed at once in a block
res = i2c_smbus_read_i2c_block_data(file, 0x3B, 14, (__u8*)values);
if(res<0)
perror("Failed to read using Block");
return res;
}
float get_Ax()
{
int c = get_values(); //calls get_values() to get all values at a time instant
int16_t xout;
if(c>0)
xout = (((int16_t)values[0])<<8) | values[1];
else
{
perror("Can't get the values");
exit(EXIT_FAILURE);
}
return xout/16384.0*9.8;
}
float get_Ay()
{
//concatenate the higher byte and the lower byte
int16_t yout = (((int16_t)values[2])<<8) | values[3];
return yout/16384.0*9.8;
}
float get_Az()
{
int16_t zout = (((int16_t)values[4])<<8) | values[5];
return zout/16384.0*9.8;
}
float get_temp_gy521()
{
__s16 temp = (((int16_t)values[6])<<8) | values[7];
return (temp/340.0 + 36.53);
}
float get_Wx()
{
__s16 xgyro = (((int16_t)values[8])<<8) | values[9];
return xgyro/131.0;
}
float get_Wy()
{
__s16 ygyro = (((int16_t)values[10])<<8) | values[11];
return ygyro/131.0;
}
float get_Wz()
{
__s16 zgyro = (((int16_t)values[12])<<8) | values[13];
return zgyro/131.0;
}
void clear_gy521()
{
close(file);
}
int main()
{
struct timespec start, end;
clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &start);
init_gy521();
printf("Wx: %f\n", get_Wx());
printf("Wy: %f\n", get_Wy());
printf("Wz: %f\n", get_Wz());
printf("Ax: %f\n", get_Ax());
printf("Ay: %f\n", get_Ay());
printf("Az: %f\n", get_Az());
clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &end);
printf("Time taken by GY521 is %d MuS\n", (end.tv_sec-start.tv_sec)*1000000L+(end.tv_nsec-start.tv_nsec)/1000);
}
LM75 Module:
#include <linux/i2c-dev-user.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <time.h>
#define ADDRESS 0x48
static int file; //use static keyword to ensure that the scope of this variable is limited to this file.
static __u8 buffer[2];
int get_temp()
{
if(i2c_smbus_read_i2c_block_data(file, 0x00, 2, buffer)<0)
perror("Failed to read the block");
return buffer[0]&127;
}
//Initializes the file used by the userspace calls. [IMPORTANT] Must be run before any other function is called for this device!. This needs to be called only once for each process.
void init_LM75()
{
int adapter_number = 0; //check this.
char filename[20];
snprintf(filename, 19, "/dev/i2c-%d", adapter_number);
file = open(filename, O_RDWR);
if(file<0)
{
perror("File not opened");
exit(1);
}
if(ioctl(file, I2C_SLAVE, ADDRESS)<0)
{
perror("ioctl could not open file");
exit(1);
}
}
int main()
{
struct timespec start, end;
clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &start);
init_LM75();
printf("Temperature is %d\n", get_temp());
clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &end);
printf("Time taken %d\n", (end.tv_sec-start.tv_sec)*1000000L+(end.tv_nsec-start.tv_nsec)/1000);
}
HMC5883L Module:
#include <linux/i2c-dev-user.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include "HMC5883L.h"
#include <time.h>
#define ADDRESS 0x1e
static int file; //use static keyword to ensure that the scope of this variable is limited to this file.
static float factor;
static __u8 buffer[6];
//register addresses
__u8 config_reg_A = 0x00;
__u8 mode_reg = 0x02;
__u8 gain_reg = 0x01;
__u8 data_X_H = 0x03;
__u8 data_X_L = 0x04;
__u8 data_Y_H = 0x07;
__u8 data_Y_L = 0x08;
__u8 data_Z_H = 0x05;
__u8 data_Z_L = 0x06;
/**
* The value of mode must be according to the following table:
* Value Mode
* 0 Continuous
* 1 Single (Default)
* 2 Idle
* 3 Idle
*
* After any mode change care must be taken to set it back to continuous mode before reading any values.
**/
void set_magnetometer_mode(int mode)
{
__u8 value = 0x00;
value |= mode;
if(i2c_smbus_write_byte_data(file, mode_reg, value)<0)
perror("Failed to change magnetometer mode");
}
void get_B()
{
if(i2c_smbus_read_i2c_block_data(file, data_X_H, 6, buffer)<0)
perror("Failed to read the block");
}
//[IMPORTANT] Note that the following 3 functions will return the field values in milli gauss by reading them from the buffer. So call get_Bx() first!
float get_Bx()
{
get_B();
int16_t temp;
//concatenate the upper and lower bits
temp = buffer[0];
int16_t b_X = (temp<<8) | buffer[1];
return (float)b_X*factor;
}
float get_By()
{
int16_t temp;
//concatenate the upper and lower bits
temp = buffer[4];
int16_t b_Y = (temp<<8) | buffer[5];
return (float)b_Y*factor;
}
float get_Bz()
{
int16_t temp;
//concatenate the upper and lower bits
temp = buffer[2];
int16_t b_Z = (temp<<8) | buffer[3];
return (float)b_Z*factor;
}
//Initializes the file used by the userspace calls. [IMPORTANT] Must be run before any other function is called for this device!. This needs to be called only once for each process.
void init_magnetometer()
{
int adapter_number = 0; //check this.
char filename[20];
snprintf(filename, 19, "/dev/i2c-%d", adapter_number);
file = open(filename, O_RDWR);
if(file<0)
{
perror("File not opened");
exit(1);
}
if(ioctl(file, I2C_SLAVE, ADDRESS)<0)
{
perror("ioctl could not open file");
exit(1);
}
factor = 0.92;
set_magnetometer_mode(0);
}
void clear_magnetometer()
{
close(file);
}
/**
* The value of freq must be according to the following table:
* Value Rate (Hz)
* 0 0.75
* 1 1.5
* 2 3
* 3 7.5
* 4 15 (Default)
* 5 30
* 6 75
**/
void set_magnetometer_frequency(int freq)
{
__u8 value = 0x00;
value |= freq<<2;
if(i2c_smbus_write_byte_data(file, config_reg_A, value)<0)
perror("Failed to change data rate");
}
/**
* The value of gain must be according to the following table:
* Value Field Range (+/- Gauss)
* 0 0.88
* 1 1.3 (Default)
* 2 1.9
* 3 2.5
* 4 4.0
* 5 4.7
* 6 5.6
* 7 8.1
*
* This function will also set the value of the factor to be multiplied to the raw data.
**/
void set_magnetometer_gain(int gain)
{
__u8 value = 0x00;
value |= gain<<5;
if(i2c_smbus_write_byte_data(file, gain_reg, value)<0)
perror("Failed to change magnetometer gain");
else
{
switch(gain)
{
case 0: factor = 0.73; break;
case 1: factor = 0.92; break;
case 2: factor = 1.22; break;
case 3: factor = 1.52; break;
case 4: factor = 2.27; break;
case 5: factor = 2.56; break;
case 6: factor = 3.03; break;
case 7: factor = 4.35; break;
}
}
}
int main()
{
struct timespec start, end;
clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &start);
init_magnetometer();
printf("%f\t%f\t%f\n", get_Bx(), get_By(), get_Bz());
clear_magnetometer();
clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &end);
printf("Time taken by HMC is %d MuS\n", (end.tv_sec-start.tv_sec)*1000000L+(end.tv_nsec-start.tv_nsec)/1000);
}
Single module that clubs all the three together and also writes data in a file:
#include <stdio.h>
#include <stdlib.h>
#include "hwfunctions.h"
#include <time.h>
int main()
{
struct timespec start_hk, end_hk, start_hmc, end_hmc, start_gy, end_gy, start_lm, end_lm;
clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &start_hk);
char *finalstr = (char* ) malloc(50);
FILE *f = fopen("fullhk.txt", "a");
if(f==NULL)
{
perror("Couldn't open file\n");
exit(0);
}
//initialization of the three sensors
//init_gy80();
time_t curt;
time(&curt);
//fseek(f, 0, SEEK_END);
sprintf(finalstr, "Time: %s\n", ctime(&curt));fputs(finalstr, f);
clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &start_hmc);
init_magnetometer();
sprintf(finalstr, "Bx: %f\n", get_Bx());fputs(finalstr, f);
sprintf(finalstr, "By: %f\n", get_By());fputs(finalstr, f);
sprintf(finalstr, "Bz: %f\n", get_Bz());fputs(finalstr, f);
clear_magnetometer();
clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &end_hmc);
sprintf(finalstr, "S1: %f\n", get_S1());fputs(finalstr, f);
sprintf(finalstr, "S2: %f\n", get_S2());fputs(finalstr, f);
sprintf(finalstr, "S3: %f\n", get_S3());fputs(finalstr, f);
sprintf(finalstr, "S4: %f\n", get_S4());fputs(finalstr, f);
sprintf(finalstr, "S5: %f\n", get_S5());fputs(finalstr, f);
clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &start_lm);
init_LM75();
sprintf(finalstr, "Temperature: %d\n", get_temp());fputs(finalstr, f);
clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &end_lm);
clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &start_gy);
init_gy521();
sprintf(finalstr, "Wy: %f\n", get_Wy());fputs(finalstr, f);
sprintf(finalstr, "Wz: %f\n", get_Wz());fputs(finalstr, f);
sprintf(finalstr, "Ax: %f\n", get_Ax());fputs(finalstr, f);
sprintf(finalstr, "Ay: %f\n", get_Ay());fputs(finalstr, f);
sprintf(finalstr, "Az: %f *end of block*\n\n", get_Az());
clear_gy521();
clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &end_gy);
fputs(finalstr, f);
fclose(f);
//closing the three sensors
//clear_gy80();
free(finalstr);
clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &end_hk);
printf("Time taken by single hmc instance: %ld microseconds\n", (end_hmc.tv_sec-start_hmc.tv_sec)*1000000L + (end_hmc.tv_nsec-start_hmc.tv_nsec)/1000);
printf("Time taken by single gy instance: %ld microseconds\n", (end_gy.tv_sec-start_gy.tv_sec)*1000000L + (end_gy.tv_nsec-start_gy.tv_nsec)/1000);
printf("Time taken by single lm instance: %ld microseconds\n", (end_lm.tv_sec-start_lm.tv_sec)*1000000L + (end_lm.tv_nsec-start_lm.tv_nsec)/1000);
printf("Time taken by single housekeeping instance: %ld microseconds\n", (end_hk.tv_sec-start_hk.tv_sec)*1000000L + (end_hk.tv_nsec-start_hk.tv_nsec)/1000);
}
Housekeeping is the name of the single module and the outputs above the housekeeping output are for the individual sensor modules. The housekeeping module has been compiled and linked with the sensor modules without the main function, and the O2 optimization flag has been used during cross compilation. This difference in the times is same even if the time is measured by CLOCK_BOOTTIME to include kernel pre-emption.
Please comment if any more information is needed to debunk this mystery!
I would suspect something happening in the background, when you use library functions for the first time.
Try to disable lazy binding, for example, by setting environment variable LD_BIND_NOW = 1 (Is there a linker flag to force it to load all shared libraries at start time?)

linux serial port : read be blocked mode

My goal is to set 2 threads for serial ports: one for read, one for write.
My example is refer to the [one](//refer to how to open, read, and write from serial port in C) heavily, but I added pthread to my code:
//refer to https://stackoverflow.com/questions/6947413/how-to-open-read-and-write-from-serial-port-in-c
//refer to https://stackoverflow.com/questions/6947413/how-to-open-read-and-write-from-serial-port-in-c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <termios.h>
#include <pthread.h> /* POSIX Threads */
#define MAX_STR_LEN 256
/*
* The values for speed are
* B115200, B230400, B9600, B19200, B38400, B57600, B1200, B2400, B4800, etc
*
* The values for parity are 0 (meaning no parity),
* PARENB|PARODD (enable parity and use odd),
* PARENB (enable parity and use even),
* PARENB|PARODD|CMSPAR (mark parity),
* and PARENB|CMSPAR (space parity).
* */
int SetInterfaceAttribs(int fd, int speed, int parity)
{
struct termios tty;
memset (&tty, 0, sizeof tty);
if (tcgetattr (fd, &tty) != 0) /* save current serial port settings */
{
printf("__LINE__ = %d, error %s\n", __LINE__, strerror(errno));
return -1;
}
cfsetospeed (&tty, speed);
cfsetispeed (&tty, speed);
tty.c_cflag = (tty.c_cflag & ~CSIZE) | CS8; // 8-bit chars
// disable IGNBRK for mismatched speed tests; otherwise receive break
// as \000 chars
tty.c_iflag &= ~IGNBRK; // disable break processing
tty.c_lflag = 0; // no signaling chars, no echo,
// no canonical processing
tty.c_oflag = 0; // no remapping, no delays
tty.c_cc[VMIN] = 0; // read doesn't block
tty.c_cc[VTIME] = 5; // 0.5 seconds read timeout
tty.c_iflag &= ~(IXON | IXOFF | IXANY); // shut off xon/xoff ctrl
tty.c_cflag |= (CLOCAL | CREAD);// ignore modem controls,
// enable reading
tty.c_cflag &= ~(PARENB | PARODD); // shut off parity
tty.c_cflag |= parity;
tty.c_cflag &= ~CSTOPB;
tty.c_cflag &= ~CRTSCTS;
if (tcsetattr (fd, TCSANOW, &tty) != 0)
{
printf("__LINE__ = %d, error %s\n", __LINE__, strerror(errno));
return -1;
}
return 0;
}/*set_interface_attribs*/
void SetBlocking(int fd, int should_block)
{
struct termios tty;
memset (&tty, 0, sizeof tty);
if (tcgetattr(fd, &tty) != 0)
{
printf("__LINE__ = %d, error %s\n", __LINE__, strerror(errno));
return;
}
tty.c_cc[VMIN] = should_block ? 1 : 0;
tty.c_cc[VTIME] = 5; // 0.5 seconds read timeout
if (tcsetattr (fd, TCSANOW, &tty) != 0)
printf("__LINE__ = %d, error %s\n", __LINE__, strerror(errno));
}/*SetBlocking*/
void *sendThread(void *parameters)
{
char sendBuff[MAX_STR_LEN];
memset(&sendBuff[0], 0, MAX_STR_LEN);
snprintf(&sendBuff[0], MAX_STR_LEN, "hello!");
int fd;
fd = *((int*)parameters);
while(1)
{
write(fd, &sendBuff[0], strlen(&sendBuff[0]) );
// sleep enough to transmit the length plus receive 25:
// approx 100 uS per char transmit
usleep((strlen(&sendBuff[0]) + 25) * 100);
}/*while*/
pthread_exit(0);
}/*sendThread */
void *readThread(void *parameters)
{
char readBuff[MAX_STR_LEN];
int fd;
fd = *((int*)parameters);
while(1)
{
ssize_t len;
memset(&readBuff[0], 0, MAX_STR_LEN);
len = read(fd, &readBuff[0], MAX_STR_LEN);
if (len == -1)
{
switch(errno)
{
case EAGAIN:
printf("__FUNCTION__ = %s, __LINE__ = %d\n", __FUNCTION__, __LINE__);
usleep(5*1000);
continue;
break;
default:
printf("__FUNCTION__ = %s, __LINE__ = %d\n", __FUNCTION__, __LINE__);
pthread_exit(0);
break;
}
}
// sleep enough to transmit the length plus receive 25:
// approx 100 uS per char transmit
usleep((len + 25) * 100);
printf("len = %d\n", (int)len);
int i;
for(i = 0; i< len; i++)
printf("%c(%d %#x)\t", readBuff[i], readBuff[i], readBuff[i]);
printf("\n");
}/*while*/
pthread_exit(0);
}/*readThread */
int main(int argc, char *argv[])
{
int fd, c, res;
struct termios oldtio,newtio;
char buf[MAX_STR_LEN];
int k;
char deviceName[MAX_STR_LEN];
memset(&deviceName[0], 0, MAX_STR_LEN);
snprintf(&deviceName[0], MAX_STR_LEN, "/dev/ttyUSB0");
k = 1;
while(argc > k)
{
if(0 == strncmp(argv[k], "-d", MAX_STR_LEN))
{
if(k + 1 < argc)
{
snprintf(&deviceName[0], MAX_STR_LEN, "%s", argv[k + 1]);
}
else
{
printf("error : -d should be follow a device!\n");
return 0;
}/*if */
}
k++;
}/*while k*/
printf("__FUNCTION__ = %s, __LINE__ = %d\n", __FUNCTION__, __LINE__);
fd = open(&deviceName[0], O_RDWR | O_NOCTTY |O_NONBLOCK| O_NDELAY);
if(0 > fd)
{
perror(&deviceName[0]);
exit(-1);
}/*if */
SetInterfaceAttribs(fd, B115200, 0); /* set speed to 115,200 bps, 8n1 (no parity)*/
SetBlocking(fd, 1);
pthread_t readThread_t, sendThread_t; /* thread variables */
pthread_create(&sendThread_t, NULL, (void *)sendThread, (void *)&fd);
pthread_create(&readThread_t, NULL, (void *)readThread, (void *)&fd);
pthread_join(sendThread_t, NULL);
pthread_join(readThread_t, NULL);
close(fd);
return 0;
}/*main*/
The send data thread works well.
But the read data thread : I could not set it as blocking, the read function returns immediately, even the read data length is zero.
How should I modify the code to make the read function be blocked?
fd = open(&deviceName[0], O_RDWR | O_NOCTTY |O_NONBLOCK| O_NDELAY);
Try removing O_NONBLOCK and O_NDELAY from your open call. Or is there a particular reason you have that even though you specifically want it to block?

I2C EEPROM Read/Write Cubieboard 2 Arch Linux

I am trying to read and write to the AT24MAC402 EEPROM over i2c on the Cubieboard 2 using Arch Linux. I am using the i2c-dev library and i2c-tools.
Datasheet:
http://www.atmel.com/images/atmel-8807-seeprom-at24mac402-602-datasheet.pdf
I can successfully write (kind of...) to a chosen address and sequentially write many bites starting at that address. The issues are:
Cannot re-select another address to write once the first address has been selected.
Cannot point the the EEPROM to the location I wish to read from (by dummy-writing), and therefore have almost no real control over the EEPROM.
Upon looking at the datasheet (for hours on end), it looks as if I don't have as much control over the I2C communications as I may need using the i2c-dev library.. It would be great if I could just write X bits or X bytes directly to the EEPROM.
In short, I would like advice on how I can read and write properly to this EEPROM.
char buf[10];
int com_serial;
int failcount;
int i2c_init(char filename[40], int addr)
{
int file;
if ((file = open(filename,O_RDWR)) < 0)
{
printf("Failed to open the bus.");
/* ERROR HANDLING; you can check errno to see what went wrong */
com_serial=0;
exit(1);
}
if (ioctl(file,I2C_SLAVE,addr) < 0)
{
printf("Failed to acquire bus access and/or talk to slave.\n");
/* ERROR HANDLING; you can check errno to see what went wrong */
com_serial=0;
exit(1);
}
return file;
}
int main (int argc, char *argv[]) {
char read_buf[16];
char write_buf[17];
int i;
int file;
file=i2c_init("/dev/i2c-1",0x50); //dev,slavei2caddr
write_buf[0] = 0x00;
write_buf[1] = 'H';
write_buf[2] = 'i';
write_buf[3] = '!';
write(file, write_buf, 4);
//Successfully prints "Hi!" to bytes 0x00 -> 0x02
//Setting EEPROM to point to address 0xA0 to start reading (arbitrary address with known values: all 0xFF)
write_buf[0] = 0xA0;
write(file, write_buf, 1);
//Reading 1 byte from EEPROM, even though there is a '2'; 2 bytes would be '3'
read(file, read_buf, 2);
for (i=1; i<3; i++){
printf("%X", read_buf[i]);
}
//Prints out from address 0x04 to 0x05 instead of 0xA0 to 0xA1
printf("\n");
}
I did work properly using the functions from the linux/i2c-dev.h.
To test the code I get the output generated by i2cdump and put as input to i2c-stub-from-dump tool, it lets you setup one or more fake I2C chips on the i2c-stub bus based on dumps of the chips you want to emulate.
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <linux/i2c-dev.h>
int i2c_init(const char * i2c_device, const int chip_address)
{
int file;
if ((file = open(i2c_device, O_RDWR)) < 0) {
return -1;
}
if (ioctl(file, I2C_SLAVE, chip_address) < 0) {
close(file);
return -1;
}
return file;
}
int i2c_write(int file, const int data_address, const unsigned char * data, size_t size)
{
return i2c_smbus_write_i2c_block_data(file, data_address, size, data);
}
void i2c_read(int file, const int data_address, unsigned char * data_vector, size_t size)
{
unsigned char reg = data_address;
unsigned int i;
for(i = 0; i < size; ++i, ++reg) {
data_vector[i] = i2c_smbus_read_byte_data(file, reg);
}
}
int main(void) {
char device[] = "/dev/i2c-6";
int address = 0x50;
unsigned char buffer_before[30] = {0};
unsigned char buffer_after[30] = {0};
unsigned char data[] = "Hello World!";
int file;
file = i2c_init(device, address);
if (file > 0) {
i2c_read(file, 0x00, buffer_before, sizeof(data));
i2c_write(file, 0x00, data, sizeof(data));
i2c_read(file, 0x00, buffer_after, sizeof(data));
close (file);
}
printf("data read before write: %s\n", buffer_before);
printf("data read after write: %s\n", buffer_after);
return 0;
}

Resources