├── .gitignore ├── LICENSE ├── README.md ├── examples ├── usbkbdpost │ └── usbkbdpost.ino └── usbkbdwifi │ └── usbkbdwifi.ino └── images ├── usbhostshield.png └── wifibarcode.png /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Compiled Object files 5 | *.slo 6 | *.lo 7 | *.o 8 | *.obj 9 | 10 | # Precompiled Headers 11 | *.gch 12 | *.pch 13 | 14 | # Compiled Dynamic libraries 15 | *.so 16 | *.dylib 17 | *.dll 18 | 19 | # Fortran module files 20 | *.mod 21 | *.smod 22 | 23 | # Compiled Static libraries 24 | *.lai 25 | *.la 26 | *.a 27 | *.lib 28 | 29 | # Executables 30 | *.exe 31 | *.out 32 | *.app 33 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 gdsports625@gmail.com 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ESP8266 USB host demos 2 | 3 | WiFi-enable a wide variety of USB devices using an ESP8266 and 4 | a USB host shield. For example, add a WiFi interface to a USB barcode 5 | reader or a USB RFID keyfob reader. 6 | 7 | ![USB host shield](./images/usbhostshield.png) 8 | 9 | The WeMos D1 R2 board appeared to be the ideal board to use with a USB host 10 | shield. The D1 is built around an ESP8266 and is laid out like an Arduino Uno. 11 | However, the D1 does not have an ICSP connector so this prevents the USB host 12 | shield board from working. This can be fixed with some modifications to the USB 13 | host shield board. The hardware build details are on the 14 | [wiki](https://github.com/gdsports/esp8266-usb-host-demos/wiki). 15 | 16 | ![USB host mini](./images/wifibarcode.png) 17 | 18 | If you want to get small and battery powered, the Adafruit Huzzah Feather and 19 | USB host mini board are made for each other. Actually, no, but with a few 20 | modifications, they can talk to each other. This combo is much smaller than 21 | the D1 and USB host shield. The hardware build details are on the 22 | [wiki](https://github.com/gdsports/esp8266-usb-host-demos/wiki). 23 | 24 | The example programs run on the D1 and the Feather. The programs are designed 25 | to work with devices that look like USB keyboards. This includes keyboards as 26 | well as barcode scannners and simple RFID keyfob scanners. usbkbdwifi 27 | implements a TCP server on port 23. A client such as netcat (nc) can connect 28 | to the barcode scanner like this: `nc 23`. usbkbdpost 29 | does an HTTP POST to a test HTTP server when a barcode is scannned. 30 | -------------------------------------------------------------------------------- /examples/usbkbdpost/usbkbdpost.ino: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | ESP8266WiFiMulti wifiMulti; 6 | 7 | // https://github.com/felis/USB_Host_Shield_2.0 library 8 | #include 9 | #include 10 | 11 | const char SSID[] = "xxxxxxxx"; 12 | const char PASSWORD[] = "yyyyyyyyyyyyyyy"; 13 | 14 | char aLine[80 + 1]; //global line buffer 15 | int aLineIndex = 0; 16 | bool aLineReady = false; 17 | 18 | class KbdRptParser : public KeyboardReportParser 19 | { 20 | protected: 21 | 22 | void OnKeyDown (uint8_t mod, uint8_t key); 23 | void OnKeyPressed(uint8_t key); 24 | }; 25 | 26 | 27 | void KbdRptParser::OnKeyDown(uint8_t mod, uint8_t key) 28 | { 29 | uint8_t c = OemToAscii(mod, key); 30 | 31 | if (c) 32 | OnKeyPressed(c); 33 | } 34 | 35 | void KbdRptParser::OnKeyPressed(uint8_t key) 36 | { 37 | if (aLineIndex < sizeof(aLine)) { 38 | if ((int)key == 19) // Carriage Return 39 | { 40 | aLine[aLineIndex] = '\0'; 41 | aLineReady = true; 42 | } 43 | else { 44 | aLine[aLineIndex] = (char)key; 45 | } 46 | aLineIndex++; 47 | } 48 | else { 49 | aLine[sizeof(aLine) - 1] = '\0'; 50 | aLineReady = true; 51 | } 52 | }; 53 | 54 | USB Usb; 55 | HIDBoot HidKeyboard(&Usb); 56 | 57 | KbdRptParser Prs; 58 | 59 | void setup() 60 | { 61 | int loops; 62 | 63 | Serial.begin( 115200 ); 64 | #if !defined(__MIPSEL__) 65 | while (!Serial); // Wait for serial port to connect - used on Leonardo, Teensy and other boards with built-in USB CDC serial connection 66 | #endif 67 | Serial.println(); 68 | 69 | wifiMulti.addAP(SSID, PASSWORD); 70 | //wifiMulti.addAP("ssid_from_AP_2", "your_password_for_AP_2"); 71 | //wifiMulti.addAP("ssid_from_AP_3", "your_password_for_AP_3"); 72 | Serial.println("Connecting Wifi..."); 73 | loops = 200; 74 | while ((wifiMulti.run() != WL_CONNECTED) && loops--) { 75 | Serial.print(','); 76 | delay(100); 77 | } 78 | if (loops == 0) { 79 | Serial.println(); 80 | Serial.print("WiFi connection FAILED : "); 81 | Serial.println(SSID); 82 | return; 83 | } 84 | Serial.println(); 85 | Serial.println("WiFi connected"); 86 | Serial.println("IP address: "); 87 | Serial.println(WiFi.localIP()); 88 | 89 | if (Usb.Init() == -1) { 90 | Serial.println(F("OSC did not start.")); 91 | return; 92 | } 93 | Serial.println(F("USB host up")); 94 | 95 | HidKeyboard.SetReportParser(0, &Prs); 96 | } 97 | 98 | void loop() 99 | { 100 | uint8_t i; 101 | 102 | Usb.Task(); 103 | 104 | if (wifiMulti.run() == WL_CONNECTED) { 105 | if (aLineReady) { 106 | HTTPClient http; 107 | 108 | Serial.println(aLine); 109 | Serial.print("[HTTP] begin...\n"); 110 | http.begin("http://posttestserver.com/post.php"); 111 | http.addHeader("Content-Type", "application/x-www-form-urlencoded", false, true); 112 | 113 | Serial.print("[HTTP] GET...\n"); 114 | // start connection and send HTTP header 115 | char postargs[89] = "barcode="; 116 | strcat(postargs, aLine); 117 | int httpCode = http.POST(postargs); 118 | 119 | // httpCode will be negative on error 120 | if (httpCode > 0) { 121 | // HTTP header has been send and Server response header has been handled 122 | Serial.printf("[HTTP] GET... code: %d\n", httpCode); 123 | 124 | // file found at server 125 | if (httpCode == HTTP_CODE_OK) { 126 | String payload = http.getString(); 127 | Serial.println(payload); 128 | } 129 | } else { 130 | Serial.printf("[HTTP] POST... failed, error: %s\n", http.errorToString(httpCode).c_str()); 131 | } 132 | 133 | http.end(); 134 | 135 | aLineIndex = 0; 136 | aLineReady = false; 137 | } 138 | } 139 | else { 140 | Serial.println("WiFi not connected!"); 141 | delay(1000); 142 | } 143 | } 144 | -------------------------------------------------------------------------------- /examples/usbkbdwifi/usbkbdwifi.ino: -------------------------------------------------------------------------------- 1 | /************************************************************************** 2 | MIT License 3 | 4 | Copyright (c) 2017 gdsports625@gmail.com 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | **************************************************************************/ 24 | 25 | #include 26 | #include 27 | 28 | ESP8266WiFiMulti wifiMulti; 29 | 30 | // https://github.com/felis/USB_Host_Shield_2.0 library 31 | #include 32 | #include 33 | 34 | const char SSID[] = "xxxxxxxx"; 35 | const char PASSWORD[] = "yyyyyyyyyyyyyyy"; 36 | 37 | //how many clients should be able to telnet to this ESP8266 38 | #define MAX_SRV_CLIENTS 1 39 | WiFiServer server(23); 40 | WiFiClient serverClients[MAX_SRV_CLIENTS]; 41 | 42 | char aLine[80+1]; //global line buffer 43 | int aLineIndex = 0; 44 | bool aLineReady = false; 45 | 46 | class KbdRptParser : public KeyboardReportParser 47 | { 48 | protected: 49 | 50 | void OnKeyDown (uint8_t mod, uint8_t key); 51 | void OnKeyPressed(uint8_t key); 52 | }; 53 | 54 | 55 | void KbdRptParser::OnKeyDown(uint8_t mod, uint8_t key) 56 | { 57 | uint8_t c = OemToAscii(mod, key); 58 | 59 | if (c) 60 | OnKeyPressed(c); 61 | } 62 | 63 | void KbdRptParser::OnKeyPressed(uint8_t key) 64 | { 65 | if (!aLineReady) { 66 | if (aLineIndex < sizeof(aLine)) { 67 | if ((int)key == 19) // Carriage Return 68 | { 69 | aLine[aLineIndex] = '\0'; 70 | aLineReady = true; 71 | } 72 | else { 73 | aLine[aLineIndex] = (char)key; 74 | } 75 | aLineIndex++; 76 | } 77 | else { 78 | aLine[sizeof(aLine)-1] = '\0'; 79 | aLineReady = true; 80 | } 81 | } 82 | }; 83 | 84 | USB Usb; 85 | HIDBoot HidKeyboard(&Usb); 86 | 87 | KbdRptParser Prs; 88 | 89 | void setup() 90 | { 91 | Serial.begin( 115200 ); 92 | #if !defined(__MIPSEL__) 93 | while (!Serial); // Wait for serial port to connect - used on Leonardo, Teensy and other boards with built-in USB CDC serial connection 94 | #endif 95 | Serial.println(); 96 | 97 | wifiMulti.addAP(SSID, PASSWORD); 98 | //wifiMulti.addAP("ssid_from_AP_2", "your_password_for_AP_2"); 99 | //wifiMulti.addAP("ssid_from_AP_3", "your_password_for_AP_3"); 100 | Serial.println("Connecting Wifi..."); 101 | while(wifiMulti.run() != WL_CONNECTED) { 102 | Serial.print(','); 103 | delay(100); 104 | } 105 | Serial.println(); 106 | Serial.println("WiFi connected"); 107 | Serial.println("IP address: "); 108 | Serial.println(WiFi.localIP()); 109 | 110 | server.begin(); 111 | server.setNoDelay(true); 112 | Serial.print("Ready! Use 'telnet "); 113 | Serial.print(WiFi.localIP()); 114 | Serial.println(" 23' to connect"); 115 | 116 | if (Usb.Init() == -1) { 117 | Serial.println(F("OSC did not start.")); 118 | return; 119 | } 120 | Serial.println(F("USB host up")); 121 | 122 | HidKeyboard.SetReportParser(0, &Prs); 123 | } 124 | 125 | void loop() 126 | { 127 | uint8_t i; 128 | 129 | Usb.Task(); 130 | 131 | if(wifiMulti.run() == WL_CONNECTED) { 132 | //check if there are any new clients 133 | if (server.hasClient()){ 134 | for(i = 0; i < MAX_SRV_CLIENTS; i++){ 135 | //find free/disconnected spot 136 | if (!serverClients[i] || !serverClients[i].connected()){ 137 | if(serverClients[i]) serverClients[i].stop(); 138 | serverClients[i] = server.available(); 139 | Serial.print("New client: "); Serial.print(i); 140 | continue; 141 | } 142 | } 143 | //no free/disconnected spot so reject 144 | WiFiClient serverClient = server.available(); 145 | serverClient.stop(); 146 | } 147 | //check clients for data 148 | for(i = 0; i < MAX_SRV_CLIENTS; i++){ 149 | if (serverClients[i] && serverClients[i].connected()){ 150 | if(serverClients[i].available()){ 151 | //get data from the telnet client and discard it 152 | while(serverClients[i].available()) serverClients[i].read(); 153 | } 154 | } 155 | } 156 | if (aLineReady) { 157 | Serial.println(aLine); 158 | for(i = 0; i < MAX_SRV_CLIENTS; i++){ 159 | if (serverClients[i] && serverClients[i].connected()){ 160 | serverClients[i].println(aLine); 161 | } 162 | } 163 | aLineIndex = 0; 164 | aLineReady = false; 165 | } 166 | } 167 | else { 168 | Serial.println("WiFi not connected!"); 169 | delay(1000); 170 | } 171 | } 172 | -------------------------------------------------------------------------------- /images/usbhostshield.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gdsports/esp8266-usb-host-demos/75ebcc4ffec0d6a7e89ca0fbe57da85b1c59ff2e/images/usbhostshield.png -------------------------------------------------------------------------------- /images/wifibarcode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gdsports/esp8266-usb-host-demos/75ebcc4ffec0d6a7e89ca0fbe57da85b1c59ff2e/images/wifibarcode.png --------------------------------------------------------------------------------