├── WS2812Remote ├── README.md ├── pkt_test │ ├── pkt_test.sln │ ├── pkt_test.vcxproj.filters │ ├── pkt_test.cpp │ ├── pkt_test.vcxproj │ ├── serialib.h │ └── serialib.cpp ├── WS2812Remote.h └── WS2812Remote.ino ├── WS2812ArtNet ├── README.md ├── ArduinoOTAMgr.h ├── ArduinoOTAMgr.cpp ├── esp8266.c ├── ArtnetWifi.h ├── ArtnetWifi.cpp ├── WiFiManager.h ├── WS2812ArtNet.ino └── WiFiManager.cpp ├── .gitignore ├── README.md └── LICENSE /WS2812Remote/README.md: -------------------------------------------------------------------------------- 1 | # WS2812Remote 2 | 3 | Serial client for WS2812B LED strips (aka NeoPixels). 4 | Supports Glediator protocol as well as its own proprietary packet protocol. -------------------------------------------------------------------------------- /WS2812ArtNet/README.md: -------------------------------------------------------------------------------- 1 | # WS2812ArtNet 2 | 3 | ESP8266 Art-Net client for WS2812B (NeoPixel) strands. 4 | Includes captive WiFi portal for configuration. 5 | 6 | Notice: Compile with 80 MHz CPU-Frequency! 7 | 8 | Included libraries governed by their individual licenses. 9 | -------------------------------------------------------------------------------- /WS2812ArtNet/ArduinoOTAMgr.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | class ArduinoOTAMgr { 6 | uint8_t _enabled; 7 | public: 8 | ArduinoOTAMgr() { _enabled = 0; } 9 | 10 | void boot(const char *hostname=NULL,const char *pw=NULL); 11 | void disable() { _enabled = 0; } 12 | void enable() { _enabled = 1; } 13 | void handle(); 14 | }; 15 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | *VC.db 3 | *.opendb 4 | Debug 5 | .vs 6 | # Compiled Object files 7 | *.slo 8 | *.lo 9 | *.o 10 | *.obj 11 | 12 | # Precompiled Headers 13 | *.gch 14 | *.pch 15 | 16 | # Compiled Dynamic libraries 17 | *.so 18 | *.dylib 19 | *.dll 20 | 21 | # Fortran module files 22 | *.mod 23 | *.smod 24 | 25 | # Compiled Static libraries 26 | *.lai 27 | *.la 28 | *.a 29 | *.lib 30 | 31 | # Executables 32 | *.exe 33 | *.out 34 | *.app 35 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # WS2812B 2 | 3 | Remote control libraries for WS2812B (aka NeoPixel) LED strands. 4 | 5 | # WS2812Remote 6 | 7 | ATmega 8-bit serial client for WS2812B LED strands 8 | Supports Glediator protocol as well as its own proprietary packet protocol. 9 | 10 | # WS2812ArtNet 11 | 12 | ESP8266 Art-Net client for WS2812B LED strands. 13 | Includes captive WiFi portal for configuration. 14 | 15 | 16 | Included libraries governed by their individual licenses. -------------------------------------------------------------------------------- /WS2812Remote/pkt_test/pkt_test.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 2012 4 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pkt_test", "pkt_test.vcxproj", "{4DE43C65-7F62-40AC-A8C3-1A37B537A032}" 5 | EndProject 6 | Global 7 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 8 | Debug|Win32 = Debug|Win32 9 | Release|Win32 = Release|Win32 10 | EndGlobalSection 11 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 12 | {4DE43C65-7F62-40AC-A8C3-1A37B537A032}.Debug|Win32.ActiveCfg = Debug|Win32 13 | {4DE43C65-7F62-40AC-A8C3-1A37B537A032}.Debug|Win32.Build.0 = Debug|Win32 14 | {4DE43C65-7F62-40AC-A8C3-1A37B537A032}.Release|Win32.ActiveCfg = Release|Win32 15 | {4DE43C65-7F62-40AC-A8C3-1A37B537A032}.Release|Win32.Build.0 = Release|Win32 16 | EndGlobalSection 17 | GlobalSection(SolutionProperties) = preSolution 18 | HideSolutionNode = FALSE 19 | EndGlobalSection 20 | EndGlobal 21 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 lincomatic 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 | -------------------------------------------------------------------------------- /WS2812Remote/pkt_test/pkt_test.vcxproj.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Source Files 20 | 21 | 22 | Source Files 23 | 24 | 25 | 26 | 27 | Header Files 28 | 29 | 30 | -------------------------------------------------------------------------------- /WS2812ArtNet/ArduinoOTAMgr.cpp: -------------------------------------------------------------------------------- 1 | #include "ArduinoOTAMgr.h" 2 | 3 | void ArduinoOTAMgr::boot(const char *hostname,const char *pw) 4 | { 5 | Serial.println("OTA boot"); 6 | // Port defaults to 8266 7 | // ArduinoOTA.setPort(8266); 8 | 9 | // Hostname defaults to esp8266-[ChipID] 10 | if (hostname) ArduinoOTA.setHostname(hostname); 11 | 12 | // No authentication by default 13 | if (pw) ArduinoOTA.setPassword(pw); 14 | 15 | ArduinoOTA.onStart([]() { 16 | Serial.println("OTA start"); 17 | }); 18 | ArduinoOTA.onEnd([]() { 19 | Serial.println("OTA end"); 20 | }); 21 | ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) { 22 | Serial.printf("Progress: %u%%\r", (progress / (total / 100))); 23 | }); 24 | ArduinoOTA.onError([](ota_error_t error) { 25 | Serial.printf("OTA error[%u]: ", error); 26 | if (error == OTA_AUTH_ERROR) Serial.println("Auth Failed"); 27 | else if (error == OTA_BEGIN_ERROR) Serial.println("Begin Failed"); 28 | else if (error == OTA_CONNECT_ERROR) Serial.println("Connect Failed"); 29 | else if (error == OTA_RECEIVE_ERROR) Serial.println("Receive Failed"); 30 | else if (error == OTA_END_ERROR) Serial.println("End Failed"); 31 | }); 32 | ArduinoOTA.begin(); 33 | 34 | _enabled = 1; 35 | 36 | Serial.print("IP: "); 37 | Serial.println(WiFi.localIP()); 38 | } 39 | 40 | void ArduinoOTAMgr::handle() 41 | { 42 | if (_enabled) ArduinoOTA.handle(); 43 | } 44 | -------------------------------------------------------------------------------- /WS2812ArtNet/esp8266.c: -------------------------------------------------------------------------------- 1 | // This is a mash-up of the Due show() code + insights from Michael Miller's 2 | // ESP8266 work for the NeoPixelBus library: github.com/Makuna/NeoPixelBus 3 | // Needs to be a separate .c file to enforce ICACHE_RAM_ATTR execution. 4 | 5 | #ifdef ESP8266 6 | 7 | #include 8 | #include 9 | 10 | static uint32_t _getCycleCount(void) __attribute__((always_inline)); 11 | static inline uint32_t _getCycleCount(void) { 12 | uint32_t ccount; 13 | __asm__ __volatile__("rsr %0,ccount":"=a" (ccount)); 14 | return ccount; 15 | } 16 | 17 | void ICACHE_RAM_ATTR espShow( 18 | uint8_t pin, uint16_t *pixels, uint32_t numBytes, boolean is800KHz) { 19 | 20 | #define CYCLES_800_T0H (F_CPU / 2500000) // 0.4us 21 | #define CYCLES_800_T1H (F_CPU / 1250000) // 0.8us 22 | #define CYCLES_800 (F_CPU / 800000) // 1.25us per bit 23 | #define CYCLES_400_T0H (F_CPU / 2000000) // 0.5uS 24 | #define CYCLES_400_T1H (F_CPU / 833333) // 1.2us 25 | #define CYCLES_400 (F_CPU / 400000) // 2.5us per bit 26 | 27 | uint8_t *p, *end, pix, mask; 28 | uint32_t t, time0, time1, period, c, startTime, pinMask; 29 | 30 | pinMask = _BV(pin); 31 | p = pixels; 32 | end = p + numBytes; 33 | pix = *p++; 34 | mask = 0x80; 35 | startTime = 0; 36 | 37 | #ifdef NEO_KHZ400 38 | if(is800KHz) { 39 | #endif 40 | time0 = CYCLES_800_T0H; 41 | time1 = CYCLES_800_T1H; 42 | period = CYCLES_800; 43 | #ifdef NEO_KHZ400 44 | } else { // 400 KHz bitstream 45 | time0 = CYCLES_400_T0H; 46 | time1 = CYCLES_400_T1H; 47 | period = CYCLES_400; 48 | } 49 | #endif 50 | 51 | noInterrupts(); // Need 100% focus on instruction timing 52 | //uint32_t savedPS = xt_rsil(15); 53 | 54 | for(t = time0;; t = time0) { 55 | if(pix & mask) t = time1; // Bit high duration 56 | while(((c = _getCycleCount()) - startTime) < period); // Wait for bit start 57 | GPIO_REG_WRITE(GPIO_OUT_W1TS_ADDRESS, pinMask); // Set high 58 | startTime = c; // Save start time 59 | while(((c = _getCycleCount()) - startTime) < t); // Wait high duration 60 | GPIO_REG_WRITE(GPIO_OUT_W1TC_ADDRESS, pinMask); // Set low 61 | if(!(mask >>= 1)) { // Next bit/byte 62 | if(p >= end) break; 63 | pix = *p++; 64 | mask = 0x80; 65 | } 66 | } 67 | while((_getCycleCount() - startTime) < period); // Wait for last bit 68 | 69 | interrupts(); 70 | //xt_wsr_ps(savedPS); 71 | } 72 | 73 | #endif // ESP8266 74 | -------------------------------------------------------------------------------- /WS2812Remote/WS2812Remote.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | 4 | //############################################################################## 5 | // # 6 | // contains code hacked from 7 | // Glediator to WS2812 pixel converter # 8 | // by R. Heller # 9 | // V 1.0 - 07.01.2014 #// 10 | // www.SolderLab.de # 11 | // # 12 | // Maximum number of supported pixels is 512 !!! # 13 | // # 14 | // In the Glediator software set output mode to "Glediator_Protocol", # 15 | // color order to "GRB" and baud rate to "1000000" # 16 | // # 17 | //############################################################################## 18 | //############################################################################## 19 | // # 20 | // To find out the correct port, ddr and pin name when you just know the # 21 | // Arduino's digital pin number just google for "Arduino pin mapping". # 22 | // In the present example digital Pin 2 is used which corresponds to "PORTD", # 23 | // "DDRD" and "2", respectively. # 24 | // # 25 | //############################################################################## 26 | 27 | // tested successfully using FTDI and Windows host PC at 1000000 baud 28 | //#define BAUD_RATE 1000000 //256000//1000000 // 115200 29 | #define BAUD_RATE 115200 30 | #define DATA_PORT PORTD 31 | #define DATA_DDR DDRD 32 | #define DATA_PIN 2 33 | #define PIXEL_CNT 16 34 | 35 | // LED for showing activity, NOT THE LED STRAND 36 | // when a packet is received, blink this LED 37 | // digital pin 13 - onboard LED = PB5 38 | // comment out LED_PORT to disable 39 | #define LED_PORT PORTB 40 | #define LED_DDR DDRB 41 | #define LED_PIN 5 42 | 43 | 44 | #define BYTE_CNT (PIXEL_CNT*3) 45 | #define BUF_LEN BYTE_CNT 46 | 47 | #define START_BYTE_GLEDIATOR 1 48 | #define START_BYTE_PKT 2 49 | 50 | // fill with RGB data 51 | #define OPC_FILL 1 52 | #define OPC_SHOW_FRAME 2 53 | #define OPC_BLANK 3 54 | #define OPC_SET_MODE 4 55 | 56 | #define MODE_GLEDIATOR 1 57 | #define MODE_PKT 2 58 | #define MODE_BOTH (MODE_GLEDIATOR|MODE_PKT) 59 | 60 | #ifdef _MSVC_VER 61 | #pragma pack(1) 62 | #endif 63 | typedef struct pixel_grb { 64 | uint8_t g; 65 | uint8_t r; 66 | uint8_t b; 67 | } PIXEL_GRB; 68 | -------------------------------------------------------------------------------- /WS2812ArtNet/ArtnetWifi.h: -------------------------------------------------------------------------------- 1 | /*The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Nathanaël Lécaudé 4 | https://github.com/natcl/Artnet, http://forum.pjrc.com/threads/24688-Artnet-to-OctoWS2811 5 | 6 | Copyright (c) 2016 Stephan Ruloff 7 | https://github.com/rstephan 8 | 9 | Permission is hereby granted, free of charge, to any person obtaining a copy 10 | of this software and associated documentation files (the "Software"), to deal 11 | in the Software without restriction, including without limitation the rights 12 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | copies of the Software, and to permit persons to whom the Software is 14 | furnished to do so, subject to the following conditions: 15 | 16 | The above copyright notice and this permission notice shall be included in 17 | all copies or substantial portions of the Software. 18 | 19 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | THE SOFTWARE. 26 | */ 27 | 28 | #ifndef ARTNET_WIFI_H 29 | #define ARTNET_WIFI_H 30 | 31 | #include 32 | #include 33 | 34 | // UDP specific 35 | #define ART_NET_PORT 6454 36 | // Opcodes 37 | #define ART_POLL 0x2000 38 | #define ART_DMX 0x5000 39 | // Buffers 40 | #define MAX_BUFFER_ARTNET 530 41 | // Packet 42 | #define ART_NET_ID "Art-Net\0" 43 | #define ART_DMX_START 18 44 | 45 | class ArtnetWifi 46 | { 47 | public: 48 | ArtnetWifi(); 49 | 50 | void begin(String hostname = ""); 51 | uint16_t read(void); 52 | /* returns 1 for Ok, or 0 on problem */ 53 | int write(void); 54 | int write(IPAddress ip); 55 | void setByte(uint16_t pos, uint8_t value); 56 | void printPacketHeader(void); 57 | void printPacketContent(void); 58 | 59 | // Return a pointer to the start of the DMX data 60 | inline uint8_t* getDmxFrame(void) 61 | { 62 | return artnetPacket + ART_DMX_START; 63 | } 64 | 65 | inline uint16_t getOpcode(void) 66 | { 67 | return opcode; 68 | } 69 | 70 | inline uint8_t getSequence(void) 71 | { 72 | return sequence; 73 | } 74 | 75 | inline uint16_t getUniverse(void) 76 | { 77 | return incomingUniverse; 78 | } 79 | 80 | inline void setUniverse(uint16_t universe) 81 | { 82 | outgoingUniverse = universe; 83 | } 84 | 85 | inline void setPhisical(uint8_t port) 86 | { 87 | phisical = port; 88 | } 89 | 90 | inline uint16_t getLength(void) 91 | { 92 | return dmxDataLength; 93 | } 94 | 95 | inline void setLength(uint16_t len) 96 | { 97 | dmxDataLength = len; 98 | } 99 | 100 | inline void setArtDmxCallback(void (*fptr)(uint16_t universe, uint16_t length, uint8_t sequence, uint8_t* data)) 101 | { 102 | artDmxCallback = fptr; 103 | } 104 | 105 | private: 106 | uint16_t makePacket(void); 107 | 108 | WiFiUDP Udp; 109 | String host; 110 | uint8_t artnetPacket[MAX_BUFFER_ARTNET]; 111 | uint16_t packetSize; 112 | uint16_t opcode; 113 | uint8_t sequence; 114 | uint8_t phisical; 115 | uint16_t incomingUniverse; 116 | uint16_t outgoingUniverse; 117 | uint16_t dmxDataLength; 118 | void (*artDmxCallback)(uint16_t universe, uint16_t length, uint8_t sequence, uint8_t* data); 119 | }; 120 | 121 | #endif 122 | -------------------------------------------------------------------------------- /WS2812Remote/pkt_test/pkt_test.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 Sam C. Lin 3 | * This file is part of WS2812Remote 4 | 5 | * WS2812Remote is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 3, or (at your option) 8 | * any later version. 9 | 10 | * WS2812Remote is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | 15 | * You should have received a copy of the GNU General Public License 16 | * along with WS2812Remote; see the file COPYING. If not, write to the 17 | * Free Software Foundation, Inc., 59 Temple Place - Suite 330, 18 | * Boston, MA 02111-1307, USA. 19 | */ 20 | 21 | // Packet Protocol Test 22 | 23 | #include 24 | #include 25 | #include 26 | #include "serialib.h" 27 | 28 | #ifdef _WIN32 29 | #include 30 | #define SLEEP(x) Sleep(x) 31 | #else 32 | #include 33 | #define SLEEP(x) usleep(x*1000) 34 | #endif 35 | 36 | 37 | 38 | #include "../WS2812Remote.h" 39 | uint8_t buf[1024]; 40 | 41 | #define COMM_PORT "\\\\.\\COM3" 42 | //#define COMM_PORT "/dev/ttyUSB0" 43 | 44 | void setChkByte(int pktlen) 45 | { 46 | uint8_t chk = buf[0] ^ buf[2]; 47 | for (int i=3;i < pktlen;i++) { 48 | chk ^= buf[i]; 49 | } 50 | buf[1] = chk; 51 | } 52 | 53 | 54 | int main(int argc,char *argv[]) 55 | { 56 | serialib serial; 57 | int rc = serial.Open(COMM_PORT,BAUD_RATE); 58 | if (rc != 1) { 59 | fprintf(stderr, "error opening %s: %d", COMM_PORT, rc); 60 | return 1; 61 | } 62 | 63 | // set the mode 64 | int pktlen = 4; 65 | buf[0] = START_BYTE_PKT; 66 | buf[2] = OPC_SET_MODE; 67 | buf[3] = MODE_BOTH; // MODE_BOTH MODE_GLEDIATOR MODE_PKT 68 | setChkByte(pktlen); 69 | serial.Write(buf, pktlen); 70 | 71 | // blank the screen 72 | printf("blank...\n"); 73 | pktlen = 3; 74 | buf[0] = START_BYTE_PKT; 75 | buf[2] = OPC_BLANK; 76 | setChkByte(pktlen); 77 | serial.Write(buf, pktlen); 78 | SLEEP(1000); 79 | 80 | // fill screen with 1 color 81 | printf("fill...\n"); 82 | pktlen = 6; 83 | buf[0] = START_BYTE_PKT; 84 | buf[2] = OPC_FILL; 85 | buf[3] = 255; 86 | buf[4] = 255; 87 | buf[5] = 255; 88 | setChkByte(pktlen); 89 | serial.Write(buf, pktlen); 90 | SLEEP(1000); 91 | 92 | // cycle random color pixels 93 | printf("cycle...\n"); 94 | PIXEL_GRB *pixBuf = (PIXEL_GRB *)(buf + 3); 95 | while (1) { 96 | buf[0] = START_BYTE_PKT; 97 | buf[2] = OPC_SHOW_FRAME; 98 | pixBuf[0].r = rand() % 256; 99 | pixBuf[0].g = rand() % 256; 100 | pixBuf[0].b = rand() % 256; 101 | int i; 102 | for (i=1;i < PIXEL_CNT;i++) { 103 | pixBuf[i].r = 0; 104 | pixBuf[i].g = 0; 105 | pixBuf[i].b = 0; 106 | } 107 | PIXEL_GRB p; 108 | for (int k=0;k < PIXEL_CNT;k++) { 109 | uint8_t chk = START_BYTE_PKT ^ OPC_SHOW_FRAME; 110 | p = pixBuf[0]; 111 | 112 | for (i=1;i < PIXEL_CNT;i++) { 113 | pixBuf[i-1] = pixBuf[i]; 114 | chk ^= pixBuf[i-1].r; 115 | chk ^= pixBuf[i-1].g; 116 | chk ^= pixBuf[i-1].b; 117 | } 118 | pixBuf[PIXEL_CNT-1] = p; 119 | chk ^= pixBuf[PIXEL_CNT-1].r; 120 | chk ^= pixBuf[PIXEL_CNT-1].g; 121 | chk ^= pixBuf[PIXEL_CNT-1].b; 122 | buf[1] = chk; 123 | serial.Write(buf,sizeof(PIXEL_GRB)*PIXEL_CNT + 3); 124 | SLEEP(25); 125 | } 126 | } 127 | return 0; 128 | } 129 | -------------------------------------------------------------------------------- /WS2812Remote/pkt_test/pkt_test.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | 14 | {4DE43C65-7F62-40AC-A8C3-1A37B537A032} 15 | Win32Proj 16 | pkt_test 17 | pkt_test 18 | 19 | 20 | 21 | Application 22 | true 23 | v140 24 | Unicode 25 | 26 | 27 | Application 28 | false 29 | v140 30 | true 31 | Unicode 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | true 45 | 46 | 47 | false 48 | 49 | 50 | 51 | 52 | 53 | Level3 54 | Disabled 55 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 56 | 57 | 58 | Console 59 | true 60 | 61 | 62 | 63 | 64 | Level3 65 | 66 | 67 | MaxSpeed 68 | true 69 | true 70 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 71 | 72 | 73 | Console 74 | true 75 | true 76 | true 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | -------------------------------------------------------------------------------- /WS2812ArtNet/ArtnetWifi.cpp: -------------------------------------------------------------------------------- 1 | /*The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Nathanaël Lécaudé 4 | https://github.com/natcl/Artnet, http://forum.pjrc.com/threads/24688-Artnet-to-OctoWS2811 5 | 6 | Copyright (c) 2016 Stephan Ruloff 7 | https://github.com/rstephan 8 | 9 | Permission is hereby granted, free of charge, to any person obtaining a copy 10 | of this software and associated documentation files (the "Software"), to deal 11 | in the Software without restriction, including without limitation the rights 12 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | copies of the Software, and to permit persons to whom the Software is 14 | furnished to do so, subject to the following conditions: 15 | 16 | The above copyright notice and this permission notice shall be included in 17 | all copies or substantial portions of the Software. 18 | 19 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | THE SOFTWARE. 26 | */ 27 | 28 | #include "ArtnetWifi.h" 29 | 30 | ArtnetWifi::ArtnetWifi() {} 31 | 32 | void ArtnetWifi::begin(String hostname) 33 | { 34 | Udp.begin(ART_NET_PORT); 35 | host = hostname; 36 | sequence = 1; 37 | phisical = 0; 38 | } 39 | 40 | uint16_t ArtnetWifi::read(void) 41 | { 42 | packetSize = Udp.parsePacket(); 43 | 44 | if (packetSize <= MAX_BUFFER_ARTNET && packetSize > 0) 45 | { 46 | Udp.read(artnetPacket, MAX_BUFFER_ARTNET); 47 | 48 | // Check that packetID is "Art-Net" else ignore 49 | for (byte i = 0 ; i < 9 ; i++) 50 | { 51 | if (artnetPacket[i] != ART_NET_ID[i]) 52 | return 0; 53 | } 54 | 55 | opcode = artnetPacket[8] | artnetPacket[9] << 8; 56 | 57 | if (opcode == ART_DMX) 58 | { 59 | sequence = artnetPacket[12]; 60 | incomingUniverse = artnetPacket[14] | artnetPacket[15] << 8; 61 | dmxDataLength = artnetPacket[17] | artnetPacket[16] << 8; 62 | 63 | if (artDmxCallback) (*artDmxCallback)(incomingUniverse, dmxDataLength, sequence, artnetPacket + ART_DMX_START); 64 | return ART_DMX; 65 | } 66 | if (opcode == ART_POLL) 67 | { 68 | return ART_POLL; 69 | } 70 | } 71 | else 72 | { 73 | return 0; 74 | } 75 | } 76 | 77 | uint16_t ArtnetWifi::makePacket(void) 78 | { 79 | uint16_t len; 80 | uint16_t version; 81 | 82 | memcpy(artnetPacket, ART_NET_ID, 8); 83 | opcode = ART_DMX; 84 | artnetPacket[8] = opcode; 85 | artnetPacket[9] = opcode >> 8; 86 | version = 14; 87 | artnetPacket[11] = version; 88 | artnetPacket[10] = version >> 8; 89 | artnetPacket[12] = sequence; 90 | sequence++; 91 | if (!sequence) { 92 | sequence = 1; 93 | } 94 | artnetPacket[13] = phisical; 95 | artnetPacket[14] = outgoingUniverse; 96 | artnetPacket[15] = outgoingUniverse >> 8; 97 | len = dmxDataLength + (dmxDataLength % 2); // make a even number 98 | artnetPacket[17] = len; 99 | artnetPacket[16] = len >> 8; 100 | 101 | return len; 102 | } 103 | 104 | int ArtnetWifi::write(void) 105 | { 106 | uint16_t len; 107 | 108 | len = makePacket(); 109 | Udp.beginPacket(host.c_str(), ART_NET_PORT); 110 | Udp.write(artnetPacket, ART_DMX_START + len); 111 | 112 | return Udp.endPacket(); 113 | } 114 | 115 | int ArtnetWifi::write(IPAddress ip) 116 | { 117 | uint16_t len; 118 | 119 | len = makePacket(); 120 | Udp.beginPacket(ip, ART_NET_PORT); 121 | Udp.write(artnetPacket, ART_DMX_START + len); 122 | 123 | return Udp.endPacket(); 124 | } 125 | 126 | void ArtnetWifi::setByte(uint16_t pos, uint8_t value) 127 | { 128 | if (pos > 512) { 129 | return; 130 | } 131 | artnetPacket[ART_DMX_START + pos] = value; 132 | } 133 | 134 | void ArtnetWifi::printPacketHeader(void) 135 | { 136 | Serial.print("packet size = "); 137 | Serial.print(packetSize); 138 | Serial.print("\topcode = "); 139 | Serial.print(opcode, HEX); 140 | Serial.print("\tuniverse number = "); 141 | Serial.print(incomingUniverse); 142 | Serial.print("\tdata length = "); 143 | Serial.print(dmxDataLength); 144 | Serial.print("\tsequence n0. = "); 145 | Serial.println(sequence); 146 | } 147 | 148 | void ArtnetWifi::printPacketContent(void) 149 | { 150 | for (uint16_t i = ART_DMX_START ; i < dmxDataLength ; i++){ 151 | Serial.print(artnetPacket[i], DEC); 152 | Serial.print(" "); 153 | } 154 | Serial.println('\n'); 155 | } 156 | -------------------------------------------------------------------------------- /WS2812Remote/WS2812Remote.ino: -------------------------------------------------------------------------------- 1 | // 20170103 SCL creation 2 | 3 | #include "WS2812Remote.h" 4 | 5 | PIXEL_GRB g_pixelBuffer[PIXEL_CNT]; 6 | uint8_t *display_buffer = (uint8_t *)g_pixelBuffer; 7 | PIXEL_GRB g_BlkPixel = {0,0,0}; 8 | uint8_t g_mode = MODE_BOTH; 9 | 10 | 11 | inline uint8_t readByte() 12 | { 13 | while(Serial.peek() == -1); 14 | return Serial.read(); 15 | } 16 | 17 | void pixelFill(PIXEL_GRB &pixel) 18 | { 19 | for (uint8_t i=0;i < PIXEL_CNT;i++) { 20 | g_pixelBuffer[i] = pixel; 21 | } 22 | } 23 | 24 | //############################################################################## 25 | // # 26 | // WS2812 output routine # 27 | // Extracted from a ligh weight WS2812 lib by Tim (cpldcpu@gmail.com) # 28 | // Found on wwww.microcontroller.net # 29 | // Requires F_CPU = 16MHz # 30 | // # 31 | //############################################################################## 32 | 33 | void ShowBuffer() 34 | { 35 | uint8_t *data = display_buffer; 36 | uint16_t datlen = PIXEL_CNT * sizeof(PIXEL_GRB); 37 | uint8_t curbyte,ctr,masklo; 38 | uint8_t maskhi = _BV(DATA_PIN); 39 | 40 | cli(); 41 | masklo =~ maskhi & DATA_PORT; 42 | maskhi |= DATA_PORT; 43 | 44 | while (datlen--) 45 | { 46 | curbyte = *data++; 47 | 48 | asm volatile 49 | ( 50 | " ldi %0,8 \n\t" // 0 51 | "loop%=:out %2, %3 \n\t" // 1 52 | "lsl %1 \n\t" // 2 53 | "dec %0 \n\t" // 3 54 | " rjmp .+0 \n\t" // 5 55 | " brcs .+2 \n\t" // 6l / 7h 56 | " out %2,%4 \n\t" // 7l / - 57 | " rjmp .+0 \n\t" // 9 58 | " nop \n\t" // 10 59 | " out %2,%4 \n\t" // 11 60 | " breq end%= \n\t" // 12 nt. 13 taken 61 | " rjmp .+0 \n\t" // 14 62 | " rjmp .+0 \n\t" // 16 63 | " rjmp .+0 \n\t" // 18 64 | " rjmp loop%= \n\t" // 20 65 | "end%=: \n\t" 66 | : "=&d" (ctr) 67 | : "r" (curbyte), "I" (_SFR_IO_ADDR(DATA_PORT)), "r" (maskhi), "r" (masklo) 68 | ); 69 | } 70 | 71 | sei(); 72 | } 73 | 74 | void doGlediator() 75 | { 76 | uint8_t *ptr = display_buffer; 77 | 78 | for (uint16_t i=0;i < BYTE_CNT;i++) { 79 | *(ptr++)=readByte(); 80 | } 81 | 82 | ShowBuffer(); 83 | } 84 | 85 | void doPkt() 86 | { 87 | uint8_t chk = START_BYTE_PKT; 88 | uint8_t chkByte = readByte(); 89 | uint8_t opCode = readByte(); 90 | chk ^= opCode; 91 | switch(opCode) { 92 | case OPC_FILL: 93 | { 94 | PIXEL_GRB p; 95 | p.r = readByte(); 96 | chk ^= p.r; 97 | p.g = readByte(); 98 | chk ^= p.g; 99 | p.b = readByte(); 100 | chk ^= p.b; 101 | if (chk == chkByte) { 102 | pixelFill(p); 103 | ShowBuffer(); 104 | } 105 | } 106 | break; 107 | case OPC_SHOW_FRAME: 108 | { 109 | uint8_t *ptr = display_buffer; 110 | 111 | for (uint16_t i=0;i < BYTE_CNT;i++) { 112 | chk ^= *(ptr++)=readByte(); 113 | } 114 | if (chk == chkByte) { 115 | ShowBuffer(); 116 | } 117 | } 118 | break; 119 | case OPC_BLANK: 120 | if (chk == chkByte) { 121 | pixelFill(g_BlkPixel); 122 | ShowBuffer(); 123 | } 124 | break; 125 | case OPC_SET_MODE: 126 | { 127 | uint8_t mode = readByte(); 128 | chk ^= mode; 129 | if (chk == chkByte) { 130 | g_mode = mode; 131 | } 132 | } 133 | break; 134 | default: 135 | ; 136 | } 137 | } 138 | 139 | //############################################################################## 140 | // # 141 | // Setup # 142 | // # 143 | //############################################################################## 144 | 145 | void setup() 146 | { 147 | // Set data pin as output 148 | DATA_DDR |= (1 << DATA_PIN); 149 | #ifdef LED_PORT 150 | // Set LED pin as output 151 | LED_DDR |= (1 << LED_PIN); 152 | // turn off LED 153 | LED_PORT &= ~(1 << LED_PIN); 154 | #endif // LED_PORT 155 | 156 | Serial.begin(BAUD_RATE); 157 | 158 | // blank out the screen on startup 159 | pixelFill(g_BlkPixel); 160 | ShowBuffer(); 161 | } 162 | 163 | //############################################################################## 164 | // # 165 | // Main loop # 166 | // # 167 | //############################################################################## 168 | 169 | 170 | void loop() 171 | { 172 | /*debug stuff 173 | uint8_t b = readByte(); 174 | Serial.write(b); 175 | switch(b) { 176 | */ 177 | switch(readByte()) { 178 | case START_BYTE_GLEDIATOR: 179 | if (g_mode & MODE_GLEDIATOR) { 180 | #ifdef LED_PORT 181 | LED_PORT |= (1 << LED_PIN); 182 | #endif 183 | doGlediator(); 184 | #ifdef LED_PORT 185 | LED_PORT &= ~(1 << LED_PIN); 186 | #endif 187 | } 188 | break; 189 | case START_BYTE_PKT: 190 | if (g_mode & MODE_PKT) { 191 | #ifdef LED_PORT 192 | LED_PORT |= (1 << LED_PIN); 193 | #endif 194 | doPkt(); 195 | #ifdef LED_PORT 196 | LED_PORT &= ~(1 << LED_PIN); 197 | #endif 198 | } 199 | break; 200 | default: 201 | ; 202 | } 203 | } 204 | 205 | 206 | -------------------------------------------------------------------------------- /WS2812Remote/pkt_test/serialib.h: -------------------------------------------------------------------------------- 1 | /*! 2 | \file serialib.h 3 | \brief Serial library to communicate throught serial port, or any device emulating a serial port. 4 | \author Philippe Lucidarme (University of Angers) 5 | \version 1.2 6 | \date 28 avril 2011 7 | This Serial library is used to communicate through serial port. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 10 | INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR 11 | PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM, 12 | DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 13 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 14 | 15 | This is a licence-free software, it can be used by anyone who try to build a better world. 16 | */ 17 | 18 | 19 | #ifndef SERIALIB_H 20 | #define SERIALIB_H 21 | 22 | 23 | // Include for windows 24 | #if defined (_WIN32) || defined( _WIN64) 25 | // Used for TimeOut operations 26 | #include 27 | // Accessing to the serial port under Windows 28 | #include 29 | #endif 30 | 31 | #if defined(__unix__) && !defined(__linux__) 32 | #define __linux__ 33 | #endif 34 | 35 | 36 | // Include for Linux 37 | #ifdef __linux__ 38 | // Used for TimeOut operations 39 | #include 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | #include 46 | // File control definitions 47 | #include 48 | #include 49 | #include 50 | #endif 51 | 52 | 53 | 54 | /*! \class serialib 55 | \brief This class can manage a serial port. The class allows basic operations (opening the connection, reading, writing data and closing the connection). 56 | \example Example1.cpp 57 | */ 58 | 59 | 60 | class serialib 61 | { 62 | public: 63 | // Constructor of the class 64 | serialib (); 65 | 66 | // Destructor 67 | ~serialib (); 68 | 69 | 70 | 71 | //_________________________________________ 72 | // ::: Configuration and initialization ::: 73 | 74 | 75 | // Open a device 76 | char Open (const char *Device,const unsigned int Bauds); 77 | 78 | // Close the current device 79 | void Close(); 80 | 81 | 82 | 83 | //___________________________________________ 84 | // ::: Read/Write operation on characters ::: 85 | 86 | 87 | // Write a char 88 | char WriteChar (char); 89 | 90 | // Read a char (with timeout) 91 | char ReadChar (char *pByte,const unsigned int TimeOut_ms=0); 92 | 93 | 94 | 95 | //________________________________________ 96 | // ::: Read/Write operation on strings ::: 97 | 98 | 99 | // Write a string 100 | char WriteString (const char *String); 101 | // Read a string (with timeout) 102 | int ReadString ( char *String, 103 | char FinalChar, 104 | unsigned int MaxNbBytes, 105 | const unsigned int TimeOut_ms=0); 106 | 107 | 108 | 109 | // _____________________________________ 110 | // ::: Read/Write operation on bytes ::: 111 | 112 | 113 | // Write an array of bytes 114 | char Write (const void *Buffer, const unsigned int NbBytes); 115 | 116 | // Read an array of byte (with timeout) 117 | int Read (void *Buffer,unsigned int MaxNbBytes,const unsigned int TimeOut_ms=0); 118 | 119 | 120 | // _________________________ 121 | // ::: Special operation ::: 122 | 123 | 124 | // Empty the received buffer 125 | void FlushReceiver(); 126 | 127 | // Return the number of bytes in the received buffer 128 | int Peek(); 129 | 130 | private: 131 | // Read a string (no timeout) 132 | int ReadStringNoTimeOut (char *String,char FinalChar,unsigned int MaxNbBytes); 133 | 134 | 135 | #if defined (_WIN32) || defined( _WIN64) 136 | HANDLE hSerial; 137 | COMMTIMEOUTS timeouts; 138 | #endif 139 | #ifdef __linux__ 140 | int fd; 141 | #endif 142 | 143 | }; 144 | 145 | 146 | 147 | /*! \class TimeOut 148 | \brief This class can manage a timer which is used as a timeout. 149 | */ 150 | // Class TimeOut 151 | class TimeOut 152 | { 153 | public: 154 | 155 | // Constructor 156 | TimeOut(); 157 | 158 | // Init the timer 159 | void InitTimer(); 160 | 161 | // Return the elapsed time since initialization 162 | unsigned long int ElapsedTime_ms(); 163 | 164 | private: 165 | struct timeval PreviousTime; 166 | }; 167 | 168 | 169 | 170 | /*! 171 | \mainpage serialib class 172 | 173 | \brief 174 | \htmlonly 175 | 176 | 184 | 195 | 196 |
177 | 178 | 179 | 180 | 181 |

