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