From bc365c4aa3c771c788753809a5e083500198f514 Mon Sep 17 00:00:00 2001 From: David Wehr <wehrdo@users.noreply.github.com> Date: Tue, 15 Nov 2016 15:11:09 -0600 Subject: [PATCH] Added ESP8266 WiFi bridge code --- wifi_dropin/circ_buffer.c | 77 +++++++++++++++++++ wifi_dropin/circ_buffer.h | 43 +++++++++++ wifi_dropin/wifi_dropin.ino | 143 ++++++++++++++++++++++++++++++++++++ 3 files changed, 263 insertions(+) create mode 100644 wifi_dropin/circ_buffer.c create mode 100644 wifi_dropin/circ_buffer.h create mode 100644 wifi_dropin/wifi_dropin.ino diff --git a/wifi_dropin/circ_buffer.c b/wifi_dropin/circ_buffer.c new file mode 100644 index 000000000..c139dc3cf --- /dev/null +++ b/wifi_dropin/circ_buffer.c @@ -0,0 +1,77 @@ +// +// Created by dawehr on 10/24/2016. +// + +#include "circ_buffer.h" + +#define circ_buf_min(a,b) \ + ({ __typeof__ (a) _a = (a); \ + __typeof__ (b) _b = (b); \ + _a < _b ? _a : _b; }) + + +unsigned char buffer[CIRC_BUFFER_SIZE]; +size_t buf_start = 0; +size_t buf_end = 0; +size_t size = 0; + + +struct data_chunk getChunk() { + size_t chunk_end = buf_end; + if (buf_end < buf_start) { + chunk_end = CIRC_BUFFER_SIZE; + } + size_t ret_size = chunk_end - buf_start; + struct data_chunk c = { + ret_size, + &buffer[buf_start] + }; + return c; +} + + +void markConsumed( size_t n_consumed) { + size_t chunk_end = buf_start + n_consumed; + buf_start = chunk_end; + size -= n_consumed; + if (buf_start == CIRC_BUFFER_SIZE) { + buf_start = 0; + } + +} + +size_t putChunk(struct data_chunk c) { + // The amount that will be placed into the buffer + size_t will_place = circ_buf_min(CIRC_BUFFER_SIZE - size, c.length); + // Actual amount placed so far + size_t placed = 0; + while (placed < will_place) { + // Available room without wrapping + size_t to_copy; + if (buf_end >= buf_start) { + // If buffer is not wrapped, we can copy until the end of the buffer + to_copy = circ_buf_min(will_place, CIRC_BUFFER_SIZE - buf_end); + } else { + // Otherwise, remaining space in buffer is contiguous + to_copy = will_place - placed; + } + memcpy(buffer + buf_end, c.data + placed, to_copy); + // Update buffer endpoint + buf_end += to_copy; + if (buf_end > CIRC_BUFFER_SIZE) { + printf("Error: buf_end: %d\n", buf_end); + } + // If we copied to the end + if (buf_end == CIRC_BUFFER_SIZE) { + buf_end = 0; + } + placed += to_copy; + } + size += placed; + return placed; +} + +size_t get_buffer_size() { + return size; +} + diff --git a/wifi_dropin/circ_buffer.h b/wifi_dropin/circ_buffer.h new file mode 100644 index 000000000..f42185a4f --- /dev/null +++ b/wifi_dropin/circ_buffer.h @@ -0,0 +1,43 @@ +// +// Created by dawehr on 10/24/2016. +// + +#ifndef CIRC_BUFFER_H +#define CIRC_BUFFER_H + +#define CIRC_BUFFER_SIZE 1024 +#include <unistd.h> +#include <stdio.h> +#include <string.h> + +struct data_chunk { + size_t length; + unsigned char* data; +}; + +/* + * Returns the largest contiguous chunk from the buffer + * Does not move the buffer forward. You must call markConsumed to + * mark the area as free. + */ +struct data_chunk getChunk(); + +/* + * Marks the n_consumed bytes as used, and that + * area of the buffer can be used for new data now + */ +void markConsumed(size_t n_consumed); + +/* + * Places data into the circular buffer. Returns the number of bytes stored. + * Will store the entire chunk, unless there is not enough remaining size in the buffer + */ +size_t putChunk(struct data_chunk); + +/* + * Returns the remaining size in the buffer + */ +size_t get_buffer_size(); + +#endif //CIRC_BUFFER_H + diff --git a/wifi_dropin/wifi_dropin.ino b/wifi_dropin/wifi_dropin.ino new file mode 100644 index 000000000..f2bf9bb4e --- /dev/null +++ b/wifi_dropin/wifi_dropin.ino @@ -0,0 +1,143 @@ +extern "C" { +#include "user_interface.h" +#include "circ_buffer.h" +} +#include <ESP8266WiFi.h> +#include <algorithm> + +char ssid[] = "uCart_AP"; // Network name of hosted network +char pass[] = "password"; +IPAddress client_ip; + +unsigned int tcp_port = 8080; +// Server object for listening for requests +WiFiServer server(tcp_port); +// Reusable client object to communicate with the connected client +WiFiClient client; + + +// Maximum number of bytes to read at a time +const int BUF_SIZE = 1024; +byte tcp_in_buffer[BUF_SIZE]; +byte serial_in_buf[BUF_SIZE]; +const int SEND_BUF_SIZE = 1024; + +void setup() { + // Set baud rate for UART + Serial.begin(115200); + Serial.setTimeout(2000); + + + WiFiEventHandler client_disconnected_handler = WiFi.onSoftAPModeStationDisconnected( + [](const WiFiEventSoftAPModeStationDisconnected& event) { + //Serial.println("disconnected"); + }); + + // Configure chip to be access point + WiFi.mode(WIFI_AP); + + // Wait for Access point to be created + while (!WiFi.softAP(ssid)) { + delay(500); // Wait half a second before re-trying + } + + waitForStation(); + + // Begin TCP on a particular port + server.begin(); + //server.setNoDelay(true); + +} + +void waitForStation() { + // Wait for a client to connect + struct station_info* connected_stns = NULL; + while (connected_stns = wifi_softap_get_station_info(), !connected_stns) { + delay(500); + } + client_ip = IPAddress(IP2STR(&connected_stns->ip)); + wifi_softap_free_station_info(); +} + +void loop() { + // Assume only one client will connect at a time. If a new request has arrived, + // that means the old client has expired, and the new one should be used + WiFiClient new_client = server.available(); + + if (new_client) { + // Read and forward any unread data + tcpToSerial(); + // Close existing client + client.stop(); + // Make new client the active one + client = new_client; + // Disable Nagle algorithm to decrease latency + //client.setNoDelay(true); + } + + if (client.connected() && client.available()) { + // Send any unsent data + //sendTCPBacklog(); + tcpToSerial(); + } + + // Try reading Serial data + int to_read = std::min(Serial.available(), BUF_SIZE); + if (to_read) { + Serial.readBytes(serial_in_buf, to_read); + sendTCP(serial_in_buf, to_read); + to_read = std::min(Serial.available(), BUF_SIZE); + } + +} + +void tcpToSerial() { + if (client.available()) { + // Don't read more than Serial can write at once, to prevent blocking + size_t n_to_read = std::min(std::min(client.available(), BUF_SIZE), Serial.availableForWrite()); + if (n_to_read) { + client.read(tcp_in_buffer, n_to_read); + } + sendSerial(tcp_in_buffer, n_to_read); + } +} + +void sendTCP(byte data[], size_t n_bytes) { + size_t to_write = n_bytes; + while (client.connected() && to_write) { + //sendTCPBacklog(); + size_t written = client.write((const uint8_t*) data, to_write); + to_write = to_write - written; + if (written != n_bytes) { + size_t remaining = n_bytes = written; + //putChunk({remaining, data + written}); + } + } + //else { + //putChunk({n_bytes, data}); + //} +} + +void sendTCPBacklog() { + struct data_chunk needs_sent = getChunk(); + if (needs_sent.length) { + size_t written = client.write((const uint8_t*) needs_sent.data, needs_sent.length); + markConsumed(written); + } +} + +//void sendUDP(byte data[], int n_bytes) { +// udp.beginPacket(address, localPort); +// udp.write(data, n_bytes); +// udp.endPacket(); +//} + +void sendSerial(byte data[], int n_bytes) { + int to_write = n_bytes; + while (to_write) { + int written = Serial.write(data, to_write); + to_write -= written; + } +} + + -- GitLab