Serial2MySQL/serial.c

667 lines
20 KiB
C

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdarg.h>
#include <string.h>
#include <termios.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <pthread.h>
#include <mysql/mysql.h>
#include <signal.h>
#include <ncurses.h>
#include <math.h>
#include <time.h>
WINDOW *header, *connections, *packages;
uint32_t counter = 0;
timer_t gTimerid;
WINDOW *create_newwin(int height, int width, int starty, int startx);
void destroy_win(WINDOW *local_win);
char *server = "localhost"; /* server host (default=localhost) */
char *user = "root"; /* username (default=login name) */
char *password = "raspberry"; /* password (default=none) */
char *database = "adatok"; /* database name (default=none) */
/*static*/
static MYSQL *conn;
struct buf_struct
{
//packed start
uint16_t start_header; //fix 0xFB55 csak a csomag elejének azonosításához kell
//innentől kerülnének az adatbázisba mind külön öszlopba
uint8_t chamber_id; //fix 0x00 felsőbb egység állítsa be
uint8_t ch_id; //jumper configurable lsb module ch0-1 select next 4 bit 16 modul select next 1 bit xy board select
int32_t inte_data; //integrated curve
uint16_t peak_amp;
uint16_t width;
uint32_t time_sec;
uint32_t time_ns;
uint16_t cmp_level;
uint16_t reserved;
//ez mehetne valami tömbbszerüségbe ha van ilyen
#ifdef debug_buf
uint16_t buff[raw_buff_size];
#endif
//crc-t lehetne ellenőrízni amikor megérkezik a csomag, nem kell az adatbázisba
uint16_t crc32;
uint16_t end_header; //fix 0xFEAA //csomag vége ez se kell!
};
#define raw_buff_size 64
#ifdef debug_buf
#define packet_size (28 + (2*raw_buff_size))
#else
#define packet_size 28
#endif
WINDOW *create_newwin(int height, int width, int starty, int startx)
{ WINDOW *local_win;
local_win = newwin(height, width, starty, startx);
//box(local_win, 0 , 0); /* 0, 0 gives default characters
// * for the vertical and horizontal
// * lines */
wborder(local_win, '|', '|', '-', '-', '+', '+', '+', '+');
wrefresh(local_win); /* Show that box */
return local_win;
}
int redrawborder(WINDOW *local_win)
{
//box(local_win, 0 , 0); /* 0, 0 gives default characters
// * for the vertical and horizontal
// * lines */
wborder(local_win, '|', '|', '-', '-', '+', '+', '+', '+');
wrefresh(local_win);
}
void destroy_win(WINDOW *local_win)
{
/* box(local_win, ' ', ' '); : This won't produce the desired
* result of erasing the window. It will leave it's four corners
* and so an ugly remnant of window.
*/
wborder(local_win, ' ', ' ', ' ',' ',' ',' ',' ',' ');
/* The parameters taken are
* 1. win: the window on which to operate
* 2. ls: character to be used for the left side of the window
* 3. rs: character to be used for the right side of the window
* 4. ts: character to be used for the top side of the window
* 5. bs: character to be used for the bottom side of the window
* 6. tl: character to be used for the top left corner of the window
* 7. tr: character to be used for the top right corner of the window
* 8. bl: character to be used for the bottom left corner of the window
* 9. br: character to be used for the bottom right corner of the window
*/
wrefresh(local_win);
delwin(local_win);
}
/*
* serialOpen:
* Open and initialise the serial port, setting all the right
* port parameters - or as many as are required - hopefully!
*********************************************************************************
*/
int serialOpen (const char *device, const int baud)
{
struct termios options ;
speed_t myBaud ;
int status, fd ;
switch (baud)
{
case 50: myBaud = B50 ; break ;
case 75: myBaud = B75 ; break ;
case 110: myBaud = B110 ; break ;
case 134: myBaud = B134 ; break ;
case 150: myBaud = B150 ; break ;
case 200: myBaud = B200 ; break ;
case 300: myBaud = B300 ; break ;
case 600: myBaud = B600 ; break ;
case 1200: myBaud = B1200 ; break ;
case 1800: myBaud = B1800 ; break ;
case 2400: myBaud = B2400 ; break ;
case 4800: myBaud = B4800 ; break ;
case 9600: myBaud = B9600 ; break ;
case 19200: myBaud = B19200 ; break ;
case 38400: myBaud = B38400 ; break ;
case 57600: myBaud = B57600 ; break ;
case 115200: myBaud = B115200 ; break ;
case 230400: myBaud = B230400 ; break ;
case 460800: myBaud = B460800 ; break ;
default:
return -2 ;
}
if ((fd = open (device, O_RDWR | O_NOCTTY | O_NDELAY | O_NONBLOCK)) == -1)
return -1 ;
fcntl (fd, F_SETFL, O_RDWR) ;
// Get and modify current options:
tcgetattr (fd, &options) ;
cfmakeraw (&options) ;
cfsetispeed (&options, myBaud) ;
cfsetospeed (&options, myBaud) ;
options.c_cflag |= (CLOCAL | CREAD) ;
options.c_cflag &= ~PARENB ;
options.c_cflag &= ~CSTOPB ;
options.c_cflag &= ~CSIZE ;
options.c_cflag |= CS8 ;
options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG) ;
options.c_oflag &= ~OPOST ;
options.c_cc [VMIN] = 0 ;
options.c_cc [VTIME] = 100 ; // Ten seconds (100 deciseconds)
tcsetattr (fd, TCSANOW | TCSAFLUSH, &options) ;
ioctl (fd, TIOCMGET, &status);
status |= TIOCM_DTR ;
status |= TIOCM_RTS ;
ioctl (fd, TIOCMSET, &status);
usleep (10000) ; // 10mS
return fd ;
}
/*
* serialFlush:
* Flush the serial buffers (both tx & rx)
*********************************************************************************
*/
void serialFlush (const int fd)
{
tcflush (fd, TCIOFLUSH) ;
}
/*
* serialClose:
* Release the serial port
*********************************************************************************
*/
void serialClose (const int fd)
{
close (fd) ;
}
/*
* serialPutchar:
* Send a single character to the serial port
*********************************************************************************
*/
void serialPutchar (const int fd, const unsigned char c)
{
write (fd, &c, 1) ;
}
/*
* serialPuts:
* Send a string to the serial port
*********************************************************************************
*/
void serialPuts (const int fd, const char *s)
{
write (fd, s, strlen (s)) ;
}
/*
* serialPrintf:
* Printf over Serial
*********************************************************************************
*/
void serialPrintf (const int fd, const char *message, ...)
{
va_list argp ;
char buffer [1024] ;
va_start (argp, message) ;
vsnprintf (buffer, 1023, message, argp) ;
va_end (argp) ;
serialPuts (fd, buffer) ;
}
/*
* serialDataAvail:
* Return the number of bytes of data avalable to be read in the serial port
*********************************************************************************
*/
int serialDataAvail (const int fd)
{
int result ;
if (ioctl (fd, FIONREAD, &result) == -1)
return -1 ;
return result ;
}
/*
* serialGetchar:
* Get a single character from the serial device.
* Note: Zero is a valid character and this function will time-out after
* 10 seconds.
*********************************************************************************
*/
int serialGetchar (const int fd)
{
uint8_t x ;
if (read (fd, &x, 1) != 1)
return -1 ;
return ((int)x) & 0xFF ;
}
/*************************************************************************************************************************************************************************************************/
/*************************************************************************************************************************************************************************************************/
/*************************************************************************************************************************************************************************************************/
/*************************************************************************************************************************************************************************************************/
/*************************************************************************************************************************************************************************************************/
/*************************************************************************************************************************************************************************************************/
int serialGetarray(const int fd, uint8_t out[], unsigned int size)
{
int i;
uint8_t x;
if((out == 0) | (fd == 0)) return -1;
if(size == 0) return -1;
for(i=0;i<size;i++)
{
if(read (fd, &out[i], 1) != 1)
return -1;
}
return 0; //nincs hiba
}
int read_packet(uint16_t size, uint8_t buff[], const int fd)
{
uint16_t i;
//find start
do{ //olvasás amíg nem a start header(0xFB55) első bájtja
//(0x55 a litle endian miatt(kisebb hejiértékü bájt érkezik hamarabb))
while(! (serialDataAvail(fd) > 0)) //vár amíg nincs adat
{
usleep(200);
}
buff[0] = serialGetchar (fd);
}while(buff[0] != 0x55); //ha start header eleje akkro tovább
while(! (serialDataAvail(fd) > 0)) //vár amíg nincs adat
{
//thread sleep? kelhet
}
buff[1] = serialGetchar (fd);
if(buff[1] != 0xFB) //nem start header return error
return -1;
//ha igen akkor beolvassa a maradék 22 bájtot
while(! (serialDataAvail(fd) >= (size-2))) //vár amíg nincs adat
{
usleep(1);
}
if(serialGetarray(fd, &buff[2], (size-2)) == -1) //beolvas 22 bájtott a bufferbe a header utánra
{
return -1; //uart hiba
}
if(buff[size-2] != 0xAA | buff[size-1] != 0xFE) //ha az end header nem passzol error
return -1;
//todo crc check
return 1; //adat beolvasva
}
int mysql_connect(WINDOW *local_win)
{
conn = mysql_init(NULL);
//printf("Mysql: Connecting to %s@%s as %s\n",database,server,user);
if (!mysql_real_connect(conn, server, user, password, database, 0, NULL, 0))
{
wattron(local_win,COLOR_PAIR(1));
mvwprintw(local_win,2,1,"MySQL Error");
wattroff(local_win,COLOR_PAIR(1));
wrefresh(local_win);
/*fprintf(stderr, "%s\n", mysql_error(conn));
exit(1);*/
}
else
{
wattron(local_win,COLOR_PAIR(2));
mvwprintw(local_win,2,1,"MySQL OK");
wattroff(local_win,COLOR_PAIR(2));
wrefresh(local_win);
} //printf("Mysql: Connected succesfully!\n");
}
int mysql_write(struct buf_struct adatok, WINDOW *local_win)
{
char data[300];
//printf("MySQL: Adatok beírása...\n");
//snprintf(data,300,"INSERT INTO fb55(chamber_id,ch_id,inte_data,peak_amp,width,time_sec,time_ns,cmp_lvl) VALUES(%d,%d,%d,%d,%d,%ld,%ld,%d)",adatok.chamber_id,adatok.ch_id,adatok.inte_data,adatok.peak_amp,adatok.width,adatok.time_sec,adatok.time_ns, adatok.cmp_level);
snprintf(data,300,"INSERT INTO fb55(chamber_id,ch_id,inte_data,peak_amp,width,time_sec,time_ns,cmp_lvl) VALUES(%hhu,%hhu,%d,%hu,%hu,%u,%u,%hu)"
,adatok.chamber_id,adatok.ch_id,adatok.inte_data,adatok.peak_amp,adatok.width,adatok.time_sec,adatok.time_ns, adatok.cmp_level);
if (!mysql_query(conn,data))
{
wattron(local_win,COLOR_PAIR(2));
mvwprintw(local_win,4,1,"Database OK");
wattroff(local_win,COLOR_PAIR(2));
wrefresh(local_win);
return 1;
}
else
{
wattron(local_win,COLOR_PAIR(1));
mvwprintw(local_win,4,1,"Database Error");
wattroff(local_win,COLOR_PAIR(1));
wrefresh(local_win);
}
}
int droptablecontent(char *tablename, WINDOW *local_win)
{
char data[100];
//printf("MySQL: Tábla ürítése...\n");
if (tablename==NULL)
{
snprintf(data,100,"truncate fb55");
}
else snprintf(data,100,"truncate %s",tablename);
if(mysql_query(conn,data)==0)
{
//printf("Sikeres ürítés!\n");
wattron(local_win,COLOR_PAIR(2));
mvwprintw(local_win,5,1,"Truncate OK");
wattroff(local_win,COLOR_PAIR(2));
wrefresh(local_win);
return 1;
}
else return -1;
}
void sigintHandler(int sig_num)
{
signal(SIGINT, sigintHandler);
mysql_close(conn);
clear();
char msg[]="Exiting...";
int row,col;
getmaxyx(stdscr,row,col);
mvprintw(row/2,(col-strlen(msg))/2,"%s",msg);
refresh();
//sleep(1);
endwin();
//printf("\nExiting... \n");
exit(1);
}
int init()
{
if ( (initscr()) == NULL )
{
fprintf(stderr, "Error initialising ncurses.\n");
exit(EXIT_FAILURE);
}
curs_set(0);
cbreak();
refresh();
if(has_colors() == FALSE)
{ endwin();
printf("Your terminal does not support color\n");
exit(1);
}
start_color(); /* Start color */
init_pair(1, COLOR_RED, COLOR_BLACK);
init_pair(2, COLOR_GREEN, COLOR_BLACK);
}
int printheader(WINDOW *header)
{
int width_max = COLS;
mvwprintw(header, 1, (width_max-58)/2, " ___ _ _ ___ __ __ ___ ___ _ ");
mvwprintw(header, 2, (width_max-58)/2, "/ __| ___ _ _(_)__ _| | |_ ) | \\/ |_ _/ __|/ _ \\| | ");
mvwprintw(header, 3, (width_max-58)/2, "\\__ \\/ -_) '_| / _` | | / / | |\\/| | || \\__ \\ (_) | |__ ");
mvwprintw(header, 4, (width_max-58)/2, "|___/\\___|_| |_\\__,_|_| /___| |_| |_|\\_, |___/\\__\\_\\____|");
mvwprintw(header, 5, (width_max-58)/2, " |__/");
wrefresh(header);
}
int printdatas(WINDOW *datas, struct buf_struct packet, int height, int width)
{
//ch_id:%d, inte:%ld, peak:%d, width:%d, time_sec:%ld, time_ns:%ld, , , , , , ,
mvwprintw(datas,height-2,1,"comp_lvl: ");
wclrtoeol(datas);
mvwprintw(datas,height-2,(width-floor((log10(packet.cmp_level+1) + 2))), "%d",packet.cmp_level);
mvwprintw(datas,height-4,1,"time_ns: ");
wclrtoeol(datas);
mvwprintw(datas,height-4,(width-floor((log10(packet.time_ns+1) + 2))), "%d",packet.time_ns);
mvwprintw(datas,height-6,1,"time_sec: ");
wclrtoeol(datas);
mvwprintw(datas,height-6,(width-floor((log10(packet.time_sec+1) + 2))), "%d",packet.time_sec);
mvwprintw(datas,height-8,1,"width: ");
wclrtoeol(datas);
mvwprintw(datas,height-8,(width-floor((log10(packet.width+1) + 2))), "%d",packet.width);
mvwprintw(datas,height-10,1,"peak_amp: ");
wclrtoeol(datas);
mvwprintw(datas,height-10,(width-floor((log10(packet.peak_amp+1) + 2))), "%d",packet.peak_amp);
mvwprintw(datas,height-12,1,"inte_data: ");
wclrtoeol(datas);
mvwprintw(datas,height-12,(width-floor((log10(abs(packet.inte_data+1)) + 2))), "%d",packet.inte_data);
mvwprintw(datas,height-14,1,"ch_id: ");
wclrtoeol(datas);
mvwprintw(datas,height-14,(width-floor((log10(packet.ch_id+1) + 2))), "%d",packet.ch_id);
redrawborder(datas);
wrefresh(datas);
}
void start_timer(void)
{
struct itimerspec value;
value.it_value.tv_sec = 1;//waits for 5 seconds before sending timer signal
value.it_value.tv_nsec = 0;
value.it_interval.tv_sec = 1; //sends timer signal every 5 seconds
value.it_interval.tv_nsec = 0;
timer_create (CLOCK_REALTIME, NULL, &gTimerid);
timer_settime (gTimerid, 0, &value, NULL);
}
void stop_timer(void)
{
struct itimerspec value;
value.it_value.tv_sec = 0;
value.it_value.tv_nsec = 0;
value.it_interval.tv_sec = 0;
value.it_interval.tv_nsec = 0;
timer_settime (gTimerid, 0, &value, NULL);
}
void timer_callback(int sig)
{
int height, width;
getmaxyx(connections,height,width);
mvwprintw(connections,height-7,1,"Received/Sec:");
wmove(connections,height-6,1);
wclrtoeol(connections);
mvwprintw(connections,height-6,(width-floor((log10(abs(counter)) + 2))),"%d", counter);
wrefresh(connections);
counter=0;
}
int main(int argc,char* argv[])
{
init();
int startx, starty, width_max, height_max, width, height, serialstatus, packages_maxx, packages_maxy;
uint8_t raw_buff[packet_size + 10]; //packet_size + egy kis tartalék, ha nincs hiba sehol akkor nem kell
uint16_t i;
uint32_t received = 0, writed = 0, count_x=0, count_y=0;
struct buf_struct packet;
width_max= 0;
height_max= 0;
height = 7;
width = width_max;
starty = 0; /* Calculating for a center placement */
startx = 0; /* of the window */
header = create_newwin(height, width, starty, startx);
connections = create_newwin(LINES-(height-1), 15, height-1, 0);
packages = create_newwin(LINES-(height-1), COLS-14, height-1, 14);
getmaxyx(connections,height_max,width_max);
getmaxyx(packages,packages_maxy,packages_maxx);
printheader(header);
mvwprintw(packages,1,1,"For debug mode use -d | For truncate use -drop | \n|You can truncate another table with -drop tablename");
wrefresh(packages);
//printf("**********************\n* Serial 2 Mysql *\n* For debug mode: -d *\n*For truncate: -drop *\n* You can truncate *\n* another table with *\n* -drop tablename *\n**********************\n* Script written *\n* by Baranyai Dávid *\n**********************\n");
mysql_connect(connections);
signal(SIGINT, sigintHandler); //CTRL + C kezelése. csak szórakozás
signal(SIGALRM, timer_callback); //timer megszakítás
start_timer();
if(argc>1)
{
if (!strcmp(argv[1],"-drop"))
{
if (argc>2)
{
droptablecontent(argv[2],connections);
}
else droptablecontent(NULL,connections);
}
}
int fd=serialOpen("/dev/ttyACM0",460800); //serial megnyitása
while (fd < 0)
{
wattron(connections,COLOR_PAIR(1));
mvwprintw(connections,1,1,"Serial Error");
wattroff(connections,COLOR_PAIR(1));
wrefresh(connections);
fd=serialOpen("/dev/ttyACM0",460800);
} //sikertelen csatlakozás esetén
//printf("Serial: Connected succesfully!");
wmove(connections,1,1);
wclrtoeol(connections);
redrawborder(connections);
wattron(connections,COLOR_PAIR(2));
mvwprintw(connections,1,1,"Serial OK");
wattroff(connections,COLOR_PAIR(2));
refresh();
wrefresh(connections);
serialFlush(fd); //buffer ürítése
while(1)
{
if(read_packet(packet_size, &raw_buff[0], fd) != -1)
{
received++;
if (serialstatus==0)
{
wmove(connections,3,1);
wclrtoeol(connections);
redrawborder(connections);
}
//sikerült beolvasni egy csomagot, feldolgozás
//printf("Sikeres fogadas\n");
wattron(connections,COLOR_PAIR(2));
mvwprintw(connections,3,1,"Receive OK");
wattroff(connections,COLOR_PAIR(2));
mvwprintw(connections,height_max-5,1,"Received: ");
wmove(connections,height_max-4,1);
wclrtoeol(connections);
mvwprintw(connections,height_max-4,(width_max-floor((log10(abs(received+1)) + 2))),"%d",received);
packet = *((struct buf_struct*) (&raw_buff[0])); //struktúrává kasztolás és átmásolás egy tényleges struktúrába
printdatas(packages, packet, packages_maxy, packages_maxx);
//struktúra tagok kiíratása
//printf("ch_id:%d, inte:%ld, peak:%d, width:%d, time_sec:%ld, time_ns:%ld, comp_lvl:%d\n", packet.ch_id, packet.inte_data, packet.peak_amp , packet.width, packet.time_sec, packet.time_ns, packet.cmp_level);
//mvprintw(3,0,"ch_id:%d, inte:%ld, peak:%d, width:%d, time_sec:%ld, time_ns:%ld, comp_lvl:%d\n", packet.ch_id, packet.inte_data, packet.peak_amp , packet.width, packet.time_sec, packet.time_ns, packet.cmp_level);
if (mysql_write(packet, connections)==1)
{
if (packet.ch_id>31)
{
count_y++;
}
else count_x++;
writed++;
counter++;
} //ideiglenes rögtönzött megoldás... struktúra átadása beírásra
mvwprintw(connections,height_max-3,1,"Writed: ");
wmove(connections,height_max-2,1);
mvwprintw(connections,height_max-2,(width_max-floor((log10(writed+1) + 2))),"%d",writed);
mvwprintw(connections,height_max-8,1,"y: %d",count_y);
mvwprintw(connections,height_max-9,1,"x: %d",count_x);
wrefresh(connections);
serialstatus = 1;
}
else
{
if (serialstatus==1)
{
wmove(connections,3,1);
wclrtoeol(connections);
redrawborder(connections);
}
wattron(connections,COLOR_PAIR(1));
mvwprintw(connections,3,1,"Receive Error");
wattroff(connections,COLOR_PAIR(1));
wrefresh(connections);
serialstatus = 0;
}
}
}