Fork of the espurna firmware for `mhsw` switches
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.

395 lines
10 KiB

  1. #include "ets_sys.h"
  2. #include "osapi.h"
  3. #include "gpio.h"
  4. #include "os_type.h"
  5. #include "user_interface.h"
  6. #include "softuart.h"
  7. //array of pointers to instances
  8. Softuart *_Softuart_GPIO_Instances[SOFTUART_GPIO_COUNT];
  9. uint8_t _Softuart_Instances_Count = 0;
  10. //intialize list of gpio names and functions
  11. softuart_reg_t softuart_reg[] =
  12. {
  13. { PERIPHS_IO_MUX_GPIO0_U, FUNC_GPIO0 }, //gpio0
  14. { PERIPHS_IO_MUX_U0TXD_U, FUNC_GPIO1 }, //gpio1 (uart)
  15. { PERIPHS_IO_MUX_GPIO2_U, FUNC_GPIO2 }, //gpio2
  16. { PERIPHS_IO_MUX_U0RXD_U, FUNC_GPIO3 }, //gpio3 (uart)
  17. { PERIPHS_IO_MUX_GPIO4_U, FUNC_GPIO4 }, //gpio4
  18. { PERIPHS_IO_MUX_GPIO5_U, FUNC_GPIO5 }, //gpio5
  19. { 0, 0 },
  20. { 0, 0 },
  21. { 0, 0 },
  22. { 0, 0 },
  23. { 0, 0 },
  24. { 0, 0 },
  25. { PERIPHS_IO_MUX_MTDI_U, FUNC_GPIO12 }, //gpio12
  26. { PERIPHS_IO_MUX_MTCK_U, FUNC_GPIO13 }, //gpio13
  27. { PERIPHS_IO_MUX_MTMS_U, FUNC_GPIO14 }, //gpio14
  28. { PERIPHS_IO_MUX_MTDO_U, FUNC_GPIO15 }, //gpio15
  29. //@TODO TODO gpio16 is missing (?include)
  30. };
  31. uint8_t Softuart_Bitcount(uint32_t x)
  32. {
  33. uint8_t count;
  34. for (count=0; x != 0; x>>=1) {
  35. if ( x & 0x01) {
  36. return count;
  37. }
  38. count++;
  39. }
  40. //error: no 1 found!
  41. return 0xFF;
  42. }
  43. uint8_t Softuart_IsGpioValid(uint8_t gpio_id)
  44. {
  45. if ((gpio_id > 5 && gpio_id < 12) || gpio_id > 15)
  46. {
  47. return 0;
  48. }
  49. return 1;
  50. }
  51. void Softuart_SetPinRx(Softuart *s, uint8_t gpio_id)
  52. {
  53. if(! Softuart_IsGpioValid(gpio_id)) {
  54. os_printf("SOFTUART GPIO not valid %d\r\n",gpio_id);
  55. } else {
  56. s->pin_rx.gpio_id = gpio_id;
  57. s->pin_rx.gpio_mux_name = softuart_reg[gpio_id].gpio_mux_name;
  58. s->pin_rx.gpio_func = softuart_reg[gpio_id].gpio_func;
  59. }
  60. }
  61. void Softuart_SetPinTx(Softuart *s, uint8_t gpio_id)
  62. {
  63. if(! Softuart_IsGpioValid(gpio_id)) {
  64. os_printf("SOFTUART GPIO not valid %d\r\n",gpio_id);
  65. } else {
  66. s->pin_tx.gpio_id = gpio_id;
  67. s->pin_tx.gpio_mux_name = softuart_reg[gpio_id].gpio_mux_name;
  68. s->pin_tx.gpio_func = softuart_reg[gpio_id].gpio_func;
  69. }
  70. }
  71. void Softuart_EnableRs485(Softuart *s, uint8_t gpio_id)
  72. {
  73. os_printf("SOFTUART RS485 init\r\n");
  74. //enable rs485
  75. s->is_rs485 = 1;
  76. //set pin in instance
  77. s->pin_rs485_tx_enable = gpio_id;
  78. //enable pin as gpio
  79. PIN_FUNC_SELECT(softuart_reg[gpio_id].gpio_mux_name,softuart_reg[gpio_id].gpio_func);
  80. PIN_PULLUP_DIS(softuart_reg[gpio_id].gpio_mux_name);
  81. //set low for tx idle (so other bus participants can send)
  82. GPIO_OUTPUT_SET(GPIO_ID_PIN(gpio_id), 0);
  83. os_printf("SOFTUART RS485 init done\r\n");
  84. }
  85. void Softuart_Init(Softuart *s, uint32_t baudrate, bool inverse)
  86. {
  87. //disable rs485
  88. s->is_rs485 = 0;
  89. s->inverse = inverse;
  90. if(! _Softuart_Instances_Count) {
  91. os_printf("SOFTUART initialize gpio\r\n");
  92. //Initilaize gpio subsystem
  93. gpio_init();
  94. }
  95. //set bit time
  96. if(baudrate <= 0) {
  97. os_printf("SOFTUART ERROR: Set baud rate (%d)\r\n",baudrate);
  98. } else {
  99. s->bit_time = (1000000 / baudrate);
  100. if ( ((100000000 / baudrate) - (100*s->bit_time)) > 50 ) s->bit_time++;
  101. os_printf("SOFTUART bit_time is %d\r\n",s->bit_time);
  102. }
  103. //init tx pin
  104. if(!s->pin_tx.gpio_mux_name) {
  105. os_printf("SOFTUART ERROR: Set tx pin (%d)\r\n",s->pin_tx.gpio_mux_name);
  106. } else {
  107. //enable pin as gpio
  108. PIN_FUNC_SELECT(s->pin_tx.gpio_mux_name, s->pin_tx.gpio_func);
  109. //set pullup (UART idle is VDD in direct logic)
  110. if (!s->inverse) PIN_PULLUP_EN(s->pin_tx.gpio_mux_name);
  111. //set high for tx idle
  112. GPIO_OUTPUT_SET(GPIO_ID_PIN(s->pin_tx.gpio_id), 1);
  113. os_delay_us(100000);
  114. os_printf("SOFTUART TX INIT DONE\r\n");
  115. }
  116. //init rx pin
  117. if(!s->pin_rx.gpio_mux_name) {
  118. os_printf("SOFTUART ERROR: Set rx pin (%d)\r\n",s->pin_rx.gpio_mux_name);
  119. } else {
  120. //enable pin as gpio
  121. PIN_FUNC_SELECT(s->pin_rx.gpio_mux_name, s->pin_rx.gpio_func);
  122. //set pullup (UART idle is VDD in direct logic)
  123. if (!s->inverse) PIN_PULLUP_EN(s->pin_rx.gpio_mux_name);
  124. //set to input -> disable output
  125. GPIO_DIS_OUTPUT(GPIO_ID_PIN(s->pin_rx.gpio_id));
  126. //set interrupt related things
  127. //disable interrupts by GPIO
  128. ETS_GPIO_INTR_DISABLE();
  129. //attach interrupt handler and a pointer that will be passed around each time
  130. ETS_GPIO_INTR_ATTACH(Softuart_Intr_Handler, s);
  131. //not sure what this does... (quote from example):
  132. // void gpio_register_set(uint32 reg_id, uint32 value);
  133. //
  134. // From include file
  135. // Set the specified GPIO register to the specified value.
  136. // This is a very general and powerful interface that is not
  137. // expected to be used during normal operation. It is intended
  138. // mainly for debug, or for unusual requirements.
  139. //
  140. // All people repeat this mantra but I don't know what it means
  141. //
  142. gpio_register_set(GPIO_PIN_ADDR(s->pin_rx.gpio_id),
  143. GPIO_PIN_INT_TYPE_SET(GPIO_PIN_INTR_DISABLE) |
  144. GPIO_PIN_PAD_DRIVER_SET(GPIO_PAD_DRIVER_DISABLE) |
  145. GPIO_PIN_SOURCE_SET(GPIO_AS_PIN_SOURCE));
  146. //clear interrupt handler status, basically writing a low to the output
  147. GPIO_REG_WRITE(GPIO_STATUS_W1TC_ADDRESS, BIT(s->pin_rx.gpio_id));
  148. //enable interrupt for pin on any edge (rise and fall)
  149. //@TODO: should work with ANYEDGE (=3), but complie error
  150. gpio_pin_intr_state_set(GPIO_ID_PIN(s->pin_rx.gpio_id), 3);
  151. //globally enable GPIO interrupts
  152. ETS_GPIO_INTR_ENABLE();
  153. os_printf("SOFTUART RX INIT DONE\r\n");
  154. }
  155. //add instance to array of instances
  156. _Softuart_GPIO_Instances[s->pin_rx.gpio_id] = s;
  157. _Softuart_Instances_Count++;
  158. os_printf("SOFTUART INIT DONE\r\n");
  159. }
  160. void Softuart_Intr_Handler(Softuart *s)
  161. {
  162. uint8_t level, gpio_id;
  163. // clear gpio status. Say ESP8266EX SDK Programming Guide in 5.1.6. GPIO interrupt handler
  164. uint32_t gpio_status = GPIO_REG_READ(GPIO_STATUS_ADDRESS);
  165. gpio_id = Softuart_Bitcount(gpio_status);
  166. //if interrupt was by an attached rx pin
  167. if (gpio_id != 0xFF)
  168. {
  169. //load instance which has rx pin on interrupt pin attached
  170. s = _Softuart_GPIO_Instances[gpio_id];
  171. // disable interrupt for GPIO0
  172. gpio_pin_intr_state_set(GPIO_ID_PIN(s->pin_rx.gpio_id), GPIO_PIN_INTR_DISABLE);
  173. // Do something, for example, increment whatyouwant indirectly
  174. //check level
  175. level = GPIO_INPUT_GET(GPIO_ID_PIN(s->pin_rx.gpio_id));
  176. if (level == s->inverse) {
  177. //pin is in trigger edge
  178. //therefore we have a start bit
  179. //wait till start bit is half over so we can sample the next one in the center
  180. os_delay_us(s->bit_time/2);
  181. //now sample bits
  182. unsigned i;
  183. unsigned d = 0;
  184. unsigned start_time = 0x7FFFFFFF & system_get_time();
  185. for(i = 0; i < 8; i ++ )
  186. {
  187. while ((0x7FFFFFFF & system_get_time()) < (start_time + (s->bit_time*(i+1))))
  188. {
  189. //If system timer overflow, escape from while loop
  190. if ((0x7FFFFFFF & system_get_time()) < start_time){break;}
  191. }
  192. //shift d to the right
  193. d >>= 1;
  194. //read bit
  195. if(GPIO_INPUT_GET(GPIO_ID_PIN(s->pin_rx.gpio_id))) {
  196. //if high, set msb of 8bit to 1
  197. d |= 0x80;
  198. }
  199. }
  200. //store byte in buffer
  201. // if buffer full, set the overflow flag and return
  202. uint8 next = (s->buffer.receive_buffer_tail + 1) % SOFTUART_MAX_RX_BUFF;
  203. if (next != s->buffer.receive_buffer_head)
  204. {
  205. // save new data in buffer: tail points to where byte goes
  206. s->buffer.receive_buffer[s->buffer.receive_buffer_tail] = d; // save new byte
  207. s->buffer.receive_buffer_tail = next;
  208. }
  209. else
  210. {
  211. s->buffer.buffer_overflow = 1;
  212. }
  213. //wait for stop bit
  214. os_delay_us(s->bit_time);
  215. //done
  216. }
  217. //clear interrupt
  218. GPIO_REG_WRITE(GPIO_STATUS_W1TC_ADDRESS, gpio_status);
  219. // Reactivate interrupts for GPIO0
  220. gpio_pin_intr_state_set(GPIO_ID_PIN(s->pin_rx.gpio_id), 3);
  221. } else {
  222. //clear interrupt, no matter from which pin
  223. //otherwise, this interrupt will be called again forever
  224. GPIO_REG_WRITE(GPIO_STATUS_W1TC_ADDRESS, gpio_status);
  225. }
  226. }
  227. // Read data from buffer
  228. uint8_t Softuart_Read(Softuart *s)
  229. {
  230. // Empty buffer?
  231. if (s->buffer.receive_buffer_head == s->buffer.receive_buffer_tail)
  232. return 0;
  233. // Read from "head"
  234. uint8_t d = s->buffer.receive_buffer[s->buffer.receive_buffer_head]; // grab next byte
  235. if (s->inverse) d = ~d;
  236. s->buffer.receive_buffer_head = (s->buffer.receive_buffer_head + 1) % SOFTUART_MAX_RX_BUFF;
  237. return d;
  238. }
  239. // Is data in buffer available?
  240. BOOL Softuart_Available(Softuart *s)
  241. {
  242. return (s->buffer.receive_buffer_tail + SOFTUART_MAX_RX_BUFF - s->buffer.receive_buffer_head) % SOFTUART_MAX_RX_BUFF;
  243. }
  244. static inline u8 chbit(u8 data, u8 bit)
  245. {
  246. if ((data & bit) != 0)
  247. {
  248. return 1;
  249. }
  250. else
  251. {
  252. return 0;
  253. }
  254. }
  255. // Function for printing individual characters
  256. void Softuart_Putchar(Softuart *s, char data)
  257. {
  258. unsigned i;
  259. unsigned start_time = 0x7FFFFFFF & system_get_time();
  260. // inverse logic
  261. if (s->inverse) data = ~data;
  262. //if rs485 set tx enable
  263. if(s->is_rs485 == 1)
  264. {
  265. GPIO_OUTPUT_SET(GPIO_ID_PIN(s->pin_rs485_tx_enable), 1);
  266. }
  267. //Start Bit
  268. GPIO_OUTPUT_SET(GPIO_ID_PIN(s->pin_tx.gpio_id), 0);
  269. for(i = 0; i < 8; i ++ )
  270. {
  271. while ((0x7FFFFFFF & system_get_time()) < (start_time + (s->bit_time*(i+1))))
  272. {
  273. //If system timer overflow, escape from while loop
  274. if ((0x7FFFFFFF & system_get_time()) < start_time){break;}
  275. }
  276. GPIO_OUTPUT_SET(GPIO_ID_PIN(s->pin_tx.gpio_id), chbit(data,1<<i));
  277. }
  278. // Stop bit
  279. while ((0x7FFFFFFF & system_get_time()) < (start_time + (s->bit_time*9)))
  280. {
  281. //If system timer overflow, escape from while loop
  282. if ((0x7FFFFFFF & system_get_time()) < start_time){break;}
  283. }
  284. GPIO_OUTPUT_SET(GPIO_ID_PIN(s->pin_tx.gpio_id), 1);
  285. // Delay after byte, for new sync
  286. os_delay_us(s->bit_time*6);
  287. //if rs485 set tx disable
  288. if(s->is_rs485 == 1)
  289. {
  290. GPIO_OUTPUT_SET(GPIO_ID_PIN(s->pin_rs485_tx_enable), 0);
  291. }
  292. }
  293. void Softuart_Puts(Softuart *s, const char *c )
  294. {
  295. while ( *c ) {
  296. Softuart_Putchar(s,( u8 )*c++);
  297. }
  298. }
  299. uint8_t Softuart_Readline(Softuart *s, char* Buffer, uint8_t MaxLen )
  300. {
  301. uint8_t NextChar;
  302. uint8_t len = 0;
  303. while( Softuart_Available(s) )
  304. {
  305. NextChar = Softuart_Read(s);
  306. if(NextChar == '\r')
  307. {
  308. continue;
  309. } else if(NextChar == '\n')
  310. {
  311. //break only if we already found a character
  312. //if it was .e.g. only \r, we wait for the first useful character
  313. if(len > 0) {
  314. break;
  315. }
  316. } else if(len < MaxLen - 1 )
  317. {
  318. *Buffer++ = NextChar;
  319. len++;
  320. } else {
  321. break;
  322. }
  323. }
  324. //add string terminator
  325. *Buffer++ = '\0';
  326. return len;
  327. }