Smart-Home am Beispiel der Präsenzerkennung im Raum Projektarbeit Lennart Heimbs, Johannes Krug, Sebastian Dohle und Kevin Holzschuh bei Prof. Oliver Hofmann SS2019
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.

SerialPort.cpp 6.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285
  1. /*
  2. * The MySensors Arduino library handles the wireless radio link and protocol
  3. * between your home built sensors/actuators and HA controller of choice.
  4. * The sensors forms a self healing radio network with optional repeaters. Each
  5. * repeater and gateway builds a routing tables in EEPROM which keeps track of the
  6. * network topology allowing messages to be routed to nodes.
  7. *
  8. * Created by Henrik Ekblad <henrik.ekblad@mysensors.org>
  9. * Copyright (C) 2013-2018 Sensnology AB
  10. * Full contributor list: https://github.com/mysensors/MySensors/graphs/contributors
  11. *
  12. * Documentation: http://www.mysensors.org
  13. * Support Forum: http://forum.mysensors.org
  14. *
  15. * This program is free software; you can redistribute it and/or
  16. * modify it under the terms of the GNU General Public License
  17. * version 2 as published by the Free Software Foundation.
  18. */
  19. #include <stdlib.h>
  20. #include <stdio.h>
  21. #include <fcntl.h>
  22. #include <sys/ioctl.h>
  23. #include <sys/types.h>
  24. #include <limits.h>
  25. #include <unistd.h>
  26. #include <termios.h>
  27. #include <grp.h>
  28. #include <errno.h>
  29. #include <sys/stat.h>
  30. #include "log.h"
  31. #include "SerialPort.h"
  32. SerialPort::SerialPort(const char *port, bool isPty) : serialPort(std::string(port)), isPty(isPty)
  33. {
  34. sd = -1;
  35. }
  36. void SerialPort::begin(int bauds)
  37. {
  38. if (!open(bauds)) {
  39. logError("Failed to open serial port.\n");
  40. exit(1);
  41. }
  42. logDebug("Serial port %s (%d baud) created\n", serialPort.c_str(), bauds);
  43. }
  44. bool SerialPort::open(int bauds)
  45. {
  46. speed_t speed;
  47. struct termios options;
  48. if (isPty) {
  49. sd = posix_openpt(O_RDWR | O_NOCTTY | O_NDELAY);
  50. if (sd < 0) {
  51. logError("Couldn't open a PTY: %s\n", strerror(errno));
  52. return false;
  53. }
  54. if (grantpt(sd) != 0) {
  55. logError("Couldn't grant permission to the PTY: %s\n", strerror(errno));
  56. return false;
  57. }
  58. if (unlockpt(sd) != 0) {
  59. logError("Couldn't unlock the PTY: %s\n", strerror(errno));
  60. return false;
  61. }
  62. /* create a symlink with predictable name to the PTY device */
  63. unlink(serialPort.c_str()); // remove the symlink if it already exists
  64. if (symlink(ptsname(sd), serialPort.c_str()) != 0) {
  65. logError("Couldn't create a symlink '%s' to PTY! (%d) %s\n", serialPort.c_str(), errno,
  66. strerror(errno));
  67. return false;
  68. }
  69. } else {
  70. if ((sd = ::open(serialPort.c_str(), O_RDWR | O_NOCTTY | O_NDELAY)) == -1) {
  71. logError("Unable to open the serial port %s\n", serialPort.c_str());
  72. return false;
  73. }
  74. // nonblocking mode
  75. fcntl(sd, F_SETFL, FNDELAY);
  76. }
  77. switch (bauds) {
  78. case 50:
  79. speed = B50 ;
  80. break ;
  81. case 75:
  82. speed = B75 ;
  83. break ;
  84. case 110:
  85. speed = B110 ;
  86. break ;
  87. case 134:
  88. speed = B134 ;
  89. break ;
  90. case 150:
  91. speed = B150 ;
  92. break ;
  93. case 200:
  94. speed = B200 ;
  95. break ;
  96. case 300:
  97. speed = B300 ;
  98. break ;
  99. case 600:
  100. speed = B600 ;
  101. break ;
  102. case 1200:
  103. speed = B1200 ;
  104. break ;
  105. case 1800:
  106. speed = B1800 ;
  107. break ;
  108. case 2400:
  109. speed = B2400 ;
  110. break ;
  111. case 9600:
  112. speed = B9600 ;
  113. break ;
  114. case 19200:
  115. speed = B19200 ;
  116. break ;
  117. case 38400:
  118. speed = B38400 ;
  119. break ;
  120. case 57600:
  121. speed = B57600 ;
  122. break ;
  123. case 115200:
  124. speed = B115200 ;
  125. break ;
  126. default:
  127. speed = B115200 ;
  128. break ;
  129. }
  130. // Get the current options of the port
  131. if (tcgetattr(sd, &options) < 0) {
  132. logError("Couldn't get term attributes: %s\n", strerror(errno));
  133. return false;
  134. }
  135. // Clear all the options
  136. bzero(&options, sizeof(options));
  137. // Set the baud rate
  138. cfsetispeed(&options, speed);
  139. cfsetospeed(&options, speed);
  140. // Configure the device : 8 bits, no parity, no control
  141. options.c_cflag |= ( CLOCAL | CREAD | CS8);
  142. // Ignore framing errors, parity errors and BREAK condition on input.
  143. options.c_iflag |= ( IGNPAR | IGNBRK );
  144. // Timer unused
  145. options.c_cc[VTIME]=0;
  146. // At least on character before satisfy reading
  147. options.c_cc[VMIN]=0;
  148. // Set parameters
  149. if (tcsetattr(sd, TCSANOW, &options) < 0) {
  150. logError("Couldn't set term attributes: %s\n", strerror(errno));
  151. return false;
  152. }
  153. // flush
  154. if (tcflush(sd, TCIOFLUSH) < 0) {
  155. logError("Couldn't flush serial: %s\n", strerror(errno));
  156. return false;
  157. }
  158. usleep(10000);
  159. return true;
  160. }
  161. bool SerialPort::setGroupPerm(const char *groupName)
  162. {
  163. const mode_t ttyPermissions = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP;
  164. if (sd != -1 && groupName != NULL) {
  165. struct group *devGrp = getgrnam(groupName);
  166. if (devGrp == NULL) {
  167. logError("getgrnam: %s failed. (%d) %s\n", groupName, errno, strerror(errno));
  168. return false;
  169. }
  170. const char *dev;
  171. if (isPty) {
  172. dev = ptsname(sd);
  173. } else {
  174. dev = serialPort.c_str();
  175. }
  176. int ret = chown(dev, -1, devGrp->gr_gid);
  177. if (ret == -1) {
  178. logError("Could not change PTY owner! (%d) %s\n", errno, strerror(errno));
  179. return false;
  180. }
  181. ret = chmod(dev, ttyPermissions);
  182. if (ret != 0) {
  183. logError("Could not change PTY permissions! (%d) %s\n", errno, strerror(errno));
  184. return false;
  185. }
  186. return true;
  187. }
  188. return false;
  189. }
  190. int SerialPort::available()
  191. {
  192. int nbytes = 0;
  193. if (ioctl(sd, FIONREAD, &nbytes) < 0) {
  194. logError("Failed to get byte count on serial.\n");
  195. exit(-1);
  196. }
  197. return nbytes;
  198. }
  199. int SerialPort::read()
  200. {
  201. unsigned char c;
  202. int ret = ::read(sd, &c, 1);
  203. if (ret < 0) {
  204. logError("Serial - read failed: %s\n", strerror(errno));
  205. } else if (ret == 1) {
  206. return c;
  207. }
  208. return -1;
  209. }
  210. size_t SerialPort::write(uint8_t b)
  211. {
  212. int ret = ::write(sd, &b, 1);
  213. if (ret < 0) {
  214. logError("Serial - write failed: %s\n", strerror(errno));
  215. }
  216. return ret;
  217. }
  218. size_t SerialPort::write(const uint8_t *buffer, size_t size)
  219. {
  220. int ret = ::write(sd, buffer, size);
  221. if (ret < 0) {
  222. logError("Serial - write failed: %s\n", strerror(errno));
  223. }
  224. return ret;
  225. }
  226. int SerialPort::peek()
  227. {
  228. FILE * f = fdopen(sd, "r+");
  229. int c = getc(f);
  230. if (c == EOF) {
  231. return -1;
  232. }
  233. ungetc(c, f);
  234. return c;
  235. }
  236. void SerialPort::flush()
  237. {
  238. // Waits until all output written to sd has been transmitted
  239. if (tcdrain(sd) < 0) {
  240. logError("Couldn't flush serial: %s\n", strerror(errno));
  241. }
  242. }
  243. void SerialPort::end()
  244. {
  245. close(sd);
  246. if (isPty) {
  247. unlink(serialPort.c_str()); // remove the symlink
  248. }
  249. }