mirror of
https://github.com/esp8266/Arduino.git
synced 2025-04-21 10:26:06 +03:00
Merge branch 'esp8266' of https://github.com/esp8266/Arduino into esp8266
This commit is contained in:
commit
6f22f15e4d
@ -172,6 +172,7 @@ int digitalRead(uint8_t);
|
|||||||
int analogRead(uint8_t);
|
int analogRead(uint8_t);
|
||||||
void analogReference(uint8_t mode);
|
void analogReference(uint8_t mode);
|
||||||
void analogWrite(uint8_t, int);
|
void analogWrite(uint8_t, int);
|
||||||
|
void analogWriteFreq(uint32_t freq);
|
||||||
|
|
||||||
unsigned long millis(void);
|
unsigned long millis(void);
|
||||||
unsigned long micros(void);
|
unsigned long micros(void);
|
||||||
|
@ -118,24 +118,14 @@ int uart_get_debug();
|
|||||||
void ICACHE_RAM_ATTR uart_interrupt_handler(uart_t* uart) {
|
void ICACHE_RAM_ATTR uart_interrupt_handler(uart_t* uart) {
|
||||||
|
|
||||||
// -------------- UART 0 --------------
|
// -------------- UART 0 --------------
|
||||||
uint32_t status = U0IS;
|
|
||||||
if(Serial.isRxEnabled()) {
|
if(Serial.isRxEnabled()) {
|
||||||
if(status & (1 << UIFF)) {
|
while(U0IS & (1 << UIFF)) {
|
||||||
while(true) {
|
Serial._rx_complete_irq((char)(U0F & 0xff));
|
||||||
int rx_count = (U0S >> USTXC) & 0xff;
|
|
||||||
if(!rx_count)
|
|
||||||
break;
|
|
||||||
|
|
||||||
while(rx_count--) {
|
|
||||||
char c = U0F & 0xff;
|
|
||||||
Serial._rx_complete_irq(c);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
U0IC = (1 << UIFF);
|
U0IC = (1 << UIFF);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(Serial.isTxEnabled()) {
|
if(Serial.isTxEnabled()) {
|
||||||
if(status & (1 << UIFE)) {
|
if(U0IS & (1 << UIFE)) {
|
||||||
U0IC = (1 << UIFE);
|
U0IC = (1 << UIFE);
|
||||||
Serial._tx_empty_irq();
|
Serial._tx_empty_irq();
|
||||||
}
|
}
|
||||||
@ -143,25 +133,14 @@ void ICACHE_RAM_ATTR uart_interrupt_handler(uart_t* uart) {
|
|||||||
|
|
||||||
// -------------- UART 1 --------------
|
// -------------- UART 1 --------------
|
||||||
|
|
||||||
status = U1IS;
|
|
||||||
if(Serial1.isRxEnabled()) {
|
if(Serial1.isRxEnabled()) {
|
||||||
if(status & (1 << UIFF)) {
|
while(U1IS & (1 << UIFF)) {
|
||||||
while(true) {
|
Serial1._rx_complete_irq((char)(U1F & 0xff));
|
||||||
int rx_count = (U1S >> USTXC) & 0xff;
|
|
||||||
if(!rx_count)
|
|
||||||
break;
|
|
||||||
|
|
||||||
while(rx_count--) {
|
|
||||||
char c = U1F & 0xff;
|
|
||||||
Serial1._rx_complete_irq(c);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
U1IC = (1 << UIFF);
|
U1IC = (1 << UIFF);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(Serial1.isTxEnabled()) {
|
if(Serial1.isTxEnabled()) {
|
||||||
status = U1IS;
|
if(U1IS & (1 << UIFE)) {
|
||||||
if(status & (1 << UIFE)) {
|
|
||||||
U1IC = (1 << UIFE);
|
U1IC = (1 << UIFE);
|
||||||
Serial1._tx_empty_irq();
|
Serial1._tx_empty_irq();
|
||||||
}
|
}
|
||||||
|
@ -30,6 +30,10 @@ void timer1_isr_handler(void *para){
|
|||||||
if(timer1_user_cb) timer1_user_cb();
|
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)) {
|
void timer1_attachInterrupt(void (*userFunc)(void)) {
|
||||||
timer1_user_cb = userFunc;
|
timer1_user_cb = userFunc;
|
||||||
ETS_FRC1_INTR_ENABLE();
|
ETS_FRC1_INTR_ENABLE();
|
||||||
@ -55,7 +59,3 @@ void timer1_disable(){
|
|||||||
T1C = 0;
|
T1C = 0;
|
||||||
T1I = 0;
|
T1I = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void timer1_isr_init(){
|
|
||||||
ETS_FRC_TIMER1_INTR_ATTACH(timer1_isr_handler, NULL);
|
|
||||||
}
|
|
@ -75,6 +75,7 @@ void delayMicroseconds(unsigned int us) {
|
|||||||
|
|
||||||
void init() {
|
void init() {
|
||||||
initPins();
|
initPins();
|
||||||
|
timer1_isr_init();
|
||||||
os_timer_setfn(µs_overflow_timer, (os_timer_func_t*) µs_overflow_tick, 0);
|
os_timer_setfn(µs_overflow_timer, (os_timer_func_t*) µs_overflow_tick, 0);
|
||||||
os_timer_arm(µs_overflow_timer, 60000, REPEAT);
|
os_timer_arm(µs_overflow_timer, 60000, REPEAT);
|
||||||
}
|
}
|
||||||
|
@ -33,13 +33,14 @@ uint16_t pwm_steps[17];
|
|||||||
uint8_t pwm_steps_len = 0;
|
uint8_t pwm_steps_len = 0;
|
||||||
uint32_t pwm_steps_mask[17];
|
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){
|
int pwm_sort_array(uint16_t a[], uint16_t al){
|
||||||
qsort(a, al, sizeof(uint16_t), pwm_sort_asc);
|
uint16_t i, j;
|
||||||
int i;
|
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;
|
int bl = 1;
|
||||||
for(i = 1; i < al; i++){
|
for(i = 1; i < al; i++){
|
||||||
if(a[i] != a[i-1]) a[bl++] = a[i];
|
if(a[i] != a[i-1]) a[bl++] = a[i];
|
||||||
@ -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 analogWrite(uint8_t pin, int val) __attribute__ ((weak, alias("__analogWrite")));
|
||||||
|
extern void analogWriteFreq(uint32_t freq) __attribute__ ((weak, alias("__analogWriteFreq")));
|
||||||
|
@ -175,6 +175,9 @@ char* ICACHE_FLASH_ATTR strtok_r(char * str, const char * delimiters, char ** te
|
|||||||
uint32_t size = 0;
|
uint32_t size = 0;
|
||||||
|
|
||||||
if(str == NULL) {
|
if(str == NULL) {
|
||||||
|
if(temp == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
start = *temp;
|
start = *temp;
|
||||||
} else {
|
} else {
|
||||||
start = str;
|
start = str;
|
||||||
@ -184,6 +187,10 @@ char* ICACHE_FLASH_ATTR strtok_r(char * str, const char * delimiters, char ** te
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(delimiters == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
end = start;
|
end = start;
|
||||||
|
|
||||||
while(1) {
|
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) {
|
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) {
|
int strcasecmp(const char * str1, const char * str2) {
|
||||||
|
@ -69,6 +69,5 @@ void setup(void){
|
|||||||
}
|
}
|
||||||
|
|
||||||
void loop(void){
|
void loop(void){
|
||||||
mdns.update();
|
|
||||||
server.handleClient();
|
server.handleClient();
|
||||||
}
|
}
|
||||||
|
@ -23,8 +23,10 @@
|
|||||||
File extensions with more than 3 charecters are not supported by the SD Library
|
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
|
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)
|
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 <ESP8266WiFi.h>
|
#include <ESP8266WiFi.h>
|
||||||
#include <WiFiClient.h>
|
#include <WiFiClient.h>
|
||||||
#include <ESP8266WebServer.h>
|
#include <ESP8266WebServer.h>
|
||||||
@ -32,8 +34,8 @@
|
|||||||
#include <SPI.h>
|
#include <SPI.h>
|
||||||
#include <SD.h>
|
#include <SD.h>
|
||||||
|
|
||||||
//do not go larger than 1460 bytes as that is the maximum that could fit in a packet
|
|
||||||
#define WWW_BUF_SIZE 1460
|
#define WWW_BUF_SIZE 1460
|
||||||
|
#define DBG_OUTPUT_PORT Serial
|
||||||
|
|
||||||
const char* ssid = "**********";
|
const char* ssid = "**********";
|
||||||
const char* password = "**********";
|
const char* password = "**********";
|
||||||
@ -45,31 +47,36 @@ ESP8266WebServer server(80);
|
|||||||
static bool hasSD = false;
|
static bool hasSD = false;
|
||||||
File uploadFile;
|
File uploadFile;
|
||||||
|
|
||||||
void handleFileUpload(){
|
void returnOK(){
|
||||||
if(server.uri() != "/upload") return;
|
WiFiClient client = server.client();
|
||||||
HTTPUpload upload = server.upload();
|
String message = "HTTP/1.1 200 OK\r\n";
|
||||||
if(upload.status == UPLOAD_FILE_START){
|
message += "Content-Type: text/plain\r\n";
|
||||||
Serial.print("Upload: START, filename:");
|
message += "Connection: close\r\n";
|
||||||
Serial.println(upload.filename);
|
message += "Access-Control-Allow-Origin: *\r\n";
|
||||||
if(SD.exists((char *)upload.filename.c_str())) SD.remove((char *)upload.filename.c_str());
|
message += "\r\n";
|
||||||
uploadFile = SD.open(upload.filename.c_str(), FILE_WRITE);
|
client.print(message);
|
||||||
} else if(upload.status == UPLOAD_FILE_WRITE){
|
message = 0;
|
||||||
Serial.print("Upload: WRITE, Bytes:");
|
client.stop();
|
||||||
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 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){
|
bool loadFromSdCard(String path){
|
||||||
String dataType = "text/plain";
|
String dataType = "text/plain";
|
||||||
//handle default index
|
|
||||||
if(path.endsWith("/")) path += "index.htm";
|
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("."));
|
if(path.endsWith(".src")) path = path.substring(0, path.lastIndexOf("."));
|
||||||
else if(path.endsWith(".htm")) dataType = "text/html";
|
else if(path.endsWith(".htm")) dataType = "text/html";
|
||||||
else if(path.endsWith(".css")) dataType = "text/css";
|
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(".pdf")) dataType = "application/pdf";
|
||||||
else if(path.endsWith(".zip")) dataType = "application/zip";
|
else if(path.endsWith(".zip")) dataType = "application/zip";
|
||||||
|
|
||||||
//Try to open the file
|
|
||||||
File dataFile = SD.open(path.c_str());
|
File dataFile = SD.open(path.c_str());
|
||||||
|
if(dataFile.isDirectory()){
|
||||||
//if it's a folder, try to open the default index
|
|
||||||
if(dataFile && dataFile.isDirectory()){
|
|
||||||
path += "/index.htm";
|
path += "/index.htm";
|
||||||
dataType = "text/html";
|
dataType = "text/html";
|
||||||
dataFile = SD.open(path.c_str());
|
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) {
|
if (dataFile) {
|
||||||
WiFiClient client = server.client();
|
WiFiClient client = server.client();
|
||||||
//send the file headers
|
|
||||||
String head = "HTTP/1.1 200 OK\r\nContent-Type: ";
|
String head = "HTTP/1.1 200 OK\r\nContent-Type: ";
|
||||||
head += dataType;
|
head += dataType;
|
||||||
head += "\r\nContent-Length: ";
|
head += "\r\nContent-Length: ";
|
||||||
head += dataFile.size();
|
head += dataFile.size();
|
||||||
|
head += "\r\nConnection: close";
|
||||||
|
head += "\r\nAccess-Control-Allow-Origin: *";
|
||||||
head += "\r\n\r\n";
|
head += "\r\n\r\n";
|
||||||
client.print(head);
|
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];
|
uint8_t obuf[WWW_BUF_SIZE];
|
||||||
|
|
||||||
while (dataFile.available() > WWW_BUF_SIZE){
|
while (dataFile.available() > WWW_BUF_SIZE){
|
||||||
dataFile.read(obuf, WWW_BUF_SIZE);
|
dataFile.read(obuf, WWW_BUF_SIZE);
|
||||||
if(client.write(obuf, WWW_BUF_SIZE) != 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();
|
dataFile.close();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//stream the last data left (size is at most WWW_BUF_SIZE bytes)
|
|
||||||
uint16_t leftLen = dataFile.available();
|
uint16_t leftLen = dataFile.available();
|
||||||
dataFile.read(obuf, leftLen);
|
dataFile.read(obuf, leftLen);
|
||||||
if(client.write(obuf, leftLen) != 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();
|
dataFile.close();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
dataFile.close();
|
dataFile.close();
|
||||||
|
client.stop();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void tryLoadFromSdCard(){
|
void handleFileUpload(){
|
||||||
String message = "FileNotFound\n\n";
|
if(server.uri() != "/edit") return;
|
||||||
if(hasSD){
|
HTTPUpload upload = server.upload();
|
||||||
//try to load the URL from SD Card
|
if(upload.status == UPLOAD_FILE_START){
|
||||||
if(loadFromSdCard(server.uri())) return;
|
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 {
|
} else {
|
||||||
message = "SDCARD Not Detected\n\n";
|
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 {
|
||||||
|
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<server.args(); i++){
|
||||||
|
message += " NAME:"+server.argName(i) + "\n VALUE:" + server.arg(i) + "\n";
|
||||||
}
|
}
|
||||||
server.send(404, "text/plain", message);
|
server.send(404, "text/plain", message);
|
||||||
|
DBG_OUTPUT_PORT.print(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
void setup(void){
|
void setup(void){
|
||||||
uint8_t i = 0;
|
DBG_OUTPUT_PORT.begin(115200);
|
||||||
Serial.begin(115200);
|
DBG_OUTPUT_PORT.setDebugOutput(true);
|
||||||
|
DBG_OUTPUT_PORT.print("\n");
|
||||||
//setup WiFi
|
|
||||||
WiFi.begin(ssid, password);
|
WiFi.begin(ssid, password);
|
||||||
Serial.print("\nConnecting to ");
|
DBG_OUTPUT_PORT.print("Connecting to ");
|
||||||
Serial.println(ssid);
|
DBG_OUTPUT_PORT.println(ssid);
|
||||||
|
|
||||||
//wait for WiFi to connect
|
// Wait for connection
|
||||||
while (WiFi.status() != WL_CONNECTED && i++ < 20) delay(500);
|
uint8_t i = 0;
|
||||||
|
while (WiFi.status() != WL_CONNECTED && i++ < 20) {//wait 10 seconds
|
||||||
//check if we have connected?
|
delay(500);
|
||||||
|
}
|
||||||
if(i == 21){
|
if(i == 21){
|
||||||
Serial.print("Could not connect to");
|
DBG_OUTPUT_PORT.print("Could not connect to");
|
||||||
Serial.println(ssid);
|
DBG_OUTPUT_PORT.println(ssid);
|
||||||
//stop execution and wait forever
|
|
||||||
while(1) delay(500);
|
while(1) delay(500);
|
||||||
}
|
}
|
||||||
Serial.print("Connected! IP address: ");
|
DBG_OUTPUT_PORT.print("Connected! IP address: ");
|
||||||
Serial.println(WiFi.localIP());
|
DBG_OUTPUT_PORT.println(WiFi.localIP());
|
||||||
|
/*
|
||||||
//start mDNS Server
|
|
||||||
if (mdns.begin(hostname, WiFi.localIP())) {
|
if (mdns.begin(hostname, WiFi.localIP())) {
|
||||||
Serial.println("MDNS responder started");
|
DBG_OUTPUT_PORT.println("MDNS responder started");
|
||||||
Serial.print("You can now connect to http://");
|
DBG_OUTPUT_PORT.print("You can now connect to http://");
|
||||||
Serial.print(hostname);
|
DBG_OUTPUT_PORT.print(hostname);
|
||||||
Serial.println(".local");
|
DBG_OUTPUT_PORT.println(".local");
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
//Attach handler
|
server.on("/list", HTTP_GET, printDirectory);
|
||||||
server.onNotFound(tryLoadFromSdCard);
|
server.on("/edit", HTTP_DELETE, handleDelete);
|
||||||
|
server.on("/edit", HTTP_PUT, handleCreate);
|
||||||
//Attach Upload handler
|
server.on("/edit", HTTP_POST, [](){ returnOK(); });
|
||||||
|
server.onNotFound(handleNotFound);
|
||||||
server.onFileUpload(handleFileUpload);
|
server.onFileUpload(handleFileUpload);
|
||||||
|
|
||||||
//Attach handler for the Upload location
|
|
||||||
server.on("/upload", HTTP_POST, [](){
|
|
||||||
WiFiClient client = server.client();
|
|
||||||
String message = "HTTP/1.1 200 OK\r\n";
|
|
||||||
message += "Content-Type: text/plain\r\n";
|
|
||||||
message += "Access-Control-Allow-Origin: *\r\n";
|
|
||||||
message += "\r\n";
|
|
||||||
client.print(message);
|
|
||||||
});
|
|
||||||
|
|
||||||
//start server
|
|
||||||
server.begin();
|
server.begin();
|
||||||
Serial.println("HTTP server started");
|
DBG_OUTPUT_PORT.println("HTTP server started");
|
||||||
|
|
||||||
//init SD Card
|
|
||||||
if (SD.begin(SS)){
|
if (SD.begin(SS)){
|
||||||
Serial.println("SD Card initialized.");
|
DBG_OUTPUT_PORT.println("SD Card initialized.");
|
||||||
hasSD = true;
|
hasSD = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void loop(void){
|
void loop(void){
|
||||||
mdns.update();
|
|
||||||
server.handleClient();
|
server.handleClient();
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,670 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<title>SD Editor</title>
|
||||||
|
<style type="text/css" media="screen">
|
||||||
|
.contextMenu {
|
||||||
|
z-index: 300;
|
||||||
|
position: absolute;
|
||||||
|
left: 5px;
|
||||||
|
border: 1px solid #444;
|
||||||
|
background-color: #F5F5F5;
|
||||||
|
display: none;
|
||||||
|
box-shadow: 0 0 10px rgba( 0, 0, 0, .4 );
|
||||||
|
font-size: 12px;
|
||||||
|
font-family: sans-serif;
|
||||||
|
font-weight:bold;
|
||||||
|
}
|
||||||
|
.contextMenu ul {
|
||||||
|
list-style: none;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
.contextMenu li {
|
||||||
|
position: relative;
|
||||||
|
min-width: 60px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
.contextMenu span {
|
||||||
|
color: #444;
|
||||||
|
display: inline-block;
|
||||||
|
padding: 6px;
|
||||||
|
}
|
||||||
|
.contextMenu li:hover { background: #444; }
|
||||||
|
.contextMenu li:hover span { color: #EEE; }
|
||||||
|
|
||||||
|
.css-treeview ul, .css-treeview li {
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
list-style: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.css-treeview input {
|
||||||
|
position: absolute;
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.css-treeview {
|
||||||
|
font: normal 11px Verdana, Arial, Sans-serif;
|
||||||
|
-moz-user-select: none;
|
||||||
|
-webkit-user-select: none;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.css-treeview span {
|
||||||
|
color: #00f;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.css-treeview span:hover {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
.css-treeview input + label + ul {
|
||||||
|
margin: 0 0 0 22px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.css-treeview input ~ ul {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.css-treeview label, .css-treeview label::before {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.css-treeview input:disabled + label {
|
||||||
|
cursor: default;
|
||||||
|
opacity: .6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.css-treeview input:checked:not(:disabled) ~ ul {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.css-treeview label, .css-treeview label::before {
|
||||||
|
background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAACgCAYAAAAFOewUAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAApxJREFUeNrslM1u00AQgGdthyalFFOK+ClIIKQKyqUVQvTEE3DmAhLwAhU8QZoH4A2Q2gMSFace4MCtJ8SPBFwAkRuiHKpA6sRN/Lu7zG5i14kctaUqRGhGXnu9O/Pt7MzsMiklvF+9t2kWTDvyIrAsA0aKRRi1T0C/hJ4LUbt5/8rNpWVlp8RSr9J40b48fxFaTQ9+ft8EZ6MJYb0Ok+dnYGpmPgXwKIAvLx8vYXc5GdMAQJgQEkpjRTh36TS2U+DWW/D17WuYgm8pwJyY1npZsZKOxImOV1I/h4+O6vEg5GCZBpgmA6hX8wHKUHDRBXQYicQ4rlc3Tf0VMs8DHBS864F2YFspjgUYjKX/Az3gsdQd2eeBHwmdGWXHcgBGSkZXOXohcEXebRoQcAgjqediNY+AVyu3Z3sAKqfKoGMsewBeEIOPgQxxPJIjcGH6qtL/0AdADzKGnuuD+2tLK7Q8DhHHbOBW+KEzcHLuYc82MkEUekLiwuvVH+guQBQzOG4XdAb8EOcRcqQvDkY2iCLuxECJ43JobMXoutqGgDa2T7UqLKwt9KRyuxKVByqVXXqIoCCUCAqhUOioTWC7G4TQEOD0APy2/7G2Xpu1J4+lxeQ4TXBbITDpoVelRN/BVFbwu5oMMJUBhoXy5tmdRcMwymP2OLQaLjx9/vnBo6V3K6izATmSnMa0Dq7ferIohJhr1p01zrlz49rZF4OMs8JkX23vVQzYp+wbYGV/KpXKjvspl8tsIKCrMNAYFxj2GKS5ZWxg4ewKsJfaGMIY5KXqPz8LBBj6+yDvVP79+yDp/9F9oIx3OisHWwe7Oal0HxCAAAQgAAEIQAACEIAABCAAAQhAAAIQgAAEIAABCEAAAhCAAAQgwD8E/BZgAP0qhKj3rXO7AAAAAElFTkSuQmCC") no-repeat;
|
||||||
|
}
|
||||||
|
|
||||||
|
.css-treeview label, .css-treeview span, .css-treeview label::before {
|
||||||
|
display: inline-block;
|
||||||
|
height: 16px;
|
||||||
|
line-height: 16px;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
|
||||||
|
.css-treeview label {
|
||||||
|
background-position: 18px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.css-treeview label::before {
|
||||||
|
content: "";
|
||||||
|
width: 16px;
|
||||||
|
margin: 0 22px 0 0;
|
||||||
|
vertical-align: middle;
|
||||||
|
background-position: 0 -32px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.css-treeview input:checked + label::before {
|
||||||
|
background-position: 0 -16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* webkit adjacent element selector bugfix */
|
||||||
|
@media screen and (-webkit-min-device-pixel-ratio:0)
|
||||||
|
{
|
||||||
|
.css-treeview{
|
||||||
|
-webkit-animation: webkit-adjacent-element-selector-bugfix infinite 1s;
|
||||||
|
}
|
||||||
|
|
||||||
|
@-webkit-keyframes webkit-adjacent-element-selector-bugfix
|
||||||
|
{
|
||||||
|
from {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#uploader {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
left: 0;
|
||||||
|
height:28px;
|
||||||
|
line-height: 24px;
|
||||||
|
padding-left: 10px;
|
||||||
|
background-color: #444;
|
||||||
|
color:#EEE;
|
||||||
|
}
|
||||||
|
#tree {
|
||||||
|
position: absolute;
|
||||||
|
top: 28px;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
width:200px;
|
||||||
|
padding: 8px;
|
||||||
|
}
|
||||||
|
#editor, #preview {
|
||||||
|
position: absolute;
|
||||||
|
top: 28px;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
left: 200px;
|
||||||
|
}
|
||||||
|
#preview {
|
||||||
|
background-color: #EEE;
|
||||||
|
padding:5px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<script>
|
||||||
|
function createFileUploader(element, tree, editor){
|
||||||
|
var xmlHttp;
|
||||||
|
var input = document.createElement("input");
|
||||||
|
input.type = "file";
|
||||||
|
input.multiple = false;
|
||||||
|
input.name = "data";
|
||||||
|
document.getElementById(element).appendChild(input);
|
||||||
|
var path = document.createElement("input");
|
||||||
|
path.id = "upload-path";
|
||||||
|
path.type = "text";
|
||||||
|
path.name = "path";
|
||||||
|
path.defaultValue = "/";
|
||||||
|
document.getElementById(element).appendChild(path);
|
||||||
|
var button = document.createElement("button");
|
||||||
|
button.innerHTML = 'Upload';
|
||||||
|
document.getElementById(element).appendChild(button);
|
||||||
|
var mkdir = document.createElement("button");
|
||||||
|
mkdir.innerHTML = 'MkDir';
|
||||||
|
document.getElementById(element).appendChild(mkdir);
|
||||||
|
var mkfile = document.createElement("button");
|
||||||
|
mkfile.innerHTML = 'MkFile';
|
||||||
|
document.getElementById(element).appendChild(mkfile);
|
||||||
|
|
||||||
|
function httpPostProcessRequest(){
|
||||||
|
if (xmlHttp.readyState == 4){
|
||||||
|
if(xmlHttp.status != 200) alert("ERROR["+xmlHttp.status+"]: "+xmlHttp.responseText);
|
||||||
|
else {
|
||||||
|
tree.refreshPath(path.value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function createPath(p){
|
||||||
|
xmlHttp = new XMLHttpRequest();
|
||||||
|
xmlHttp.onreadystatechange = httpPostProcessRequest;
|
||||||
|
var formData = new FormData();
|
||||||
|
formData.append("path", p);
|
||||||
|
xmlHttp.open("PUT", "/edit");
|
||||||
|
xmlHttp.send(formData);
|
||||||
|
}
|
||||||
|
|
||||||
|
mkfile.onclick = function(e){
|
||||||
|
if(path.value.indexOf(".") === -1) return;
|
||||||
|
createPath(path.value);
|
||||||
|
editor.loadUrl(path.value);
|
||||||
|
};
|
||||||
|
mkdir.onclick = function(e){
|
||||||
|
if(path.value.length < 2) return;
|
||||||
|
var dir = path.value
|
||||||
|
if(dir.indexOf(".") !== -1){
|
||||||
|
if(dir.lastIndexOf("/") === 0) return;
|
||||||
|
dir = dir.substring(0, dir.lastIndexOf("/"));
|
||||||
|
}
|
||||||
|
createPath(dir);
|
||||||
|
};
|
||||||
|
button.onclick = function(e){
|
||||||
|
if(input.files.length === 0){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
xmlHttp = new XMLHttpRequest();
|
||||||
|
xmlHttp.onreadystatechange = httpPostProcessRequest;
|
||||||
|
var formData = new FormData();
|
||||||
|
formData.append("data", input.files[0], path.value);
|
||||||
|
xmlHttp.open("POST", "/edit");
|
||||||
|
xmlHttp.send(formData);
|
||||||
|
}
|
||||||
|
input.onchange = function(e){
|
||||||
|
if(input.files.length === 0) return;
|
||||||
|
var filename = input.files[0].name;
|
||||||
|
var ext = /(?:\.([^.]+))?$/.exec(filename)[1];
|
||||||
|
var name = /(.*)\.[^.]+$/.exec(filename)[1];
|
||||||
|
if(typeof name !== undefined){
|
||||||
|
if(name.length > 8) name = name.substring(0, 8);
|
||||||
|
filename = name;
|
||||||
|
}
|
||||||
|
if(typeof ext !== undefined){
|
||||||
|
if(ext === "html") ext = "htm";
|
||||||
|
else if(ext === "jpeg") ext = "jpg";
|
||||||
|
filename = filename + "." + ext;
|
||||||
|
}
|
||||||
|
if(path.value === "/" || path.value.lastIndexOf("/") === 0){
|
||||||
|
path.value = "/"+filename;
|
||||||
|
} else {
|
||||||
|
path.value = path.value.substring(0, path.value.lastIndexOf("/")+1)+filename;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function createTree(element, editor){
|
||||||
|
var preview = document.getElementById("preview");
|
||||||
|
var treeRoot = document.createElement("div");
|
||||||
|
treeRoot.className = "css-treeview";
|
||||||
|
document.getElementById(element).appendChild(treeRoot);
|
||||||
|
|
||||||
|
function loadDownload(path){
|
||||||
|
document.getElementById('download-frame').src = path+"?download=true";
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadPreview(path){
|
||||||
|
document.getElementById("editor").style.display = "none";
|
||||||
|
preview.style.display = "block";
|
||||||
|
preview.innerHTML = '<img src="'+path+'" style="max-width:100%; max-height:100%; margin:auto; display:block;" />';
|
||||||
|
}
|
||||||
|
|
||||||
|
function fillFolderMenu(el, path){
|
||||||
|
var list = document.createElement("ul");
|
||||||
|
el.appendChild(list);
|
||||||
|
var action = document.createElement("li");
|
||||||
|
list.appendChild(action);
|
||||||
|
var isChecked = document.getElementById(path).checked;
|
||||||
|
var expnd = document.createElement("li");
|
||||||
|
list.appendChild(expnd);
|
||||||
|
if(isChecked){
|
||||||
|
expnd.innerHTML = "<span>Collapse</span>";
|
||||||
|
expnd.onclick = function(e){
|
||||||
|
document.getElementById(path).checked = false;
|
||||||
|
if(document.body.getElementsByClassName('contextMenu').length > 0) document.body.removeChild(el);
|
||||||
|
};
|
||||||
|
var refrsh = document.createElement("li");
|
||||||
|
list.appendChild(refrsh);
|
||||||
|
refrsh.innerHTML = "<span>Refresh</span>";
|
||||||
|
refrsh.onclick = function(e){
|
||||||
|
var leaf = document.getElementById(path).parentNode;
|
||||||
|
if(leaf.childNodes.length == 3) leaf.removeChild(leaf.childNodes[2]);
|
||||||
|
httpGet(leaf, path);
|
||||||
|
if(document.body.getElementsByClassName('contextMenu').length > 0) document.body.removeChild(el);
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
expnd.innerHTML = "<span>Expand</span>";
|
||||||
|
expnd.onclick = function(e){
|
||||||
|
document.getElementById(path).checked = true;
|
||||||
|
var leaf = document.getElementById(path).parentNode;
|
||||||
|
if(leaf.childNodes.length == 3) leaf.removeChild(leaf.childNodes[2]);
|
||||||
|
httpGet(leaf, path);
|
||||||
|
if(document.body.getElementsByClassName('contextMenu').length > 0) document.body.removeChild(el);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
var upload = document.createElement("li");
|
||||||
|
list.appendChild(upload);
|
||||||
|
upload.innerHTML = "<span>Upload</span>";
|
||||||
|
upload.onclick = function(e){
|
||||||
|
var pathEl = document.getElementById("upload-path");
|
||||||
|
if(pathEl){
|
||||||
|
var subPath = pathEl.value;
|
||||||
|
if(subPath.lastIndexOf("/") < 1) pathEl.value = path+subPath;
|
||||||
|
else pathEl.value = path.substring(subPath.lastIndexOf("/"))+subPath;
|
||||||
|
}
|
||||||
|
if(document.body.getElementsByClassName('contextMenu').length > 0) document.body.removeChild(el);
|
||||||
|
};
|
||||||
|
var delFile = document.createElement("li");
|
||||||
|
list.appendChild(delFile);
|
||||||
|
delFile.innerHTML = "<span>Delete</span>";
|
||||||
|
delFile.onclick = function(e){
|
||||||
|
httpDelete(path);
|
||||||
|
if(document.body.getElementsByClassName('contextMenu').length > 0) document.body.removeChild(el);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function fillFileMenu(el, path){
|
||||||
|
var list = document.createElement("ul");
|
||||||
|
el.appendChild(list);
|
||||||
|
var action = document.createElement("li");
|
||||||
|
list.appendChild(action);
|
||||||
|
if(isTextFile(path)){
|
||||||
|
action.innerHTML = "<span>Edit</span>";
|
||||||
|
action.onclick = function(e){
|
||||||
|
editor.loadUrl(path);
|
||||||
|
if(document.body.getElementsByClassName('contextMenu').length > 0) document.body.removeChild(el);
|
||||||
|
};
|
||||||
|
} else if(isImageFile(path)){
|
||||||
|
action.innerHTML = "<span>Preview</span>";
|
||||||
|
action.onclick = function(e){
|
||||||
|
loadPreview(path);
|
||||||
|
if(document.body.getElementsByClassName('contextMenu').length > 0) document.body.removeChild(el);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
var download = document.createElement("li");
|
||||||
|
list.appendChild(download);
|
||||||
|
download.innerHTML = "<span>Download</span>";
|
||||||
|
download.onclick = function(e){
|
||||||
|
loadDownload(path);
|
||||||
|
if(document.body.getElementsByClassName('contextMenu').length > 0) document.body.removeChild(el);
|
||||||
|
};
|
||||||
|
var delFile = document.createElement("li");
|
||||||
|
list.appendChild(delFile);
|
||||||
|
delFile.innerHTML = "<span>Delete</span>";
|
||||||
|
delFile.onclick = function(e){
|
||||||
|
httpDelete(path);
|
||||||
|
if(document.body.getElementsByClassName('contextMenu').length > 0) document.body.removeChild(el);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function showContextMenu(e, path, isfile){
|
||||||
|
var divContext = document.createElement("div");
|
||||||
|
var scrollTop = document.body.scrollTop ? document.body.scrollTop : document.documentElement.scrollTop;
|
||||||
|
var scrollLeft = document.body.scrollLeft ? document.body.scrollLeft : document.documentElement.scrollLeft;
|
||||||
|
var left = event.clientX + scrollLeft;
|
||||||
|
var top = event.clientY + scrollTop;
|
||||||
|
divContext.className = 'contextMenu';
|
||||||
|
divContext.style.display = 'block';
|
||||||
|
divContext.style.left = left + 'px';
|
||||||
|
divContext.style.top = top + 'px';
|
||||||
|
if(isfile) fillFileMenu(divContext, path);
|
||||||
|
else fillFolderMenu(divContext, path);
|
||||||
|
document.body.appendChild(divContext);
|
||||||
|
var width = divContext.offsetWidth;
|
||||||
|
var height = divContext.offsetHeight;
|
||||||
|
divContext.onmouseout = function(e){
|
||||||
|
if(e.clientX < left || e.clientX > (left + width) || e.clientY < top || e.clientY > (top + height)){
|
||||||
|
if(document.body.getElementsByClassName('contextMenu').length > 0) document.body.removeChild(divContext);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function createTreeLeaf(path, name, size){
|
||||||
|
var leaf = document.createElement("li");
|
||||||
|
leaf.id = (((path == "/")?"":path)+"/"+name).toLowerCase();
|
||||||
|
var label = document.createElement("span");
|
||||||
|
label.innerText = name.toLowerCase();
|
||||||
|
leaf.appendChild(label);
|
||||||
|
leaf.onclick = function(e){
|
||||||
|
if(isTextFile(leaf.id)){
|
||||||
|
editor.loadUrl(leaf.id);
|
||||||
|
} else if(isImageFile(leaf.id)){
|
||||||
|
loadPreview(leaf.id);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
leaf.oncontextmenu = function(e){
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
showContextMenu(e, leaf.id, true);
|
||||||
|
};
|
||||||
|
return leaf;
|
||||||
|
}
|
||||||
|
|
||||||
|
function createTreeBranch(path, name, disabled){
|
||||||
|
var leaf = document.createElement("li");
|
||||||
|
var check = document.createElement("input");
|
||||||
|
check.type = "checkbox";
|
||||||
|
check.id = (((path == "/")?"":path)+"/"+name).toLowerCase();
|
||||||
|
if(typeof disabled !== "undefined" && disabled) check.disabled = "disabled";
|
||||||
|
leaf.appendChild(check);
|
||||||
|
var label = document.createElement("label");
|
||||||
|
label.for = check.id;
|
||||||
|
label.innerText = name.toLowerCase();
|
||||||
|
leaf.appendChild(label);
|
||||||
|
check.onchange = function(e){
|
||||||
|
if(check.checked){
|
||||||
|
if(leaf.childNodes.length == 3) leaf.removeChild(leaf.childNodes[2]);
|
||||||
|
httpGet(leaf, check.id);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
label.onclick = function(e){
|
||||||
|
if(!check.checked){
|
||||||
|
check.checked = true;
|
||||||
|
if(leaf.childNodes.length == 3) leaf.removeChild(leaf.childNodes[2]);
|
||||||
|
httpGet(leaf, check.id);
|
||||||
|
} else {
|
||||||
|
check.checked = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
leaf.oncontextmenu = function(e){
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
showContextMenu(e, check.id, false);
|
||||||
|
}
|
||||||
|
return leaf;
|
||||||
|
}
|
||||||
|
|
||||||
|
function addList(parent, path, items){
|
||||||
|
var list = document.createElement("ul");
|
||||||
|
parent.appendChild(list);
|
||||||
|
var ll = items.length;
|
||||||
|
for(var i = 0; i < ll; i++){
|
||||||
|
var item = items[i];
|
||||||
|
var itemEl;
|
||||||
|
if(item.type === "file"){
|
||||||
|
itemEl = createTreeLeaf(path, item.name, item.size);
|
||||||
|
} else {
|
||||||
|
itemEl = createTreeBranch(path, item.name);
|
||||||
|
}
|
||||||
|
list.appendChild(itemEl);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function isTextFile(path){
|
||||||
|
var ext = /(?:\.([^.]+))?$/.exec(path)[1];
|
||||||
|
if(typeof ext !== undefined){
|
||||||
|
switch(ext){
|
||||||
|
case "txt":
|
||||||
|
case "htm":
|
||||||
|
case "js":
|
||||||
|
case "c":
|
||||||
|
case "cpp":
|
||||||
|
case "css":
|
||||||
|
case "xml":
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function isImageFile(path){
|
||||||
|
var ext = /(?:\.([^.]+))?$/.exec(path)[1];
|
||||||
|
if(typeof ext !== undefined){
|
||||||
|
switch(ext){
|
||||||
|
case "png":
|
||||||
|
case "jpg":
|
||||||
|
case "gif":
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.refreshPath = function(path){
|
||||||
|
if(path.lastIndexOf('/') < 1){
|
||||||
|
path = '/';
|
||||||
|
treeRoot.removeChild(treeRoot.childNodes[0]);
|
||||||
|
httpGet(treeRoot, "/");
|
||||||
|
} else {
|
||||||
|
path = path.substring(0, path.lastIndexOf('/'));
|
||||||
|
var leaf = document.getElementById(path).parentNode;
|
||||||
|
if(leaf.childNodes.length == 3) leaf.removeChild(leaf.childNodes[2]);
|
||||||
|
httpGet(leaf, path);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
function delCb(path){
|
||||||
|
return function(){
|
||||||
|
if (xmlHttp.readyState == 4){
|
||||||
|
if(xmlHttp.status != 200){
|
||||||
|
alert("ERROR["+xmlHttp.status+"]: "+xmlHttp.responseText);
|
||||||
|
} else {
|
||||||
|
if(path.lastIndexOf('/') < 1){
|
||||||
|
path = '/';
|
||||||
|
treeRoot.removeChild(treeRoot.childNodes[0]);
|
||||||
|
httpGet(treeRoot, "/");
|
||||||
|
} else {
|
||||||
|
path = path.substring(0, path.lastIndexOf('/'));
|
||||||
|
var leaf = document.getElementById(path).parentNode;
|
||||||
|
if(leaf.childNodes.length == 3) leaf.removeChild(leaf.childNodes[2]);
|
||||||
|
httpGet(leaf, path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function httpDelete(filename){
|
||||||
|
xmlHttp = new XMLHttpRequest();
|
||||||
|
xmlHttp.onreadystatechange = delCb(filename);
|
||||||
|
var formData = new FormData();
|
||||||
|
formData.append("path", filename);
|
||||||
|
xmlHttp.open("DELETE", "/edit");
|
||||||
|
xmlHttp.send(formData);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getCb(parent, path){
|
||||||
|
return function(){
|
||||||
|
if (xmlHttp.readyState == 4){
|
||||||
|
//clear loading
|
||||||
|
if(xmlHttp.status == 200) addList(parent, path, JSON.parse(xmlHttp.responseText));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function httpGet(parent, path){
|
||||||
|
xmlHttp = new XMLHttpRequest(parent, path);
|
||||||
|
xmlHttp.onreadystatechange = getCb(parent, path);
|
||||||
|
xmlHttp.open("GET", "/list?dir="+path, true);
|
||||||
|
xmlHttp.send(null);
|
||||||
|
//start loading
|
||||||
|
}
|
||||||
|
|
||||||
|
httpGet(treeRoot, "/");
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
function createEditor(element, file, lang, theme, type){
|
||||||
|
function getLangFromFilename(filename){
|
||||||
|
var lang = "plain";
|
||||||
|
var ext = /(?:\.([^.]+))?$/.exec(filename)[1];
|
||||||
|
if(typeof ext !== undefined){
|
||||||
|
switch(ext){
|
||||||
|
case "txt": lang = "plain"; break;
|
||||||
|
case "htm": lang = "html"; break;
|
||||||
|
case "js": lang = "javascript"; break;
|
||||||
|
case "c": lang = "c_cpp"; break;
|
||||||
|
case "cpp": lang = "c_cpp"; break;
|
||||||
|
case "css":
|
||||||
|
case "scss":
|
||||||
|
case "php":
|
||||||
|
case "html":
|
||||||
|
case "json":
|
||||||
|
case "xml":
|
||||||
|
lang = ext;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return lang;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(typeof file === "undefined") file = "/index.htm";
|
||||||
|
|
||||||
|
if(typeof lang === "undefined"){
|
||||||
|
lang = getLangFromFilename(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(typeof theme === "undefined") theme = "textmate";
|
||||||
|
|
||||||
|
if(typeof type === "undefined"){
|
||||||
|
type = "text/"+lang;
|
||||||
|
if(lang === "c_cpp") type = "text/plain";
|
||||||
|
}
|
||||||
|
|
||||||
|
var xmlHttp = null;
|
||||||
|
var editor = ace.edit(element);
|
||||||
|
|
||||||
|
//post
|
||||||
|
function httpPostProcessRequest(){
|
||||||
|
if (xmlHttp.readyState == 4){
|
||||||
|
if(xmlHttp.status != 200) alert("ERROR["+xmlHttp.status+"]: "+xmlHttp.responseText);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function httpPost(filename, data, type){
|
||||||
|
xmlHttp = new XMLHttpRequest();
|
||||||
|
xmlHttp.onreadystatechange = httpPostProcessRequest;
|
||||||
|
var formData = new FormData();
|
||||||
|
formData.append("data", new Blob([data], { type: type }), filename);
|
||||||
|
xmlHttp.open("POST", "/edit");
|
||||||
|
xmlHttp.send(formData);
|
||||||
|
}
|
||||||
|
//get
|
||||||
|
function httpGetProcessRequest(){
|
||||||
|
if (xmlHttp.readyState == 4){
|
||||||
|
document.getElementById("preview").style.display = "none";
|
||||||
|
document.getElementById("editor").style.display = "block";
|
||||||
|
if(xmlHttp.status == 200) editor.setValue(xmlHttp.responseText);
|
||||||
|
else editor.setValue("");
|
||||||
|
editor.clearSelection();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function httpGet(theUrl){
|
||||||
|
xmlHttp = new XMLHttpRequest();
|
||||||
|
xmlHttp.onreadystatechange = httpGetProcessRequest;
|
||||||
|
xmlHttp.open("GET", theUrl, true);
|
||||||
|
xmlHttp.send(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(lang !== "plain") editor.getSession().setMode("ace/mode/"+lang);
|
||||||
|
editor.setTheme("ace/theme/"+theme);
|
||||||
|
editor.$blockScrolling = Infinity;
|
||||||
|
editor.getSession().setUseSoftTabs(true);
|
||||||
|
editor.getSession().setTabSize(2);
|
||||||
|
editor.setHighlightActiveLine(true);
|
||||||
|
editor.setShowPrintMargin(false);
|
||||||
|
editor.commands.addCommand({
|
||||||
|
name: 'saveCommand',
|
||||||
|
bindKey: {win: 'Ctrl-S', mac: 'Command-S'},
|
||||||
|
exec: function(editor) {
|
||||||
|
httpPost(file, editor.getValue()+"", type);
|
||||||
|
},
|
||||||
|
readOnly: false
|
||||||
|
});
|
||||||
|
editor.commands.addCommand({
|
||||||
|
name: 'undoCommand',
|
||||||
|
bindKey: {win: 'Ctrl-Z', mac: 'Command-Z'},
|
||||||
|
exec: function(editor) {
|
||||||
|
editor.getSession().getUndoManager().undo(false);
|
||||||
|
},
|
||||||
|
readOnly: false
|
||||||
|
});
|
||||||
|
editor.commands.addCommand({
|
||||||
|
name: 'redoCommand',
|
||||||
|
bindKey: {win: 'Ctrl-Shift-Z', mac: 'Command-Shift-Z'},
|
||||||
|
exec: function(editor) {
|
||||||
|
editor.getSession().getUndoManager().redo(false);
|
||||||
|
},
|
||||||
|
readOnly: false
|
||||||
|
});
|
||||||
|
httpGet(file);
|
||||||
|
editor.loadUrl = function(filename){
|
||||||
|
file = filename;
|
||||||
|
lang = getLangFromFilename(file);
|
||||||
|
type = "text/"+lang;
|
||||||
|
if(lang !== "plain") editor.getSession().setMode("ace/mode/"+lang);
|
||||||
|
httpGet(file);
|
||||||
|
}
|
||||||
|
return editor;
|
||||||
|
}
|
||||||
|
function onBodyLoad(){
|
||||||
|
var vars = {};
|
||||||
|
var parts = window.location.href.replace(/[?&]+([^=&]+)=([^&]*)/gi, function(m,key,value) { vars[key] = value; });
|
||||||
|
var editor = createEditor("editor", vars.file, vars.lang, vars.theme);
|
||||||
|
var tree = createTree("tree", editor);
|
||||||
|
createFileUploader("uploader", tree, editor);
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.1.9/ace.js" type="text/javascript" charset="utf-8"></script>
|
||||||
|
</head>
|
||||||
|
<body onload="onBodyLoad();">
|
||||||
|
<div id="uploader"></div>
|
||||||
|
<div id="tree"></div>
|
||||||
|
<div id="editor"></div>
|
||||||
|
<div id="preview" style="display:none;"></div>
|
||||||
|
<iframe id=download-frame style='display:none;'></iframe>
|
||||||
|
</body>
|
||||||
|
</html>
|
@ -0,0 +1,22 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta http-equiv="Content-type" content="text/html; charset=utf-8">
|
||||||
|
<title>ESP Index</title>
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
background-color:black;
|
||||||
|
color:white;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<script type="text/javascript">
|
||||||
|
function onBodyLoad(){
|
||||||
|
console.log("we are loaded!!");
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
<body id="index" onload="onBodyLoad()">
|
||||||
|
<h1>ESP8266 Pin Functions</h1>
|
||||||
|
<img src="pins.png" />
|
||||||
|
</body>
|
||||||
|
</html>
|
BIN
libraries/ESP8266WebServer/examples/SDWebServer/SdRoot/pins.png
Normal file
BIN
libraries/ESP8266WebServer/examples/SDWebServer/SdRoot/pins.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 174 KiB |
@ -152,7 +152,7 @@ void ESP8266WebServer::handleClient()
|
|||||||
|
|
||||||
String formData;
|
String formData;
|
||||||
//bellow is needed only when POST type request
|
//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 boundaryStr;
|
||||||
String headerName;
|
String headerName;
|
||||||
String headerValue;
|
String headerValue;
|
||||||
@ -391,7 +391,8 @@ void ESP8266WebServer::_parseForm(WiFiClient& client, String boundary, uint32_t
|
|||||||
line = client.readStringUntil('\r');
|
line = client.readStringUntil('\r');
|
||||||
client.readStringUntil('\n');
|
client.readStringUntil('\n');
|
||||||
if(line.startsWith("--"+boundary)) break;
|
if(line.startsWith("--"+boundary)) break;
|
||||||
argValue += line+"\n";
|
if(argValue.length() > 0) argValue += "\n";
|
||||||
|
argValue += line;
|
||||||
}
|
}
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
DEBUG_OUTPUT.print("PostArg Value: ");
|
DEBUG_OUTPUT.print("PostArg Value: ");
|
||||||
@ -441,8 +442,6 @@ readfile:
|
|||||||
|
|
||||||
argByte = client.read();
|
argByte = client.read();
|
||||||
if(argByte == 0x0A){
|
if(argByte == 0x0A){
|
||||||
line = client.readStringUntil(0x0D);
|
|
||||||
client.readStringUntil(0x0A);
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
DEBUG_OUTPUT.print("Write File: ");
|
DEBUG_OUTPUT.print("Write File: ");
|
||||||
DEBUG_OUTPUT.println(_currentUpload.buflen);
|
DEBUG_OUTPUT.println(_currentUpload.buflen);
|
||||||
@ -450,7 +449,28 @@ readfile:
|
|||||||
if(_fileUploadHandler) _fileUploadHandler();
|
if(_fileUploadHandler) _fileUploadHandler();
|
||||||
_currentUpload.size += _currentUpload.buflen;
|
_currentUpload.size += _currentUpload.buflen;
|
||||||
_currentUpload.buflen = 0;
|
_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;
|
_currentUpload.status = UPLOAD_FILE_END;
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
DEBUG_OUTPUT.print("End File: ");
|
DEBUG_OUTPUT.print("End File: ");
|
||||||
@ -461,7 +481,9 @@ readfile:
|
|||||||
DEBUG_OUTPUT.println(_currentUpload.size);
|
DEBUG_OUTPUT.println(_currentUpload.size);
|
||||||
#endif
|
#endif
|
||||||
if(_fileUploadHandler) _fileUploadHandler();
|
if(_fileUploadHandler) _fileUploadHandler();
|
||||||
if(line == ("--"+boundary+"--")){
|
line = client.readStringUntil(0x0D);
|
||||||
|
client.readStringUntil(0x0A);
|
||||||
|
if(line == "--"){
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
DEBUG_OUTPUT.println("Done Parsing POST");
|
DEBUG_OUTPUT.println("Done Parsing POST");
|
||||||
#endif
|
#endif
|
||||||
@ -471,10 +493,9 @@ readfile:
|
|||||||
} else {
|
} else {
|
||||||
_currentUpload.buf[_currentUpload.buflen++] = 0x0D;
|
_currentUpload.buf[_currentUpload.buflen++] = 0x0D;
|
||||||
_currentUpload.buf[_currentUpload.buflen++] = 0x0A;
|
_currentUpload.buf[_currentUpload.buflen++] = 0x0A;
|
||||||
const char * lineChars = line.c_str();
|
|
||||||
uint32_t i = 0;
|
uint32_t i = 0;
|
||||||
while(i < os_strlen(lineChars)){
|
while(i < boundary.length()){
|
||||||
_currentUpload.buf[_currentUpload.buflen++] = lineChars[i++];
|
_currentUpload.buf[_currentUpload.buflen++] = endBuf[i++];
|
||||||
if(_currentUpload.buflen == 1460){
|
if(_currentUpload.buflen == 1460){
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
DEBUG_OUTPUT.println("Write File: 1460");
|
DEBUG_OUTPUT.println("Write File: 1460");
|
||||||
|
@ -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 <ESP8266WiFi.h>
|
||||||
|
|
||||||
|
//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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -73,8 +73,24 @@ void WiFiServer::begin()
|
|||||||
tcp_arg(listen_pcb, (void*) this);
|
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();
|
extern "C" uint32_t esp_micros_at_task_start();
|
||||||
|
|
||||||
|
bool WiFiServer::hasClient(){
|
||||||
|
if (_unclaimed) return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
WiFiClient WiFiServer::available(byte* status)
|
WiFiClient WiFiServer::available(byte* status)
|
||||||
{
|
{
|
||||||
static uint32_t lastPollTime = 0;
|
static uint32_t lastPollTime = 0;
|
||||||
|
@ -44,7 +44,10 @@ private:
|
|||||||
public:
|
public:
|
||||||
WiFiServer(uint16_t port);
|
WiFiServer(uint16_t port);
|
||||||
WiFiClient available(uint8_t* status = NULL);
|
WiFiClient available(uint8_t* status = NULL);
|
||||||
|
bool hasClient();
|
||||||
void begin();
|
void begin();
|
||||||
|
void setNoDelay(bool nodelay);
|
||||||
|
bool getNoDelay();
|
||||||
virtual size_t write(uint8_t);
|
virtual size_t write(uint8_t);
|
||||||
virtual size_t write(const uint8_t *buf, size_t size);
|
virtual size_t write(const uint8_t *buf, size_t size);
|
||||||
uint8_t status();
|
uint8_t status();
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#define LWIP_INTERNAL
|
#define LWIP_INTERNAL
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
extern "C"
|
extern "C"
|
||||||
{
|
{
|
||||||
@ -168,7 +169,6 @@ int WiFiUDP::endPacket()
|
|||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
_ctx->send();
|
_ctx->send();
|
||||||
_ctx->disconnect();
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -40,6 +40,38 @@ class ClientContext {
|
|||||||
tcp_err(pcb, &_s_error);
|
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() {
|
~ClientContext() {
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -58,26 +90,26 @@ class ClientContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void unref() {
|
void unref() {
|
||||||
err_t err;
|
|
||||||
DEBUGV(":ur %d\r\n", _refcnt);
|
DEBUGV(":ur %d\r\n", _refcnt);
|
||||||
if(--_refcnt == 0) {
|
if(--_refcnt == 0) {
|
||||||
flush();
|
flush();
|
||||||
if(_pcb) {
|
close();
|
||||||
tcp_arg(_pcb, NULL);
|
if(_discard_cb) _discard_cb(_discard_cb_arg, this);
|
||||||
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;
|
|
||||||
}
|
|
||||||
delete 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() {
|
uint32_t getRemoteAddress() {
|
||||||
if(!_pcb) return 0;
|
if(!_pcb) return 0;
|
||||||
|
|
||||||
@ -179,6 +211,13 @@ class ClientContext {
|
|||||||
|
|
||||||
private:
|
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) {
|
void _consume(size_t size) {
|
||||||
ptrdiff_t left = _rx_buf->len - _rx_buf_offset - size;
|
ptrdiff_t left = _rx_buf->len - _rx_buf_offset - size;
|
||||||
if(left > 0) {
|
if(left > 0) {
|
||||||
@ -203,22 +242,9 @@ class ClientContext {
|
|||||||
err_t _recv(tcp_pcb* pcb, pbuf* pb, err_t err) {
|
err_t _recv(tcp_pcb* pcb, pbuf* pb, err_t err) {
|
||||||
|
|
||||||
if(pb == 0) // connection closed
|
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");
|
DEBUGV(":rcla\r\n");
|
||||||
tcp_abort(pcb);
|
return abort();
|
||||||
_pcb = 0;
|
|
||||||
return ERR_ABRT;
|
|
||||||
}
|
|
||||||
_pcb = 0;
|
|
||||||
return ERR_OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(_rx_buf) {
|
if(_rx_buf) {
|
||||||
@ -231,27 +257,12 @@ class ClientContext {
|
|||||||
_rx_buf = pb;
|
_rx_buf = pb;
|
||||||
_rx_buf_offset = 0;
|
_rx_buf_offset = 0;
|
||||||
}
|
}
|
||||||
// tcp_recved(pcb, received);
|
|
||||||
// pbuf_free(pb);
|
|
||||||
return ERR_OK;
|
return ERR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
void _error(err_t err) {
|
void _error(err_t err) {
|
||||||
DEBUGV(":er %d\r\n", err);
|
DEBUGV(":er %d\r\n", err);
|
||||||
|
close();
|
||||||
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;
|
|
||||||
|
|
||||||
if(_size_sent && _send_waiting) {
|
if(_size_sent && _send_waiting) {
|
||||||
esp_schedule();
|
esp_schedule();
|
||||||
}
|
}
|
||||||
@ -261,13 +272,6 @@ class ClientContext {
|
|||||||
return ERR_OK;
|
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) {
|
static err_t _s_recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *pb, err_t err) {
|
||||||
return reinterpret_cast<ClientContext*>(arg)->_recv(tpcb, pb, err);
|
return reinterpret_cast<ClientContext*>(arg)->_recv(tpcb, pb, err);
|
||||||
}
|
}
|
||||||
|
@ -28,9 +28,13 @@ extern "C" void esp_schedule();
|
|||||||
|
|
||||||
#define GET_IP_HDR(pb) reinterpret_cast<ip_hdr*>(((uint8_t*)((pb)->payload)) - UDP_HLEN - IP_HLEN);
|
#define GET_IP_HDR(pb) reinterpret_cast<ip_hdr*>(((uint8_t*)((pb)->payload)) - UDP_HLEN - IP_HLEN);
|
||||||
#define GET_UDP_HDR(pb) reinterpret_cast<udp_hdr*>(((uint8_t*)((pb)->payload)) - UDP_HLEN);
|
#define GET_UDP_HDR(pb) reinterpret_cast<udp_hdr*>(((uint8_t*)((pb)->payload)) - UDP_HLEN);
|
||||||
|
|
||||||
class UdpContext
|
class UdpContext
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
typedef std::function<void(void)> rxhandler_t;
|
||||||
|
|
||||||
UdpContext()
|
UdpContext()
|
||||||
: _pcb(0)
|
: _pcb(0)
|
||||||
, _rx_buf(0)
|
, _rx_buf(0)
|
||||||
@ -40,8 +44,11 @@ public:
|
|||||||
, _tx_buf_head(0)
|
, _tx_buf_head(0)
|
||||||
, _tx_buf_cur(0)
|
, _tx_buf_cur(0)
|
||||||
, _tx_buf_offset(0)
|
, _tx_buf_offset(0)
|
||||||
|
, _multicast_ttl(1)
|
||||||
|
, _dest_port(0)
|
||||||
{
|
{
|
||||||
_pcb = udp_new();
|
_pcb = udp_new();
|
||||||
|
_dest_addr.addr = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
~UdpContext()
|
~UdpContext()
|
||||||
@ -79,8 +86,9 @@ public:
|
|||||||
|
|
||||||
bool connect(ip_addr_t addr, uint16_t port)
|
bool connect(ip_addr_t addr, uint16_t port)
|
||||||
{
|
{
|
||||||
err_t err = udp_connect(_pcb, &addr, port);
|
_dest_addr = addr;
|
||||||
return err == ERR_OK;
|
_dest_port = port;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool listen(ip_addr_t addr, uint16_t port)
|
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
|
// newer versions of lwip have an additional field (mcast_ttl) for this purpose
|
||||||
// and a macro to set it instead of direct field access
|
// and a macro to set it instead of direct field access
|
||||||
// udp_set_multicast_ttl(_pcb, ttl);
|
// 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
|
size_t getSize() const
|
||||||
@ -173,10 +187,10 @@ public:
|
|||||||
return _rx_buf != 0;
|
return _rx_buf != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
char read()
|
int read()
|
||||||
{
|
{
|
||||||
if (!_rx_buf || _rx_buf->len == _rx_buf_offset)
|
if (!_rx_buf || _rx_buf->len == _rx_buf_offset)
|
||||||
return 0;
|
return -1;
|
||||||
|
|
||||||
char c = reinterpret_cast<char*>(_rx_buf->payload)[_rx_buf_offset];
|
char c = reinterpret_cast<char*>(_rx_buf->payload)[_rx_buf_offset];
|
||||||
_consume(1);
|
_consume(1);
|
||||||
@ -190,7 +204,7 @@ public:
|
|||||||
|
|
||||||
size_t max_size = _rx_buf->len - _rx_buf_offset;
|
size_t max_size = _rx_buf->len - _rx_buf_offset;
|
||||||
size = (size < max_size) ? size : max_size;
|
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<char*>(_rx_buf->payload) + _rx_buf_offset, size);
|
os_memcpy(dst, reinterpret_cast<char*>(_rx_buf->payload) + _rx_buf_offset, size);
|
||||||
_consume(size);
|
_consume(size);
|
||||||
@ -257,10 +271,19 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (addr)
|
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);
|
udp_sendto(_pcb, _tx_buf_head, addr, port);
|
||||||
else
|
|
||||||
udp_send(_pcb, _tx_buf_head);
|
_pcb->ttl = old_ttl;
|
||||||
|
|
||||||
for (pbuf* p = _tx_buf_head; p; p = p->next)
|
for (pbuf* p = _tx_buf_head; p; p = p->next)
|
||||||
{
|
{
|
||||||
@ -281,7 +304,7 @@ private:
|
|||||||
|
|
||||||
void _reserve(size_t size)
|
void _reserve(size_t size)
|
||||||
{
|
{
|
||||||
const size_t pbuf_unit_size = 1024;
|
const size_t pbuf_unit_size = 512;
|
||||||
if (!_tx_buf_head)
|
if (!_tx_buf_head)
|
||||||
{
|
{
|
||||||
_tx_buf_head = pbuf_alloc(PBUF_TRANSPORT, pbuf_unit_size, PBUF_RAM);
|
_tx_buf_head = pbuf_alloc(PBUF_TRANSPORT, pbuf_unit_size, PBUF_RAM);
|
||||||
@ -317,16 +340,19 @@ private:
|
|||||||
{
|
{
|
||||||
// there is some unread data
|
// there is some unread data
|
||||||
// chain the new pbuf to the existing one
|
// 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);
|
pbuf_cat(_rx_buf, pb);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
DEBUGV(":rn %d\r\n", pb->tot_len);
|
DEBUGV(":urn %d\r\n", pb->tot_len);
|
||||||
_first_buf_taken = false;
|
_first_buf_taken = false;
|
||||||
_rx_buf = pb;
|
_rx_buf = pb;
|
||||||
_rx_buf_offset = 0;
|
_rx_buf_offset = 0;
|
||||||
}
|
}
|
||||||
|
if (_on_rx) {
|
||||||
|
_on_rx();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -341,6 +367,11 @@ private:
|
|||||||
int _refcnt;
|
int _refcnt;
|
||||||
udp_pcb* _pcb;
|
udp_pcb* _pcb;
|
||||||
|
|
||||||
|
ip_addr_t _dest_addr;
|
||||||
|
uint16_t _dest_port;
|
||||||
|
|
||||||
|
uint16_t _multicast_ttl;
|
||||||
|
|
||||||
bool _first_buf_taken;
|
bool _first_buf_taken;
|
||||||
pbuf* _rx_buf;
|
pbuf* _rx_buf;
|
||||||
size_t _rx_buf_offset;
|
size_t _rx_buf_offset;
|
||||||
@ -348,6 +379,8 @@ private:
|
|||||||
pbuf* _tx_buf_head;
|
pbuf* _tx_buf_head;
|
||||||
pbuf* _tx_buf_cur;
|
pbuf* _tx_buf_cur;
|
||||||
size_t _tx_buf_offset;
|
size_t _tx_buf_offset;
|
||||||
|
|
||||||
|
rxhandler_t _on_rx;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -30,7 +30,27 @@ License (MIT license):
|
|||||||
// - DNS request and response: http://www.ietf.org/rfc/rfc1035.txt
|
// - DNS request and response: http://www.ietf.org/rfc/rfc1035.txt
|
||||||
// - Multicast DNS: http://www.ietf.org/rfc/rfc6762.txt
|
// - Multicast DNS: http://www.ietf.org/rfc/rfc6762.txt
|
||||||
|
|
||||||
|
#define LWIP_INTERNAL
|
||||||
#include "ESP8266mDNS.h"
|
#include "ESP8266mDNS.h"
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
|
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
|
// #define MDNS_DEBUG
|
||||||
@ -42,6 +62,10 @@ License (MIT license):
|
|||||||
#define TTL_OFFSET 4
|
#define TTL_OFFSET 4
|
||||||
#define IP_OFFSET 10
|
#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()
|
MDNSResponder::MDNSResponder()
|
||||||
: _expected(NULL)
|
: _expected(NULL)
|
||||||
@ -49,6 +73,7 @@ MDNSResponder::MDNSResponder()
|
|||||||
, _response(NULL)
|
, _response(NULL)
|
||||||
, _responseLen(0)
|
, _responseLen(0)
|
||||||
, _index(0)
|
, _index(0)
|
||||||
|
, _conn(0)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
MDNSResponder::~MDNSResponder() {
|
MDNSResponder::~MDNSResponder() {
|
||||||
@ -149,21 +174,37 @@ bool MDNSResponder::begin(const char* domain, IPAddress addr, uint32_t ttlSecond
|
|||||||
records[IP_OFFSET + 0] = (uint8_t) ipAddress;
|
records[IP_OFFSET + 0] = (uint8_t) ipAddress;
|
||||||
|
|
||||||
// Open the MDNS socket if it isn't already open.
|
// Open the MDNS socket if it isn't already open.
|
||||||
if (!_mdnsConn) {
|
if (!_conn) {
|
||||||
if (!_mdnsConn.beginMulticast(addr, IPAddress(224, 0, 0, 251), 5353)) {
|
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;
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MDNSResponder::update() {
|
void MDNSResponder::update() {
|
||||||
if (!_mdnsConn.parsePacket())
|
if (!_conn->next()) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Read available data.
|
// Read available data.
|
||||||
int n = _mdnsConn.available();
|
int n = _conn->getSize();
|
||||||
|
|
||||||
_index = 0;
|
_index = 0;
|
||||||
|
|
||||||
@ -172,7 +213,7 @@ void MDNSResponder::update() {
|
|||||||
#endif
|
#endif
|
||||||
// Look for domain name in request and respond with canned response if found.
|
// Look for domain name in request and respond with canned response if found.
|
||||||
for (int i = 0; i < n; ++i) {
|
for (int i = 0; i < n; ++i) {
|
||||||
uint8_t ch = tolower(_mdnsConn.read());
|
uint8_t ch = tolower(_conn->read());
|
||||||
|
|
||||||
#ifdef MDNS_DEBUG
|
#ifdef MDNS_DEBUG
|
||||||
String str(ch, 16);
|
String str(ch, 16);
|
||||||
@ -191,9 +232,12 @@ void MDNSResponder::update() {
|
|||||||
Serial.print("responding, i=");
|
Serial.print("responding, i=");
|
||||||
Serial.println(i);
|
Serial.println(i);
|
||||||
#endif
|
#endif
|
||||||
_mdnsConn.beginPacketMulticast(IPAddress(224, 0, 0, 251), 5353, _localAddr);
|
ip_addr_t multicast_addr;
|
||||||
_mdnsConn.write(_response, _responseLen);
|
multicast_addr.addr = (uint32_t) MDNS_MULTICAST_ADDR;
|
||||||
_mdnsConn.endPacket();
|
|
||||||
|
_conn->append(reinterpret_cast<const char*>(_response), _responseLen);
|
||||||
|
_conn->send();
|
||||||
|
|
||||||
_index = 0;
|
_index = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -46,6 +46,9 @@ License (MIT license):
|
|||||||
#include "ESP8266WiFi.h"
|
#include "ESP8266WiFi.h"
|
||||||
#include "WiFiUdp.h"
|
#include "WiFiUdp.h"
|
||||||
|
|
||||||
|
|
||||||
|
class UdpContext;
|
||||||
|
|
||||||
class MDNSResponder {
|
class MDNSResponder {
|
||||||
public:
|
public:
|
||||||
MDNSResponder();
|
MDNSResponder();
|
||||||
@ -63,7 +66,7 @@ private:
|
|||||||
uint8_t* _response;
|
uint8_t* _response;
|
||||||
int _responseLen;
|
int _responseLen;
|
||||||
// Socket for MDNS communication
|
// Socket for MDNS communication
|
||||||
WiFiUDP _mdnsConn;
|
UdpContext* _conn;
|
||||||
// local IP Address
|
// local IP Address
|
||||||
IPAddress _localAddr;
|
IPAddress _localAddr;
|
||||||
};
|
};
|
||||||
|
@ -68,9 +68,6 @@ void setup(void)
|
|||||||
|
|
||||||
void loop(void)
|
void loop(void)
|
||||||
{
|
{
|
||||||
// Check for any mDNS queries and send responses
|
|
||||||
mdns.update();
|
|
||||||
|
|
||||||
// Check if a client has connected
|
// Check if a client has connected
|
||||||
WiFiClient client = server.available();
|
WiFiClient client = server.available();
|
||||||
if (!client) {
|
if (!client) {
|
||||||
|
@ -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.
|
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 true if initialization succeeds, false otherwise.
|
||||||
|
|
||||||
*/
|
*/
|
||||||
return card.init(SPI_HALF_SPEED, csPin) &&
|
return card.init(speed, csPin) &&
|
||||||
volume.init(card) &&
|
volume.init(card) &&
|
||||||
root.openRoot(volume);
|
root.openRoot(volume);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// this little helper is used to traverse paths
|
// this little helper is used to traverse paths
|
||||||
SdFile SDClass::getParentDir(const char *filepath, int *index) {
|
SdFile SDClass::getParentDir(const char *filepath, int *index) {
|
||||||
// get parent directory
|
// get parent directory
|
||||||
|
@ -65,7 +65,7 @@ private:
|
|||||||
public:
|
public:
|
||||||
// This needs to be called to set up the connection to the SD card
|
// This needs to be called to set up the connection to the SD card
|
||||||
// before other methods are used.
|
// 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
|
// Open the specified file/directory with the supplied mode (e.g. read or
|
||||||
// write, etc). Returns a File object for interacting with the file.
|
// write, etc). Returns a File object for interacting with the file.
|
||||||
|
@ -33,9 +33,13 @@ static void spiSend(uint8_t b) {
|
|||||||
SPDR = b;
|
SPDR = b;
|
||||||
while (!(SPSR & (1 << SPIF)))
|
while (!(SPSR & (1 << SPIF)))
|
||||||
;
|
;
|
||||||
|
#else
|
||||||
|
#ifdef ESP8266
|
||||||
|
SPI.write(b);
|
||||||
#else
|
#else
|
||||||
SPI.transfer(b);
|
SPI.transfer(b);
|
||||||
#endif
|
#endif
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
/** Receive a byte from the card */
|
/** Receive a byte from the card */
|
||||||
static uint8_t spiRec(void) {
|
static uint8_t spiRec(void) {
|
||||||
@ -116,8 +120,14 @@ uint8_t Sd2Card::cardCommand(uint8_t cmd, uint32_t arg) {
|
|||||||
// send command
|
// send command
|
||||||
spiSend(cmd | 0x40);
|
spiSend(cmd | 0x40);
|
||||||
|
|
||||||
|
#ifdef ESP8266
|
||||||
|
// send argument
|
||||||
|
SPI.write32(arg, true);
|
||||||
|
#else
|
||||||
// send argument
|
// send argument
|
||||||
for (int8_t s = 24; s >= 0; s -= 8) spiSend(arg >> s);
|
for (int8_t s = 24; s >= 0; s -= 8) spiSend(arg >> s);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
// send CRC
|
// send CRC
|
||||||
uint8_t crc = 0xFF;
|
uint8_t crc = 0xFF;
|
||||||
@ -424,7 +434,14 @@ uint8_t Sd2Card::readData(uint32_t block,
|
|||||||
dst[n] = SPDR;
|
dst[n] = SPDR;
|
||||||
|
|
||||||
#else // OPTIMIZE_HARDWARE_SPI
|
#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
|
// skip data before offset
|
||||||
for (;offset_ < offset; offset_++) {
|
for (;offset_ < offset; offset_++) {
|
||||||
spiRec();
|
spiRec();
|
||||||
@ -433,6 +450,7 @@ uint8_t Sd2Card::readData(uint32_t block,
|
|||||||
for (uint16_t i = 0; i < count; i++) {
|
for (uint16_t i = 0; i < count; i++) {
|
||||||
dst[i] = spiRec();
|
dst[i] = spiRec();
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
#endif // OPTIMIZE_HARDWARE_SPI
|
#endif // OPTIMIZE_HARDWARE_SPI
|
||||||
|
|
||||||
offset_ += count;
|
offset_ += count;
|
||||||
@ -463,7 +481,11 @@ void Sd2Card::readEnd(void) {
|
|||||||
while (!(SPSR & (1 << SPIF)))
|
while (!(SPSR & (1 << SPIF)))
|
||||||
;
|
;
|
||||||
#else // OPTIMIZE_HARDWARE_SPI
|
#else // OPTIMIZE_HARDWARE_SPI
|
||||||
|
#ifdef ESP8266
|
||||||
|
SPI.transferBytes(NULL, NULL, (514-offset_));
|
||||||
|
#else
|
||||||
while (offset_++ < 514) spiRec();
|
while (offset_++ < 514) spiRec();
|
||||||
|
#endif
|
||||||
#endif // OPTIMIZE_HARDWARE_SPI
|
#endif // OPTIMIZE_HARDWARE_SPI
|
||||||
chipSelectHigh();
|
chipSelectHigh();
|
||||||
inBlock_ = 0;
|
inBlock_ = 0;
|
||||||
@ -479,7 +501,11 @@ uint8_t Sd2Card::readRegister(uint8_t cmd, void* buf) {
|
|||||||
}
|
}
|
||||||
if (!waitStartBlock()) goto fail;
|
if (!waitStartBlock()) goto fail;
|
||||||
// transfer data
|
// transfer data
|
||||||
|
#ifdef ESP8266
|
||||||
|
SPI.transferBytes(NULL, dst, 16);
|
||||||
|
#else
|
||||||
for (uint16_t i = 0; i < 16; i++) dst[i] = spiRec();
|
for (uint16_t i = 0; i < 16; i++) dst[i] = spiRec();
|
||||||
|
#endif
|
||||||
spiRec(); // get first crc byte
|
spiRec(); // get first crc byte
|
||||||
spiRec(); // get second crc byte
|
spiRec(); // get second crc byte
|
||||||
chipSelectHigh();
|
chipSelectHigh();
|
||||||
@ -646,13 +672,21 @@ uint8_t Sd2Card::writeData(uint8_t token, const uint8_t* src) {
|
|||||||
|
|
||||||
#else // OPTIMIZE_HARDWARE_SPI
|
#else // OPTIMIZE_HARDWARE_SPI
|
||||||
spiSend(token);
|
spiSend(token);
|
||||||
|
#ifdef ESP8266
|
||||||
|
// send argument
|
||||||
|
SPI.writeBytes((uint8_t *)src, 512);
|
||||||
|
#else
|
||||||
for (uint16_t i = 0; i < 512; i++) {
|
for (uint16_t i = 0; i < 512; i++) {
|
||||||
spiSend(src[i]);
|
spiSend(src[i]);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
#endif // OPTIMIZE_HARDWARE_SPI
|
#endif // OPTIMIZE_HARDWARE_SPI
|
||||||
|
#ifdef ESP8266
|
||||||
|
SPI.write16(0xFFFF, true);
|
||||||
|
#else
|
||||||
spiSend(0xff); // dummy crc
|
spiSend(0xff); // dummy crc
|
||||||
spiSend(0xff); // dummy crc
|
spiSend(0xff); // dummy crc
|
||||||
|
#endif
|
||||||
status_ = spiRec();
|
status_ = spiRec();
|
||||||
if ((status_ & DATA_RES_MASK) != DATA_RES_ACCEPTED) {
|
if ((status_ & DATA_RES_MASK) != DATA_RES_ACCEPTED) {
|
||||||
error(SD_CARD_ERROR_WRITE);
|
error(SD_CARD_ERROR_WRITE);
|
||||||
|
@ -36,6 +36,7 @@ typedef union {
|
|||||||
SPIClass SPI;
|
SPIClass SPI;
|
||||||
|
|
||||||
SPIClass::SPIClass() {
|
SPIClass::SPIClass() {
|
||||||
|
useHwCs = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SPIClass::begin() {
|
void SPIClass::begin() {
|
||||||
@ -54,9 +55,26 @@ void SPIClass::end() {
|
|||||||
pinMode(SCK, INPUT);
|
pinMode(SCK, INPUT);
|
||||||
pinMode(MISO, INPUT);
|
pinMode(MISO, INPUT);
|
||||||
pinMode(MOSI, 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) {
|
void SPIClass::beginTransaction(SPISettings settings) {
|
||||||
|
while(SPI1CMD & SPIBUSY) {}
|
||||||
setFrequency(settings._clock);
|
setFrequency(settings._clock);
|
||||||
setBitOrder(settings._bitOrder);
|
setBitOrder(settings._bitOrder);
|
||||||
setDataMode(settings._dataMode);
|
setDataMode(settings._dataMode);
|
||||||
@ -198,13 +216,19 @@ void SPIClass::setClockDivider(uint32_t clockDiv) {
|
|||||||
SPI1CLK = 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) {
|
uint8_t SPIClass::transfer(uint8_t data) {
|
||||||
while(SPI1CMD & SPIBUSY)
|
while(SPI1CMD & SPIBUSY) {}
|
||||||
;
|
// reset to 8Bit mode
|
||||||
|
setDataBits(8);
|
||||||
SPI1W0 = data;
|
SPI1W0 = data;
|
||||||
SPI1CMD |= SPIBUSY;
|
SPI1CMD |= SPIBUSY;
|
||||||
while(SPI1CMD & SPIBUSY)
|
while(SPI1CMD & SPIBUSY) {}
|
||||||
;
|
|
||||||
return (uint8_t) (SPI1W0 & 0xff);
|
return (uint8_t) (SPI1W0 & 0xff);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -230,3 +254,177 @@ uint16_t SPIClass::transfer16(uint16_t data) {
|
|||||||
return out.val;
|
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++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -64,6 +64,7 @@ public:
|
|||||||
SPIClass();
|
SPIClass();
|
||||||
void begin();
|
void begin();
|
||||||
void end();
|
void end();
|
||||||
|
void setHwCs(bool use);
|
||||||
void setBitOrder(uint8_t bitOrder);
|
void setBitOrder(uint8_t bitOrder);
|
||||||
void setDataMode(uint8_t dataMode);
|
void setDataMode(uint8_t dataMode);
|
||||||
void setFrequency(uint32_t freq);
|
void setFrequency(uint32_t freq);
|
||||||
@ -71,7 +72,21 @@ public:
|
|||||||
void beginTransaction(SPISettings settings);
|
void beginTransaction(SPISettings settings);
|
||||||
uint8_t transfer(uint8_t data);
|
uint8_t transfer(uint8_t data);
|
||||||
uint16_t transfer16(uint16_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);
|
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;
|
extern SPIClass SPI;
|
||||||
|
@ -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.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.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.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.cmd=xtensa-lx106-elf-g++
|
||||||
compiler.cpp.flags=-c -Os -mlongcalls -mtext-section-literals -fno-exceptions -fno-rtti -std=c++11 -MMD
|
compiler.cpp.flags=-c -Os -mlongcalls -mtext-section-literals -fno-exceptions -fno-rtti -std=c++11 -MMD
|
||||||
|
Loading…
x
Reference in New Issue
Block a user