#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <linux/gpio.h>
#include <termios.h>
#include <linux/ioctl.h>
#include <linux/serial.h>
#include <asm-generic/ioctls.h> /* TIOCGRS485 + TIOCSRS485 ioctl definitions */
#include <sys/types.h>
#include <sys/stat.h>
#include <getopt.h>
#include<pthread.h>
#include <signal.h>
int gpio_init();
void gpio_setnum(unsigned char value);
int port_open(char *device);
int port_init(int fd,struct termios oldtio ,int nSpeed, int nBits, char nEvent, int nStop);
static void print_usage(FILE *stream, int exit_code);
void print_usage(FILE *stream, int exit_code);
struct pthread_par
{
int fd,sig; //fd:串口设备
struct gpiohandle_request req; //申请gpio的结构体信息
struct gpiohandle_data data; //设置gpio的值
char *write_buf;
char read_buf[100];
pthread_mutex_t mut;
}par;
int gpio_init()
{
int fd1,ret1;
fd1 = open("/dev/gpiochip3", 0);
if (fd1 == -1) {
ret1 = -errno;
fprintf(stderr, "Failed to open %s\n","/dev/gpiochip3");
exit(1);
}
/* request GPIO line: GPIO_D_12 */
par.req.lineoffsets[0] = 12;
par.req.flags = GPIOHANDLE_REQUEST_OUTPUT; //output
//memcpy(req->default_values, data, sizeof(req->default_values));
strcpy(par.req.consumer_label, "gpio_d_12");
par.req.lines = 1;
ret1 = ioctl(fd1, GPIO_GET_LINEHANDLE_IOCTL, &par.req);
if (ret1 == -1) {
ret1 = -errno;
fprintf(stderr,"Failed to issue GET LINEHANDLE IOCTL (%d)\n",ret1);
}
if (close(fd1) == -1)
perror("Failed to close GPIO character device file");
return 0;
}
void gpio_setnum(unsigned char value)
{
int ret;
par.data.values[0] = value;
ret = ioctl(par.req.fd, GPIOHANDLE_SET_LINE_VALUES_IOCTL, &par.data);
if (ret == -1)
{
ret = -errno;
fprintf(stderr,"Failed to issue %s (%d)\n", ret);
}
}
int port_open(char *device)
{
int fd;
fd = open(device, O_RDWR);
if (fd < 0)
{
perror("port_open");
}
return fd;
}
int port_init(int fd,struct termios oldtio, int nSpeed, int nBits, char nEvent, int nStop)
{
struct termios newtio;
memset(&oldtio, 0, sizeof(oldtio));
/* save the old serial port configuration */
if (tcgetattr(fd, &oldtio) != 0)
{
perror("set_port/tcgetattr");
exit(1);
}
memset(&newtio, 0, sizeof(newtio));
/* ignore modem control lines and enable receiver */
newtio.c_cflag |= CLOCAL | CREAD;
newtio.c_cflag &= ~CSIZE;
/* set character size */
switch (nBits)
{
case 8:
newtio.c_cflag |= CS8;
break;
case 7:
newtio.c_cflag |= CS7;
break;
case 6:
newtio.c_cflag |= CS6;
break;
case 5:
newtio.c_cflag |= CS5;
break;
default:
newtio.c_cflag |= CS8;
break;
}
/* set the parity */
switch (nEvent)
{
case 'o':
case 'O':
newtio.c_cflag |= PARENB;
newtio.c_cflag |= PARODD;
newtio.c_iflag |= (INPCK | ISTRIP);
break;
case 'e':
case 'E':
newtio.c_cflag |= PARENB;
newtio.c_cflag &= ~PARODD;
newtio.c_iflag |= (INPCK | ISTRIP);
break;
case 'n':
case 'N':
newtio.c_cflag &= ~PARENB;
break;
default:
newtio.c_cflag &= ~PARENB;
break;
}
/* set the stop bits */
switch (nStop)
{
case 1:
newtio.c_cflag &= ~CSTOPB;
break;
case 2:
newtio.c_cflag |= CSTOPB;
break;
default:
newtio.c_cflag &= ~CSTOPB;
break;
}
/* set output and input baud rate */
switch (nSpeed)
{
case 0:
cfsetospeed(&newtio, B0);
cfsetispeed(&newtio, B0);
break;
case 50:
cfsetospeed(&newtio, B50);
cfsetispeed(&newtio, B50);
break;
case 75:
cfsetospeed(&newtio, B75);
cfsetispeed(&newtio, B75);
break;
case 110:
cfsetospeed(&newtio, B110);
cfsetispeed(&newtio, B110);
break;
case 134:
cfsetospeed(&newtio, B134);
cfsetispeed(&newtio, B134);
break;
case 150:
cfsetospeed(&newtio, B150);
cfsetispeed(&newtio, B150);
break;
case 200:
cfsetospeed(&newtio, B200);
cfsetispeed(&newtio, B200);
break;
case 300:
cfsetospeed(&newtio, B300);
cfsetispeed(&newtio, B300);
break;
case 600:
cfsetospeed(&newtio, B600);
cfsetispeed(&newtio, B600);
break;
case 1200:
cfsetospeed(&newtio, B1200);
cfsetispeed(&newtio, B1200);
break;
case 1800:
cfsetospeed(&newtio, B1800);
cfsetispeed(&newtio, B1800);
break;
case 2400:
cfsetospeed(&newtio, B2400);
cfsetispeed(&newtio, B2400);
break;
case 4800:
cfsetospeed(&newtio, B4800);
cfsetispeed(&newtio, B4800);
break;
case 9600:
cfsetospeed(&newtio, B9600);
cfsetispeed(&newtio, B9600);
break;
case 19200:
cfsetospeed(&newtio, B19200);
cfsetispeed(&newtio, B19200);
break;
case 38400:
cfsetospeed(&newtio, B38400);
cfsetispeed(&newtio, B38400);
break;
case 57600:
cfsetospeed(&newtio, B57600);
cfsetispeed(&newtio, B57600);
break;
case 115200:
cfsetospeed(&newtio, B115200);
cfsetispeed(&newtio, B115200);
break;
case 230400:
cfsetospeed(&newtio, B230400);
cfsetispeed(&newtio, B230400);
break;
default:
cfsetospeed(&newtio, B115200);
cfsetispeed(&newtio, B115200);
break;
}
/* set timeout in deciseconds for non-canonical read */
newtio.c_cc[VTIME] = 1;
/* set minimum number of characters for non-canonical read */
newtio.c_cc[VMIN] = 100;
/* flushes data received but not read */
tcflush(fd, TCIFLUSH);
/* set the parameters associated with the terminal from
the termios structure and the change occurs immediately */
if ((tcsetattr(fd, TCSANOW, &newtio)) != 0)
{
perror("set_port/tcsetattr");
exit(1);
}
return 0;
}
int input_init(int argc,char**argv,struct termios oldtio)
{
int r=1,speed,fd;
char *device;
int next_option;
int speed_flag = 0, device_flag = 0;
const char *const short_options = "hd:s:b:e:";
const struct option long_options[] = {
{"help", 0, NULL, 'h'},
{"device", 1, NULL, 'd'},
{"string", 1, NULL, 's'},
{"baudrate", 1, NULL, 'b'},
{NULL, 0, NULL, 0}};
if (argc < 2)
{
print_usage(stdout, 0);
exit(0);
}
while (r)
{
next_option = getopt_long(argc, argv, short_options, long_options, NULL);
if (next_option < 0)
break;
switch (next_option)
{
case 'h':
print_usage(stdout, 0);
break;
case 'd':
device = optarg;
device_flag = 1;
break;
case 'b':
speed = atoi(optarg);
speed_flag = 1;
break;
// case 's':
// write_buf = optarg;
// break;
case 'e':
r = atoi(optarg);
break;
case '?':
print_usage(stderr, 1);
break;
default:
abort();
}
}
if ((!device_flag) || (!speed_flag))
{
print_usage(stderr, 1);
exit(0);
}
fd = port_open(device);
port_init(fd,oldtio, speed, 8, 'N', 1);
return fd;
}
void print_usage(FILE *stream, int exit_code)
{
fprintf(stream, "Usage: option [ dev... ] \n");
fprintf(stream,
"\t-h --help Display this usage information.\n"
"\t-d --device The device ttyS[0-3] or ttySCMA[0-1]\n"
"\t-b --baudrate Set the baud rate you can select\n"
"\t [230400, 115200, 57600, 38400, 19200, 9600, 4800, 2400, 1200, 300]\n"
"\t-s --string Write the device data\n");
//"\t-e --1 or 0 Write 1 to enable the rs485_mode(only at atmel)\n");
exit(exit_code);
}
void *thread_func1()
{
int nread;
while (1)
{
//pthread_mutex_lock(&par.mut);
if(par.sig%2 == 0)
{
//pthread_mutex_lock(&par->mut);
memset(par.read_buf,0,sizeof(par.read_buf));
gpio_setnum(0);
nread = read(par.fd,par.read_buf,sizeof(par.read_buf));
if(nread<0)
{
perror("read error");
exit(1);
}
//pthread_mutex_unlock(&par->mut);
if(nread > 0)
{
printf("RECV[%3d]: ", nread);
for (int i = 0; i < nread; i++)
printf("%c", par.read_buf[i]);
printf("\n");
}
if(strcmp("quit",par.read_buf)==0)
{
par.sig ++;
}
}
}
printf("thread1 stop\n");
pthread_exit(NULL);
}
void *thread_func2()
{
int nwrite;
//struct pthread_par *par = p;
par.write_buf = malloc(100);
while (1)
{
if(par.sig%2 == 1)
{
//pthread_mutex_lock(&par->mut);
printf("please input something\n");
scanf("%[^\n]",par.write_buf);
getchar();
//gets(par.write_buf);
gpio_setnum(1);
nwrite = write(par.fd, par.write_buf,strlen(par.write_buf));
usleep(40000); // 40ms
//pthread_mutex_unlock(&par->mut);
if(strcmp("quit",par.write_buf)==0)
{
par.sig ++;
}
}
}
free(par.write_buf);
printf("thread2 stop\n");
pthread_exit(NULL);
}
void sigint_handler()
{
par.sig ++;
printf("\n");
if(par.sig%2 == 0)
{
gpio_setnum(0);
}
else
{
gpio_setnum(1);
}
}
int main(int argc, char **argv)
{
int ret;
struct termios oldtio;
pthread_t pthread[2];
memset(&pthread,0,sizeof(pthread));
/*input device ... and open device*/
par.fd = input_init(argc,argv,oldtio);
par.sig = 0;
/*request gpio_d_12*/
gpio_init();
signal(SIGINT, sigint_handler);
pthread_mutex_init(&par.mut,NULL);
printf("creat thread\n");
ret = pthread_create(&pthread[0], NULL, thread_func1, NULL);
if(ret != 0)
{
perror("pthread[0] error");
exit(1);
}
usleep(10);
ret = pthread_create(&pthread[1], NULL, thread_func2, NULL);
if(ret != 0)
{
perror("pthread[1] error");
exit(1);
}
/*等待线程结束*/
pthread_join(pthread[0],NULL);
pthread_join(pthread[1],NULL);
printf("thread close\n");
tcsetattr(par.fd,TCSANOW,&oldtio);
//pthread_mutex_destroy(&par.mut);
close(par.fd);
ret = close(par.req.fd);
if (ret == -1)
{
perror("Failed to close GPIO LINEHANDLE device file");
ret = -errno;
}
return 0;
}
RS485通信
于 2024-09-01 16:19:17 首次发布