diff --git a/cores/esp8266/Arduino.h b/cores/esp8266/Arduino.h index 51aa65602..6db13a088 100644 --- a/cores/esp8266/Arduino.h +++ b/cores/esp8266/Arduino.h @@ -172,6 +172,7 @@ int digitalRead(uint8_t); int analogRead(uint8_t); void analogReference(uint8_t mode); void analogWrite(uint8_t, int); +void analogWriteFreq(uint32_t freq); unsigned long millis(void); unsigned long micros(void); diff --git a/cores/esp8266/HardwareSerial.cpp b/cores/esp8266/HardwareSerial.cpp index 727eb2639..87fd6dfbb 100644 --- a/cores/esp8266/HardwareSerial.cpp +++ b/cores/esp8266/HardwareSerial.cpp @@ -118,24 +118,14 @@ int uart_get_debug(); void ICACHE_RAM_ATTR uart_interrupt_handler(uart_t* uart) { // -------------- UART 0 -------------- - uint32_t status = U0IS; if(Serial.isRxEnabled()) { - if(status & (1 << UIFF)) { - while(true) { - int rx_count = (U0S >> USTXC) & 0xff; - if(!rx_count) - break; - - while(rx_count--) { - char c = U0F & 0xff; - Serial._rx_complete_irq(c); - } - } + while(U0IS & (1 << UIFF)) { + Serial._rx_complete_irq((char)(U0F & 0xff)); U0IC = (1 << UIFF); } } if(Serial.isTxEnabled()) { - if(status & (1 << UIFE)) { + if(U0IS & (1 << UIFE)) { U0IC = (1 << UIFE); Serial._tx_empty_irq(); } @@ -143,25 +133,14 @@ void ICACHE_RAM_ATTR uart_interrupt_handler(uart_t* uart) { // -------------- UART 1 -------------- - status = U1IS; if(Serial1.isRxEnabled()) { - if(status & (1 << UIFF)) { - while(true) { - int rx_count = (U1S >> USTXC) & 0xff; - if(!rx_count) - break; - - while(rx_count--) { - char c = U1F & 0xff; - Serial1._rx_complete_irq(c); - } - } + while(U1IS & (1 << UIFF)) { + Serial1._rx_complete_irq((char)(U1F & 0xff)); U1IC = (1 << UIFF); } } if(Serial1.isTxEnabled()) { - status = U1IS; - if(status & (1 << UIFE)) { + if(U1IS & (1 << UIFE)) { U1IC = (1 << UIFE); Serial1._tx_empty_irq(); } diff --git a/cores/esp8266/core_esp8266_timer.c b/cores/esp8266/core_esp8266_timer.c index 54ec65692..bfdd3692c 100644 --- a/cores/esp8266/core_esp8266_timer.c +++ b/cores/esp8266/core_esp8266_timer.c @@ -30,6 +30,10 @@ void timer1_isr_handler(void *para){ if(timer1_user_cb) timer1_user_cb(); } +void timer1_isr_init(){ + ETS_FRC_TIMER1_INTR_ATTACH(timer1_isr_handler, NULL); +} + void timer1_attachInterrupt(void (*userFunc)(void)) { timer1_user_cb = userFunc; ETS_FRC1_INTR_ENABLE(); @@ -55,7 +59,3 @@ void timer1_disable(){ T1C = 0; T1I = 0; } - -void timer1_isr_init(){ - ETS_FRC_TIMER1_INTR_ATTACH(timer1_isr_handler, NULL); -} \ No newline at end of file diff --git a/cores/esp8266/core_esp8266_wiring.c b/cores/esp8266/core_esp8266_wiring.c index b16acc242..0170b4bcf 100644 --- a/cores/esp8266/core_esp8266_wiring.c +++ b/cores/esp8266/core_esp8266_wiring.c @@ -75,6 +75,7 @@ void delayMicroseconds(unsigned int us) { void init() { initPins(); + timer1_isr_init(); os_timer_setfn(µs_overflow_timer, (os_timer_func_t*) µs_overflow_tick, 0); os_timer_arm(µs_overflow_timer, 60000, REPEAT); } diff --git a/cores/esp8266/core_esp8266_wiring_pwm.c b/cores/esp8266/core_esp8266_wiring_pwm.c index 25ddceb2e..b175f6e55 100644 --- a/cores/esp8266/core_esp8266_wiring_pwm.c +++ b/cores/esp8266/core_esp8266_wiring_pwm.c @@ -33,18 +33,19 @@ uint16_t pwm_steps[17]; uint8_t pwm_steps_len = 0; uint32_t pwm_steps_mask[17]; -int pwm_sort_asc(const void* a, const void* b){ - return (*((uint16_t*)a) > *((uint16_t*)b)) - (*((uint16_t*)a) < *((uint16_t*)b)); -} - int pwm_sort_array(uint16_t a[], uint16_t al){ - qsort(a, al, sizeof(uint16_t), pwm_sort_asc); - int i; - int bl = 1; - for(i = 1; i < al; i++){ - if(a[i] != a[i-1]) a[bl++] = a[i]; - } - return bl; + uint16_t i, j; + for (i = 1; i < al; i++) { + uint16_t tmp = a[i]; + for (j = i; j >= 1 && tmp < a[j-1]; j--) + a[j] = a[j-1]; + a[j] = tmp; + } + int bl = 1; + for(i = 1; i < al; i++){ + if(a[i] != a[i-1]) a[bl++] = a[i]; + } + return bl; } uint32_t pwm_get_mask(uint16_t value){ @@ -139,4 +140,10 @@ extern void __analogWrite(uint8_t pin, int value) { } } +extern void __analogWriteFreq(uint32_t freq){ + pwm_freq = freq; + prep_pwm_steps(); +} + extern void analogWrite(uint8_t pin, int val) __attribute__ ((weak, alias("__analogWrite"))); +extern void analogWriteFreq(uint32_t freq) __attribute__ ((weak, alias("__analogWriteFreq"))); diff --git a/cores/esp8266/libc_replacements.c b/cores/esp8266/libc_replacements.c index 0554184d5..c1abbcf6f 100644 --- a/cores/esp8266/libc_replacements.c +++ b/cores/esp8266/libc_replacements.c @@ -175,6 +175,9 @@ char* ICACHE_FLASH_ATTR strtok_r(char * str, const char * delimiters, char ** te uint32_t size = 0; if(str == NULL) { + if(temp == NULL) { + return NULL; + } start = *temp; } else { start = str; @@ -184,6 +187,10 @@ char* ICACHE_FLASH_ATTR strtok_r(char * str, const char * delimiters, char ** te return NULL; } + if(delimiters == NULL) { + return NULL; + } + end = start; while(1) { @@ -211,7 +218,9 @@ char* ICACHE_FLASH_ATTR strtok_r(char * str, const char * delimiters, char ** te } char* ICACHE_FLASH_ATTR strtok(char * str, const char * delimiters) { - return strtok_r(str, delimiters, NULL); + static char * ret = NULL; + ret = strtok_r(str, delimiters, &ret); + return ret; } int strcasecmp(const char * str1, const char * str2) { diff --git a/libraries/ESP8266WebServer/examples/HelloServer/HelloServer.ino b/libraries/ESP8266WebServer/examples/HelloServer/HelloServer.ino index 326f0df80..4264aeca9 100644 --- a/libraries/ESP8266WebServer/examples/HelloServer/HelloServer.ino +++ b/libraries/ESP8266WebServer/examples/HelloServer/HelloServer.ino @@ -69,6 +69,5 @@ void setup(void){ } void loop(void){ - mdns.update(); server.handleClient(); } diff --git a/libraries/ESP8266WebServer/examples/SDWebServer/SDWebServer.ino b/libraries/ESP8266WebServer/examples/SDWebServer/SDWebServer.ino index bdc945d33..d9e230c77 100644 --- a/libraries/ESP8266WebServer/examples/SDWebServer/SDWebServer.ino +++ b/libraries/ESP8266WebServer/examples/SDWebServer/SDWebServer.ino @@ -23,8 +23,10 @@ File extensions with more than 3 charecters are not supported by the SD Library File Names longer than 8 charecters will be truncated by the SD library, so keep filenames shorter index.htm is the default index (works on subfolders as well) -*/ + + upload the contents of SdRoot to the root of the SDcard and access the editor by going to http://esp8266sd.local/edit +*/ #include #include #include @@ -32,8 +34,8 @@ #include #include -//do not go larger than 1460 bytes as that is the maximum that could fit in a packet #define WWW_BUF_SIZE 1460 +#define DBG_OUTPUT_PORT Serial const char* ssid = "**********"; const char* password = "**********"; @@ -45,31 +47,36 @@ ESP8266WebServer server(80); static bool hasSD = false; File uploadFile; -void handleFileUpload(){ - if(server.uri() != "/upload") return; - HTTPUpload upload = server.upload(); - if(upload.status == UPLOAD_FILE_START){ - Serial.print("Upload: START, filename:"); - Serial.println(upload.filename); - if(SD.exists((char *)upload.filename.c_str())) SD.remove((char *)upload.filename.c_str()); - uploadFile = SD.open(upload.filename.c_str(), FILE_WRITE); - } else if(upload.status == UPLOAD_FILE_WRITE){ - Serial.print("Upload: WRITE, Bytes:"); - Serial.println(upload.buflen); - if(uploadFile) uploadFile.write(upload.buf, upload.buflen); - } else if(upload.status == UPLOAD_FILE_END){ - Serial.print("Upload: END, Size:"); - Serial.println(upload.size); - if(uploadFile) uploadFile.close(); - } +void returnOK(){ + WiFiClient client = server.client(); + String message = "HTTP/1.1 200 OK\r\n"; + message += "Content-Type: text/plain\r\n"; + message += "Connection: close\r\n"; + message += "Access-Control-Allow-Origin: *\r\n"; + message += "\r\n"; + client.print(message); + message = 0; + client.stop(); +} + +void returnFail(String msg){ + WiFiClient client = server.client(); + String message = "HTTP/1.1 500 Fail\r\n"; + message += "Content-Type: text/plain\r\n"; + message += "Connection: close\r\n"; + message += "Access-Control-Allow-Origin: *\r\n"; + message += "\r\n"; + message += msg; + message += "\r\n"; + client.print(message); + message = 0; + client.stop(); } bool loadFromSdCard(String path){ String dataType = "text/plain"; - //handle default index if(path.endsWith("/")) path += "index.htm"; - //set proper Content-Type for the most common extensions if(path.endsWith(".src")) path = path.substring(0, path.lastIndexOf(".")); else if(path.endsWith(".htm")) dataType = "text/html"; else if(path.endsWith(".css")) dataType = "text/css"; @@ -82,121 +89,224 @@ bool loadFromSdCard(String path){ else if(path.endsWith(".pdf")) dataType = "application/pdf"; else if(path.endsWith(".zip")) dataType = "application/zip"; - //Try to open the file File dataFile = SD.open(path.c_str()); - - //if it's a folder, try to open the default index - if(dataFile && dataFile.isDirectory()){ + if(dataFile.isDirectory()){ path += "/index.htm"; dataType = "text/html"; dataFile = SD.open(path.c_str()); } - //and finally if the file exists, stream the content to the client + if(server.hasArg("download")) dataType = "application/octet-stream"; + if (dataFile) { WiFiClient client = server.client(); - //send the file headers String head = "HTTP/1.1 200 OK\r\nContent-Type: "; head += dataType; head += "\r\nContent-Length: "; head += dataFile.size(); + head += "\r\nConnection: close"; + head += "\r\nAccess-Control-Allow-Origin: *"; head += "\r\n\r\n"; client.print(head); + dataType = 0; + path = 0; - //partition the data packets to fit in a TCP packet (1460 bytes MAX) uint8_t obuf[WWW_BUF_SIZE]; + while (dataFile.available() > WWW_BUF_SIZE){ dataFile.read(obuf, WWW_BUF_SIZE); if(client.write(obuf, WWW_BUF_SIZE) != WWW_BUF_SIZE){ - Serial.println("Sent less data than expected!"); + DBG_OUTPUT_PORT.println("Sent less data than expected!"); dataFile.close(); return true; } } - //stream the last data left (size is at most WWW_BUF_SIZE bytes) uint16_t leftLen = dataFile.available(); dataFile.read(obuf, leftLen); if(client.write(obuf, leftLen) != leftLen){ - Serial.println("Sent less data than expected!"); + DBG_OUTPUT_PORT.println("Sent less data than expected!"); dataFile.close(); return true; } - dataFile.close(); + client.stop(); return true; } return false; } -void tryLoadFromSdCard(){ - String message = "FileNotFound\n\n"; - if(hasSD){ - //try to load the URL from SD Card - if(loadFromSdCard(server.uri())) return; +void handleFileUpload(){ + if(server.uri() != "/edit") return; + HTTPUpload upload = server.upload(); + if(upload.status == UPLOAD_FILE_START){ + if(SD.exists((char *)upload.filename.c_str())) SD.remove((char *)upload.filename.c_str()); + uploadFile = SD.open(upload.filename.c_str(), FILE_WRITE); + DBG_OUTPUT_PORT.print("Upload: START, filename: "); DBG_OUTPUT_PORT.println(upload.filename); + } else if(upload.status == UPLOAD_FILE_WRITE){ + if(uploadFile) uploadFile.write(upload.buf, upload.buflen); + DBG_OUTPUT_PORT.print("Upload: WRITE, Bytes: "); DBG_OUTPUT_PORT.println(upload.buflen); + } else if(upload.status == UPLOAD_FILE_END){ + if(uploadFile) uploadFile.close(); + DBG_OUTPUT_PORT.print("Upload: END, Size: "); DBG_OUTPUT_PORT.println(upload.size); + } +} + +void deleteRecursive(String path){ + File file = SD.open((char *)path.c_str()); + if(!file.isDirectory()){ + file.close(); + SD.remove((char *)path.c_str()); + return; + } + file.rewindDirectory(); + File entry; + String entryPath; + while(true) { + entry = file.openNextFile(); + if (!entry) break; + entryPath = path + "/" +entry.name(); + if(entry.isDirectory()){ + entry.close(); + deleteRecursive(entryPath); + } else { + entry.close(); + SD.remove((char *)entryPath.c_str()); + } + entryPath = 0; + yield(); + } + SD.rmdir((char *)path.c_str()); + path = 0; + file.close(); +} + +void handleDelete(){ + if(server.args() == 0) return returnFail("BAD ARGS"); + String path = server.arg(0); + if(path == "/" || !SD.exists((char *)path.c_str())) return returnFail("BAD PATH"); + deleteRecursive(path); + returnOK(); + path = 0; +} + +void handleCreate(){ + if(server.args() == 0) return returnFail("BAD ARGS"); + String path = server.arg(0); + if(path == "/" || SD.exists((char *)path.c_str())) return returnFail("BAD PATH"); + if(path.indexOf('.') > 0){ + File file = SD.open((char *)path.c_str(), FILE_WRITE); + if(file){ + file.write((const char *)0); + file.close(); + } } else { - message = "SDCARD Not Detected\n\n"; + SD.mkdir((char *)path.c_str()); + } + returnOK(); + path = 0; +} + +void printDirectory() { + if(!server.hasArg("dir")) return returnFail("BAD ARGS"); + String path = server.arg("dir"); + if(path != "/" && !SD.exists((char *)path.c_str())) return returnFail("BAD PATH"); + File dir = SD.open((char *)path.c_str()); + path = 0; + if(!dir.isDirectory()){ + dir.close(); + return returnFail("NOT DIR"); + } + dir.rewindDirectory(); + + File entry; + WiFiClient client = server.client(); + client.print("HTTP/1.1 200 OK\r\nContent-Type: text/json\r\n\r\n"); + String output = "["; + while(true) { + entry = dir.openNextFile(); + if (!entry) break; + if(output != "[") output += ','; + output += "{\"type\":\""; + output += (entry.isDirectory())?"dir":"file"; + output += "\",\"name\":\""; + output += entry.name(); + output += "\""; + output += "}"; + entry.close(); + if(output.length() > 1460){ + client.write(output.substring(0, 1460).c_str(), 1460); + output = output.substring(1460); + } + } + dir.close(); + output += "]"; + client.write(output.c_str(), output.length()); + client.stop(); + output = 0; +} + +void handleNotFound(){ + if(hasSD && loadFromSdCard(server.uri())) return; + String message = "SDCARD Not Detected\n\n"; + message += "URI: "; + message += server.uri(); + message += "\nMethod: "; + message += (server.method() == HTTP_GET)?"GET":"POST"; + message += "\nArguments: "; + message += server.args(); + message += "\n"; + for (uint8_t i=0; i + + + SD Editor + + + + + +
+
+
+ + + + diff --git a/libraries/ESP8266WebServer/examples/SDWebServer/SdRoot/index.htm b/libraries/ESP8266WebServer/examples/SDWebServer/SdRoot/index.htm new file mode 100644 index 000000000..55fe5a66c --- /dev/null +++ b/libraries/ESP8266WebServer/examples/SDWebServer/SdRoot/index.htm @@ -0,0 +1,22 @@ + + + + + ESP Index + + + + +

ESP8266 Pin Functions

+ + + diff --git a/libraries/ESP8266WebServer/examples/SDWebServer/SdRoot/pins.png b/libraries/ESP8266WebServer/examples/SDWebServer/SdRoot/pins.png new file mode 100644 index 000000000..ac7fc0f9c Binary files /dev/null and b/libraries/ESP8266WebServer/examples/SDWebServer/SdRoot/pins.png differ diff --git a/libraries/ESP8266WebServer/src/ESP8266WebServer.cpp b/libraries/ESP8266WebServer/src/ESP8266WebServer.cpp index 0057a2d1b..cc4fffcce 100644 --- a/libraries/ESP8266WebServer/src/ESP8266WebServer.cpp +++ b/libraries/ESP8266WebServer/src/ESP8266WebServer.cpp @@ -152,7 +152,7 @@ void ESP8266WebServer::handleClient() String formData; //bellow is needed only when POST type request - if(method == HTTP_POST || method == HTTP_PUT || method == HTTP_PATCH){ + if(method == HTTP_POST || method == HTTP_PUT || method == HTTP_PATCH || method == HTTP_DELETE){ String boundaryStr; String headerName; String headerValue; @@ -391,7 +391,8 @@ void ESP8266WebServer::_parseForm(WiFiClient& client, String boundary, uint32_t line = client.readStringUntil('\r'); client.readStringUntil('\n'); if(line.startsWith("--"+boundary)) break; - argValue += line+"\n"; + if(argValue.length() > 0) argValue += "\n"; + argValue += line; } #ifdef DEBUG DEBUG_OUTPUT.print("PostArg Value: "); @@ -441,8 +442,6 @@ readfile: argByte = client.read(); if(argByte == 0x0A){ - line = client.readStringUntil(0x0D); - client.readStringUntil(0x0A); #ifdef DEBUG DEBUG_OUTPUT.print("Write File: "); DEBUG_OUTPUT.println(_currentUpload.buflen); @@ -450,7 +449,28 @@ readfile: if(_fileUploadHandler) _fileUploadHandler(); _currentUpload.size += _currentUpload.buflen; _currentUpload.buflen = 0; - if(line.startsWith("--"+boundary)){ + + argByte = client.read(); + if((char)argByte != '-'){ + //continue reading the file + _currentUpload.buf[_currentUpload.buflen++] = 0x0D; + _currentUpload.buf[_currentUpload.buflen++] = 0x0A; + goto readfile; + } else { + argByte = client.read(); + if((char)argByte != '-'){ + //continue reading the file + _currentUpload.buf[_currentUpload.buflen++] = 0x0D; + _currentUpload.buf[_currentUpload.buflen++] = 0x0A; + _currentUpload.buf[_currentUpload.buflen++] = (uint8_t)('-'); + goto readfile; + } + } + + uint8_t endBuf[boundary.length()]; + client.readBytes(endBuf, boundary.length()); + + if(strstr((const char*)endBuf, (const char*)(boundary.c_str())) != NULL){ _currentUpload.status = UPLOAD_FILE_END; #ifdef DEBUG DEBUG_OUTPUT.print("End File: "); @@ -461,7 +481,9 @@ readfile: DEBUG_OUTPUT.println(_currentUpload.size); #endif if(_fileUploadHandler) _fileUploadHandler(); - if(line == ("--"+boundary+"--")){ + line = client.readStringUntil(0x0D); + client.readStringUntil(0x0A); + if(line == "--"){ #ifdef DEBUG DEBUG_OUTPUT.println("Done Parsing POST"); #endif @@ -471,10 +493,9 @@ readfile: } else { _currentUpload.buf[_currentUpload.buflen++] = 0x0D; _currentUpload.buf[_currentUpload.buflen++] = 0x0A; - const char * lineChars = line.c_str(); uint32_t i = 0; - while(i < os_strlen(lineChars)){ - _currentUpload.buf[_currentUpload.buflen++] = lineChars[i++]; + while(i < boundary.length()){ + _currentUpload.buf[_currentUpload.buflen++] = endBuf[i++]; if(_currentUpload.buflen == 1460){ #ifdef DEBUG DEBUG_OUTPUT.println("Write File: 1460"); diff --git a/libraries/ESP8266WiFi/examples/WiFiTelnetToSerial/WiFiTelnetToSerial.ino b/libraries/ESP8266WiFi/examples/WiFiTelnetToSerial/WiFiTelnetToSerial.ino new file mode 100644 index 000000000..43a9d8259 --- /dev/null +++ b/libraries/ESP8266WiFi/examples/WiFiTelnetToSerial/WiFiTelnetToSerial.ino @@ -0,0 +1,90 @@ +/* + WiFiTelnetToSerial - Example Transparent UART to Telnet Server for esp8266 + + Copyright (c) 2015 Hristo Gochkov. All rights reserved. + This file is part of the ESP8266WiFi library for Arduino environment. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ +#include + +//how many clients should be able to telnet to this ESP8266 +#define MAX_SRV_CLIENTS 1 +const char* ssid = "**********"; +const char* password = "**********"; + +WiFiServer server(21); +WiFiClient serverClients[MAX_SRV_CLIENTS]; + +void setup() { + Serial1.begin(115200); + WiFi.begin(ssid, password); + Serial1.print("\nConnecting to "); Serial1.println(ssid); + uint8_t i = 0; + while (WiFi.status() != WL_CONNECTED && i++ < 20) delay(500); + if(i == 21){ + Serial1.print("Could not connect to"); Serial1.println(ssid); + while(1) delay(500); + } + //start UART and the server + Serial.begin(115200); + server.begin(); + server.setNoDelay(true); + + Serial1.print("Ready! Use 'telnet "); + Serial1.print(WiFi.localIP()); + Serial1.println(" 21' to connect"); +} + +void loop() { + uint8_t i; + //check if there are any new clients + if (server.hasClient()){ + for(i = 0; i < MAX_SRV_CLIENTS; i++){ + //find free/disconnected spot + if (!serverClients[i] || !serverClients[i].connected()){ + if(serverClients[i]) serverClients[i].stop(); + serverClients[i] = server.available(); + Serial1.print("New client: "); Serial1.print(i); + continue; + } + } + //no free/disconnected spot so reject + WiFiClient serverClient = server.available(); + serverClient.stop(); + } + //check clients for data + for(i = 0; i < MAX_SRV_CLIENTS; i++){ + if (serverClients[i] && serverClients[i].connected()){ + if(serverClients[i].available()){ + //get data from the telnet client and push it to the UART + while(serverClients[i].available()) Serial.write(serverClients[i].read()); + } + } + } + //check UART for data + if(Serial.available()){ + size_t len = Serial.available(); + uint8_t sbuf[len]; + Serial.readBytes(sbuf, len); + //push UART data to all connected telnet clients + for(i = 0; i < MAX_SRV_CLIENTS; i++){ + if (serverClients[i] && serverClients[i].connected()){ + serverClients[i].write(sbuf, len); + delay(1); + } + } + } +} diff --git a/libraries/ESP8266WiFi/src/WiFiServer.cpp b/libraries/ESP8266WiFi/src/WiFiServer.cpp index ec61b424b..69ad4ff81 100644 --- a/libraries/ESP8266WiFi/src/WiFiServer.cpp +++ b/libraries/ESP8266WiFi/src/WiFiServer.cpp @@ -73,8 +73,24 @@ void WiFiServer::begin() tcp_arg(listen_pcb, (void*) this); } +void WiFiServer::setNoDelay(bool nodelay){ + if(!_pcb) return; + if(nodelay) tcp_nagle_disable(_pcb); + else tcp_nagle_enable(_pcb); +} + +bool WiFiServer::getNoDelay(){ + if(!_pcb) return false; + return tcp_nagle_disabled(_pcb); +} + extern "C" uint32_t esp_micros_at_task_start(); +bool WiFiServer::hasClient(){ + if (_unclaimed) return true; + return false; +} + WiFiClient WiFiServer::available(byte* status) { static uint32_t lastPollTime = 0; diff --git a/libraries/ESP8266WiFi/src/WiFiServer.h b/libraries/ESP8266WiFi/src/WiFiServer.h index 0bd427e2f..3dd02da7d 100644 --- a/libraries/ESP8266WiFi/src/WiFiServer.h +++ b/libraries/ESP8266WiFi/src/WiFiServer.h @@ -44,7 +44,10 @@ private: public: WiFiServer(uint16_t port); WiFiClient available(uint8_t* status = NULL); + bool hasClient(); void begin(); + void setNoDelay(bool nodelay); + bool getNoDelay(); virtual size_t write(uint8_t); virtual size_t write(const uint8_t *buf, size_t size); uint8_t status(); diff --git a/libraries/ESP8266WiFi/src/WiFiUdp.cpp b/libraries/ESP8266WiFi/src/WiFiUdp.cpp index f2328aa6b..7696d747b 100644 --- a/libraries/ESP8266WiFi/src/WiFiUdp.cpp +++ b/libraries/ESP8266WiFi/src/WiFiUdp.cpp @@ -21,7 +21,8 @@ */ #define LWIP_INTERNAL - +#include + extern "C" { #include "include/wl_definitions.h" @@ -168,7 +169,6 @@ int WiFiUDP::endPacket() return 0; _ctx->send(); - _ctx->disconnect(); return 1; } diff --git a/libraries/ESP8266WiFi/src/include/ClientContext.h b/libraries/ESP8266WiFi/src/include/ClientContext.h index f9fd4e524..79c68127f 100644 --- a/libraries/ESP8266WiFi/src/include/ClientContext.h +++ b/libraries/ESP8266WiFi/src/include/ClientContext.h @@ -39,7 +39,39 @@ class ClientContext { tcp_sent(pcb, &_s_sent); tcp_err(pcb, &_s_error); } - + + err_t abort(){ + if(_pcb) { + DEBUGV(":abort\r\n"); + tcp_arg(_pcb, NULL); + tcp_sent(_pcb, NULL); + tcp_recv(_pcb, NULL); + tcp_err(_pcb, NULL); + tcp_abort(_pcb); + _pcb = 0; + } + return ERR_ABRT; + } + + err_t close(){ + err_t err = ERR_OK; + if(_pcb) { + DEBUGV(":close\r\n"); + tcp_arg(_pcb, NULL); + tcp_sent(_pcb, NULL); + tcp_recv(_pcb, NULL); + tcp_err(_pcb, NULL); + err = tcp_close(_pcb); + if(err != ERR_OK) { + DEBUGV(":tc err %d\r\n", err); + tcp_abort(_pcb); + err = ERR_ABRT; + } + _pcb = 0; + } + return err; + } + ~ClientContext() { } @@ -58,26 +90,26 @@ class ClientContext { } void unref() { - err_t err; DEBUGV(":ur %d\r\n", _refcnt); if(--_refcnt == 0) { flush(); - if(_pcb) { - tcp_arg(_pcb, NULL); - tcp_sent(_pcb, NULL); - tcp_recv(_pcb, NULL); - tcp_err(_pcb, NULL); - err = tcp_close(_pcb); - if(err != ERR_OK) { - DEBUGV(":tc err %d\r\n", err); - tcp_abort(_pcb); - } - _pcb = 0; - } + close(); + if(_discard_cb) _discard_cb(_discard_cb_arg, this); delete this; } } - + + void setNoDelay(bool nodelay){ + if(!_pcb) return; + if(nodelay) tcp_nagle_disable(_pcb); + else tcp_nagle_enable(_pcb); + } + + bool getNoDelay(){ + if(!_pcb) return false; + return tcp_nagle_disabled(_pcb); + } + uint32_t getRemoteAddress() { if(!_pcb) return 0; @@ -179,6 +211,13 @@ class ClientContext { private: + err_t _sent(tcp_pcb* pcb, uint16_t len) { + DEBUGV(":sent %d\r\n", len); + _size_sent -= len; + if(_size_sent == 0 && _send_waiting) esp_schedule(); + return ERR_OK; + } + void _consume(size_t size) { ptrdiff_t left = _rx_buf->len - _rx_buf_offset - size; if(left > 0) { @@ -204,21 +243,8 @@ class ClientContext { if(pb == 0) // connection closed { - DEBUGV(":rcl\r\n"); - tcp_arg(pcb, NULL); - tcp_sent(pcb, NULL); - tcp_recv(pcb, NULL); - tcp_err(pcb, NULL); - // int error = tcp_close(pcb); - // if (error != ERR_OK) - { - DEBUGV(":rcla\r\n"); - tcp_abort(pcb); - _pcb = 0; - return ERR_ABRT; - } - _pcb = 0; - return ERR_OK; + DEBUGV(":rcla\r\n"); + return abort(); } if(_rx_buf) { @@ -231,27 +257,12 @@ class ClientContext { _rx_buf = pb; _rx_buf_offset = 0; } - // tcp_recved(pcb, received); - // pbuf_free(pb); return ERR_OK; } void _error(err_t err) { DEBUGV(":er %d\r\n", err); - - if(_pcb) { - tcp_arg(_pcb, NULL); - tcp_sent(_pcb, NULL); - tcp_recv(_pcb, NULL); - tcp_err(_pcb, NULL); - err = tcp_close(_pcb); - if(err != ERR_OK) { - DEBUGV(":tc err %d\r\n", err); - tcp_abort(_pcb); - } - } - _pcb = 0; - + close(); if(_size_sent && _send_waiting) { esp_schedule(); } @@ -261,13 +272,6 @@ class ClientContext { return ERR_OK; } - err_t _sent(tcp_pcb* pcb, uint16_t len) { - DEBUGV(":sent %d\r\n", len); - _size_sent -= len; - if(_size_sent == 0 && _send_waiting) esp_schedule(); - return ERR_OK; - } - static err_t _s_recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *pb, err_t err) { return reinterpret_cast(arg)->_recv(tpcb, pb, err); } diff --git a/libraries/ESP8266WiFi/src/include/UdpContext.h b/libraries/ESP8266WiFi/src/include/UdpContext.h index e244486e1..c86e050ed 100644 --- a/libraries/ESP8266WiFi/src/include/UdpContext.h +++ b/libraries/ESP8266WiFi/src/include/UdpContext.h @@ -28,9 +28,13 @@ extern "C" void esp_schedule(); #define GET_IP_HDR(pb) reinterpret_cast(((uint8_t*)((pb)->payload)) - UDP_HLEN - IP_HLEN); #define GET_UDP_HDR(pb) reinterpret_cast(((uint8_t*)((pb)->payload)) - UDP_HLEN); + class UdpContext { public: + + typedef std::function rxhandler_t; + UdpContext() : _pcb(0) , _rx_buf(0) @@ -40,8 +44,11 @@ public: , _tx_buf_head(0) , _tx_buf_cur(0) , _tx_buf_offset(0) + , _multicast_ttl(1) + , _dest_port(0) { _pcb = udp_new(); + _dest_addr.addr = 0; } ~UdpContext() @@ -79,8 +86,9 @@ public: bool connect(ip_addr_t addr, uint16_t port) { - err_t err = udp_connect(_pcb, &addr, port); - return err == ERR_OK; + _dest_addr = addr; + _dest_port = port; + return true; } bool listen(ip_addr_t addr, uint16_t port) @@ -107,7 +115,13 @@ public: // newer versions of lwip have an additional field (mcast_ttl) for this purpose // and a macro to set it instead of direct field access // udp_set_multicast_ttl(_pcb, ttl); - _pcb->ttl = ttl; + _multicast_ttl = ttl; + } + + // warning: handler is called from tcp stack context + // esp_yield and non-reentrant functions which depend on it will fail + void onRx(rxhandler_t handler) { + _on_rx = handler; } size_t getSize() const @@ -173,10 +187,10 @@ public: return _rx_buf != 0; } - char read() + int read() { if (!_rx_buf || _rx_buf->len == _rx_buf_offset) - return 0; + return -1; char c = reinterpret_cast(_rx_buf->payload)[_rx_buf_offset]; _consume(1); @@ -190,7 +204,7 @@ public: size_t max_size = _rx_buf->len - _rx_buf_offset; size = (size < max_size) ? size : max_size; - DEBUGV(":rd %d, %d, %d\r\n", size, _rx_buf->len, _rx_buf_offset); + DEBUGV(":urd %d, %d, %d\r\n", size, _rx_buf->len, _rx_buf_offset); os_memcpy(dst, reinterpret_cast(_rx_buf->payload) + _rx_buf_offset, size); _consume(size); @@ -257,10 +271,19 @@ public: } } - if (addr) - udp_sendto(_pcb, _tx_buf_head, addr, port); - else - udp_send(_pcb, _tx_buf_head); + if (!addr) { + addr = &_dest_addr; + port = _dest_port; + } + + uint16_t old_ttl = _pcb->ttl; + if (ip_addr_ismulticast(addr)) { + _pcb->ttl = _multicast_ttl; + } + + udp_sendto(_pcb, _tx_buf_head, addr, port); + + _pcb->ttl = old_ttl; for (pbuf* p = _tx_buf_head; p; p = p->next) { @@ -281,7 +304,7 @@ private: void _reserve(size_t size) { - const size_t pbuf_unit_size = 1024; + const size_t pbuf_unit_size = 512; if (!_tx_buf_head) { _tx_buf_head = pbuf_alloc(PBUF_TRANSPORT, pbuf_unit_size, PBUF_RAM); @@ -317,16 +340,19 @@ private: { // there is some unread data // chain the new pbuf to the existing one - DEBUGV(":rch %d, %d\r\n", _rx_buf->tot_len, pb->tot_len); + DEBUGV(":urch %d, %d\r\n", _rx_buf->tot_len, pb->tot_len); pbuf_cat(_rx_buf, pb); } else { - DEBUGV(":rn %d\r\n", pb->tot_len); + DEBUGV(":urn %d\r\n", pb->tot_len); _first_buf_taken = false; _rx_buf = pb; _rx_buf_offset = 0; } + if (_on_rx) { + _on_rx(); + } } @@ -341,6 +367,11 @@ private: int _refcnt; udp_pcb* _pcb; + ip_addr_t _dest_addr; + uint16_t _dest_port; + + uint16_t _multicast_ttl; + bool _first_buf_taken; pbuf* _rx_buf; size_t _rx_buf_offset; @@ -348,6 +379,8 @@ private: pbuf* _tx_buf_head; pbuf* _tx_buf_cur; size_t _tx_buf_offset; + + rxhandler_t _on_rx; }; diff --git a/libraries/ESP8266mDNS/ESP8266mDNS.cpp b/libraries/ESP8266mDNS/ESP8266mDNS.cpp index 14ff6bcf8..5721c5272 100644 --- a/libraries/ESP8266mDNS/ESP8266mDNS.cpp +++ b/libraries/ESP8266mDNS/ESP8266mDNS.cpp @@ -30,7 +30,27 @@ License (MIT license): // - DNS request and response: http://www.ietf.org/rfc/rfc1035.txt // - Multicast DNS: http://www.ietf.org/rfc/rfc6762.txt +#define LWIP_INTERNAL #include "ESP8266mDNS.h" +#include + +extern "C" +{ + #include "osapi.h" + #include "ets_sys.h" +} + +#include "debug.h" + +#include "WiFiUdp.h" +#include "lwip/opt.h" +#include "lwip/udp.h" +#include "lwip/inet.h" +#include "lwip/igmp.h" +#include "lwip/mem.h" +#include "include/UdpContext.h" + + // #define MDNS_DEBUG @@ -42,6 +62,10 @@ License (MIT license): #define TTL_OFFSET 4 #define IP_OFFSET 10 +static const IPAddress MDNS_MULTICAST_ADDR(224, 0, 0, 251); +static const int MDNS_MULTICAST_TTL = 1; +static const int MDNS_PORT = 5353; + MDNSResponder::MDNSResponder() : _expected(NULL) @@ -49,6 +73,7 @@ MDNSResponder::MDNSResponder() , _response(NULL) , _responseLen(0) , _index(0) + , _conn(0) { } MDNSResponder::~MDNSResponder() { @@ -149,21 +174,37 @@ bool MDNSResponder::begin(const char* domain, IPAddress addr, uint32_t ttlSecond records[IP_OFFSET + 0] = (uint8_t) ipAddress; // Open the MDNS socket if it isn't already open. - if (!_mdnsConn) { - if (!_mdnsConn.beginMulticast(addr, IPAddress(224, 0, 0, 251), 5353)) { + if (!_conn) { + ip_addr_t ifaddr; + ifaddr.addr = (uint32_t) addr; + ip_addr_t multicast_addr; + multicast_addr.addr = (uint32_t) MDNS_MULTICAST_ADDR; + + if (igmp_joingroup(&ifaddr, &multicast_addr)!= ERR_OK) { return false; } - } + _conn = new UdpContext; + _conn->ref(); + + if (!_conn->listen(*IP_ADDR_ANY, MDNS_PORT)) { + return false; + } + _conn->setMulticastInterface(ifaddr); + _conn->setMulticastTTL(MDNS_MULTICAST_TTL); + _conn->onRx(std::bind(&MDNSResponder::update, this)); + _conn->connect(multicast_addr, MDNS_PORT); + } return true; } void MDNSResponder::update() { - if (!_mdnsConn.parsePacket()) - return; + if (!_conn->next()) { + return; + } // Read available data. - int n = _mdnsConn.available(); + int n = _conn->getSize(); _index = 0; @@ -172,7 +213,7 @@ void MDNSResponder::update() { #endif // Look for domain name in request and respond with canned response if found. for (int i = 0; i < n; ++i) { - uint8_t ch = tolower(_mdnsConn.read()); + uint8_t ch = tolower(_conn->read()); #ifdef MDNS_DEBUG String str(ch, 16); @@ -191,9 +232,12 @@ void MDNSResponder::update() { Serial.print("responding, i="); Serial.println(i); #endif - _mdnsConn.beginPacketMulticast(IPAddress(224, 0, 0, 251), 5353, _localAddr); - _mdnsConn.write(_response, _responseLen); - _mdnsConn.endPacket(); + ip_addr_t multicast_addr; + multicast_addr.addr = (uint32_t) MDNS_MULTICAST_ADDR; + + _conn->append(reinterpret_cast(_response), _responseLen); + _conn->send(); + _index = 0; } } diff --git a/libraries/ESP8266mDNS/ESP8266mDNS.h b/libraries/ESP8266mDNS/ESP8266mDNS.h index 65dd491ec..9a1fc56d3 100644 --- a/libraries/ESP8266mDNS/ESP8266mDNS.h +++ b/libraries/ESP8266mDNS/ESP8266mDNS.h @@ -46,6 +46,9 @@ License (MIT license): #include "ESP8266WiFi.h" #include "WiFiUdp.h" + +class UdpContext; + class MDNSResponder { public: MDNSResponder(); @@ -63,7 +66,7 @@ private: uint8_t* _response; int _responseLen; // Socket for MDNS communication - WiFiUDP _mdnsConn; + UdpContext* _conn; // local IP Address IPAddress _localAddr; }; diff --git a/libraries/ESP8266mDNS/examples/mDNS_Web_Server/mDNS_Web_Server.ino b/libraries/ESP8266mDNS/examples/mDNS_Web_Server/mDNS_Web_Server.ino index c174f4638..08ed4b4eb 100644 --- a/libraries/ESP8266mDNS/examples/mDNS_Web_Server/mDNS_Web_Server.ino +++ b/libraries/ESP8266mDNS/examples/mDNS_Web_Server/mDNS_Web_Server.ino @@ -68,9 +68,6 @@ void setup(void) void loop(void) { - // Check for any mDNS queries and send responses - mdns.update(); - // Check if a client has connected WiFiClient client = server.available(); if (!client) { diff --git a/libraries/SD/src/SD.cpp b/libraries/SD/src/SD.cpp index 65d32741c..6862daed8 100644 --- a/libraries/SD/src/SD.cpp +++ b/libraries/SD/src/SD.cpp @@ -332,7 +332,7 @@ boolean callback_rmdir(SdFile& parentDir, char *filePathComponent, -boolean SDClass::begin(uint8_t csPin) { +boolean SDClass::begin(uint8_t csPin, uint32_t speed) { /* Performs the initialisation required by the sdfatlib library. @@ -340,13 +340,11 @@ boolean SDClass::begin(uint8_t csPin) { Return true if initialization succeeds, false otherwise. */ - return card.init(SPI_HALF_SPEED, csPin) && + return card.init(speed, csPin) && volume.init(card) && root.openRoot(volume); } - - // this little helper is used to traverse paths SdFile SDClass::getParentDir(const char *filepath, int *index) { // get parent directory diff --git a/libraries/SD/src/SD.h b/libraries/SD/src/SD.h index 7435cf577..449984219 100644 --- a/libraries/SD/src/SD.h +++ b/libraries/SD/src/SD.h @@ -65,8 +65,8 @@ private: public: // This needs to be called to set up the connection to the SD card // before other methods are used. - boolean begin(uint8_t csPin = SD_CHIP_SELECT_PIN); - + boolean begin(uint8_t csPin = SD_CHIP_SELECT_PIN, uint32_t speed = SPI_HALF_SPEED); + // Open the specified file/directory with the supplied mode (e.g. read or // write, etc). Returns a File object for interacting with the file. // Note that currently only one file can be open at a time. diff --git a/libraries/SD/src/utility/Sd2Card.cpp b/libraries/SD/src/utility/Sd2Card.cpp index 98a02ba42..2d7618d65 100644 --- a/libraries/SD/src/utility/Sd2Card.cpp +++ b/libraries/SD/src/utility/Sd2Card.cpp @@ -33,9 +33,13 @@ static void spiSend(uint8_t b) { SPDR = b; while (!(SPSR & (1 << SPIF))) ; +#else +#ifdef ESP8266 + SPI.write(b); #else SPI.transfer(b); #endif +#endif } /** Receive a byte from the card */ static uint8_t spiRec(void) { @@ -116,8 +120,14 @@ uint8_t Sd2Card::cardCommand(uint8_t cmd, uint32_t arg) { // send command spiSend(cmd | 0x40); +#ifdef ESP8266 + // send argument + SPI.write32(arg, true); +#else // send argument for (int8_t s = 24; s >= 0; s -= 8) spiSend(arg >> s); +#endif + // send CRC uint8_t crc = 0xFF; @@ -424,7 +434,14 @@ uint8_t Sd2Card::readData(uint32_t block, dst[n] = SPDR; #else // OPTIMIZE_HARDWARE_SPI +#ifdef ESP8266 + // skip data before offset + SPI.transferBytes(NULL, NULL, offset_); + // transfer data + SPI.transferBytes(NULL, dst, count); + +#else // skip data before offset for (;offset_ < offset; offset_++) { spiRec(); @@ -433,6 +450,7 @@ uint8_t Sd2Card::readData(uint32_t block, for (uint16_t i = 0; i < count; i++) { dst[i] = spiRec(); } +#endif #endif // OPTIMIZE_HARDWARE_SPI offset_ += count; @@ -463,7 +481,11 @@ void Sd2Card::readEnd(void) { while (!(SPSR & (1 << SPIF))) ; #else // OPTIMIZE_HARDWARE_SPI +#ifdef ESP8266 + SPI.transferBytes(NULL, NULL, (514-offset_)); +#else while (offset_++ < 514) spiRec(); +#endif #endif // OPTIMIZE_HARDWARE_SPI chipSelectHigh(); inBlock_ = 0; @@ -479,7 +501,11 @@ uint8_t Sd2Card::readRegister(uint8_t cmd, void* buf) { } if (!waitStartBlock()) goto fail; // transfer data +#ifdef ESP8266 + SPI.transferBytes(NULL, dst, 16); +#else for (uint16_t i = 0; i < 16; i++) dst[i] = spiRec(); +#endif spiRec(); // get first crc byte spiRec(); // get second crc byte chipSelectHigh(); @@ -646,13 +672,21 @@ uint8_t Sd2Card::writeData(uint8_t token, const uint8_t* src) { #else // OPTIMIZE_HARDWARE_SPI spiSend(token); +#ifdef ESP8266 + // send argument + SPI.writeBytes((uint8_t *)src, 512); +#else for (uint16_t i = 0; i < 512; i++) { spiSend(src[i]); } +#endif #endif // OPTIMIZE_HARDWARE_SPI +#ifdef ESP8266 + SPI.write16(0xFFFF, true); +#else spiSend(0xff); // dummy crc spiSend(0xff); // dummy crc - +#endif status_ = spiRec(); if ((status_ & DATA_RES_MASK) != DATA_RES_ACCEPTED) { error(SD_CARD_ERROR_WRITE); diff --git a/libraries/SPI/SPI.cpp b/libraries/SPI/SPI.cpp index d9f9ea1eb..be4627740 100644 --- a/libraries/SPI/SPI.cpp +++ b/libraries/SPI/SPI.cpp @@ -36,6 +36,7 @@ typedef union { SPIClass SPI; SPIClass::SPIClass() { + useHwCs = false; } void SPIClass::begin() { @@ -54,9 +55,26 @@ void SPIClass::end() { pinMode(SCK, INPUT); pinMode(MISO, INPUT); pinMode(MOSI, INPUT); + if(useHwCs) { + pinMode(SS, INPUT); + } +} + +void SPIClass::setHwCs(bool use) { + if(use) { + pinMode(SS, SPECIAL); ///< GPIO15 + SPI1U |= (SPIUCSSETUP | SPIUCSHOLD); + } else { + if(useHwCs) { + pinMode(SS, INPUT); + SPI1U &= ~(SPIUCSSETUP | SPIUCSHOLD); + } + } + useHwCs = use; } void SPIClass::beginTransaction(SPISettings settings) { + while(SPI1CMD & SPIBUSY) {} setFrequency(settings._clock); setBitOrder(settings._bitOrder); setDataMode(settings._dataMode); @@ -198,13 +216,19 @@ void SPIClass::setClockDivider(uint32_t clockDiv) { SPI1CLK = clockDiv; } +inline void SPIClass::setDataBits(uint16_t bits) { + const uint32_t mask = ~((SPIMMOSI << SPILMOSI) | (SPIMMISO << SPILMISO)); + bits--; + SPI1U1 = ((SPI1U1 & mask) | ((bits << SPILMOSI) | (bits << SPILMISO))); +} + uint8_t SPIClass::transfer(uint8_t data) { - while(SPI1CMD & SPIBUSY) - ; + while(SPI1CMD & SPIBUSY) {} + // reset to 8Bit mode + setDataBits(8); SPI1W0 = data; SPI1CMD |= SPIBUSY; - while(SPI1CMD & SPIBUSY) - ; + while(SPI1CMD & SPIBUSY) {} return (uint8_t) (SPI1W0 & 0xff); } @@ -230,3 +254,177 @@ uint16_t SPIClass::transfer16(uint16_t data) { return out.val; } +void SPIClass::write(uint8_t data) { + while(SPI1CMD & SPIBUSY) {} + // reset to 8Bit mode + setDataBits(8); + SPI1W0 = data; + SPI1CMD |= SPIBUSY; + while(SPI1CMD & SPIBUSY) {} +} + +void SPIClass::write16(uint16_t data) { + write16(data, !(SPI1C & (SPICWBO | SPICRBO))); +} + +void SPIClass::write16(uint16_t data, bool msb) { + while(SPI1CMD & SPIBUSY) {} + // Set to 16Bits transfer + setDataBits(16); + if(msb) { + // MSBFIRST Byte first + SPI1W0 = (data >> 8) | (data << 8); + SPI1CMD |= SPIBUSY; + } else { + // LSBFIRST Byte first + SPI1W0 = data; + SPI1CMD |= SPIBUSY; + } + while(SPI1CMD & SPIBUSY) {} +} + +void SPIClass::write32(uint32_t data) { + write32(data, !(SPI1C & (SPICWBO | SPICRBO))); +} + +void SPIClass::write32(uint32_t data, bool msb) { + while(SPI1CMD & SPIBUSY) {} + // Set to 32Bits transfer + setDataBits(32); + if(msb) { + union { + uint32_t l; + uint8_t b[4]; + } data_; + data_.l = data; + // MSBFIRST Byte first + SPI1W0 = (data_.b[3] | (data_.b[2] << 8) | (data_.b[1] << 16) | (data_.b[0] << 24)); + SPI1CMD |= SPIBUSY; + } else { + // LSBFIRST Byte first + SPI1W0 = data; + SPI1CMD |= SPIBUSY; + } + while(SPI1CMD & SPIBUSY) {} +} + +void SPIClass::writeBytes(uint8_t * data, uint32_t size) { + while(size) { + if(size > 64) { + writeBytes_(data, 64); + size -= 64; + data += 64; + } else { + writeBytes_(data, size); + size = 0; + } + } +} + +void SPIClass::writeBytes_(uint8_t * data, uint8_t size) { + while(SPI1CMD & SPIBUSY) {} + // Set Bits to transfer + setDataBits(size * 8); + + volatile uint32_t * fifoPtr = &SPI1W0; + uint32_t * dataPtr = (uint32_t*) data; + uint8_t dataSize = ((size + 3) / 4); + + while(dataSize--) { + *fifoPtr = *dataPtr; + dataPtr++; + fifoPtr++; + } + + SPI1CMD |= SPIBUSY; + while(SPI1CMD & SPIBUSY) {} +} + +void SPIClass::writePattern(uint8_t * data, uint8_t size, uint32_t repeat) { + if(size > 64) return; //max Hardware FIFO + + uint32_t byte = (size * repeat); + uint8_t r = (64 / size); + + while(byte) { + if(byte > 64) { + writePattern_(data, size, r); + byte -= 64; + } else { + writePattern_(data, size, (byte / size)); + byte = 0; + } + } +} + +void SPIClass::writePattern_(uint8_t * data, uint8_t size, uint8_t repeat) { + uint8_t bytes = (size * repeat); + uint8_t buffer[64]; + uint8_t * bufferPtr = &buffer[0]; + uint8_t * dataPtr; + uint8_t dataSize = bytes; + for(uint8_t i = 0; i < repeat; i++) { + dataSize = size; + dataPtr = data; + while(dataSize--) { + *bufferPtr = *dataPtr; + dataPtr++; + bufferPtr++; + } + } + + writeBytes(&buffer[0], bytes); +} + +void SPIClass::transferBytes(uint8_t * out, uint8_t * in, uint32_t size) { + while(size) { + if(size > 64) { + transferBytes_(out, in, 64); + size -= 64; + if(out) out += 64; + if(in) in += 64; + } else { + transferBytes_(out, in, size); + size = 0; + } + } +} + +void SPIClass::transferBytes_(uint8_t * out, uint8_t * in, uint8_t size) { + while(SPI1CMD & SPIBUSY) {} + // Set in/out Bits to transfer + + setDataBits(size * 8); + + volatile uint32_t * fifoPtr = &SPI1W0; + uint8_t dataSize = ((size + 3) / 4); + + if(out) { + uint32_t * dataPtr = (uint32_t*) out; + while(dataSize--) { + *fifoPtr = *dataPtr; + dataPtr++; + fifoPtr++; + } + } else { + // no out data only read fill with dummy data! + while(dataSize--) { + *fifoPtr = 0xFFFFFFFF; + fifoPtr++; + } + } + + SPI1CMD |= SPIBUSY; + while(SPI1CMD & SPIBUSY) {} + + if(in) { + volatile uint8_t * fifoPtr8 = (volatile uint8_t *) &SPI1W0; + dataSize = size; + while(dataSize--) { + *in = *fifoPtr8; + in++; + fifoPtr8++; + } + } +} + diff --git a/libraries/SPI/SPI.h b/libraries/SPI/SPI.h index 3a37c52e1..e67b5b0d5 100644 --- a/libraries/SPI/SPI.h +++ b/libraries/SPI/SPI.h @@ -64,6 +64,7 @@ public: SPIClass(); void begin(); void end(); + void setHwCs(bool use); void setBitOrder(uint8_t bitOrder); void setDataMode(uint8_t dataMode); void setFrequency(uint32_t freq); @@ -71,7 +72,21 @@ public: void beginTransaction(SPISettings settings); uint8_t transfer(uint8_t data); uint16_t transfer16(uint16_t data); + void write(uint8_t data); + void write16(uint16_t data); + void write16(uint16_t data, bool msb); + void write32(uint32_t data); + void write32(uint32_t data, bool msb); + void writeBytes(uint8_t * data, uint32_t size); + void writePattern(uint8_t * data, uint8_t size, uint32_t repeat); + void transferBytes(uint8_t * out, uint8_t * in, uint32_t size); void endTransaction(void); +private: + bool useHwCs; + void writeBytes_(uint8_t * data, uint8_t size); + void writePattern_(uint8_t * data, uint8_t size, uint8_t repeat); + void transferBytes_(uint8_t * out, uint8_t * in, uint8_t size); + inline void setDataBits(uint16_t bits); }; extern SPIClass SPI; diff --git a/platform.txt b/platform.txt index ebeeadfd4..cd09aff98 100644 --- a/platform.txt +++ b/platform.txt @@ -23,7 +23,7 @@ compiler.S.flags=-c -g -x assembler-with-cpp -MMD compiler.c.elf.ldscript=eagle.app.v6.ld compiler.c.elf.flags=-nostdlib -Wl,--no-check-sections -u call_user_start -Wl,-static "-L{compiler.sdk.path}/lib" "-L{compiler.sdk.path}/ld" "-T{compiler.c.elf.ldscript}" compiler.c.elf.cmd=xtensa-lx106-elf-gcc -compiler.c.elf.libs=-lm -lc -lgcc -lhal -lphy -lnet80211 -llwip -lwpa -lmain -lpp -lsmartconfig +compiler.c.elf.libs=-lm -lgcc -lhal -lphy -lnet80211 -llwip -lwpa -lmain -lpp -lsmartconfig compiler.cpp.cmd=xtensa-lx106-elf-g++ compiler.cpp.flags=-c -Os -mlongcalls -mtext-section-literals -fno-exceptions -fno-rtti -std=c++11 -MMD