[Download]

182 |
183 |
185 | 191 | 194 |
197 | 198 | \endhtmlonly 199 | 200 | The class serialib offers simple access to the serial port devices for windows and linux. It can be used for any serial device (Built-in serial port, USB to RS232 converter, arduino board or any hardware using or emulating a serial port) 201 | \image html serialib.png 202 | The class can be used under Windows and Linux. 203 | The class allows basic operations like : 204 | - opening and closing connection 205 | - reading data (characters, array of bytes or strings) 206 | - writing data (characters, array of bytes or strings) 207 | - non-blocking functions (based on timeout). 208 | 209 | 210 | \author Philippe Lucidarme (University of Angers) 211 | \date 1th may 2011 (Last update: 25th september 2012) 212 | \version 1.2 213 | 214 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 215 | INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR 216 | PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM, 217 | DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 218 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 219 | 220 | This is a licence-free software, it can be used by anyone who try to build a better world. 221 | */ 222 | 223 | 224 | 225 | 226 | #endif // SERIALIB_H 227 | 228 | -------------------------------------------------------------------------------- /WS2812ArtNet/WiFiManager.h: -------------------------------------------------------------------------------- 1 | /************************************************************** 2 | WiFiManager is a library for the ESP8266/Arduino platform 3 | (https://github.com/esp8266/Arduino) to enable easy 4 | configuration and reconfiguration of WiFi credentials using a Captive Portal 5 | inspired by: 6 | http://www.esp8266.com/viewtopic.php?f=29&t=2520 7 | https://github.com/chriscook8/esp-arduino-apboot 8 | https://github.com/esp8266/Arduino/tree/esp8266/hardware/esp8266com/esp8266/libraries/DNSServer/examples/CaptivePortalAdvanced 9 | Built by AlexT https://github.com/tzapu 10 | Licensed under MIT license 11 | **************************************************************/ 12 | 13 | #ifndef WiFiManager_h 14 | #define WiFiManager_h 15 | 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | #define NOHIDEPASS // don't hide passphrase with dots 22 | 23 | extern "C" { 24 | #include "user_interface.h" 25 | } 26 | 27 | const char HTTP_HEAD[] PROGMEM = "{v}"; 28 | const char HTTP_STYLE[] PROGMEM = ""; 29 | const char HTTP_SCRIPT[] PROGMEM = ""; 30 | const char HTTP_HEAD_END[] PROGMEM = "
"; 31 | const char HTTP_PORTAL_OPTIONS[] PROGMEM = "



"; 32 | const char HTTP_ITEM[] PROGMEM = "
{v} {r}%
"; 33 | #ifdef NOHIDEPASS 34 | const char HTTP_FORM_START[] PROGMEM = "


"; 35 | #else 36 | const char HTTP_FORM_START[] PROGMEM = "

"; 37 | #endif 38 | const char HTTP_FORM_PARAM[] PROGMEM = "
"; 39 | const char HTTP_FORM_END[] PROGMEM = "
"; 40 | const char HTTP_SCAN_LINK[] PROGMEM = "
"; 41 | const char HTTP_SAVED[] PROGMEM = "
Credentials Saved
Trying to connect ESP to network.
If it fails reconnect to AP to try again
"; 42 | const char HTTP_END[] PROGMEM = "
"; 43 | 44 | #define WIFI_MANAGER_MAX_PARAMS 10 45 | 46 | class WiFiManagerParameter { 47 | public: 48 | WiFiManagerParameter(const char *custom); 49 | WiFiManagerParameter(const char *id, const char *placeholder, const char *defaultValue, int length); 50 | WiFiManagerParameter(const char *id, const char *placeholder, const char *defaultValue, int length, const char *custom); 51 | 52 | const char *getID(); 53 | const char *getValue(); 54 | const char *getPlaceholder(); 55 | int getValueLength(); 56 | const char *getCustomHTML(); 57 | private: 58 | const char *_id; 59 | const char *_placeholder; 60 | char *_value; 61 | int _length; 62 | const char *_customHTML; 63 | 64 | void init(const char *id, const char *placeholder, const char *defaultValue, int length, const char *custom); 65 | 66 | friend class WiFiManager; 67 | }; 68 | 69 | 70 | class WiFiManager 71 | { 72 | public: 73 | WiFiManager(); 74 | 75 | boolean autoConnect(); 76 | boolean autoConnect(char const *apName, char const *apPassword = NULL); 77 | 78 | //if you want to always start the config portal, without trying to connect first 79 | boolean startConfigPortal(); 80 | boolean startConfigPortal(char const *apName, char const *apPassword = NULL); 81 | 82 | // get the AP name of the config portal, so it can be used in the callback 83 | String getConfigPortalSSID(); 84 | 85 | void resetSettings(); 86 | 87 | //sets timeout before webserver loop ends and exits even if there has been no setup. 88 | //usefully for devices that failed to connect at some point and got stuck in a webserver loop 89 | //in seconds setConfigPortalTimeout is a new name for setTimeout 90 | void setConfigPortalTimeout(unsigned long seconds); 91 | 92 | //sets timeout for which to attempt connecting, usefull if you get a lot of failed connects 93 | void setConnectTimeout(unsigned long seconds); 94 | 95 | 96 | void setDebugOutput(boolean debug); 97 | //defaults to not showing anything under 8% signal quality if called 98 | void setMinimumSignalQuality(int quality = 8); 99 | //sets a custom ip /gateway /subnet configuration 100 | void setAPStaticIPConfig(IPAddress ip, IPAddress gw, IPAddress sn); 101 | //sets config for a static IP 102 | void setSTAStaticIPConfig(IPAddress ip, IPAddress gw, IPAddress sn); 103 | //called when AP mode and config portal is started 104 | void setAPCallback( void (*func)(WiFiManager*) ); 105 | //called when settings have been changed and connection was successful 106 | void setSaveConfigCallback( void (*func)(void) ); 107 | //adds a custom parameter 108 | void addParameter(WiFiManagerParameter *p); 109 | //if this is set, it will exit after config, even if connection is unsucessful. 110 | void setBreakAfterConfig(boolean shouldBreak); 111 | //if this is set, try WPS setup when starting (this will delay config portal for up to 2 mins) 112 | //TODO 113 | //if this is set, customise style 114 | void setCustomHeadElement(const char* element); 115 | //if this is true, remove duplicated Access Points - defaut true 116 | void setRemoveDuplicateAPs(boolean removeDuplicates); 117 | 118 | private: 119 | std::unique_ptr dnsServer; 120 | std::unique_ptr server; 121 | 122 | //const int WM_DONE = 0; 123 | //const int WM_WAIT = 10; 124 | 125 | //const String HTTP_HEAD = "{v}"; 126 | 127 | void setupConfigPortal(); 128 | void startWPS(); 129 | 130 | const char* _apName = "no-net"; 131 | const char* _apPassword = NULL; 132 | String _ssid = ""; 133 | String _pass = ""; 134 | unsigned long _configPortalTimeout = 0; 135 | unsigned long _connectTimeout = 0; 136 | unsigned long _configPortalStart = 0; 137 | 138 | IPAddress _ap_static_ip; 139 | IPAddress _ap_static_gw; 140 | IPAddress _ap_static_sn; 141 | IPAddress _sta_static_ip; 142 | IPAddress _sta_static_gw; 143 | IPAddress _sta_static_sn; 144 | 145 | int _paramsCount = 0; 146 | int _minimumQuality = -1; 147 | boolean _removeDuplicateAPs = true; 148 | boolean _shouldBreakAfterConfig = false; 149 | boolean _tryWPS = false; 150 | 151 | const char* _customHeadElement = ""; 152 | 153 | //String getEEPROMString(int start, int len); 154 | //void setEEPROMString(int start, int len, String string); 155 | 156 | int status = WL_IDLE_STATUS; 157 | int connectWifi(String ssid, String pass); 158 | uint8_t waitForConnectResult(); 159 | 160 | void handleRoot(); 161 | void handleWifi(boolean scan); 162 | void handleWifiSave(); 163 | void handleInfo(); 164 | void handleReset(); 165 | void handleNotFound(); 166 | void handle204(); 167 | boolean captivePortal(); 168 | 169 | // DNS server 170 | const byte DNS_PORT = 53; 171 | 172 | //helpers 173 | int getRSSIasQuality(int RSSI); 174 | boolean isIp(String str); 175 | String toStringIp(IPAddress ip); 176 | 177 | boolean connect; 178 | boolean _debug = true; 179 | 180 | void (*_apcallback)(WiFiManager*) = NULL; 181 | void (*_savecallback)(void) = NULL; 182 | 183 | WiFiManagerParameter* _params[WIFI_MANAGER_MAX_PARAMS]; 184 | 185 | template 186 | void DEBUG_WM(Generic text); 187 | 188 | template 189 | auto optionalIPFromString(T *obj, const char *s) -> decltype( obj->fromString(s) ) { 190 | return obj->fromString(s); 191 | } 192 | auto optionalIPFromString(...) -> bool { 193 | DEBUG_WM("NO fromString METHOD ON IPAddress, you need ESP8266 core 2.1.0 or newer for Custom IP configuration to work."); 194 | return false; 195 | } 196 | }; 197 | 198 | #endif 199 | -------------------------------------------------------------------------------- /WS2812ArtNet/WS2812ArtNet.ino: -------------------------------------------------------------------------------- 1 | /* 2 | Hacked by SCL from 3 | https://github.com/natcl/Artnet/blob/master/examples/ArtnetNeoPixel/ArtnetNeoPixel.ino 4 | https://github.com/overflo23/ESP8266_ARTNET_WS2801/tree/master/artnet_esp 5 | 6 | This example will receive multiple universes via Artnet and control a strip of ws2811 leds 7 | */ 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include "ArtnetWifi.h" 14 | #include "ArduinoOTAMgr.h" 15 | 16 | // 17 | // --- begin configuration 18 | // 19 | #define WIFI_MGR // use AP mode to configure via captive portal 20 | #define OTA_UPDATE // OTA firmware update 21 | 22 | #define PIXEL_CNT 64 // number of LED's 23 | 24 | #define PIN_DATA 1 25 | #define PIN_LED 2 26 | // n.b. pin 15 internal pullup doesn't seem to work so shouldn't be used for reset 27 | #define PIN_FACTORY_RESET 12 // ground this pin to wipe out EEPROM & WiFi settings 28 | 29 | #define AP_PREFIX "WS2812ArtNet_" 30 | 31 | // OTA_UPDATE 32 | #define OTA_HOST "WS2812ArtNet" 33 | #define OTA_PASS "ws2812artnet" 34 | 35 | #ifndef WIFI_MGR 36 | //Wifi settings 37 | const char* ssid = "YOUR-SSID"; 38 | const char* password = "YOUR-PASSPHRASE"; 39 | #endif // !WIFI_MGR 40 | 41 | 42 | // 43 | // --- end configuration 44 | // 45 | 46 | #define CHANNEL_CNT (PIXEL_CNT*3) // Total number of channels you want to receive (1 led = 3 channels) 47 | #define BYTE_CNT (PIXEL_CNT*3) 48 | 49 | // Artnet settings 50 | int startUniverse = 0; 51 | const int maxUniverses = CHANNEL_CNT / 512 + ((CHANNEL_CNT % 512) ? 1 : 0); 52 | 53 | #ifdef OTA_UPDATE 54 | ArduinoOTAMgr AOTAMgr; 55 | #endif 56 | 57 | typedef struct pixel_grb { 58 | uint8_t g; 59 | uint8_t r; 60 | uint8_t b; 61 | } PIXEL_GRB; 62 | PIXEL_GRB g_BlkPixel = {0,0,0}; 63 | 64 | class WS2812Strand { 65 | PIXEL_GRB pixelBuffer[PIXEL_CNT]; 66 | uint16_t *displayBuffer; 67 | uint32_t endTime; // Latch timing reference 68 | uint8_t dataPin; 69 | 70 | inline bool canShow(void) { return (micros() - endTime) >= 50L; } 71 | public: 72 | WS2812Strand(uint8_t datapin); 73 | 74 | void begin(); 75 | void fill(PIXEL_GRB *pixel); 76 | void show(); 77 | uint16_t *getDisplayBuffer() { return displayBuffer; } 78 | void setPixel(uint16_t idx,PIXEL_GRB *p); 79 | PIXEL_GRB *getPixel(uint16_t idx) { return pixelBuffer + idx; } 80 | }; 81 | 82 | WS2812Strand::WS2812Strand(uint8_t datapin) 83 | { 84 | displayBuffer = (uint16_t *)pixelBuffer; 85 | dataPin = datapin; 86 | endTime = 0; 87 | } 88 | 89 | void WS2812Strand::begin() 90 | { 91 | pinMode(dataPin, OUTPUT); 92 | digitalWrite(dataPin, LOW); 93 | endTime = micros(); 94 | } 95 | 96 | void WS2812Strand::fill(PIXEL_GRB *pixel) 97 | { 98 | for (uint16_t i=0;i < PIXEL_CNT;i++) { 99 | pixelBuffer[i] = *pixel; 100 | } 101 | } 102 | 103 | void WS2812Strand::setPixel(uint16_t idx,PIXEL_GRB *p) 104 | { 105 | if (idx < PIXEL_CNT) { 106 | pixelBuffer[idx] = *p; 107 | } 108 | } 109 | 110 | 111 | #ifdef ESP8266 112 | // ESP8266 show() is external to enforce ICACHE_RAM_ATTR execution 113 | extern "C" void ICACHE_RAM_ATTR espShow( 114 | uint8_t pin, uint16_t *pixels, uint32_t numBytes, uint8_t type); 115 | #endif // ESP8266 116 | 117 | void WS2812Strand::show() 118 | { 119 | // Data latch = 50+ microsecond pause in the output stream. Rather than 120 | // put a delay at the end of the function, the ending time is noted and 121 | // the function will simply hold off (if needed) on issuing the 122 | // subsequent round of data until the latch time has elapsed. This 123 | // allows the mainline code to start generating the next frame of data 124 | // rather than stalling for the latch. 125 | while(!canShow()); 126 | espShow(dataPin,displayBuffer,BYTE_CNT,1); 127 | endTime = micros(); // Save EOD time for latch on next call 128 | } 129 | 130 | 131 | #define BTN_PRESS_SHORT 50 // ms 132 | #define BTN_PRESS_LONG 500 // ms 133 | 134 | #define BTN_STATE_OFF 0 135 | #define BTN_STATE_SHORT 1 // short press 136 | #define BTN_STATE_LONG 2 // long press 137 | 138 | class Btn { 139 | uint8_t btnGpio; 140 | uint8_t buttonState; 141 | unsigned long lastDebounceTime; // the last time the output pin was toggled 142 | 143 | public: 144 | Btn(uint8_t gpio); 145 | void init(); 146 | 147 | void read(); 148 | uint8_t shortPress(); 149 | uint8_t longPress(); 150 | }; 151 | 152 | Btn::Btn(uint8_t gpio) 153 | { 154 | btnGpio = gpio; 155 | buttonState = BTN_STATE_OFF; 156 | lastDebounceTime = 0; 157 | } 158 | 159 | void Btn::init() 160 | { 161 | pinMode(btnGpio,INPUT_PULLUP); 162 | } 163 | 164 | void Btn::read() 165 | { 166 | uint8_t sample; 167 | unsigned long delta; 168 | sample = digitalRead(btnGpio) ? 0 : 1; 169 | if (!sample && (buttonState == BTN_STATE_LONG) && !lastDebounceTime) { 170 | buttonState = BTN_STATE_OFF; 171 | } 172 | if ((buttonState == BTN_STATE_OFF) || 173 | ((buttonState == BTN_STATE_SHORT) && lastDebounceTime)) { 174 | if (sample) { 175 | if (!lastDebounceTime && (buttonState == BTN_STATE_OFF)) { 176 | lastDebounceTime = millis(); 177 | } 178 | delta = millis() - lastDebounceTime; 179 | 180 | if (buttonState == BTN_STATE_OFF) { 181 | if (delta >= BTN_PRESS_SHORT) { 182 | buttonState = BTN_STATE_SHORT; 183 | } 184 | } 185 | else if (buttonState == BTN_STATE_SHORT) { 186 | if (delta >= BTN_PRESS_LONG) { 187 | buttonState = BTN_STATE_LONG; 188 | } 189 | } 190 | } 191 | else { //!sample 192 | lastDebounceTime = 0; 193 | } 194 | } 195 | } 196 | 197 | uint8_t Btn::shortPress() 198 | { 199 | if ((buttonState == BTN_STATE_SHORT) && !lastDebounceTime) { 200 | buttonState = BTN_STATE_OFF; 201 | return 1; 202 | } 203 | else { 204 | return 0; 205 | } 206 | } 207 | 208 | uint8_t Btn::longPress() 209 | { 210 | if ((buttonState == BTN_STATE_LONG) && lastDebounceTime) { 211 | lastDebounceTime = 0; 212 | return 1; 213 | } 214 | else { 215 | return 0; 216 | } 217 | } 218 | 219 | #ifdef WIFI_MGR 220 | #include "WiFiManager.h" // https://github.com/tzapu/WiFiManager 221 | 222 | typedef struct config_parms { 223 | int startUniverse; 224 | char artnet_universe[3]; 225 | char staticIP[16]; // optional static IP 226 | char staticGW[16]; // optional static gateway 227 | char staticNM[16]; // optional static netmask 228 | } CONFIG_PARMS; 229 | 230 | 231 | 232 | 233 | //flag for saving data 234 | 235 | class WifiConfigurator { 236 | CONFIG_PARMS configParms; 237 | // a flag for ip setup 238 | boolean set_static_ip; 239 | 240 | //network stuff 241 | //default custom static IP, changeable from the webinterface 242 | void resetConfigParms() { memset(&configParms,0,sizeof(configParms)); } 243 | public: 244 | static bool shouldSaveConfig; 245 | 246 | WifiConfigurator(); 247 | 248 | void StartManager(void); 249 | String getUniqueSystemName(); 250 | void printMac(); 251 | void readCfg(); 252 | void resetCfg(int dowifi=0); 253 | uint8_t getConfigSize() { return sizeof(configParms); } 254 | }; 255 | 256 | 257 | bool WifiConfigurator::shouldSaveConfig; // instantiate 258 | 259 | WifiConfigurator::WifiConfigurator() 260 | { 261 | resetConfigParms(); 262 | 263 | set_static_ip = false; 264 | } 265 | 266 | 267 | 268 | //creates the string that shows if the device goes into accces point mode 269 | #define WL_MAC_ADDR_LENGTH 6 270 | String WifiConfigurator::getUniqueSystemName() 271 | { 272 | uint8_t mac[WL_MAC_ADDR_LENGTH]; 273 | WiFi.softAPmacAddress(mac); 274 | 275 | 276 | String macID = String(mac[WL_MAC_ADDR_LENGTH - 2], HEX) + String(mac[WL_MAC_ADDR_LENGTH - 1], HEX); 277 | 278 | macID.toUpperCase(); 279 | String UniqueSystemName = String(AP_PREFIX) + macID; 280 | 281 | return UniqueSystemName; 282 | } 283 | 284 | 285 | 286 | 287 | 288 | // displays mac address on serial port 289 | void WifiConfigurator::printMac() 290 | { 291 | uint8_t mac[WL_MAC_ADDR_LENGTH]; 292 | WiFi.softAPmacAddress(mac); 293 | 294 | Serial.print("MAC: "); 295 | for (int i = 0; i < 5; i++){ 296 | Serial.print(mac[i], HEX); 297 | Serial.print(":"); 298 | } 299 | Serial.println(mac[5],HEX); 300 | } 301 | 302 | //callback notifying us of the need to save config 303 | void saveConfigCallback () { 304 | Serial.println("Should save config"); 305 | WifiConfigurator::shouldSaveConfig = true; 306 | } 307 | 308 | 309 | void WifiConfigurator::StartManager(void) 310 | { 311 | Serial.println("StartManager() called"); 312 | 313 | shouldSaveConfig = false; 314 | 315 | // add parameter for artnet setup in GUI 316 | WiFiManagerParameter custom_artnet_universe("artnet_universe", "Art-Net Universe (Default: 0)", configParms.artnet_universe, sizeof(configParms.artnet_universe)); 317 | 318 | // add parameters for IP setup in GUI 319 | WiFiManagerParameter custom_ip("ip", "Static IP (Blank for DHCP)", configParms.staticIP, sizeof(configParms.staticIP)); 320 | WiFiManagerParameter custom_gw("gw", "Static Gateway (Blank for DHCP)", configParms.staticGW, sizeof(configParms.staticGW)); 321 | WiFiManagerParameter custom_nm("nm", "Static Netmask (Blank for DHCP)", configParms.staticNM, sizeof(configParms.staticNM)); 322 | //WiFiManager 323 | //Local intialization. Once its business is done, there is no need to keep it around 324 | WiFiManager wifiManager; 325 | 326 | // this is what is called if the webinterface want to save data, callback is right above this function and just sets a flag. 327 | wifiManager.setSaveConfigCallback(saveConfigCallback); 328 | 329 | // this actually adds the parameters defined above to the GUI 330 | wifiManager.addParameter(&custom_artnet_universe); 331 | 332 | // if the flag is set we configure a STATIC IP! 333 | if (set_static_ip) { 334 | //set static ip 335 | IPAddress _ip, _gw, _nm; 336 | _ip.fromString(configParms.staticIP); 337 | _gw.fromString(configParms.staticGW); 338 | _nm.fromString(configParms.staticNM); 339 | 340 | // this adds 3 fields to the GUI for ip, gw and netmask, but IP needs to be defined for this fields to show up. 341 | wifiManager.setSTAStaticIPConfig(_ip, _gw, _nm); 342 | 343 | Serial.println("Setting IP to:"); 344 | Serial.print("IP: "); 345 | Serial.println(configParms.staticIP); 346 | Serial.print("GATEWAY: "); 347 | Serial.println(configParms.staticIP); 348 | Serial.print("NETMASK: "); 349 | Serial.println(configParms.staticNM); 350 | } 351 | else { 352 | // i dont want to fill these fields per default so i had to implement this workaround .. its ugly.. but hey. whatever. 353 | wifiManager.addParameter(&custom_ip); 354 | wifiManager.addParameter(&custom_gw); 355 | wifiManager.addParameter(&custom_nm); 356 | } 357 | 358 | //sets timeout until configuration portal gets turned off 359 | //useful to make it all retry or go to sleep in seconds 360 | // also really annoying if you just connected and the damn thing resets in the middle of filling in the GUI.. 361 | wifiManager.setConfigPortalTimeout(10*60); 362 | 363 | //fetches ssid and pass and tries to connect 364 | //if it does not connect it starts an access point with the specified name 365 | //here "AutoConnectAP" 366 | //and goes into a blocking loop awaiting configuration 367 | if (!wifiManager.autoConnect(getUniqueSystemName().c_str())) { 368 | Serial.println("timed out and failed to connect"); 369 | Serial.println("rebooting..."); 370 | //reset and try again, or maybe put it to deep sleep 371 | reboot(); 372 | // we never get here. 373 | } 374 | 375 | //everything below here is only executed once we are connected to a wifi. 376 | 377 | //if you get here you have connected to the WiFi 378 | 379 | digitalWrite(PIN_LED,LOW); // turn on LED 380 | Serial.print("CONNECTED to "); 381 | Serial.println(WiFi.SSID()); 382 | Serial.print("IP address: "); 383 | Serial.println(WiFi.localIP()); 384 | 385 | // this is true if we come from the GUI and clicked "save" 386 | // the flag is created in the callback above.. 387 | if (shouldSaveConfig) { 388 | // connection worked so lets save all those parameters to the config file 389 | strcpy(configParms.artnet_universe, custom_artnet_universe.getValue()); 390 | if (*configParms.artnet_universe) { 391 | startUniverse = atoi(configParms.artnet_universe); 392 | } 393 | else { 394 | startUniverse = 0; 395 | } 396 | strcpy(configParms.staticIP, custom_ip.getValue()); 397 | strcpy(configParms.staticGW, custom_gw.getValue()); 398 | strcpy(configParms.staticNM, custom_nm.getValue()); 399 | 400 | // if we defined something in the gui before that does not work we might to get rid of previous settings in the config file 401 | // so if the form is transmitted empty, delete the entries. 402 | //if (strlen(ip) < 8) { 403 | // resetConfigParms(); 404 | // } 405 | 406 | 407 | Serial.println("saving config"); 408 | 409 | int eepidx = 0; 410 | int i; 411 | EEPROM.write(eepidx++,strlen(configParms.artnet_universe)); 412 | for (i=0;i < (int)strlen(configParms.artnet_universe);i++) { 413 | EEPROM.write(eepidx++,configParms.artnet_universe[i]); 414 | } 415 | 416 | EEPROM.write(eepidx++,strlen(configParms.staticIP)); 417 | for (i=0;i < (int)strlen(configParms.staticIP);i++) { 418 | EEPROM.write(eepidx++,configParms.staticIP[i]); 419 | } 420 | 421 | EEPROM.write(eepidx++,strlen(configParms.staticGW)); 422 | for (i=0;i < (int)strlen(configParms.staticGW);i++) { 423 | EEPROM.write(eepidx++,configParms.staticGW[i]); 424 | } 425 | 426 | EEPROM.write(eepidx++,strlen(configParms.staticNM)); 427 | for (i=0;i < (int)strlen(configParms.staticNM);i++) { 428 | EEPROM.write(eepidx++,configParms.staticNM[i]); 429 | } 430 | 431 | EEPROM.commit(); 432 | 433 | Serial.print("artnet_universe: "); 434 | Serial.println(*configParms.artnet_universe ? configParms.artnet_universe : "(default)"); 435 | Serial.print("IP: "); 436 | Serial.println(*configParms.staticNM ? configParms.staticNM : "(DHCP)"); 437 | Serial.print("GW: "); 438 | Serial.println(*configParms.staticGW ? configParms.staticGW : "(DHCP)"); 439 | Serial.print("NM: "); 440 | Serial.println(*configParms.staticNM ? configParms.staticNM : "(DHCP)"); 441 | //end save 442 | } 443 | } 444 | 445 | 446 | void WifiConfigurator::resetCfg(int dowifi) 447 | { 448 | Serial.print("resetCfg()"); 449 | 450 | // reset config parameters 451 | resetConfigParms(); 452 | 453 | // clear EEPROM 454 | EEPROM.write(0,0); 455 | EEPROM.commit(); 456 | 457 | if (dowifi) { 458 | // erase WiFi settings (SSID/passphrase/etc 459 | WiFiManager wifiManager; 460 | wifiManager.resetSettings(); 461 | } 462 | } 463 | 464 | void WifiConfigurator::readCfg() 465 | { 466 | int resetit = 0; 467 | 468 | int eepidx = 0; 469 | int i; 470 | 471 | resetConfigParms(); 472 | 473 | uint8_t len = EEPROM.read(eepidx++); 474 | if ((len == 0) || (len >= sizeof(configParms.artnet_universe))) { 475 | // assume uninitialized 476 | resetit = 1; 477 | } 478 | else { 479 | for (i=0;i < len;i++) { 480 | configParms.artnet_universe[i] = EEPROM.read(eepidx++); 481 | } 482 | configParms.artnet_universe[i] = 0; 483 | 484 | len = EEPROM.read(eepidx++); 485 | if ((len > 0) && (len < sizeof(configParms.staticIP))) { 486 | for (i=0;i < len;i++) { 487 | configParms.staticIP[i] = EEPROM.read(eepidx++); 488 | } 489 | configParms.staticIP[i] = 0; 490 | } 491 | else { 492 | resetit = 1; 493 | } 494 | 495 | if (!resetit) { 496 | len = EEPROM.read(eepidx++); 497 | if ((len > 0) && (len < sizeof(configParms.staticGW))) { 498 | for (i=0;i < len;i++) { 499 | configParms.staticGW[i] = EEPROM.read(eepidx++); 500 | } 501 | configParms.staticGW[i] = 0; 502 | } 503 | else { 504 | resetit = 1; 505 | } 506 | } 507 | 508 | if (!resetit) { 509 | len = EEPROM.read(eepidx++); 510 | if ((len > 0) && (len < sizeof(configParms.staticNM))) { 511 | for (i=0;i < len;i++) { 512 | configParms.staticNM[i] = EEPROM.read(eepidx++); 513 | } 514 | configParms.staticNM[i] = 0; 515 | } 516 | else { 517 | resetit = 1; 518 | } 519 | } 520 | } 521 | 522 | if (!resetit) { // valid config 523 | startUniverse = atoi(configParms.artnet_universe); 524 | 525 | if (*configParms.staticIP) { 526 | // lets use the IP settings from the config file for network config. 527 | Serial.println("setting static ip from config"); 528 | set_static_ip = 1; 529 | } 530 | else { 531 | Serial.println("using DHCP"); 532 | } 533 | } 534 | else { 535 | resetCfg(0); 536 | } 537 | } 538 | 539 | WifiConfigurator wfCfg; 540 | #endif // WIFI_MGR 541 | WS2812Strand leds(PIN_DATA); 542 | Btn btnReset(PIN_FACTORY_RESET); 543 | 544 | 545 | ArtnetWifi artnet; 546 | // Check if we got all universes 547 | bool universesReceived[maxUniverses]; 548 | bool sendFrame = 1; 549 | int previousDataLength = 0; 550 | 551 | #ifndef WIFI_MGR 552 | // connect to wifi – returns true if successful or false if not 553 | boolean ConnectWifi(void) 554 | { 555 | boolean state = true; 556 | int i = 0; 557 | 558 | WiFi.begin(ssid, password); 559 | Serial.println(""); 560 | Serial.println("Connecting to WiFi"); 561 | 562 | // Wait for connection 563 | Serial.print("Connecting"); 564 | while (WiFi.status() != WL_CONNECTED) { 565 | delay(500); 566 | Serial.print("."); 567 | if (i > 20){ 568 | state = false; 569 | break; 570 | } 571 | i++; 572 | } 573 | if (state){ 574 | digitalWrite(0,LOW); // turn on onboard LED 575 | 576 | Serial.println(""); 577 | Serial.print("Connected to "); 578 | Serial.println(ssid); 579 | Serial.print("IP address: "); 580 | Serial.println(WiFi.localIP()); 581 | } else { 582 | Serial.println(""); 583 | Serial.println("Connection failed."); 584 | } 585 | 586 | return state; 587 | } 588 | 589 | #endif // !WIFI_MGR 590 | 591 | 592 | void reboot() 593 | { 594 | WiFi.disconnect(); 595 | delay(1000); 596 | ESP.reset(); 597 | } 598 | 599 | void initTest() 600 | { 601 | delay(100); 602 | leds.fill(&g_BlkPixel); 603 | leds.show(); 604 | delay(100); 605 | 606 | PIXEL_GRB p; 607 | p.r = 80; 608 | p.g = 0; 609 | p.b = 0; 610 | leds.fill(&p); 611 | leds.show(); 612 | delay(1000); 613 | 614 | p.r = 0; 615 | p.g = 80; 616 | p.b = 0; 617 | leds.fill(&p); 618 | leds.show(); 619 | delay(1000); 620 | 621 | p.r = 0; 622 | p.g = 0; 623 | p.b = 80; 624 | leds.fill(&p); 625 | leds.show(); 626 | delay(1000); 627 | 628 | leds.fill(&g_BlkPixel); 629 | leds.show(); 630 | } 631 | 632 | void onDmxFrame(uint16_t universe, uint16_t length, uint8_t sequence, uint8_t* data) 633 | { 634 | digitalWrite(PIN_LED,LOW); // onboard LED on 635 | 636 | sendFrame = 1; 637 | /* 638 | // set brightness of the whole strip 639 | if (universe == 15) 640 | { 641 | leds.setBrightness(data[0]); 642 | leds.show(); 643 | } 644 | */ 645 | 646 | // Store which universe has got in 647 | if ((universe - startUniverse) < maxUniverses) 648 | universesReceived[universe - startUniverse] = 1; 649 | 650 | for (int i = 0 ; i < maxUniverses ; i++) 651 | { 652 | if (universesReceived[i] == 0) 653 | { 654 | //Serial.println("Broke"); 655 | sendFrame = 0; 656 | break; 657 | } 658 | } 659 | 660 | // read universe and put into the right part of the display buffer 661 | PIXEL_GRB *p = (PIXEL_GRB *)data; 662 | for (int i = 0; i < length / 3; i++) 663 | { 664 | int led = i + (universe - startUniverse) * (previousDataLength / 3); 665 | leds.setPixel(led,p++); 666 | } 667 | previousDataLength = length; 668 | 669 | if (sendFrame) 670 | { 671 | leds.show(); 672 | // Reset universeReceived to 0 673 | memset(universesReceived, 0, maxUniverses); 674 | } 675 | 676 | digitalWrite(PIN_LED,HIGH); // onboard LED off 677 | } 678 | 679 | void factoryReset() 680 | { 681 | Serial.println("Factory Reset"); 682 | wfCfg.resetCfg(1); 683 | reboot(); 684 | } 685 | 686 | void setup() 687 | { 688 | // onboard leds also outputs 689 | pinMode(PIN_LED, OUTPUT); // onboard LED 690 | digitalWrite(PIN_LED,HIGH); // turn off onboard LED 691 | Serial.begin(115200); 692 | 693 | btnReset.init(); 694 | 695 | #ifdef WIFI_MGR 696 | EEPROM.begin(wfCfg.getConfigSize()); 697 | 698 | // display the MAC on Serial 699 | wfCfg.printMac(); 700 | 701 | wfCfg.readCfg(); 702 | Serial.println("readCfg() done."); 703 | 704 | wfCfg.StartManager(); 705 | Serial.println("StartManager() done."); 706 | #else 707 | ConnectWifi(); 708 | #endif // WIFI_MGR 709 | 710 | #ifdef OTA_UPDATE 711 | AOTAMgr.boot(OTA_HOST,OTA_PASS); 712 | #endif 713 | 714 | 715 | Serial.print("Art-Net universe: "); 716 | Serial.println(startUniverse); 717 | Serial.println("Starting Art-Net"); 718 | artnet.begin(); 719 | leds.begin(); 720 | initTest(); 721 | 722 | // this will be called for each packet received 723 | artnet.setArtDmxCallback(onDmxFrame); 724 | } 725 | 726 | void loop() 727 | { 728 | btnReset.read(); 729 | if (btnReset.longPress()) { 730 | Serial.println("long press"); 731 | factoryReset(); 732 | } 733 | 734 | 735 | // we call the read function inside the loop 736 | artnet.read(); 737 | 738 | #ifdef OTA_UPDATE 739 | AOTAMgr.handle(); 740 | #endif 741 | 742 | } 743 | -------------------------------------------------------------------------------- /WS2812ArtNet/WiFiManager.cpp: -------------------------------------------------------------------------------- 1 | /************************************************************** 2 | WiFiManager is a library for the ESP8266/Arduino platform 3 | (https://github.com/esp8266/Arduino) to enable easy 4 | configuration and reconfiguration of WiFi credentials using a Captive Portal 5 | inspired by: 6 | http://www.esp8266.com/viewtopic.php?f=29&t=2520 7 | https://github.com/chriscook8/esp-arduino-apboot 8 | https://github.com/esp8266/Arduino/tree/esp8266/hardware/esp8266com/esp8266/libraries/DNSServer/examples/CaptivePortalAdvanced 9 | Built by AlexT https://github.com/tzapu 10 | Licensed under MIT license 11 | **************************************************************/ 12 | 13 | #include "WiFiManager.h" 14 | 15 | WiFiManagerParameter::WiFiManagerParameter(const char *custom) { 16 | _id = NULL; 17 | _placeholder = NULL; 18 | _length = 0; 19 | _value = NULL; 20 | 21 | _customHTML = custom; 22 | } 23 | 24 | WiFiManagerParameter::WiFiManagerParameter(const char *id, const char *placeholder, const char *defaultValue, int length) { 25 | init(id, placeholder, defaultValue, length, ""); 26 | } 27 | 28 | WiFiManagerParameter::WiFiManagerParameter(const char *id, const char *placeholder, const char *defaultValue, int length, const char *custom) { 29 | init(id, placeholder, defaultValue, length, custom); 30 | } 31 | 32 | void WiFiManagerParameter::init(const char *id, const char *placeholder, const char *defaultValue, int length, const char *custom) { 33 | _id = id; 34 | _placeholder = placeholder; 35 | _length = length; 36 | _value = new char[length + 1]; 37 | for (int i = 0; i < length; i++) { 38 | _value[i] = 0; 39 | } 40 | if (defaultValue != NULL) { 41 | strncpy(_value, defaultValue, length); 42 | } 43 | 44 | _customHTML = custom; 45 | } 46 | 47 | const char* WiFiManagerParameter::getValue() { 48 | return _value; 49 | } 50 | const char* WiFiManagerParameter::getID() { 51 | return _id; 52 | } 53 | const char* WiFiManagerParameter::getPlaceholder() { 54 | return _placeholder; 55 | } 56 | int WiFiManagerParameter::getValueLength() { 57 | return _length; 58 | } 59 | const char* WiFiManagerParameter::getCustomHTML() { 60 | return _customHTML; 61 | } 62 | 63 | WiFiManager::WiFiManager() { 64 | } 65 | 66 | void WiFiManager::addParameter(WiFiManagerParameter *p) { 67 | _params[_paramsCount] = p; 68 | _paramsCount++; 69 | DEBUG_WM("Adding parameter"); 70 | DEBUG_WM(p->getID()); 71 | } 72 | 73 | void WiFiManager::setupConfigPortal() { 74 | dnsServer.reset(new DNSServer()); 75 | server.reset(new ESP8266WebServer(80)); 76 | 77 | DEBUG_WM(F("")); 78 | _configPortalStart = millis(); 79 | 80 | DEBUG_WM(F("Configuring access point... ")); 81 | DEBUG_WM(_apName); 82 | if (_apPassword != NULL) { 83 | if (strlen(_apPassword) < 8 || strlen(_apPassword) > 63) { 84 | // fail passphrase to short or long! 85 | DEBUG_WM(F("Invalid AccessPoint password. Ignoring")); 86 | _apPassword = NULL; 87 | } 88 | DEBUG_WM(_apPassword); 89 | } 90 | 91 | //optional soft ip config 92 | if (_ap_static_ip) { 93 | DEBUG_WM(F("Custom AP IP/GW/Subnet")); 94 | WiFi.softAPConfig(_ap_static_ip, _ap_static_gw, _ap_static_sn); 95 | } 96 | 97 | if (_apPassword != NULL) { 98 | WiFi.softAP(_apName, _apPassword);//password option 99 | } else { 100 | WiFi.softAP(_apName); 101 | } 102 | 103 | delay(500); // Without delay I've seen the IP address blank 104 | DEBUG_WM(F("AP IP address: ")); 105 | DEBUG_WM(WiFi.softAPIP()); 106 | 107 | /* Setup the DNS server redirecting all the domains to the apIP */ 108 | dnsServer->setErrorReplyCode(DNSReplyCode::NoError); 109 | dnsServer->start(DNS_PORT, "*", WiFi.softAPIP()); 110 | 111 | /* Setup web pages: root, wifi config pages, SO captive portal detectors and not found. */ 112 | server->on("/", std::bind(&WiFiManager::handleRoot, this)); 113 | server->on("/wifi", std::bind(&WiFiManager::handleWifi, this, true)); 114 | server->on("/0wifi", std::bind(&WiFiManager::handleWifi, this, false)); 115 | server->on("/wifisave", std::bind(&WiFiManager::handleWifiSave, this)); 116 | server->on("/i", std::bind(&WiFiManager::handleInfo, this)); 117 | server->on("/r", std::bind(&WiFiManager::handleReset, this)); 118 | //server->on("/generate_204", std::bind(&WiFiManager::handle204, this)); //Android/Chrome OS captive portal check. 119 | server->on("/fwlink", std::bind(&WiFiManager::handleRoot, this)); //Microsoft captive portal. Maybe not needed. Might be handled by notFound handler. 120 | server->onNotFound (std::bind(&WiFiManager::handleNotFound, this)); 121 | server->begin(); // Web server start 122 | DEBUG_WM(F("HTTP server started")); 123 | 124 | } 125 | 126 | boolean WiFiManager::autoConnect() { 127 | String ssid = "ESP" + String(ESP.getChipId()); 128 | return autoConnect(ssid.c_str(), NULL); 129 | } 130 | 131 | boolean WiFiManager::autoConnect(char const *apName, char const *apPassword) { 132 | DEBUG_WM(F("")); 133 | DEBUG_WM(F("AutoConnect")); 134 | 135 | // read eeprom for ssid and pass 136 | //String ssid = getSSID(); 137 | //String pass = getPassword(); 138 | 139 | // attempt to connect; should it fail, fall back to AP 140 | WiFi.mode(WIFI_STA); 141 | 142 | if (connectWifi("", "") == WL_CONNECTED) { 143 | DEBUG_WM(F("IP Address:")); 144 | DEBUG_WM(WiFi.localIP()); 145 | //connected 146 | return true; 147 | } 148 | 149 | return startConfigPortal(apName, apPassword); 150 | } 151 | 152 | boolean WiFiManager::startConfigPortal() { 153 | String ssid = "ESP" + String(ESP.getChipId()); 154 | return startConfigPortal(ssid.c_str(), NULL); 155 | } 156 | 157 | boolean WiFiManager::startConfigPortal(char const *apName, char const *apPassword) { 158 | //setup AP 159 | WiFi.mode(WIFI_AP_STA); 160 | DEBUG_WM("SET AP STA"); 161 | 162 | _apName = apName; 163 | _apPassword = apPassword; 164 | 165 | //notify we entered AP mode 166 | if ( _apcallback != NULL) { 167 | _apcallback(this); 168 | } 169 | 170 | connect = false; 171 | setupConfigPortal(); 172 | 173 | while (_configPortalTimeout == 0 || millis() < _configPortalStart + _configPortalTimeout) { 174 | //DNS 175 | dnsServer->processNextRequest(); 176 | //HTTP 177 | server->handleClient(); 178 | 179 | 180 | if (connect) { 181 | connect = false; 182 | delay(2000); 183 | DEBUG_WM(F("Connecting to new AP")); 184 | 185 | // using user-provided _ssid, _pass in place of system-stored ssid and pass 186 | if (connectWifi(_ssid, _pass) != WL_CONNECTED) { 187 | DEBUG_WM(F("Failed to connect.")); 188 | } else { 189 | //connected 190 | WiFi.mode(WIFI_STA); 191 | //notify that configuration has changed and any optional parameters should be saved 192 | if ( _savecallback != NULL) { 193 | //todo: check if any custom parameters actually exist, and check if they really changed maybe 194 | _savecallback(); 195 | } 196 | break; 197 | } 198 | 199 | if (_shouldBreakAfterConfig) { 200 | //flag set to exit after config after trying to connect 201 | //notify that configuration has changed and any optional parameters should be saved 202 | if ( _savecallback != NULL) { 203 | //todo: check if any custom parameters actually exist, and check if they really changed maybe 204 | _savecallback(); 205 | } 206 | break; 207 | } 208 | } 209 | yield(); 210 | } 211 | 212 | server.reset(); 213 | dnsServer.reset(); 214 | 215 | return WiFi.status() == WL_CONNECTED; 216 | } 217 | 218 | 219 | int WiFiManager::connectWifi(String ssid, String pass) { 220 | DEBUG_WM(F("Connecting as wifi client...")); 221 | 222 | // check if we've got static_ip settings, if we do, use those. 223 | if (_sta_static_ip) { 224 | DEBUG_WM(F("Custom STA IP/GW/Subnet")); 225 | WiFi.config(_sta_static_ip, _sta_static_gw, _sta_static_sn); 226 | DEBUG_WM(WiFi.localIP()); 227 | } 228 | //fix for auto connect racing issue 229 | if (WiFi.status() == WL_CONNECTED) { 230 | DEBUG_WM("Already connected. Bailing out."); 231 | return WL_CONNECTED; 232 | } 233 | //check if we have ssid and pass and force those, if not, try with last saved values 234 | if (ssid != "") { 235 | WiFi.begin(ssid.c_str(), pass.c_str()); 236 | } else { 237 | if (WiFi.SSID()) { 238 | DEBUG_WM("Using last saved values, should be faster"); 239 | //trying to fix connection in progress hanging 240 | ETS_UART_INTR_DISABLE(); 241 | wifi_station_disconnect(); 242 | ETS_UART_INTR_ENABLE(); 243 | 244 | WiFi.begin(); 245 | } else { 246 | DEBUG_WM("No saved credentials"); 247 | } 248 | } 249 | 250 | int connRes = waitForConnectResult(); 251 | DEBUG_WM ("Connection result: "); 252 | DEBUG_WM ( connRes ); 253 | //not connected, WPS enabled, no pass - first attempt 254 | if (_tryWPS && connRes != WL_CONNECTED && pass == "") { 255 | startWPS(); 256 | //should be connected at the end of WPS 257 | connRes = waitForConnectResult(); 258 | } 259 | return connRes; 260 | } 261 | 262 | uint8_t WiFiManager::waitForConnectResult() { 263 | if (_connectTimeout == 0) { 264 | return WiFi.waitForConnectResult(); 265 | } else { 266 | DEBUG_WM (F("Waiting for connection result with time out")); 267 | unsigned long start = millis(); 268 | boolean keepConnecting = true; 269 | uint8_t status; 270 | while (keepConnecting) { 271 | status = WiFi.status(); 272 | if (millis() > start + _connectTimeout) { 273 | keepConnecting = false; 274 | DEBUG_WM (F("Connection timed out")); 275 | } 276 | if (status == WL_CONNECTED || status == WL_CONNECT_FAILED) { 277 | keepConnecting = false; 278 | } 279 | delay(100); 280 | } 281 | return status; 282 | } 283 | } 284 | 285 | void WiFiManager::startWPS() { 286 | DEBUG_WM("START WPS"); 287 | WiFi.beginWPSConfig(); 288 | DEBUG_WM("END WPS"); 289 | } 290 | /* 291 | String WiFiManager::getSSID() { 292 | if (_ssid == "") { 293 | DEBUG_WM(F("Reading SSID")); 294 | _ssid = WiFi.SSID(); 295 | DEBUG_WM(F("SSID: ")); 296 | DEBUG_WM(_ssid); 297 | } 298 | return _ssid; 299 | } 300 | 301 | String WiFiManager::getPassword() { 302 | if (_pass == "") { 303 | DEBUG_WM(F("Reading Password")); 304 | _pass = WiFi.psk(); 305 | DEBUG_WM("Password: " + _pass); 306 | //DEBUG_WM(_pass); 307 | } 308 | return _pass; 309 | } 310 | */ 311 | String WiFiManager::getConfigPortalSSID() { 312 | return _apName; 313 | } 314 | 315 | void WiFiManager::resetSettings() { 316 | DEBUG_WM(F("wifi settings invalidated")); 317 | // DEBUG_WM(F("THIS MAY CAUSE AP NOT TO START UP PROPERLY. YOU NEED TO COMMENT IT OUT AFTER ERASING THE DATA.")); 318 | WiFi.disconnect(true); 319 | //delay(200); 320 | } 321 | 322 | void WiFiManager::setConfigPortalTimeout(unsigned long seconds) { 323 | _configPortalTimeout = seconds * 1000; 324 | } 325 | 326 | void WiFiManager::setConnectTimeout(unsigned long seconds) { 327 | _connectTimeout = seconds * 1000; 328 | } 329 | 330 | void WiFiManager::setDebugOutput(boolean debug) { 331 | _debug = debug; 332 | } 333 | 334 | void WiFiManager::setAPStaticIPConfig(IPAddress ip, IPAddress gw, IPAddress sn) { 335 | _ap_static_ip = ip; 336 | _ap_static_gw = gw; 337 | _ap_static_sn = sn; 338 | } 339 | 340 | void WiFiManager::setSTAStaticIPConfig(IPAddress ip, IPAddress gw, IPAddress sn) { 341 | _sta_static_ip = ip; 342 | _sta_static_gw = gw; 343 | _sta_static_sn = sn; 344 | } 345 | 346 | void WiFiManager::setMinimumSignalQuality(int quality) { 347 | _minimumQuality = quality; 348 | } 349 | 350 | void WiFiManager::setBreakAfterConfig(boolean shouldBreak) { 351 | _shouldBreakAfterConfig = shouldBreak; 352 | } 353 | 354 | /** Handle root or redirect to captive portal */ 355 | void WiFiManager::handleRoot() { 356 | DEBUG_WM(F("Handle root")); 357 | if (captivePortal()) { // If caprive portal redirect instead of displaying the page. 358 | return; 359 | } 360 | 361 | String page = FPSTR(HTTP_HEAD); 362 | page.replace("{v}", "Options"); 363 | page += FPSTR(HTTP_SCRIPT); 364 | page += FPSTR(HTTP_STYLE); 365 | page += _customHeadElement; 366 | page += FPSTR(HTTP_HEAD_END); 367 | page += "

