PlatformIO package of the Teensy core framework compatible with GCC 10 & C++20
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

302 lines
7.3KB

  1. // RH_TCP.cpp
  2. //
  3. // Copyright (C) 2014 Mike McCauley
  4. // $Id: RH_TCP.cpp,v 1.5 2015/08/13 02:45:47 mikem Exp $
  5. #include <RadioHead.h>
  6. // This can only build on Linux and compatible systems
  7. #if (RH_PLATFORM == RH_PLATFORM_UNIX)
  8. #include <RH_TCP.h>
  9. #include <sys/types.h>
  10. #include <errno.h>
  11. #include <sys/socket.h>
  12. #include <netinet/in.h>
  13. #include <arpa/inet.h>
  14. #include <unistd.h>
  15. #include <sys/ioctl.h>
  16. #include <netdb.h>
  17. #include <string>
  18. RH_TCP::RH_TCP(const char* server)
  19. : _server(server),
  20. _rxBufLen(0),
  21. _rxBufValid(false),
  22. _socket(-1)
  23. {
  24. }
  25. bool RH_TCP::init()
  26. {
  27. if (!connectToServer())
  28. return false;
  29. return sendThisAddress(_thisAddress);
  30. }
  31. bool RH_TCP::connectToServer()
  32. {
  33. struct addrinfo hints;
  34. struct addrinfo *result, *rp;
  35. int sfd, s;
  36. struct sockaddr_storage peer_addr;
  37. socklen_t peer_addr_len;
  38. memset(&hints, 0, sizeof(struct addrinfo));
  39. hints.ai_family = AF_UNSPEC; // Allow IPv4 or IPv6
  40. hints.ai_socktype = SOCK_STREAM; // Stream socket
  41. hints.ai_flags = AI_PASSIVE; // For wildcard IP address
  42. hints.ai_protocol = 0; // Any protocol
  43. hints.ai_canonname = NULL;
  44. hints.ai_addr = NULL;
  45. hints.ai_next = NULL;
  46. std::string server(_server);
  47. std::string port("4000");
  48. size_t indexOfSeparator = server.find_first_of(':');
  49. if (indexOfSeparator != std::string::npos)
  50. {
  51. port = server.substr(indexOfSeparator+1);
  52. server.erase(indexOfSeparator);
  53. }
  54. s = getaddrinfo(server.c_str(), port.c_str(), &hints, &result);
  55. if (s != 0)
  56. {
  57. fprintf(stderr, "RH_TCP::connect getaddrinfo failed: %s\n", gai_strerror(s));
  58. return false;
  59. }
  60. // getaddrinfo() returns a list of address structures.
  61. // Try each address until we successfully connect(2).
  62. // If socket(2) (or connect(2)) fails, we (close the socket
  63. // and) try the next address. */
  64. for (rp = result; rp != NULL; rp = rp->ai_next)
  65. {
  66. _socket = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
  67. if (_socket == -1)
  68. continue;
  69. if (connect(_socket, rp->ai_addr, rp->ai_addrlen) == 0)
  70. break; /* Success */
  71. close(_socket);
  72. }
  73. if (rp == NULL)
  74. { /* No address succeeded */
  75. fprintf(stderr, "RH_TCP::connect could not connect to %s\n", _server);
  76. return false;
  77. }
  78. freeaddrinfo(result); /* No longer needed */
  79. // Now make the socket non-blocking
  80. int on = 1;
  81. int rc = ioctl(_socket, FIONBIO, (char *)&on);
  82. if (rc < 0)
  83. {
  84. fprintf(stderr,"RH_TCP::init failed to set socket non-blocking: %s\n", strerror(errno));
  85. close(_socket);
  86. _socket = -1;
  87. return false;
  88. }
  89. return true;
  90. }
  91. void RH_TCP::clearRxBuf()
  92. {
  93. _rxBufValid = false;
  94. _rxBufLen = 0;
  95. }
  96. void RH_TCP::checkForEvents()
  97. {
  98. #define RH_TCP_SOCKETBUF_LEN 500
  99. static uint8_t socketBuf[RH_TCP_SOCKETBUF_LEN]; // Room for several messages
  100. static uint16_t socketBufLen = 0;
  101. // Read at most the amount of space we have left in the buffer
  102. ssize_t count = read(_socket, socketBuf + socketBufLen, sizeof(socketBuf) - socketBufLen);
  103. if (count < 0)
  104. {
  105. if (errno != EAGAIN)
  106. {
  107. fprintf(stderr,"RH_TCP::checkForEvents read error: %s\n", strerror(errno));
  108. exit(1);
  109. }
  110. }
  111. else if (count == 0)
  112. {
  113. // End of file
  114. fprintf(stderr,"RH_TCP::checkForEvents unexpected end of file on read\n");
  115. exit(1);
  116. }
  117. else
  118. {
  119. socketBufLen += count;
  120. while (socketBufLen >= 5)
  121. {
  122. RHTcpTypeMessage* message = ((RHTcpTypeMessage*)socketBuf);
  123. uint32_t len = ntohl(message->length);
  124. uint32_t messageLen = len + sizeof(message->length);
  125. if (len > sizeof(socketBuf) - sizeof(message->length))
  126. {
  127. // Bogus length
  128. fprintf(stderr, "RH_TCP::checkForEvents read ridiculous length: %d. Corrupt message stream? Aborting\n", len);
  129. exit(1);
  130. }
  131. if (socketBufLen >= len + sizeof(message->length))
  132. {
  133. // Got at least all of this message
  134. if (message->type == RH_TCP_MESSAGE_TYPE_PACKET && len >= 5)
  135. {
  136. // REVISIT: need to check if we are actually receiving?
  137. // Its a new packet, extract the headers and payload
  138. RHTcpPacket* packet = ((RHTcpPacket*)socketBuf);
  139. _rxHeaderTo = packet->to;
  140. _rxHeaderFrom = packet->from;
  141. _rxHeaderId = packet->id;
  142. _rxHeaderFlags = packet->flags;
  143. uint32_t payloadLen = len - 5;
  144. if (payloadLen <= sizeof(_rxBuf))
  145. {
  146. // Enough room in our receiver buffer
  147. memcpy(_rxBuf, packet->payload, payloadLen);
  148. _rxBufLen = payloadLen;
  149. _rxBufFull = true;
  150. }
  151. }
  152. // check for other message types here
  153. // Now remove the used message by copying the trailing bytes (maybe start of a new message?)
  154. // to the top of the buffer
  155. memcpy(socketBuf, socketBuf + messageLen, sizeof(socketBuf) - messageLen);
  156. socketBufLen -= messageLen;
  157. }
  158. }
  159. }
  160. }
  161. void RH_TCP::validateRxBuf()
  162. {
  163. // The headers have already been extracted
  164. if (_promiscuous ||
  165. _rxHeaderTo == _thisAddress ||
  166. _rxHeaderTo == RH_BROADCAST_ADDRESS)
  167. {
  168. _rxGood++;
  169. _rxBufValid = true;
  170. }
  171. }
  172. bool RH_TCP::available()
  173. {
  174. if (_socket < 0)
  175. return false;
  176. checkForEvents();
  177. if (_rxBufFull)
  178. {
  179. validateRxBuf();
  180. _rxBufFull= false;
  181. }
  182. return _rxBufValid;
  183. }
  184. // Block until something is available
  185. void RH_TCP::waitAvailable()
  186. {
  187. waitAvailableTimeout(0); // 0 = Wait forever
  188. }
  189. // Block until something is available or timeout expires
  190. bool RH_TCP::waitAvailableTimeout(uint16_t timeout)
  191. {
  192. int max_fd;
  193. fd_set input;
  194. int result;
  195. FD_ZERO(&input);
  196. FD_SET(_socket, &input);
  197. max_fd = _socket + 1;
  198. if (timeout)
  199. {
  200. struct timeval timer;
  201. // Timeout is in milliseconds
  202. timer.tv_sec = timeout / 1000;
  203. timer.tv_usec = (timeout % 1000) * 1000;
  204. result = select(max_fd, &input, NULL, NULL, &timer);
  205. }
  206. else
  207. {
  208. result = select(max_fd, &input, NULL, NULL, NULL);
  209. }
  210. if (result < 0)
  211. fprintf(stderr, "RH_TCP::waitAvailableTimeout: select failed %s\n", strerror(errno));
  212. return result > 0;
  213. }
  214. bool RH_TCP::recv(uint8_t* buf, uint8_t* len)
  215. {
  216. if (!available())
  217. return false;
  218. if (buf && len)
  219. {
  220. if (*len > _rxBufLen)
  221. *len = _rxBufLen;
  222. memcpy(buf, _rxBuf, *len);
  223. }
  224. clearRxBuf();
  225. return true;
  226. }
  227. bool RH_TCP::send(const uint8_t* data, uint8_t len)
  228. {
  229. bool ret = sendPacket(data, len);
  230. delay(10); // Wait for transmit to succeed. REVISIT: depends on length and speed
  231. return ret;
  232. }
  233. uint8_t RH_TCP::maxMessageLength()
  234. {
  235. return RH_TCP_MAX_MESSAGE_LEN;
  236. }
  237. void RH_TCP::setThisAddress(uint8_t address)
  238. {
  239. RHGenericDriver::setThisAddress(address);
  240. sendThisAddress(_thisAddress);
  241. }
  242. bool RH_TCP::sendThisAddress(uint8_t thisAddress)
  243. {
  244. if (_socket < 0)
  245. return false;
  246. RHTcpThisAddress m;
  247. m.length = htonl(2);
  248. m.type = RH_TCP_MESSAGE_TYPE_THISADDRESS;
  249. m.thisAddress = thisAddress;
  250. ssize_t sent = write(_socket, &m, sizeof(m));
  251. return sent > 0;
  252. }
  253. bool RH_TCP::sendPacket(const uint8_t* data, uint8_t len)
  254. {
  255. if (_socket < 0)
  256. return false;
  257. RHTcpPacket m;
  258. m.length = htonl(len + 4);
  259. m.type = RH_TCP_MESSAGE_TYPE_PACKET;
  260. m.to = _txHeaderTo;
  261. m.from = _txHeaderFrom;
  262. m.id = _txHeaderId;
  263. m.flags = _txHeaderFlags;
  264. memcpy(m.payload, data, len);
  265. ssize_t sent = write(_socket, &m, len + 8);
  266. return sent > 0;
  267. }
  268. #endif