Advertisement
Guest User

Untitled

a guest
Oct 18th, 2019
170
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 8.81 KB | None | 0 0
  1. #include "socket_task.h"
  2.  
  3.  
  4. /*
  5. *******************************************************************************
  6. * Symbolic Constants *
  7. *******************************************************************************
  8. */
  9.  
  10.  
  11. // Maximum amount of bytes that can be received from a socket on a call
  12. #define SOCK_MAX_RECV_SIZE TASK_QUEUE_DATA_MAX
  13.  
  14.  
  15. /*
  16. *******************************************************************************
  17. * Global Variables *
  18. *******************************************************************************
  19. */
  20.  
  21.  
  22. // Socket table
  23. sock_t g_socket_table[MAX_SOCKET_COUNT];
  24.  
  25.  
  26. // Socket table length
  27. int g_tab_len;
  28.  
  29.  
  30. /*
  31. *******************************************************************************
  32. * Internal Function Definitions *
  33. *******************************************************************************
  34. */
  35.  
  36.  
  37. // Initializes a TCP/IP stream socket (but does not connect it).
  38. int init_socket (int index) {
  39.  
  40. // Extract entry
  41. sock_t *entry = g_socket_table + index;
  42.  
  43. // Initialize socket
  44. if ((entry->sock = socket(AF_INET, SOCK_STREAM, IPPROTO_IP)) < 0) {
  45. ESP_LOGE("SOCK", "Couldn't initialize socket!");
  46. entry->sock = -1;
  47. return -1;
  48. }
  49.  
  50. ESP_LOGI("SOCK", "Initialized socket!");
  51.  
  52. return 0;
  53. }
  54.  
  55.  
  56. // Connects a socket. Returns zero on success, nonzero on error
  57. int connect_socket (int index) {
  58.  
  59. // Extract entry
  60. sock_t *entry = g_socket_table + index;
  61.  
  62. // Configure descriptor
  63. const struct sockaddr_in sock_descr = {
  64. .sin_addr.s_addr = entry->addr,
  65. .sin_family = AF_INET,
  66. .sin_port = entry->port,
  67. };
  68.  
  69. // Connect socket
  70. if (connect(entry->sock, (struct sockaddr *)&sock_descr, sizeof(sock_descr))
  71. != 0) {
  72. ESP_LOGE("SOCK", "Couldn't connect socket!");
  73. return -1;
  74. }
  75.  
  76. ESP_LOGI("SOCK", "Connected socket!");
  77.  
  78. return 0;
  79. }
  80.  
  81.  
  82. // Closes a socket
  83. void close_socket (int index) {
  84. // Extract entry
  85. sock_t *entry = g_socket_table + index;
  86.  
  87. // If the socket is not active, then return now
  88. if (entry->sock < 0) {
  89. return;
  90. }
  91.  
  92. // Close the socket
  93. close(entry->sock);
  94. entry->sock = -1;
  95. }
  96.  
  97.  
  98. // Writes the given buffer to the socket. Returns nonzero on error
  99. int send_socket (int sock, uint8_t *data, size_t size) {
  100. size_t sent = 0; int res = 0;
  101.  
  102. while (sent < size) {
  103.  
  104. if ((res = send(sock, data + sent, size - sent, 0x0)) <= 0) {
  105. break;
  106. }
  107.  
  108. sent += res;
  109. }
  110.  
  111. if (res == 0) {
  112. ESP_LOGI("SOCK", "Zero bytes written to socket!");
  113. return 0;
  114. }
  115.  
  116. return (res < 0);
  117. }
  118.  
  119.  
  120. // Receives data from a socket and puts on recv queue. Returns nonzero on error
  121. int recv_socket (int index) {
  122. int32_t ret;
  123. esp_err_t err;
  124. static uint8_t recv_buffer[SOCK_MAX_RECV_SIZE];
  125.  
  126. // Extract entry
  127. sock_t *entry = g_socket_table + index;
  128.  
  129. // Read bytes
  130. if ((ret = recv(entry->sock, recv_buffer, SOCK_MAX_RECV_SIZE, 0x0))
  131. < 0) {
  132. return -1;
  133. }
  134.  
  135. // If the socket closed (return error value but don't log as one)
  136. if (ret == 0) {
  137. return -1;
  138. }
  139.  
  140. // If the task didn't register a handler, ignore the data and return now
  141. if (entry->recv_queue == NULL) {
  142. return 0;
  143. }
  144.  
  145. // Otherwise place the data on the receive queue
  146. if ((err = ipc_enqueue(entry->recv_queue, index, ret, recv_buffer))
  147. != ESP_OK) {
  148. ESP_LOGE("SOCK", "Couldn't put data on recv queue");
  149. }
  150.  
  151. // Notify tasks that data is ready (so they should check their queues)
  152. xEventGroupSetBits(g_event_group, FLAG_SOCK_RECV_MSG);
  153.  
  154. return 0;
  155. }
  156.  
  157.  
  158. /*
  159. *******************************************************************************
  160. * External Function Definitions *
  161. *******************************************************************************
  162. */
  163.  
  164.  
  165. int task_sock_manager_register (uint32_t addr, uint16_t port,
  166. QueueHandle_t recv_queue) {
  167.  
  168. // If no room remains in the table, return an invalid index
  169. if (g_tab_len >= MAX_SOCKET_COUNT) {
  170. return -1;
  171. }
  172.  
  173. // Register the new table entry
  174. g_socket_table[g_tab_len] = (sock_t){
  175. .sock = -1,
  176. .addr = addr,
  177. .port = port,
  178. .recv_queue = recv_queue,
  179. };
  180.  
  181. // Return index (post-incremented)
  182. return g_tab_len++;
  183. }
  184.  
  185.  
  186. void task_sock_manager (void *args) {
  187. uint32_t flags;
  188. fd_set select_fds;
  189. int s;
  190. uint8_t active_connections = 0;
  191. task_queue_msg_t queue_msg;
  192. const TickType_t flag_block_time = 8; // Ticks to wait for flags to be set
  193. struct timeval sock_block_time = (struct timeval){
  194. .tv_sec = 0,
  195. .tv_usec = 10000, // Wait 10ms (10k us)
  196. };
  197.  
  198. /* State Bit Flags
  199. * 0x1: WiFi is connected if set
  200. */
  201. uint8_t state = 0x0;
  202.  
  203. do {
  204.  
  205. // Block until something needs to be sent (idea: variable block time)
  206. flags = xEventGroupWaitBits(g_event_group,
  207. FLAG_SOCK_SEND_MSG | FLAG_WIFI_CONNECTED | FLAG_WIFI_DISCONNECTED,
  208. pdFALSE, pdFALSE, flag_block_time);
  209.  
  210. // Clear the flag owned by this task
  211. xEventGroupClearBits(g_event_group, FLAG_SOCK_SEND_MSG);
  212.  
  213. // If WiFi is connected
  214. if (flags & FLAG_WIFI_CONNECTED) {
  215. state |= 0x1;
  216. }
  217.  
  218. // If WiFi is disconnected
  219. if (flags & FLAG_WIFI_DISCONNECTED) {
  220. state &= ~0x1;
  221. }
  222.  
  223. // Try to send everything in the queue
  224. while (uxQueueMessagesWaiting(g_sock_tx_queue) > 0) {
  225.  
  226. // Dequeue next message
  227. xQueueReceive(g_sock_tx_queue, (void *)&queue_msg,
  228. TASK_QUEUE_MAX_TICKS);
  229.  
  230. // Check the ID
  231. if (queue_msg.id >= g_tab_len) {
  232. ESP_LOGE("SOCK", "Invalid socket index for outgoing message");
  233. continue;
  234. }
  235.  
  236. // If WiFi isn't available, discard message
  237. if ((state & 0x1) == 0) {
  238. ESP_LOGW("SOCK", "Discarding unsendable message (no WiFi)");
  239. continue;
  240. }
  241.  
  242. // Create the socket if needed
  243. if (g_socket_table[queue_msg.id].sock == -1) {
  244. if (init_socket(queue_msg.id) != 0) {
  245. ESP_LOGE("SOCK", "Unable to initialize socket");
  246. continue;
  247. }
  248. if (connect_socket(queue_msg.id) != 0) {
  249. ESP_LOGE("SOCK", "Unable to connect socket");
  250. close_socket(queue_msg.id);
  251. continue;
  252. }
  253.  
  254. // Increment active connections
  255. active_connections++;
  256.  
  257. }
  258.  
  259. // Close socket if size to send is zero
  260. if (queue_msg.size == 0) {
  261. FD_CLR(g_socket_table[queue_msg.id].sock, &select_fds);
  262. ESP_LOGI("SOCK", "Closing socket by instruction");
  263. close_socket(queue_msg.id);
  264. active_connections--;
  265. continue;
  266. }
  267.  
  268. // Close the socket if an error occurred sending the message
  269. if (send_socket(g_socket_table[queue_msg.id].sock,
  270. queue_msg.data, queue_msg.size) != 0) {
  271. ESP_LOGE("SOCK", "Couldn't send on socket");
  272. close_socket(queue_msg.id);
  273. active_connections--;
  274. continue;
  275. }
  276. }
  277.  
  278. // Do not run select unless there are active connections
  279. if (active_connections == 0) {
  280. continue;
  281. }
  282.  
  283. // Update file-descriptor set
  284. FD_ZERO(&select_fds);
  285. for (int i = 0; i < g_tab_len; ++i) {
  286. if (g_socket_table[i].sock != -1) {
  287. FD_SET(g_socket_table[i].sock, &select_fds);
  288. }
  289. }
  290.  
  291. // Perform select (read-events only)
  292. s = select(FD_SETSIZE, &select_fds, NULL, NULL, &sock_block_time);
  293.  
  294. // Continue if an error occurred
  295. if (s < 0) {
  296. ESP_LOGE("SOCK", "Select error!");
  297. continue;
  298. }
  299.  
  300. // Continue if no events occurred within the blocking interval
  301. if (s == 0) {
  302. continue;
  303. }
  304.  
  305. // Otherwise check all the sockets and take action on possible events
  306. for (int i = 0; i < g_tab_len; ++i) {
  307.  
  308. // Ignore inactive sockets
  309. if (g_socket_table[i].sock < 0) {
  310. continue;
  311. }
  312.  
  313. // If a read event occurred
  314. if (FD_ISSET(g_socket_table[i].sock, &select_fds)) {
  315. if (recv_socket(i) == -1) {
  316. ESP_LOGE("SOCK", "Error receiving data from socket");
  317. close_socket(i);
  318. }
  319. }
  320.  
  321. }
  322.  
  323. } while (1);
  324.  
  325. // Destroy task
  326. vTaskDelete(NULL);
  327. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement