├── README.md ├── esp8266_pwm.h └── esp8266_ser2net.ino /README.md: -------------------------------------------------------------------------------- 1 | What is this? 2 | ============= 3 | 4 | This code can be loaded into an ESP8266 module to allow it to forward a serial connection from a device to a socket on a WiFi network. 5 | 6 | It is very rough. 7 | 8 | 9 | How do I use it? 10 | ================ 11 | 12 | 1. Download and install the ESP8266 enabled version of the Arduino "IDE" 13 | 2. Change the config in the main file to match your network and serial device 14 | 3. Compile 15 | 4. Load the code into your module 16 | 5. Profit 17 | 18 | -------------------------------------------------------------------------------- /esp8266_pwm.h: -------------------------------------------------------------------------------- 1 | /* 2 | ESP8266 PWM code for Arduino by Daniel Parnell 2nd of May 2015 3 | 4 | This code is butchered from the official ESP8266 SDK to make it work in a more Arduino like way. 5 | It also allows any GPIO pin to be used for PWM, rather than the hard coded 3 pins in the original. 6 | */ 7 | #ifndef __ESP8266_pwm_h__ 8 | #define __ESP8266_pwm_h__ 9 | 10 | // bring in the ESP8266 hardware stuff 11 | extern "C" { 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | } 18 | 19 | #define PWM_CHANNELS 3 20 | #define PWM_1S 1000000 21 | #define PWM_MAX_DUTY 255 22 | 23 | #define PWM_0_OUT_IO_MUX PERIPHS_IO_MUX_MTDI_U 24 | #define PWM_1_OUT_IO_MUX PERIPHS_IO_MUX_MTDO_U 25 | #define PWM_2_OUT_IO_MUX PERIPHS_IO_MUX_MTCK_U 26 | 27 | #define os_timer_arm_us(a, b, c) ets_timer_arm_new(a, b, c, 0) 28 | 29 | struct pwm_single_param { 30 | os_timer_t pwm_timer; 31 | uint16 h_time; 32 | uint8 duty; 33 | }; 34 | 35 | struct pwm_period_param { 36 | os_timer_t pwm_timer; 37 | uint16 period; 38 | uint16 freq; 39 | }; 40 | 41 | #define PWM_OUTPUT_HIGH(pwm_out_io_num) \ 42 | gpio_output_set(1< 500) { 123 | pwm_period.freq = 500; 124 | } else if (freq < 1) { 125 | pwm_period.freq = 1; 126 | } else { 127 | pwm_period.freq = freq; 128 | } 129 | 130 | pwm_period.period = PWM_1S / pwm_period.freq; 131 | 132 | /* init each channel's high level timer of pwm. */ 133 | for (i = 0; i < pwm_count; i++) { 134 | os_timer_disarm(&pwm_single[i].pwm_timer); 135 | os_timer_setfn(&pwm_single[i].pwm_timer, (os_timer_func_t *)pwm_output_low, (void*)i); 136 | } 137 | 138 | /* init period timer of pwm. */ 139 | os_timer_disarm(&pwm_period.pwm_timer); 140 | os_timer_setfn(&pwm_period.pwm_timer, (os_timer_func_t *)pwm_period_timer, NULL); 141 | os_timer_arm_us(&pwm_period.pwm_timer, pwm_period.period, 1); 142 | } 143 | 144 | // Overloaded index operator to allow getting and setting individual PWM channels 145 | void set(uint8_t index, uint8_t duty) { 146 | pwm_single[index].duty = duty; 147 | pwm_single[index].h_time = pwm_period.period * duty / PWM_MAX_DUTY; 148 | } 149 | 150 | uint8 get(uint8_t index) { 151 | return pwm_single[index].duty; 152 | } 153 | }; 154 | 155 | #endif 156 | 157 | -------------------------------------------------------------------------------- /esp8266_ser2net.ino: -------------------------------------------------------------------------------- 1 | /* 2 | ESP8266 mDNS serial wifi bridge by Daniel Parnell 2nd of May 2015 3 | */ 4 | 5 | //#define BONJOUR_SUPPORT 6 | #define USE_WDT 7 | 8 | #include 9 | #ifdef BONJOUR_SUPPORT 10 | #include 11 | #endif 12 | #include 13 | 14 | #include "esp8266_pwm.h" 15 | 16 | // application config 17 | 18 | // comment out the following line to enable DHCP 19 | #define STATIC_IP 20 | 21 | #ifdef STATIC_IP 22 | // change the IP address and gateway to match your network 23 | #define IP_ADDRESS "192.168.10.42" 24 | #define GATEWAY_ADDRESS "192.168.10.1" 25 | #define NET_MASK "255.255.255.0" 26 | #endif 27 | 28 | // change the network details to match your wifi network 29 | #define WIFI_SSID "my network" 30 | #define WIFI_PASSWORD "supersecret password nobody could ever guess" 31 | 32 | #define BAUD_RATE 9600 33 | #define TCP_LISTEN_PORT 9999 34 | 35 | // if the bonjour support is turned on, then use the following as the name 36 | #define DEVICE_NAME "ser2net" 37 | 38 | // serial end ethernet buffer size 39 | #define BUFFER_SIZE 128 40 | 41 | // hardware config 42 | #define WIFI_LED 14 43 | //#define CONNECTION_LED 16 44 | #define TX_LED 12 45 | #define RX_LED 13 46 | 47 | #ifdef BONJOUR_SUPPORT 48 | // multicast DNS responder 49 | MDNSResponder mdns; 50 | #endif 51 | 52 | WiFiServer server(TCP_LISTEN_PORT); 53 | ESP8266_PWM pwm; 54 | 55 | #ifdef STATIC_IP 56 | IPAddress parse_ip_address(const char *str) { 57 | IPAddress result; 58 | int index = 0; 59 | 60 | result[0] = 0; 61 | while (*str) { 62 | if (isdigit((unsigned char)*str)) { 63 | result[index] *= 10; 64 | result[index] += *str - '0'; 65 | } else { 66 | index++; 67 | if(index<4) { 68 | result[index] = 0; 69 | } 70 | } 71 | str++; 72 | } 73 | 74 | return result; 75 | } 76 | 77 | #endif 78 | 79 | void connect_to_wifi() { 80 | int count = 0; 81 | 82 | WiFi.mode(WIFI_STA); 83 | WiFi.disconnect(); 84 | delay(100); 85 | WiFi.begin(WIFI_SSID, WIFI_PASSWORD); 86 | 87 | #ifdef STATIC_IP 88 | IPAddress ip_address = parse_ip_address(IP_ADDRESS); 89 | IPAddress gateway_address = parse_ip_address(GATEWAY_ADDRESS); 90 | IPAddress netmask = parse_ip_address(NET_MASK); 91 | 92 | WiFi.config(ip_address, gateway_address, netmask); 93 | #endif 94 | 95 | #ifdef CONNECTION_LED 96 | digitalWrite(CONNECTION_LED, LOW); 97 | #endif 98 | digitalWrite(TX_LED, LOW); 99 | digitalWrite(RX_LED, LOW); 100 | 101 | // Wait for WIFI connection 102 | while (WiFi.status() != WL_CONNECTED) { 103 | #ifdef USE_WDT 104 | wdt_reset(); 105 | #endif 106 | pwm.set(0, (count & 1) ? PWM_MAX_DUTY : 0); 107 | count++; 108 | delay(250); 109 | } 110 | 111 | pwm.set(0, PWM_MAX_DUTY); 112 | } 113 | 114 | void error() { 115 | int count = 0; 116 | 117 | #ifdef CONNECTION_LED 118 | digitalWrite(CONNECTION_LED, LOW); 119 | #endif 120 | digitalWrite(TX_LED, LOW); 121 | digitalWrite(RX_LED, LOW); 122 | 123 | while(1) { 124 | count++; 125 | pwm.set(0, (count & 1) ? PWM_MAX_DUTY : 0); 126 | delay(100); 127 | } 128 | } 129 | 130 | void setup(void) 131 | { 132 | #ifdef USE_WDT 133 | wdt_enable(1000); 134 | #endif 135 | 136 | digitalWrite(WIFI_LED, LOW); 137 | #ifdef CONNECTION_LED 138 | digitalWrite(CONNECTION_LED, LOW); 139 | #endif 140 | digitalWrite(TX_LED, LOW); 141 | digitalWrite(RX_LED, LOW); 142 | 143 | pinMode(WIFI_LED, OUTPUT); 144 | #ifdef CONNECTION_LED 145 | pinMode(CONNECTION_LED, OUTPUT); 146 | #endif 147 | pinMode(TX_LED, OUTPUT); 148 | pinMode(RX_LED, OUTPUT); 149 | 150 | // set up the Wifi LED for PWM 151 | pwm.connect(0, WIFI_LED); 152 | pwm.set(0, 0); 153 | pwm.begin(1, 500); 154 | 155 | Serial.begin(BAUD_RATE); 156 | 157 | // Connect to WiFi network 158 | connect_to_wifi(); 159 | 160 | #ifdef BONJOUR_SUPPORT 161 | // Set up mDNS responder: 162 | if (!mdns.begin(DEVICE_NAME, WiFi.localIP())) { 163 | error(); 164 | } 165 | #endif 166 | 167 | // Start TCP server 168 | server.begin(); 169 | } 170 | 171 | WiFiClient client; 172 | uint8 pulse = 0; 173 | uint8 pulse_dir = 1; 174 | int pulse_counter = 1; 175 | 176 | void loop(void) 177 | { 178 | size_t bytes_read; 179 | uint8_t net_buf[BUFFER_SIZE]; 180 | uint8_t serial_buf[BUFFER_SIZE]; 181 | 182 | #ifdef USE_WDT 183 | wdt_reset(); 184 | #endif 185 | 186 | if(WiFi.status() != WL_CONNECTED) { 187 | // we've lost the connection, so we need to reconnect 188 | if(client) { 189 | client.stop(); 190 | } 191 | connect_to_wifi(); 192 | } 193 | 194 | pulse_counter--; 195 | if(pulse_counter == 0) { 196 | pulse_counter = 1000; 197 | if(pulse_dir) { 198 | pulse++; 199 | if(pulse == PWM_MAX_DUTY) { 200 | pulse_dir = 0; 201 | } 202 | } else { 203 | pulse--; 204 | if(pulse == 0) { 205 | pulse_dir = 1; 206 | } 207 | } 208 | 209 | pwm.set(0, pulse); 210 | } 211 | 212 | #ifdef BONJOUR_SUPPORT 213 | // Check for any mDNS queries and send responses 214 | mdns.update(); 215 | #endif 216 | 217 | // Check if a client has connected 218 | if (!client) { 219 | // eat any bytes in the serial buffer as there is nothing to see them 220 | while(Serial.available()) { 221 | Serial.read(); 222 | } 223 | 224 | client = server.available(); 225 | if(!client) { 226 | #ifdef CONNECTION_LED 227 | digitalWrite(CONNECTION_LED, LOW); 228 | #endif 229 | return; 230 | } 231 | 232 | #ifdef CONNECTION_LED 233 | digitalWrite(CONNECTION_LED, HIGH); 234 | #endif 235 | } 236 | #define min(a,b) ((a)<(b)?(a):(b)) 237 | if(client.connected()) { 238 | // check the network for any bytes to send to the serial 239 | int count = client.available(); 240 | if(count > 0) { 241 | digitalWrite(TX_LED, HIGH); 242 | 243 | bytes_read = client.read(net_buf, min(count, BUFFER_SIZE)); 244 | Serial.write(net_buf, bytes_read); 245 | Serial.flush(); 246 | } else { 247 | digitalWrite(TX_LED, LOW); 248 | } 249 | 250 | // now check the serial for any bytes to send to the network 251 | bytes_read = 0; 252 | while(Serial.available() && bytes_read < BUFFER_SIZE) { 253 | serial_buf[bytes_read] = Serial.read(); 254 | bytes_read++; 255 | } 256 | 257 | if(bytes_read > 0) { 258 | digitalWrite(RX_LED, HIGH); 259 | client.write((const uint8_t*)serial_buf, bytes_read); 260 | client.flush(); 261 | } else { 262 | digitalWrite(RX_LED, LOW); 263 | } 264 | } else { 265 | // make sure the TX and RX LEDs aren't on 266 | digitalWrite(TX_LED, LOW); 267 | digitalWrite(RX_LED, LOW); 268 | #ifdef CONNECTION_LED 269 | digitalWrite(CONNECTION_LED, LOW); 270 | #endif 271 | 272 | client.stop(); 273 | } 274 | } 275 | 276 | --------------------------------------------------------------------------------