You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

210 lines
4.7 KiB

  1. #include <linux/module.h>
  2. #include <linux/gpio.h>
  3. #include <linux/hrtimer.h>
  4. #include <linux/interrupt.h>
  5. #include <linux/ktime.h>
  6. #include <linux/proc_fs.h>
  7. #include <linux/seq_file.h>
  8. #include <linux/version.h>
  9. MODULE_LICENSE("GPL");
  10. MODULE_AUTHOR("Nuno Goncalves");
  11. MODULE_DESCRIPTION("GL-MiFi power monitoring MCU interface");
  12. MODULE_VERSION("0.1");
  13. static int gpio_tx = 19;
  14. static int gpio_rx = 8;
  15. static int baudrate = 1200;
  16. static int query_interval_sec = 4;
  17. static struct hrtimer timer_tx;
  18. static struct hrtimer timer_rx;
  19. static ktime_t period;
  20. static int rx_bit_index = -1;
  21. static unsigned read_buf_ready = 0;
  22. static unsigned read_buf_size = 0;
  23. static char read_buf[2][64] = {{0},{0}};
  24. static int proc_show(struct seq_file *m, void *v)
  25. {
  26. seq_printf(m, "%s\n", read_buf[read_buf_ready]);
  27. return 0;
  28. }
  29. static int proc_open(struct inode *inode, struct file *file)
  30. {
  31. return single_open(file, proc_show, NULL);
  32. }
  33. #if LINUX_VERSION_CODE >= KERNEL_VERSION(5,6,0)
  34. static const struct proc_ops hello_proc_ops = {
  35. .proc_open = proc_open,
  36. .proc_read = seq_read,
  37. .proc_lseek = seq_lseek,
  38. .proc_release = single_release,
  39. };
  40. #else
  41. static const struct file_operations hello_proc_ops = {
  42. .owner = THIS_MODULE,
  43. .open = proc_open,
  44. .read = seq_read,
  45. .llseek = seq_lseek,
  46. .release = single_release,
  47. };
  48. #endif
  49. static irq_handler_t handle_rx_start(unsigned int irq, void* device, struct pt_regs* registers)
  50. {
  51. if (rx_bit_index == -1)
  52. {
  53. hrtimer_start(&timer_rx, ktime_set(0, period / 2), HRTIMER_MODE_REL);
  54. }
  55. return (irq_handler_t) IRQ_HANDLED;
  56. }
  57. static enum hrtimer_restart handle_tx(struct hrtimer* timer)
  58. {
  59. ktime_t current_time = ktime_get();
  60. const unsigned char character = 'g';
  61. static int bit_index = -1;
  62. // Start bit.
  63. if (bit_index == -1)
  64. {
  65. gpio_set_value(gpio_tx, 0);
  66. bit_index++;
  67. }
  68. // Data bits.
  69. else if (0 <= bit_index && bit_index < 8)
  70. {
  71. gpio_set_value(gpio_tx, 1 & (character >> bit_index));
  72. bit_index++;
  73. }
  74. // Stop bit.
  75. else if (bit_index == 8)
  76. {
  77. gpio_set_value(gpio_tx, 1);
  78. bit_index = -1;
  79. }
  80. hrtimer_forward(&timer_tx, current_time, bit_index == 8
  81. ? ktime_set(query_interval_sec, 0) //wait for next query cycle
  82. : period); //wait for next bit period
  83. return HRTIMER_RESTART;
  84. }
  85. void receive_character(unsigned char character)
  86. {
  87. if(character == '{')
  88. read_buf_size = 0;
  89. if(read_buf_size < (sizeof(read_buf[0])-1) || character == '}')
  90. {
  91. read_buf[!read_buf_ready][read_buf_size++] = character;
  92. if(character == '}')
  93. {
  94. read_buf[!read_buf_ready][read_buf_size] = '\0';
  95. read_buf_ready = !read_buf_ready;
  96. read_buf_size = 0;
  97. }
  98. }
  99. }
  100. static enum hrtimer_restart handle_rx(struct hrtimer* timer)
  101. {
  102. ktime_t current_time = ktime_get();
  103. static unsigned int character = 0;
  104. int bit_value = gpio_get_value(gpio_rx);
  105. enum hrtimer_restart result = HRTIMER_NORESTART;
  106. bool must_restart_timer = false;
  107. // Start bit.
  108. if (rx_bit_index == -1)
  109. {
  110. rx_bit_index++;
  111. character = 0;
  112. must_restart_timer = true;
  113. }
  114. // Data bits.
  115. else if (0 <= rx_bit_index && rx_bit_index < 8)
  116. {
  117. if (bit_value == 0)
  118. {
  119. character &= 0xfeff;
  120. }
  121. else
  122. {
  123. character |= 0x0100;
  124. }
  125. rx_bit_index++;
  126. character >>= 1;
  127. must_restart_timer = true;
  128. }
  129. // Stop bit.
  130. else if (rx_bit_index == 8)
  131. {
  132. receive_character(character);
  133. rx_bit_index = -1;
  134. }
  135. // Restarts the RX timer.
  136. if (must_restart_timer)
  137. {
  138. hrtimer_forward(&timer_rx, current_time, period);
  139. result = HRTIMER_RESTART;
  140. }
  141. return result;
  142. }
  143. static int __init init(void)
  144. {
  145. bool success = true;
  146. proc_create("gl_mifi_mcu", 0, NULL, &hello_proc_ops);
  147. success &= gpio_request(gpio_tx, "soft_uart_tx") == 0;
  148. success &= gpio_direction_output(gpio_tx, 1) == 0;
  149. success &= gpio_request(gpio_rx, "soft_uart_rx") == 0;
  150. success &= gpio_direction_input(gpio_rx) == 0;
  151. success &= gpio_set_debounce(gpio_rx, 1000/baudrate/2);
  152. success &= request_irq(
  153. gpio_to_irq(gpio_rx),
  154. (irq_handler_t) handle_rx_start,
  155. IRQF_TRIGGER_FALLING,
  156. "gl_mifi_mcu_irq_handler",
  157. NULL) == 0;
  158. hrtimer_init(&timer_tx, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
  159. timer_tx.function = &handle_tx;
  160. hrtimer_init(&timer_rx, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
  161. timer_rx.function = &handle_rx;
  162. period = ktime_set(0, 1000000000/baudrate);
  163. hrtimer_start(&timer_tx, period, HRTIMER_MODE_REL);
  164. return success;
  165. }
  166. static void __exit exit(void)
  167. {
  168. disable_irq(gpio_to_irq(gpio_rx));
  169. hrtimer_cancel(&timer_tx);
  170. hrtimer_cancel(&timer_rx);
  171. free_irq(gpio_to_irq(gpio_rx), NULL);
  172. gpio_set_value(gpio_tx, 0);
  173. gpio_free(gpio_tx);
  174. gpio_free(gpio_rx);
  175. remove_proc_entry("gl_mifi_mcu", NULL);
  176. }
  177. module_init(init);
  178. module_exit(exit);