"; 368 | page += _apName; 369 | page += "

"; 370 | page += F("

WiFiManager

"); 371 | page += FPSTR(HTTP_PORTAL_OPTIONS); 372 | page += FPSTR(HTTP_END); 373 | 374 | server->send(200, "text/html", page); 375 | 376 | } 377 | 378 | /** Wifi config page handler */ 379 | void WiFiManager::handleWifi(boolean scan) { 380 | 381 | String page = FPSTR(HTTP_HEAD); 382 | page.replace("{v}", "Config ESP"); 383 | page += FPSTR(HTTP_SCRIPT); 384 | page += FPSTR(HTTP_STYLE); 385 | page += _customHeadElement; 386 | page += FPSTR(HTTP_HEAD_END); 387 | 388 | if (scan) { 389 | int n = WiFi.scanNetworks(); 390 | DEBUG_WM(F("Scan done")); 391 | if (n == 0) { 392 | DEBUG_WM(F("No networks found")); 393 | page += F("No networks found. Refresh to scan again."); 394 | } else { 395 | 396 | //sort networks 397 | int indices[n]; 398 | for (int i = 0; i < n; i++) { 399 | indices[i] = i; 400 | } 401 | 402 | // RSSI SORT 403 | 404 | // old sort 405 | for (int i = 0; i < n; i++) { 406 | for (int j = i + 1; j < n; j++) { 407 | if (WiFi.RSSI(indices[j]) > WiFi.RSSI(indices[i])) { 408 | std::swap(indices[i], indices[j]); 409 | } 410 | } 411 | } 412 | 413 | /*std::sort(indices, indices + n, [](const int & a, const int & b) -> bool 414 | { 415 | return WiFi.RSSI(a) > WiFi.RSSI(b); 416 | });*/ 417 | 418 | // remove duplicates ( must be RSSI sorted ) 419 | if (_removeDuplicateAPs) { 420 | String cssid; 421 | for (int i = 0; i < n; i++) { 422 | if (indices[i] == -1) continue; 423 | cssid = WiFi.SSID(indices[i]); 424 | for (int j = i + 1; j < n; j++) { 425 | if (cssid == WiFi.SSID(indices[j])) { 426 | DEBUG_WM("DUP AP: " + WiFi.SSID(indices[j])); 427 | indices[j] = -1; // set dup aps to index -1 428 | } 429 | } 430 | } 431 | } 432 | 433 | //display networks in page 434 | for (int i = 0; i < n; i++) { 435 | if (indices[i] == -1) continue; // skip dups 436 | DEBUG_WM(WiFi.SSID(indices[i])); 437 | DEBUG_WM(WiFi.RSSI(indices[i])); 438 | int quality = getRSSIasQuality(WiFi.RSSI(indices[i])); 439 | 440 | if (_minimumQuality == -1 || _minimumQuality < quality) { 441 | String item = FPSTR(HTTP_ITEM); 442 | String rssiQ; 443 | rssiQ += quality; 444 | item.replace("{v}", WiFi.SSID(indices[i])); 445 | item.replace("{r}", rssiQ); 446 | if (WiFi.encryptionType(indices[i]) != ENC_TYPE_NONE) { 447 | item.replace("{i}", "l"); 448 | } else { 449 | item.replace("{i}", ""); 450 | } 451 | //DEBUG_WM(item); 452 | page += item; 453 | delay(0); 454 | } else { 455 | DEBUG_WM(F("Skipping due to quality")); 456 | } 457 | 458 | } 459 | page += "
"; 460 | } 461 | } 462 | 463 | page += FPSTR(HTTP_FORM_START); 464 | char parLength[2]; 465 | // add the extra parameters to the form 466 | for (int i = 0; i < _paramsCount; i++) { 467 | if (_params[i] == NULL) { 468 | break; 469 | } 470 | 471 | String pitem = FPSTR(HTTP_FORM_PARAM); 472 | if (_params[i]->getID() != NULL) { 473 | pitem.replace("{i}", _params[i]->getID()); 474 | pitem.replace("{n}", _params[i]->getID()); 475 | pitem.replace("{p}", _params[i]->getPlaceholder()); 476 | snprintf(parLength, 2, "%d", _params[i]->getValueLength()); 477 | pitem.replace("{l}", parLength); 478 | pitem.replace("{v}", _params[i]->getValue()); 479 | pitem.replace("{c}", _params[i]->getCustomHTML()); 480 | } else { 481 | pitem = _params[i]->getCustomHTML(); 482 | } 483 | 484 | page += pitem; 485 | } 486 | if (_params[0] != NULL) { 487 | page += "
"; 488 | } 489 | 490 | if (_sta_static_ip) { 491 | 492 | String item = FPSTR(HTTP_FORM_PARAM); 493 | item.replace("{i}", "ip"); 494 | item.replace("{n}", "ip"); 495 | item.replace("{p}", "Static IP"); 496 | item.replace("{l}", "15"); 497 | item.replace("{v}", _sta_static_ip.toString()); 498 | 499 | page += item; 500 | 501 | item = FPSTR(HTTP_FORM_PARAM); 502 | item.replace("{i}", "gw"); 503 | item.replace("{n}", "gw"); 504 | item.replace("{p}", "Static Gateway"); 505 | item.replace("{l}", "15"); 506 | item.replace("{v}", _sta_static_gw.toString()); 507 | 508 | page += item; 509 | 510 | item = FPSTR(HTTP_FORM_PARAM); 511 | item.replace("{i}", "sn"); 512 | item.replace("{n}", "sn"); 513 | item.replace("{p}", "Subnet"); 514 | item.replace("{l}", "15"); 515 | item.replace("{v}", _sta_static_sn.toString()); 516 | 517 | page += item; 518 | 519 | page += "
"; 520 | } 521 | 522 | page += FPSTR(HTTP_FORM_END); 523 | page += FPSTR(HTTP_SCAN_LINK); 524 | 525 | page += FPSTR(HTTP_END); 526 | 527 | server->send(200, "text/html", page); 528 | 529 | 530 | DEBUG_WM(F("Sent config page")); 531 | } 532 | 533 | /** Handle the WLAN save form and redirect to WLAN config page again */ 534 | void WiFiManager::handleWifiSave() { 535 | DEBUG_WM(F("WiFi save")); 536 | 537 | //SAVE/connect here 538 | _ssid = server->arg("s").c_str(); 539 | _pass = server->arg("p").c_str(); 540 | 541 | //parameters 542 | for (int i = 0; i < _paramsCount; i++) { 543 | if (_params[i] == NULL) { 544 | break; 545 | } 546 | //read parameter 547 | String value = server->arg(_params[i]->getID()).c_str(); 548 | //store it in array 549 | value.toCharArray(_params[i]->_value, _params[i]->_length); 550 | DEBUG_WM(F("Parameter")); 551 | DEBUG_WM(_params[i]->getID()); 552 | DEBUG_WM(value); 553 | } 554 | 555 | if (server->arg("ip") != "") { 556 | DEBUG_WM(F("static ip")); 557 | DEBUG_WM(server->arg("ip")); 558 | //_sta_static_ip.fromString(server->arg("ip")); 559 | String ip = server->arg("ip"); 560 | optionalIPFromString(&_sta_static_ip, ip.c_str()); 561 | } 562 | if (server->arg("gw") != "") { 563 | DEBUG_WM(F("static gateway")); 564 | DEBUG_WM(server->arg("gw")); 565 | String gw = server->arg("gw"); 566 | optionalIPFromString(&_sta_static_gw, gw.c_str()); 567 | } 568 | if (server->arg("sn") != "") { 569 | DEBUG_WM(F("static netmask")); 570 | DEBUG_WM(server->arg("sn")); 571 | String sn = server->arg("sn"); 572 | optionalIPFromString(&_sta_static_sn, sn.c_str()); 573 | } 574 | 575 | String page = FPSTR(HTTP_HEAD); 576 | page.replace("{v}", "Credentials Saved"); 577 | page += FPSTR(HTTP_SCRIPT); 578 | page += FPSTR(HTTP_STYLE); 579 | page += _customHeadElement; 580 | page += FPSTR(HTTP_HEAD_END); 581 | page += FPSTR(HTTP_SAVED); 582 | page += FPSTR(HTTP_END); 583 | 584 | server->send(200, "text/html", page); 585 | 586 | DEBUG_WM(F("Sent wifi save page")); 587 | 588 | connect = true; //signal ready to connect/reset 589 | } 590 | 591 | /** Handle the info page */ 592 | void WiFiManager::handleInfo() { 593 | DEBUG_WM(F("Info")); 594 | 595 | String page = FPSTR(HTTP_HEAD); 596 | page.replace("{v}", "Info"); 597 | page += FPSTR(HTTP_SCRIPT); 598 | page += FPSTR(HTTP_STYLE); 599 | page += _customHeadElement; 600 | page += FPSTR(HTTP_HEAD_END); 601 | page += F("
"); 602 | page += F("
Chip ID
"); 603 | page += ESP.getChipId(); 604 | page += F("
"); 605 | page += F("
Flash Chip ID
"); 606 | page += ESP.getFlashChipId(); 607 | page += F("
"); 608 | page += F("
IDE Flash Size
"); 609 | page += ESP.getFlashChipSize(); 610 | page += F(" bytes
"); 611 | page += F("
Real Flash Size
"); 612 | page += ESP.getFlashChipRealSize(); 613 | page += F(" bytes
"); 614 | page += F("
Soft AP IP
"); 615 | page += WiFi.softAPIP().toString(); 616 | page += F("
"); 617 | page += F("
Soft AP MAC
"); 618 | page += WiFi.softAPmacAddress(); 619 | page += F("
"); 620 | page += F("
Station MAC
"); 621 | page += WiFi.macAddress(); 622 | page += F("
"); 623 | page += F("
"); 624 | page += FPSTR(HTTP_END); 625 | 626 | server->send(200, "text/html", page); 627 | 628 | DEBUG_WM(F("Sent info page")); 629 | } 630 | 631 | /** Handle the reset page */ 632 | void WiFiManager::handleReset() { 633 | DEBUG_WM(F("Reset")); 634 | 635 | String page = FPSTR(HTTP_HEAD); 636 | page.replace("{v}", "Info"); 637 | page += FPSTR(HTTP_SCRIPT); 638 | page += FPSTR(HTTP_STYLE); 639 | page += _customHeadElement; 640 | page += FPSTR(HTTP_HEAD_END); 641 | page += F("Module will reset in a few seconds."); 642 | page += FPSTR(HTTP_END); 643 | server->send(200, "text/html", page); 644 | 645 | DEBUG_WM(F("Sent reset page")); 646 | delay(5000); 647 | ESP.reset(); 648 | delay(2000); 649 | } 650 | 651 | 652 | 653 | //removed as mentioned here https://github.com/tzapu/WiFiManager/issues/114 654 | /*void WiFiManager::handle204() { 655 | DEBUG_WM(F("204 No Response")); 656 | server->sendHeader("Cache-Control", "no-cache, no-store, must-revalidate"); 657 | server->sendHeader("Pragma", "no-cache"); 658 | server->sendHeader("Expires", "-1"); 659 | server->send ( 204, "text/plain", ""); 660 | }*/ 661 | 662 | void WiFiManager::handleNotFound() { 663 | if (captivePortal()) { // If captive portal redirect instead of displaying the error page. 664 | return; 665 | } 666 | String message = "File Not Found\n\n"; 667 | message += "URI: "; 668 | message += server->uri(); 669 | message += "\nMethod: "; 670 | message += ( server->method() == HTTP_GET ) ? "GET" : "POST"; 671 | message += "\nArguments: "; 672 | message += server->args(); 673 | message += "\n"; 674 | 675 | for ( uint8_t i = 0; i < server->args(); i++ ) { 676 | message += " " + server->argName ( i ) + ": " + server->arg ( i ) + "\n"; 677 | } 678 | server->sendHeader("Cache-Control", "no-cache, no-store, must-revalidate"); 679 | server->sendHeader("Pragma", "no-cache"); 680 | server->sendHeader("Expires", "-1"); 681 | server->send ( 404, "text/plain", message ); 682 | } 683 | 684 | 685 | /** Redirect to captive portal if we got a request for another domain. Return true in that case so the page handler do not try to handle the request again. */ 686 | boolean WiFiManager::captivePortal() { 687 | if (!isIp(server->hostHeader()) ) { 688 | DEBUG_WM(F("Request redirected to captive portal")); 689 | server->sendHeader("Location", String("http://") + toStringIp(server->client().localIP()), true); 690 | server->send ( 302, "text/plain", ""); // Empty content inhibits Content-length header so we have to close the socket ourselves. 691 | server->client().stop(); // Stop is needed because we sent no content length 692 | return true; 693 | } 694 | return false; 695 | } 696 | 697 | //start up config portal callback 698 | void WiFiManager::setAPCallback( void (*func)(WiFiManager* myWiFiManager) ) { 699 | _apcallback = func; 700 | } 701 | 702 | //start up save config callback 703 | void WiFiManager::setSaveConfigCallback( void (*func)(void) ) { 704 | _savecallback = func; 705 | } 706 | 707 | //sets a custom element to add to head, like a new style tag 708 | void WiFiManager::setCustomHeadElement(const char* element) { 709 | _customHeadElement = element; 710 | } 711 | 712 | //if this is true, remove duplicated Access Points - defaut true 713 | void WiFiManager::setRemoveDuplicateAPs(boolean removeDuplicates) { 714 | _removeDuplicateAPs = removeDuplicates; 715 | } 716 | 717 | 718 | 719 | template 720 | void WiFiManager::DEBUG_WM(Generic text) { 721 | if (_debug) { 722 | Serial.print("*WM: "); 723 | Serial.println(text); 724 | } 725 | } 726 | 727 | int WiFiManager::getRSSIasQuality(int RSSI) { 728 | int quality = 0; 729 | 730 | if (RSSI <= -100) { 731 | quality = 0; 732 | } else if (RSSI >= -50) { 733 | quality = 100; 734 | } else { 735 | quality = 2 * (RSSI + 100); 736 | } 737 | return quality; 738 | } 739 | 740 | /** Is this an IP? */ 741 | boolean WiFiManager::isIp(String str) { 742 | for (int i = 0; i < str.length(); i++) { 743 | int c = str.charAt(i); 744 | if (c != '.' && (c < '0' || c > '9')) { 745 | return false; 746 | } 747 | } 748 | return true; 749 | } 750 | 751 | /** IP to String? */ 752 | String WiFiManager::toStringIp(IPAddress ip) { 753 | String res = ""; 754 | for (int i = 0; i < 3; i++) { 755 | res += String((ip >> (8 * i)) & 0xFF) + "."; 756 | } 757 | res += String(((ip >> 8 * 3)) & 0xFF); 758 | return res; 759 | } 760 | -------------------------------------------------------------------------------- /WS2812Remote/pkt_test/serialib.cpp: -------------------------------------------------------------------------------- 1 | /*! 2 | \file serialib.cpp 3 | \brief Class to manage the serial port 4 | \author Philippe Lucidarme (University of Angers) 5 | \version 1.2 6 | \date 28 avril 2011 7 | 8 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 9 | INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR 10 | PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM, 11 | DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 12 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 13 | 14 | 15 | This is a licence-free software, it can be used by anyone who try to build a better world. 16 | */ 17 | #define _CRT_SECURE_NO_WARNINGS 18 | 19 | #include "serialib.h" 20 | 21 | 22 | #if defined (_WIN32) || defined( _WIN64) 23 | #if defined(_MSC_VER) || defined(_MSC_EXTENSIONS) 24 | #define DELTA_EPOCH_IN_MICROSECS 11644473600000000Ui64 25 | #else 26 | #define DELTA_EPOCH_IN_MICROSECS 11644473600000000ULL 27 | #endif 28 | 29 | struct timezone 30 | { 31 | int tz_minuteswest; /* minutes W of Greenwich */ 32 | int tz_dsttime; /* type of dst correction */ 33 | }; 34 | 35 | int gettimeofday(struct timeval *tv, struct timezone *tz) 36 | { 37 | FILETIME ft; 38 | unsigned __int64 tmpres = 0; 39 | static int tzflag; 40 | 41 | if (NULL != tv) 42 | { 43 | GetSystemTimeAsFileTime(&ft); 44 | 45 | tmpres |= ft.dwHighDateTime; 46 | tmpres <<= 32; 47 | tmpres |= ft.dwLowDateTime; 48 | 49 | /*converting file time to unix epoch*/ 50 | tmpres -= DELTA_EPOCH_IN_MICROSECS; 51 | tmpres /= 10; /*convert into microseconds*/ 52 | tv->tv_sec = (long)(tmpres / 1000000UL); 53 | tv->tv_usec = (long)(tmpres % 1000000UL); 54 | } 55 | 56 | if (NULL != tz) 57 | { 58 | if (!tzflag) 59 | { 60 | _tzset(); 61 | tzflag++; 62 | } 63 | tz->tz_minuteswest = _timezone / 60; 64 | tz->tz_dsttime = _daylight; 65 | } 66 | 67 | return 0; 68 | } 69 | #endif // defined (_WIN32) || defined( _WIN64) 70 | 71 | /*! 72 | \brief Constructor of the class serialib. 73 | */ 74 | // Class constructor 75 | serialib::serialib() 76 | { 77 | #if defined (_WIN32) || defined( _WIN64) 78 | hSerial = INVALID_HANDLE_VALUE; 79 | #else 80 | fd = 0; 81 | #endif 82 | } 83 | 84 | 85 | /*! 86 | \brief Destructor of the class serialib. It close the connection 87 | */ 88 | // Class desctructor 89 | serialib::~serialib() 90 | { 91 | Close(); 92 | } 93 | 94 | 95 | 96 | //_________________________________________ 97 | // ::: Configuration and initialization ::: 98 | 99 | 100 | 101 | /*! 102 | \brief Open the serial port 103 | \param Device : Port name (COM1, COM2, ... for Windows ) or (/dev/ttyS0, /dev/ttyACM0, /dev/ttyUSB0 ... for linux) 104 | \param Bauds : Baud rate of the serial port. 105 | 106 | \n Supported baud rate for Windows : 107 | - 110 108 | - 300 109 | - 600 110 | - 1200 111 | - 2400 112 | - 4800 113 | - 9600 114 | - 14400 115 | - 19200 116 | - 38400 117 | - 56000 118 | - 57600 119 | - 115200 120 | - 128000 121 | - 256000 122 | 123 | \n Supported baud rate for Linux :\n 124 | - 110 125 | - 300 126 | - 600 127 | - 1200 128 | - 2400 129 | - 4800 130 | - 9600 131 | - 19200 132 | - 38400 133 | - 57600 134 | - 115200 135 | 136 | \return 1 success 137 | \return -1 device not found 138 | \return -2 error while opening the device 139 | \return -3 error while getting port parameters 140 | \return -4 Speed (Bauds) not recognized 141 | \return -5 error while writing port parameters 142 | \return -6 error while writing timeout parameters 143 | */ 144 | char serialib::Open(const char *Device,const unsigned int Bauds) 145 | { 146 | #if defined (_WIN32) || defined( _WIN64) 147 | 148 | // Open serial port 149 | hSerial = CreateFileA( Device,GENERIC_READ | GENERIC_WRITE,0,0,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0); 150 | if(hSerial==INVALID_HANDLE_VALUE) { 151 | if(GetLastError()==ERROR_FILE_NOT_FOUND) 152 | return -1; // Device not found 153 | return -2; // Error while opening the device 154 | } 155 | 156 | SetupComm(hSerial,50,50); 157 | 158 | // Set parameters 159 | DCB dcbSerialParams = {0}; // Structure for the port parameters 160 | dcbSerialParams.DCBlength=sizeof(dcbSerialParams); 161 | if (!GetCommState(hSerial, &dcbSerialParams)) // Get the port parameters 162 | return -3; // Error while getting port parameters 163 | 164 | dcbSerialParams.fBinary = TRUE; 165 | dcbSerialParams.fDtrControl = DTR_CONTROL_DISABLE; 166 | dcbSerialParams.fDsrSensitivity = FALSE; 167 | dcbSerialParams.fTXContinueOnXoff = FALSE; 168 | dcbSerialParams.fOutX = FALSE; 169 | dcbSerialParams.fInX = FALSE; 170 | dcbSerialParams.fErrorChar = FALSE; 171 | dcbSerialParams.fNull = FALSE; 172 | dcbSerialParams.fRtsControl = RTS_CONTROL_DISABLE; 173 | dcbSerialParams.fAbortOnError = FALSE; 174 | dcbSerialParams.fOutxCtsFlow = FALSE; 175 | dcbSerialParams.fOutxDsrFlow = FALSE; 176 | 177 | switch (Bauds) // Set the speed (Bauds) 178 | { 179 | case 110 : dcbSerialParams.BaudRate=CBR_110; break; 180 | case 300 : dcbSerialParams.BaudRate=CBR_300; break; 181 | case 600 : dcbSerialParams.BaudRate=CBR_600; break; 182 | case 1200 : dcbSerialParams.BaudRate=CBR_1200; break; 183 | case 2400 : dcbSerialParams.BaudRate=CBR_2400; break; 184 | case 4800 : dcbSerialParams.BaudRate=CBR_4800; break; 185 | case 9600 : dcbSerialParams.BaudRate=CBR_9600; break; 186 | case 14400 : dcbSerialParams.BaudRate=CBR_14400; break; 187 | case 19200 : dcbSerialParams.BaudRate=CBR_19200; break; 188 | case 38400 : dcbSerialParams.BaudRate=CBR_38400; break; 189 | case 56000 : dcbSerialParams.BaudRate=CBR_56000; break; 190 | case 57600 : dcbSerialParams.BaudRate=CBR_57600; break; 191 | case 115200 : 192 | dcbSerialParams.BaudRate=CBR_115200; break; 193 | case 128000 : dcbSerialParams.BaudRate=CBR_128000; break; 194 | case 256000 : dcbSerialParams.BaudRate=CBR_256000; break; 195 | default : dcbSerialParams.BaudRate = Bauds; //return -4; 196 | } 197 | 198 | dcbSerialParams.ByteSize=8; // 8 bit data 199 | dcbSerialParams.StopBits=ONESTOPBIT; // One stop bit 200 | dcbSerialParams.Parity=NOPARITY; // No parity 201 | if(!SetCommState(hSerial, &dcbSerialParams)) // Write the parameters 202 | return -5; // Error while writing 203 | 204 | // Set TimeOut 205 | timeouts.ReadIntervalTimeout=0; // Set the Timeout parameters 206 | timeouts.ReadTotalTimeoutConstant=MAXDWORD; // No TimeOut 207 | timeouts.ReadTotalTimeoutMultiplier=0; 208 | timeouts.WriteTotalTimeoutConstant=MAXDWORD; 209 | timeouts.WriteTotalTimeoutMultiplier=0; 210 | if(!SetCommTimeouts(hSerial, &timeouts)) // Write the parameters 211 | return -6; // Error while writting the parameters 212 | Sleep(250); 213 | return 1; // Opening successfull 214 | 215 | #endif 216 | #ifdef __linux__ 217 | struct termios options; // Structure with the device's options 218 | 219 | 220 | // Open device 221 | fd = open(Device, O_RDWR | O_NOCTTY | O_NDELAY); // Open port 222 | if (fd == -1) return -2; // If the device is not open, return -1 223 | fcntl(fd, F_SETFL, FNDELAY); // Open the device in nonblocking mode 224 | 225 | // Set parameters 226 | tcgetattr(fd, &options); // Get the current options of the port 227 | bzero(&options, sizeof(options)); // Clear all the options 228 | speed_t Speed; 229 | switch (Bauds) // Set the speed (Bauds) 230 | { 231 | case 110 : Speed=B110; break; 232 | case 300 : Speed=B300; break; 233 | case 600 : Speed=B600; break; 234 | case 1200 : Speed=B1200; break; 235 | case 2400 : Speed=B2400; break; 236 | case 4800 : Speed=B4800; break; 237 | case 9600 : Speed=B9600; break; 238 | case 19200 : Speed=B19200; break; 239 | case 38400 : Speed=B38400; break; 240 | case 57600 : Speed=B57600; break; 241 | case 115200 : Speed=B115200; break; 242 | default : return -4; 243 | } 244 | cfsetispeed(&options, Speed); // Set the baud rate at 115200 bauds 245 | cfsetospeed(&options, Speed); 246 | options.c_cflag |= ( CLOCAL | CREAD | CS8); // Configure the device : 8 bits, no parity, no control 247 | options.c_iflag |= ( IGNPAR | IGNBRK ); 248 | options.c_cc[VTIME]=0; // Timer unused 249 | options.c_cc[VMIN]=0; // At least on character before satisfy reading 250 | tcsetattr(fd, TCSANOW, &options); // Activate the settings 251 | return (1); // Success 252 | #endif 253 | } 254 | 255 | 256 | /*! 257 | \brief Close the connection with the current device 258 | */ 259 | void serialib::Close() 260 | { 261 | #if defined (_WIN32) || defined( _WIN64) 262 | if (hSerial != INVALID_HANDLE_VALUE) { 263 | CloseHandle(hSerial); 264 | hSerial = INVALID_HANDLE_VALUE; 265 | } 266 | #endif 267 | #ifdef __linux__ 268 | if (fd) { 269 | close (fd); 270 | fd = 0; 271 | } 272 | #endif 273 | } 274 | 275 | 276 | 277 | 278 | //___________________________________________ 279 | // ::: Read/Write operation on characters ::: 280 | 281 | 282 | 283 | /*! 284 | \brief Write a char on the current serial port 285 | \param Byte : char to send on the port (must be terminated by '\0') 286 | \return 1 success 287 | \return -1 error while writting data 288 | */ 289 | char serialib::WriteChar(const char Byte) 290 | { 291 | #if defined (_WIN32) || defined( _WIN64) 292 | DWORD dwBytesWritten; // Number of bytes written 293 | if(!WriteFile(hSerial,&Byte,1,&dwBytesWritten,NULL)) // Write the char 294 | return -1; // Error while writing 295 | return 1; // Write operation successfull 296 | #endif 297 | #ifdef __linux__ 298 | if (write(fd,&Byte,1)!=1) // Write the char 299 | return -1; // Error while writting 300 | return 1; // Write operation successfull 301 | #endif 302 | } 303 | 304 | 305 | 306 | //________________________________________ 307 | // ::: Read/Write operation on strings ::: 308 | 309 | 310 | /*! 311 | \brief Write a string on the current serial port 312 | \param String : string to send on the port (must be terminated by '\0') 313 | \return 1 success 314 | \return -1 error while writting data 315 | */ 316 | char serialib::WriteString(const char *String) 317 | { 318 | #if defined (_WIN32) || defined( _WIN64) 319 | DWORD dwBytesWritten; // Number of bytes written 320 | if(!WriteFile(hSerial,String,strlen(String),&dwBytesWritten,NULL)) // Write the string 321 | return -1; // Error while writing 322 | FlushFileBuffers(hSerial); 323 | return 1; // Write operation successfull 324 | #endif 325 | #ifdef __linux__ 326 | int Lenght=strlen(String); // Lenght of the string 327 | if (write(fd,String,Lenght)!=Lenght) // Write the string 328 | return -1; // error while writing 329 | return 1; // Write operation successfull 330 | #endif 331 | } 332 | 333 | // _____________________________________ 334 | // ::: Read/Write operation on bytes ::: 335 | 336 | 337 | 338 | /*! 339 | \brief Write an array of data on the current serial port 340 | \param Buffer : array of bytes to send on the port 341 | \param NbBytes : number of byte to send 342 | \return 1 success 343 | \return -1 error while writting data 344 | */ 345 | char serialib::Write(const void *Buffer, const unsigned int NbBytes) 346 | { 347 | #if defined (_WIN32) || defined( _WIN64) 348 | DWORD dwBytesWritten; // Number of byte written 349 | if(!WriteFile(hSerial, Buffer, NbBytes, &dwBytesWritten, NULL)) // Write data 350 | return -1; // Error while writing 351 | return 1; // Write operation successfull 352 | #endif 353 | #ifdef __linux__ 354 | if (write (fd,Buffer,NbBytes)!=(ssize_t)NbBytes) // Write data 355 | return -1; // Error while writing 356 | return 1; // Write operation successfull 357 | #endif 358 | } 359 | 360 | 361 | 362 | /*! 363 | \brief Wait for a byte from the serial device and return the data read 364 | \param pByte : data read on the serial device 365 | \param TimeOut_ms : delay of timeout before giving up the reading 366 | If set to zero, timeout is disable (Optional) 367 | \return 1 success 368 | \return 0 Timeout reached 369 | \return -1 error while setting the Timeout 370 | \return -2 error while reading the byte 371 | */ 372 | char serialib::ReadChar(char *pByte,unsigned int TimeOut_ms) 373 | { 374 | #if defined (_WIN32) || defined(_WIN64) 375 | 376 | DWORD dwBytesRead = 0; 377 | timeouts.ReadTotalTimeoutConstant=TimeOut_ms; // Set the TimeOut 378 | if(!SetCommTimeouts(hSerial, &timeouts)) // Write the parameters 379 | return -1; // Error while writting the parameters 380 | if(!ReadFile(hSerial,pByte, 1, &dwBytesRead, NULL)) // Read the byte 381 | return -2; // Error while reading the byte 382 | if (dwBytesRead==0) return 0; // Return 1 if the timeout is reached 383 | return 1; // Success 384 | #endif 385 | #ifdef __linux__ 386 | TimeOut Timer; // Timer used for timeout 387 | Timer.InitTimer(); // Initialise the timer 388 | while (Timer.ElapsedTime_ms()0 success, return the number of bytes read 407 | \return -1 error while setting the Timeout 408 | \return -2 error while reading the byte 409 | \return -3 MaxNbBytes is reached 410 | */ 411 | int serialib::ReadStringNoTimeOut(char *String,char FinalChar,unsigned int MaxNbBytes) 412 | { 413 | unsigned int NbBytes=0; // Number of bytes read 414 | char ret; // Returned value from Read 415 | while (NbBytes0 success, return the number of bytes read 439 | \return 0 timeout is reached 440 | \return -1 error while setting the Timeout 441 | \return -2 error while reading the byte 442 | \return -3 MaxNbBytes is reached 443 | */ 444 | int serialib::ReadString(char *String,char FinalChar,unsigned int MaxNbBytes,unsigned int TimeOut_ms) 445 | { 446 | if (TimeOut_ms==0) 447 | return ReadStringNoTimeOut(String,FinalChar,MaxNbBytes); 448 | 449 | unsigned int NbBytes=0; // Number of bytes read 450 | char ret; // Returned value from Read 451 | TimeOut Timer; // Timer used for timeout 452 | long int TimeOutParam; 453 | Timer.InitTimer(); // Initialize the timer 454 | 455 | while (NbBytes0) // If the parameter is higher than zero 459 | { 460 | ret=ReadChar(&String[NbBytes],TimeOutParam); // Wait for a byte on the serial link 461 | if (ret==1) // If a byte has been read 462 | { 463 | 464 | if (String[NbBytes]==FinalChar) // Check if it is the final char 465 | { 466 | String [++NbBytes]=0; // Yes : add the end character 0 467 | return NbBytes; // Return the number of bytes read 468 | } 469 | NbBytes++; // If not, just increase the number of bytes read 470 | } 471 | if (ret<0) return ret; // Error while reading : return the error number 472 | } 473 | if (Timer.ElapsedTime_ms()>TimeOut_ms) { // Timeout is reached 474 | String[NbBytes]=0; // Add the end caracter 475 | return 0; // Return 0 476 | } 477 | } 478 | return -3; // Buffer is full : return -3 479 | } 480 | 481 | 482 | /*! 483 | \brief Read an array of bytes from the serial device (with timeout) 484 | \param Buffer : array of bytes read from the serial device 485 | \param MaxNbBytes : maximum allowed number of bytes read 486 | \param TimeOut_ms : delay of timeout before giving up the reading 487 | \return 1 success, return the number of bytes read 488 | \return 0 Timeout reached 489 | \return -1 error while setting the Timeout 490 | \return -2 error while reading the byte 491 | */ 492 | int serialib::Read (void *Buffer,unsigned int MaxNbBytes,unsigned int TimeOut_ms) 493 | { 494 | #if defined (_WIN32) || defined(_WIN64) 495 | DWORD dwBytesRead = 0; 496 | timeouts.ReadTotalTimeoutConstant=(DWORD)TimeOut_ms; // Set the TimeOut 497 | if(!SetCommTimeouts(hSerial, &timeouts)) // Write the parameters 498 | return -1; // Error while writting the parameters 499 | if(!ReadFile(hSerial,Buffer,(DWORD)MaxNbBytes,&dwBytesRead, NULL)) // Read the bytes from the serial device 500 | return -2; // Error while reading the byte 501 | if (dwBytesRead!=(DWORD)MaxNbBytes) return 0; // Return 0 if the timeout is reached 502 | return 1; // Success 503 | #endif 504 | #ifdef __linux__ 505 | TimeOut Timer; // Timer used for timeout 506 | Timer.InitTimer(); // Initialise the timer 507 | unsigned int NbByteRead=0; 508 | while (Timer.ElapsedTime_ms()0) { // One or several byte(s) has been read on the device 514 | NbByteRead+=Ret; // Increase the number of read bytes 515 | if (NbByteRead>=MaxNbBytes) // Success : bytes has been read 516 | return 1; 517 | } 518 | } 519 | return 0; // Timeout reached, return 0 520 | #endif 521 | } 522 | 523 | 524 | 525 | 526 | // _________________________ 527 | // ::: Special operation ::: 528 | 529 | 530 | 531 | /*! 532 | \brief Empty receiver buffer (UNIX only) 533 | */ 534 | 535 | void serialib::FlushReceiver() 536 | { 537 | #ifdef __linux__ 538 | tcflush(fd,TCIFLUSH); 539 | #endif 540 | } 541 | 542 | 543 | 544 | /*! 545 | \brief Return the number of bytes in the received buffer (UNIX only) 546 | \return The number of bytes in the received buffer 547 | */ 548 | #if defined(__linux__) && defined(FIONREAD) 549 | int serialib::Peek() 550 | { 551 | int Nbytes=0; 552 | ioctl(fd, FIONREAD, &Nbytes); 553 | return Nbytes; 554 | } 555 | #endif 556 | 557 | // ****************************************** 558 | // Class TimeOut 559 | // ****************************************** 560 | 561 | 562 | /*! 563 | \brief Constructor of the class TimeOut. 564 | */ 565 | // Constructor 566 | TimeOut::TimeOut() 567 | {} 568 | 569 | /*! 570 | \brief Initialise the timer. It writes the current time of the day in the structure PreviousTime. 571 | */ 572 | //Initialize the timer 573 | void TimeOut::InitTimer() 574 | { 575 | gettimeofday(&PreviousTime, NULL); 576 | } 577 | 578 | /*! 579 | \brief Returns the time elapsed since initialization. It write the current time of the day in the structure CurrentTime. 580 | Then it returns the difference between CurrentTime and PreviousTime. 581 | \return The number of microseconds elapsed since the functions InitTimer was called. 582 | */ 583 | //Return the elapsed time since initialization 584 | unsigned long int TimeOut::ElapsedTime_ms() 585 | { 586 | struct timeval CurrentTime; 587 | int sec,usec; 588 | gettimeofday(&CurrentTime, NULL); // Get current time 589 | sec=CurrentTime.tv_sec-PreviousTime.tv_sec; // Compute the number of second elapsed since last call 590 | usec=CurrentTime.tv_usec-PreviousTime.tv_usec; // Compute 591 | if (usec<0) { // If the previous usec is higher than the current one 592 | usec=1000000-PreviousTime.tv_usec+CurrentTime.tv_usec; // Recompute the microseonds 593 | sec--; // Substract one second 594 | } 595 | return sec*1000+usec/1000; 596 | } 597 | 598 | --------------------------------------------------------------------------------