• Linux:TTY串口接收中断


    Linux的串口接收中断一般都是使能的,无论是否是DMA接收。

     当串口接收到数据的时候,会调用 stm32_usart_push_buffer_dma函数。在这个函数内部向用户层发送信号,然后就可以调用read方法,读取数据了。从而避免循环读取数据。

    n_tty.c 

    1. // application pid, application use ioctl method to set this value
    2. int app_pid_ttySTM2 = 0;
    3. typedef enum{
    4. IOCTL_SET_APP_PID = 0x111,
    5. } MODULE_CMD;
    6. static int n_tty_ioctl(struct tty_struct *tty, struct file *file,
    7. unsigned int cmd, unsigned long arg)
    8. {
    9. struct n_tty_data *ldata = tty->disc_data;
    10. int retval;
    11. printk(KERN_INFO "gpio_XXXX_ioctl:%s cmd=0x%x,arg=0x%lx\n", __func__, cmd, arg);
    12. switch (cmd) {
    13. case TIOCOUTQ:
    14. return put_user(tty_chars_in_buffer(tty), (int __user *) arg);
    15. case TIOCINQ:
    16. down_write(&tty->termios_rwsem);
    17. if (L_ICANON(tty) && !L_EXTPROC(tty))
    18. retval = inq_canon(ldata);
    19. else
    20. retval = read_cnt(ldata);
    21. up_write(&tty->termios_rwsem);
    22. return put_user(retval, (unsigned int __user *) arg);
    23. case IOCTL_SET_APP_PID:
    24. {
    25. if(tty->index == 2)
    26. {
    27. if(copy_from_user(&app_pid_ttySTM2, (int *)arg, sizeof(int)))
    28. {
    29. return -EFAULT;
    30. }
    31. }
    32. return 0;
    33. }
    34. default:
    35. return n_tty_ioctl_helper(tty, file, cmd, arg);
    36. }
    37. }

     stm32-usart.c

    1. #define SIGETX 44
    2. static void stm32_usart_push_buffer_dma(struct uart_port *port,
    3. unsigned int dma_size)
    4. {
    5. struct stm32_port *stm32_port = to_stm32_port(port);
    6. struct tty_port *ttyport = &stm32_port->port.state->port;
    7. unsigned char *dma_start;
    8. int dma_count;
    9. struct kernel_siginfo info;
    10. struct task_struct *task = NULL;
    11. dma_start = stm32_port->rx_buf + (RX_BUF_L - stm32_port->last_res);
    12. dma_count = tty_insert_flip_string(ttyport, dma_start, dma_size);
    13. port->icount.rx += dma_count;
    14. stm32_port->last_res -= dma_count;
    15. if (stm32_port->last_res == 0)
    16. stm32_port->last_res = RX_BUF_L;
    17. if (app_pid_ttySTM2 == 0)
    18. {
    19. printk(KERN_ALERT "XXXX_NOTIFIER: gpio_XXXX_handler not set user pid\n");
    20. return ;
    21. }
    22. //Sending signal to app
    23. memset(&info, 0, sizeof(struct kernel_siginfo));
    24. info.si_signo = SIGETX;
    25. info.si_code = 0;
    26. info.si_int = 1234;
    27. printk(KERN_INFO "gpio_XXXX_handler Interrupt received from GPIO XXXX pin\n");
    28. rcu_read_lock();
    29. task = pid_task(find_vpid(app_pid_ttySTM2), PIDTYPE_PID);
    30. rcu_read_unlock();
    31. if (task == NULL) {
    32. printk(KERN_ALERT "XXXX_NOTIFIER: get_current failed\n");
    33. return;
    34. }
    35. else
    36. {
    37. printk(KERN_INFO "Sending signal to app\n");
    38. if(send_sig_info(SIGETX, &info, task) < 0) {
    39. printk(KERN_ALERT "gpio_XXXX_handler Unable to send signal\n");
    40. }
    41. }
    42. }

     应用程序:

    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. #include
    7. #include
    8. #include
    9. #include
    10. #include
    11. #include
    12. #include
    13. #include
    14. #define FALSE 0
    15. #define TRUE 1
    16. char *recchr="We received:\"";
    17. void print_usage();
    18. int speed_arr[] = {
    19. B921600, B460800, B230400, B115200, B57600, B38400, B19200,
    20. B9600, B4800, B2400, B1200, B300,
    21. };
    22. int name_arr[] = {
    23. 921600, 460800, 230400, 115200, 57600, 38400, 19200,
    24. 9600, 4800, 2400, 1200, 300,
    25. };
    26. #define SIGETX 44
    27. int check = 0;
    28. typedef enum{
    29. IOCTL_SET_APP_PID = 0x111,
    30. } APP_CMD;
    31. bool readyReadFlag = FALSE;
    32. void sig_event_handler(int n, siginfo_t *info, void *unused)
    33. {
    34. printf ("sig_event_handler Received signal from kernel");
    35. if (n == SIGETX) {
    36. check = info->si_int;
    37. printf ("Received signal from kernel : Value = %u\n", check);
    38. readyReadFlag = TRUE;
    39. }
    40. }
    41. void set_speed(int fd, int speed)
    42. {
    43. int i;
    44. int status;
    45. struct termios Opt;
    46. tcgetattr(fd, &Opt);
    47. for ( i= 0; i < sizeof(speed_arr) / sizeof(int); i++) {
    48. if (speed == name_arr[i]) {
    49. tcflush(fd, TCIOFLUSH);
    50. cfsetispeed(&Opt, speed_arr[i]);
    51. cfsetospeed(&Opt, speed_arr[i]);
    52. status = tcsetattr(fd, TCSANOW, &Opt);
    53. if (status != 0)
    54. perror("tcsetattr fd1");
    55. return;
    56. }
    57. tcflush(fd,TCIOFLUSH);
    58. }
    59. if (i == 12){
    60. printf("\tSorry, please set the correct baud rate!\n\n");
    61. print_usage(stderr, 1);
    62. }
    63. }
    64. /*
    65. *@brief 璁剧疆涓插彛鏁版嵁浣嶏紝鍋滄浣嶅拰鏁堥獙浣�
    66. *@param fd 绫诲瀷 int 鎵撳紑鐨勪覆鍙f枃浠跺彞鏌�*
    67. *@param databits 绫诲瀷 int 鏁版嵁浣� 鍙栧�� 涓� 7 鎴栬��8*
    68. *@param stopbits 绫诲瀷 int 鍋滄浣� 鍙栧�间负 1 鎴栬��2*
    69. *@param parity 绫诲瀷 int 鏁堥獙绫诲瀷 鍙栧�间负N,E,O,,S
    70. */
    71. int set_Parity(int fd,int databits,int stopbits,int parity)
    72. {
    73. struct termios options;
    74. if ( tcgetattr( fd,&options) != 0) {
    75. perror("SetupSerial 1");
    76. return(FALSE);
    77. }
    78. options.c_cflag &= ~CSIZE ;
    79. switch (databits) /*璁剧疆鏁版嵁浣嶆暟*/ {
    80. case 7:
    81. options.c_cflag |= CS7;
    82. break;
    83. case 8:
    84. options.c_cflag |= CS8;
    85. break;
    86. default:
    87. fprintf(stderr,"Unsupported data size\n");
    88. return (FALSE);
    89. }
    90. switch (parity) {
    91. case 'n':
    92. case 'N':
    93. options.c_cflag &= ~PARENB; /* Clear parity enable */
    94. options.c_iflag &= ~INPCK; /* Enable parity checking */
    95. break;
    96. case 'o':
    97. case 'O':
    98. options.c_cflag |= (PARODD | PARENB); /* 璁剧疆涓哄鏁堥獙*/
    99. options.c_iflag |= INPCK; /* Disnable parity checking */
    100. break;
    101. case 'e':
    102. case 'E':
    103. options.c_cflag |= PARENB; /* Enable parity */
    104. options.c_cflag &= ~PARODD; /* 杞崲涓哄伓鏁堥獙*/
    105. options.c_iflag |= INPCK; /* Disnable parity checking */
    106. break;
    107. case 'S':
    108. case 's': /*as no parity*/
    109. options.c_cflag &= ~PARENB;
    110. options.c_cflag &= ~CSTOPB;
    111. break;
    112. default:
    113. fprintf(stderr,"Unsupported parity\n");
    114. return (FALSE);
    115. }
    116. /* 璁剧疆鍋滄浣�*/
    117. switch (stopbits) {
    118. case 1:
    119. options.c_cflag &= ~CSTOPB;
    120. break;
    121. case 2:
    122. options.c_cflag |= CSTOPB;
    123. break;
    124. default:
    125. fprintf(stderr,"Unsupported stop bits\n");
    126. return (FALSE);
    127. }
    128. /* Set input parity option */
    129. if (parity != 'n')
    130. options.c_iflag |= INPCK;
    131. options.c_cc[VTIME] = 150; // 15 seconds
    132. options.c_cc[VMIN] = 0;
    133. //options.c_lflag &= ~(ECHO | ICANON);
    134. options.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON);
    135. options.c_oflag &= ~OPOST;
    136. options.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
    137. options.c_cflag &= ~(CSIZE | PARENB);
    138. tcflush(fd,TCIFLUSH); /* Update the options and do it NOW */
    139. if (tcsetattr(fd,TCSANOW,&options) != 0) {
    140. perror("SetupSerial 3");
    141. return (FALSE);
    142. }
    143. return (TRUE);
    144. }
    145. /**
    146. *@breif 鎵撳紑涓插彛
    147. */
    148. int OpenDev(char *Dev)
    149. {
    150. int fd = open( Dev, O_RDWR ); //| O_NOCTTY | O_NDELAY
    151. if (-1 == fd) { /*璁剧疆鏁版嵁浣嶆暟*/
    152. perror("Can't Open Serial Port");
    153. return -1;
    154. } else
    155. return fd;
    156. }
    157. /* The name of this program */
    158. const char * program_name;
    159. /* Prints usage information for this program to STREAM (typically
    160. * stdout or stderr), and exit the program with EXIT_CODE. Does not
    161. * return.
    162. */
    163. void print_usage (FILE *stream, int exit_code)
    164. {
    165. fprintf(stream, "Usage: %s option [ dev... ] \n", program_name);
    166. fprintf(stream,
    167. "\t-h --help Display this usage information.\n"
    168. "\t-d --device The device ttyS[0-3] or ttySCMA[0-1]\n"
    169. "\t-b --baudrate Set the baud rate you can select\n"
    170. "\t [230400, 115200, 57600, 38400, 19200, 9600, 4800, 2400, 1200, 300]\n"
    171. "\t-s --string Write the device data\n");
    172. exit(exit_code);
    173. }
    174. /*
    175. *@breif main()
    176. */
    177. int main(int argc, char *argv[])
    178. {
    179. int fd, next_option, havearg = 0;
    180. char *device;
    181. int i=0,j=0;
    182. int nread; /* Read the counts of data */
    183. char buff[512]; /* Recvice data buffer */
    184. pid_t pid;
    185. int app_pid;
    186. struct sigaction act;
    187. //char *xmit = "1234567890"; /* Default send data */
    188. char *xmit = "0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x20"; /* Default send data */
    189. char xmit_data[15] = {0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25};
    190. int speed, send_mode = 0;
    191. const char *const short_options = "hd:s:b:m:";
    192. const struct option long_options[] = {
    193. { "help", 0, NULL, 'h'},
    194. { "device", 1, NULL, 'd'},
    195. { "string", 1, NULL, 's'},
    196. { "baudrate", 1, NULL, 'b'},
    197. { "send/recv mode", 0, NULL, 'm'},
    198. { NULL, 0, NULL, 0 }
    199. };
    200. /* install custom signal handler */
    201. sigemptyset(&act.sa_mask);
    202. act.sa_flags = SA_NODEFER;
    203. act.sa_sigaction = sig_event_handler;
    204. sigaction(SIGETX, &act, NULL);
    205. printf("Installed signal handler for SIGETX = %d\n", SIGETX);
    206. app_pid = getpid();
    207. program_name = argv[0];
    208. do {
    209. next_option = getopt_long (argc, argv, short_options, long_options, NULL);
    210. switch (next_option) {
    211. case 'h':
    212. print_usage (stdout, 0);
    213. case 'd':
    214. device = optarg;
    215. havearg = 1;
    216. break;
    217. case 'b':
    218. speed = atoi(optarg);
    219. break;
    220. case 's':
    221. xmit = optarg;
    222. havearg = 1;
    223. break;
    224. case 'm':
    225. send_mode = atoi(optarg);
    226. break;
    227. case -1:
    228. if (havearg) break;
    229. case '?':
    230. print_usage (stderr, 1);
    231. default:
    232. abort ();
    233. }
    234. }while(next_option != -1);
    235. sleep(1);
    236. fd = OpenDev(device);
    237. if (fd > 0) {
    238. set_speed(fd, speed);
    239. } else {
    240. fprintf(stderr, "Error opening %s: %s\n", device, strerror(errno));
    241. exit(1);
    242. }
    243. if (set_Parity(fd,8,1,'N')== FALSE) {
    244. fprintf(stderr, "Set Parity Error\n");
    245. close(fd);
    246. exit(1);
    247. }
    248. ioctl(fd, IOCTL_SET_APP_PID, &app_pid);
    249. #if 0
    250. pid = fork();
    251. if (pid < 0) {
    252. fprintf(stderr, "Error in fork!\n");
    253. } else if (pid == 0){
    254. #endif
    255. if (send_mode){
    256. while(1) {
    257. printf("%s SEND: %s\n",device, xmit);
    258. //write(fd, xmit, strlen(xmit));
    259. write(fd, xmit_data, sizeof(xmit_data));
    260. sleep(1);
    261. i++;
    262. }
    263. }else {
    264. while(1) {
    265. if(readyReadFlag)
    266. {
    267. printf("Start to read. \n");
    268. nread = read(fd, buff, sizeof(buff));
    269. if (nread > 0) {
    270. printf("RECV nread = %d\n", nread);
    271. for(int id = 0; id < nread; id++)
    272. {
    273. printf("RECV[%d]: %d\n", id, buff[id]);
    274. }
    275. buff[nread] = '\0';
    276. //printf("%s RECV[%d]: %s\n", device, nread, buff);
    277. }
    278. readyReadFlag = FALSE;
    279. }
    280. sleep(1);
    281. }
    282. }
    283. close(fd);
    284. exit(0);
    285. }

     

     

     

  • 相关阅读:
    爆破内网路由和主机密码
    Modbus转Profinet网关连接皖仪氦质谱检漏仪SFJ-16M通信配置案例
    【监控系统】Promethus整合Alertmanager监控告警邮件通知
    excel导出图片中的单位问题
    数据库学习笔记——DDL
    JAVA:实现PiNilakantha方法计算pi算法(附完整源码)
    卡塔尔世界杯倒计时!世界杯直播在哪里观看?美家市场汇总来了!
    【C++】入门三
    数据分析er看过来,五款工具有你需要的
    SpringBoot集成Redis实战——步骤、坑点、解决方案
  • 原文地址:https://blog.csdn.net/xikangsoon/article/details/126891820