PlatformIO package of the Teensy core framework compatible with GCC 10 & C++20
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.

247 line
5.3KB

  1. // HardwareSerial.cpp
  2. //
  3. // Copyright (C) 2015 Mike McCauley
  4. // $Id: HardwareSerial.cpp,v 1.3 2015/08/13 02:45:47 mikem Exp mikem $
  5. #include <RadioHead.h>
  6. #if (RH_PLATFORM == RH_PLATFORM_UNIX)
  7. #include <HardwareSerial.h>
  8. #include <string.h>
  9. #include <unistd.h>
  10. #include <fcntl.h>
  11. #include <errno.h>
  12. #include <termios.h>
  13. #include <sys/ioctl.h>
  14. #include <sys/select.h>
  15. HardwareSerial::HardwareSerial(const char* deviceName)
  16. : _deviceName(deviceName),
  17. _device(-1)
  18. {
  19. // Override device name from environment
  20. char* e = getenv("RH_HARDWARESERIAL_DEVICE_NAME");
  21. if (e)
  22. _deviceName = e;
  23. }
  24. void HardwareSerial::begin(int baud)
  25. {
  26. if (openDevice())
  27. setBaud(baud);
  28. }
  29. void HardwareSerial::end()
  30. {
  31. closeDevice();
  32. }
  33. void HardwareSerial::flush()
  34. {
  35. tcdrain(_device);
  36. }
  37. int HardwareSerial::peek(void)
  38. {
  39. printf("HardwareSerial::peek not implemented\n");
  40. return 0;
  41. }
  42. int HardwareSerial::available()
  43. {
  44. int bytes;
  45. if (ioctl(_device, FIONREAD, &bytes) != 0)
  46. {
  47. fprintf(stderr, "HardwareSerial::available ioctl failed: %s\n", strerror(errno));
  48. return 0;
  49. }
  50. return bytes;
  51. }
  52. int HardwareSerial::read()
  53. {
  54. uint8_t data;
  55. ssize_t result = ::read(_device, &data, 1);
  56. if (result != 1)
  57. {
  58. fprintf(stderr, "HardwareSerial::read read failed: %s\n", strerror(errno));
  59. return 0;
  60. }
  61. // printf("got: %02x\n", data);
  62. return data;
  63. }
  64. size_t HardwareSerial::write(uint8_t ch)
  65. {
  66. size_t result = ::write(_device, &ch, 1);
  67. if (result != 1)
  68. {
  69. fprintf(stderr, "HardwareSerial::write failed: %s\n", strerror(errno));
  70. return 0;
  71. }
  72. // printf("sent: %02x\n", ch);
  73. return 1; // OK
  74. }
  75. bool HardwareSerial::openDevice()
  76. {
  77. if (_device == -1)
  78. closeDevice();
  79. _device = open(_deviceName, O_RDWR | O_NOCTTY | O_NDELAY);
  80. if (_device == -1)
  81. {
  82. // Could not open the port.
  83. fprintf(stderr, "HardwareSerial::openDevice could not open %s: %s\n", _deviceName, strerror(errno));
  84. return false;
  85. }
  86. // Device opened
  87. fcntl(_device, F_SETFL, 0);
  88. return true;
  89. }
  90. bool HardwareSerial::closeDevice()
  91. {
  92. if (_device != -1)
  93. close(_device);
  94. _device = -1;
  95. return true;
  96. }
  97. bool HardwareSerial::setBaud(int baud)
  98. {
  99. speed_t speed;
  100. // This is kind of ugly, but its prob better than a case
  101. if (baud == 50)
  102. speed = B50;
  103. else if (baud == 75)
  104. speed = B75;
  105. else if (baud == 110)
  106. speed = B110;
  107. else if (baud == 134)
  108. speed = B134;
  109. else if (baud == 150)
  110. speed = B150;
  111. else if (baud == 200)
  112. speed = B200;
  113. else if (baud == 300)
  114. speed = B300;
  115. else if (baud == 600)
  116. speed = B600;
  117. else if (baud == 1200)
  118. speed = B1200;
  119. else if (baud == 1800)
  120. speed = B1800;
  121. else if (baud == 2400)
  122. speed = B2400;
  123. else if (baud == 4800)
  124. speed = B4800;
  125. else if (baud == 9600)
  126. speed = B9600;
  127. else if (baud == 19200)
  128. speed = B19200;
  129. else if (baud == 38400)
  130. speed = B38400;
  131. else if (baud == 57600)
  132. speed = B57600;
  133. #ifdef B76800
  134. else if (baud == 76800) // Not available on Linux
  135. speed = B76800;
  136. #endif
  137. else if (baud == 115200)
  138. speed = B115200;
  139. else if (baud == 230400)
  140. speed = B230400;
  141. #ifdef B460800
  142. else if (baud == 460800) // Not available on OSX
  143. speed = B460800;
  144. #endif
  145. #ifdef B921600
  146. else if (baud == 921600) // Not available on OSX
  147. speed = B921600;
  148. #endif
  149. else
  150. {
  151. fprintf(stderr, "HardwareSerial::setBaud: unsupported baud rate %d\n", baud);
  152. return false;
  153. }
  154. struct termios options;
  155. // Get current options
  156. if (tcgetattr(_device, &options) != 0)
  157. {
  158. fprintf(stderr, "HardwareSerial::setBaud: could not tcgetattr %s\n", strerror(errno));
  159. return false;
  160. }
  161. // Set new speed options
  162. cfsetispeed(&options, speed);
  163. cfsetospeed(&options, speed);
  164. // Enable the receiver and set local mode...
  165. options.c_cflag |= (CLOCAL | CREAD);
  166. // Force mode to 8,N,1
  167. // to be compatible with Arduino HardwareSerial
  168. // Should this be configurable? Prob not, must have 8 bits, dont need parity.
  169. options.c_cflag &= ~(PARENB | CSTOPB | CSIZE);
  170. options.c_cflag |= CS8;
  171. // Disable flow control and input character conversions
  172. options.c_iflag &= ~(IXON | IXOFF | IXANY | ICRNL | INLCR);
  173. // Raw input:
  174. options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
  175. // Raw output
  176. options.c_oflag &= ~(OPOST | OCRNL | ONLCR);
  177. // Set the options in the port
  178. if (tcsetattr(_device, TCSANOW, &options) != 0)
  179. {
  180. fprintf(stderr, "HardwareSerial::setBaud: could not tcsetattr %s\n", strerror(errno));
  181. return false;
  182. }
  183. _baud = baud;
  184. return true;
  185. }
  186. // Block until something is available
  187. void HardwareSerial::waitAvailable()
  188. {
  189. waitAvailableTimeout(0); // 0 = Wait forever
  190. }
  191. // Block until something is available or timeout expires
  192. bool HardwareSerial::waitAvailableTimeout(uint16_t timeout)
  193. {
  194. int max_fd;
  195. fd_set input;
  196. int result;
  197. FD_ZERO(&input);
  198. FD_SET(_device, &input);
  199. max_fd = _device + 1;
  200. if (timeout)
  201. {
  202. struct timeval timer;
  203. // Timeout is in milliseconds
  204. timer.tv_sec = timeout / 1000;
  205. timer.tv_usec = (timeout % 1000) * 1000;
  206. result = select(max_fd, &input, NULL, NULL, &timer);
  207. }
  208. else
  209. {
  210. result = select(max_fd, &input, NULL, NULL, NULL);
  211. }
  212. if (result < 0)
  213. fprintf(stderr, "HardwareSerial::waitAvailableTimeout: select failed %s\n", strerror(errno));
  214. return result > 0;
  215. }
  216. #endif