mirror of
https://github.com/esp8266/Arduino.git
synced 2025-06-07 16:23:38 +03:00
commit
d641b3f701
@ -24,6 +24,8 @@ script:
|
|||||||
- which arduino
|
- which arduino
|
||||||
- source hardware/esp8266com/esp8266/tests/common.sh
|
- source hardware/esp8266com/esp8266/tests/common.sh
|
||||||
- arduino --board esp8266com:esp8266:generic --save-prefs
|
- arduino --board esp8266com:esp8266:generic --save-prefs
|
||||||
|
- arduino --get-pref sketchbook.path
|
||||||
|
- install_libraries
|
||||||
- build_sketches arduino $PWD/hardware/esp8266com/esp8266
|
- build_sketches arduino $PWD/hardware/esp8266com/esp8266
|
||||||
|
|
||||||
notifications:
|
notifications:
|
||||||
|
@ -181,7 +181,7 @@ nodemcu.name=NodeMCU 0.9 (ESP-12 Module)
|
|||||||
|
|
||||||
nodemcu.upload.tool=esptool
|
nodemcu.upload.tool=esptool
|
||||||
nodemcu.upload.speed=115200
|
nodemcu.upload.speed=115200
|
||||||
nodemcu.upload.resetmethod=ck
|
nodemcu.upload.resetmethod=nodemcu
|
||||||
nodemcu.upload.maximum_size=1044464
|
nodemcu.upload.maximum_size=1044464
|
||||||
nodemcu.upload.maximum_data_size=81920
|
nodemcu.upload.maximum_data_size=81920
|
||||||
nodemcu.upload.wait_for_upload_port=true
|
nodemcu.upload.wait_for_upload_port=true
|
||||||
|
@ -137,17 +137,29 @@ void timer0_detachInterrupt(void);
|
|||||||
void ets_intr_lock();
|
void ets_intr_lock();
|
||||||
void ets_intr_unlock();
|
void ets_intr_unlock();
|
||||||
|
|
||||||
// level (0-15),
|
#ifndef __STRINGIFY
|
||||||
// level 15 will disable ALL interrupts,
|
#define __STRINGIFY(a) #a
|
||||||
// level 0 will disable most software interrupts
|
#endif
|
||||||
|
|
||||||
|
// these low level routines provide a replacement for SREG interrupt save that AVR uses
|
||||||
|
// but are esp8266 specific. A normal use pattern is like
|
||||||
//
|
//
|
||||||
#define xt_disable_interrupts(state, level) __asm__ __volatile__("rsil %0," __STRINGIFY(level) : "=a" (state))
|
//{
|
||||||
#define xt_enable_interrupts(state) __asm__ __volatile__("wsr %0,ps; isync" :: "a" (state) : "memory")
|
// uint32_t savedPS = xt_rsil(1); // this routine will allow level 2 and above
|
||||||
|
// // do work here
|
||||||
|
// xt_wsr_ps(savedPS); // restore the state
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
// level (0-15), interrupts of the given level and above will be active
|
||||||
|
// level 15 will disable ALL interrupts,
|
||||||
|
// level 0 will enable ALL interrupts,
|
||||||
|
//
|
||||||
|
#define xt_rsil(level) (__extension__({uint32_t state; __asm__ __volatile__("rsil %0," __STRINGIFY(level) : "=a" (state)); state;}))
|
||||||
|
#define xt_wsr_ps(state) __asm__ __volatile__("wsr %0,ps; isync" :: "a" (state) : "memory")
|
||||||
|
|
||||||
extern uint32_t interruptsState;
|
#define interrupts() xt_rsil(0)
|
||||||
|
#define noInterrupts() xt_rsil(15)
|
||||||
|
|
||||||
#define interrupts() xt_enable_interrupts(interruptsState)
|
|
||||||
#define noInterrupts() __asm__ __volatile__("rsil %0,15" : "=a" (interruptsState))
|
|
||||||
|
|
||||||
#define clockCyclesPerMicrosecond() ( F_CPU / 1000000L )
|
#define clockCyclesPerMicrosecond() ( F_CPU / 1000000L )
|
||||||
#define clockCyclesToMicroseconds(a) ( (a) / clockCyclesPerMicrosecond() )
|
#define clockCyclesToMicroseconds(a) ( (a) / clockCyclesPerMicrosecond() )
|
||||||
@ -179,12 +191,12 @@ void initVariant(void);
|
|||||||
|
|
||||||
int atexit(void (*func)()) __attribute__((weak));
|
int atexit(void (*func)()) __attribute__((weak));
|
||||||
|
|
||||||
void pinMode(uint8_t, uint8_t);
|
void pinMode(uint8_t pin, uint8_t mode);
|
||||||
void digitalWrite(uint8_t, uint8_t);
|
void digitalWrite(uint8_t pin, uint8_t val);
|
||||||
int digitalRead(uint8_t);
|
int digitalRead(uint8_t pin);
|
||||||
int analogRead(uint8_t);
|
int analogRead(uint8_t pin);
|
||||||
void analogReference(uint8_t mode);
|
void analogReference(uint8_t mode);
|
||||||
void analogWrite(uint8_t, int);
|
void analogWrite(uint8_t pin, int val);
|
||||||
void analogWriteFreq(uint32_t freq);
|
void analogWriteFreq(uint32_t freq);
|
||||||
void analogWriteRange(uint32_t range);
|
void analogWriteRange(uint32_t range);
|
||||||
|
|
||||||
@ -198,8 +210,8 @@ unsigned long pulseInLong(uint8_t pin, uint8_t state, unsigned long timeout);
|
|||||||
void shiftOut(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder, uint8_t val);
|
void shiftOut(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder, uint8_t val);
|
||||||
uint8_t shiftIn(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder);
|
uint8_t shiftIn(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder);
|
||||||
|
|
||||||
void attachInterrupt(uint8_t, void (*)(void), int mode);
|
void attachInterrupt(uint8_t pin, void (*)(void), int mode);
|
||||||
void detachInterrupt(uint8_t);
|
void detachInterrupt(uint8_t pin);
|
||||||
|
|
||||||
void setup(void);
|
void setup(void);
|
||||||
void loop(void);
|
void loop(void);
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
/*
|
/*
|
||||||
Esp.cpp - ESP8266-specific APIs
|
Esp.cpp - ESP8266-specific APIs
|
||||||
Copyright (c) 2015 Ivan Grokhotkov. All rights reserved.
|
Copyright (c) 2015 Ivan Grokhotkov. All rights reserved.
|
||||||
This file is part of the esp8266 core for Arduino environment.
|
This file is part of the esp8266 core for Arduino environment.
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
This library is free software; you can redistribute it and/or
|
||||||
modify it under the terms of the GNU Lesser General Public
|
modify it under the terms of the GNU Lesser General Public
|
||||||
License as published by the Free Software Foundation; either
|
License as published by the Free Software Foundation; either
|
||||||
@ -22,6 +22,7 @@
|
|||||||
#include "flash_utils.h"
|
#include "flash_utils.h"
|
||||||
#include "eboot_command.h"
|
#include "eboot_command.h"
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include "interrupts.h"
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#include "user_interface.h"
|
#include "user_interface.h"
|
||||||
@ -32,7 +33,7 @@ extern struct rst_info resetInfo;
|
|||||||
|
|
||||||
//#define DEBUG_SERIAL Serial
|
//#define DEBUG_SERIAL Serial
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* User-defined Literals
|
* User-defined Literals
|
||||||
* usage:
|
* usage:
|
||||||
@ -92,23 +93,25 @@ void EspClass::wdtEnable(WDTO_t timeout_ms)
|
|||||||
|
|
||||||
void EspClass::wdtDisable(void)
|
void EspClass::wdtDisable(void)
|
||||||
{
|
{
|
||||||
/// Please don’t stop software watchdog too long (less than 6 seconds),
|
/// Please don't stop software watchdog too long (less than 6 seconds),
|
||||||
/// otherwise it will trigger hardware watchdog reset.
|
/// otherwise it will trigger hardware watchdog reset.
|
||||||
system_soft_wdt_stop();
|
system_soft_wdt_stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
void EspClass::wdtFeed(void)
|
void EspClass::wdtFeed(void)
|
||||||
{
|
{
|
||||||
|
system_soft_wdt_feed();
|
||||||
}
|
|
||||||
|
|
||||||
void EspClass::deepSleep(uint32_t time_us, WakeMode mode)
|
|
||||||
{
|
|
||||||
system_deep_sleep_set_option(static_cast<int>(mode));
|
|
||||||
system_deep_sleep(time_us);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" void esp_yield();
|
extern "C" void esp_yield();
|
||||||
|
|
||||||
|
void EspClass::deepSleep(uint32_t time_us, WakeMode mode)
|
||||||
|
{
|
||||||
|
system_deep_sleep_set_option(static_cast<int>(mode));
|
||||||
|
system_deep_sleep(time_us);
|
||||||
|
esp_yield();
|
||||||
|
}
|
||||||
|
|
||||||
extern "C" void __real_system_restart_local();
|
extern "C" void __real_system_restart_local();
|
||||||
void EspClass::reset(void)
|
void EspClass::reset(void)
|
||||||
{
|
{
|
||||||
@ -119,13 +122,11 @@ void EspClass::restart(void)
|
|||||||
{
|
{
|
||||||
system_restart();
|
system_restart();
|
||||||
esp_yield();
|
esp_yield();
|
||||||
// todo: provide an alternative code path if this was called
|
|
||||||
// from system context, not from continuation
|
|
||||||
// (implement esp_is_cont_ctx()?)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t EspClass::getVcc(void)
|
uint16_t EspClass::getVcc(void)
|
||||||
{
|
{
|
||||||
|
InterruptLock lock;
|
||||||
return system_get_vdd33();
|
return system_get_vdd33();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -333,7 +334,7 @@ uint32_t EspClass::getSketchSize() {
|
|||||||
DEBUG_SERIAL.printf("num_segments=%u\r\n", image_header.num_segments);
|
DEBUG_SERIAL.printf("num_segments=%u\r\n", image_header.num_segments);
|
||||||
#endif
|
#endif
|
||||||
for (uint32_t section_index = 0;
|
for (uint32_t section_index = 0;
|
||||||
section_index < image_header.num_segments;
|
section_index < image_header.num_segments;
|
||||||
++section_index)
|
++section_index)
|
||||||
{
|
{
|
||||||
section_header_t section_header = {0};
|
section_header_t section_header = {0};
|
||||||
@ -395,8 +396,7 @@ bool EspClass::updateSketch(Stream& in, uint32_t size, bool restartOnFail, bool
|
|||||||
|
|
||||||
#ifdef DEBUG_SERIAL
|
#ifdef DEBUG_SERIAL
|
||||||
DEBUG_SERIAL.println("Update SUCCESS");
|
DEBUG_SERIAL.println("Update SUCCESS");
|
||||||
#endif
|
#endif
|
||||||
if(restartOnSuccess) ESP.restart();
|
if(restartOnSuccess) ESP.restart();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
/*
|
/*
|
||||||
Esp.h - ESP8266-specific APIs
|
Esp.h - ESP8266-specific APIs
|
||||||
Copyright (c) 2015 Ivan Grokhotkov. All rights reserved.
|
Copyright (c) 2015 Ivan Grokhotkov. All rights reserved.
|
||||||
This file is part of the esp8266 core for Arduino environment.
|
This file is part of the esp8266 core for Arduino environment.
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
This library is free software; you can redistribute it and/or
|
||||||
modify it under the terms of the GNU Lesser General Public
|
modify it under the terms of the GNU Lesser General Public
|
||||||
License as published by the Free Software Foundation; either
|
License as published by the Free Software Foundation; either
|
||||||
@ -20,6 +20,9 @@
|
|||||||
|
|
||||||
#ifndef ESP_H
|
#ifndef ESP_H
|
||||||
#define ESP_H
|
#define ESP_H
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* AVR macros for WDT managment
|
* AVR macros for WDT managment
|
||||||
*/
|
*/
|
||||||
|
@ -21,6 +21,8 @@
|
|||||||
#include "FS.h"
|
#include "FS.h"
|
||||||
#include "FSImpl.h"
|
#include "FSImpl.h"
|
||||||
|
|
||||||
|
using namespace fs;
|
||||||
|
|
||||||
static bool sflags(const char* mode, OpenMode& om, AccessMode& am);
|
static bool sflags(const char* mode, OpenMode& om, AccessMode& am);
|
||||||
|
|
||||||
size_t File::write(uint8_t c) {
|
size_t File::write(uint8_t c) {
|
||||||
@ -41,7 +43,7 @@ int File::available() {
|
|||||||
if (!_p)
|
if (!_p)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return _p->position() < _p->size();
|
return _p->size() - _p->position();
|
||||||
}
|
}
|
||||||
|
|
||||||
int File::read() {
|
int File::read() {
|
||||||
@ -112,6 +114,13 @@ File::operator bool() const {
|
|||||||
return !!_p;
|
return !!_p;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char* File::name() const {
|
||||||
|
if (!_p)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
return _p->name();
|
||||||
|
}
|
||||||
|
|
||||||
File Dir::openFile(const char* mode) {
|
File Dir::openFile(const char* mode) {
|
||||||
if (!_impl) {
|
if (!_impl) {
|
||||||
return File();
|
return File();
|
||||||
@ -135,6 +144,14 @@ String Dir::fileName() {
|
|||||||
return _impl->fileName();
|
return _impl->fileName();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t Dir::fileSize() {
|
||||||
|
if (!_impl) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return _impl->fileSize();
|
||||||
|
}
|
||||||
|
|
||||||
bool Dir::next() {
|
bool Dir::next() {
|
||||||
if (!_impl) {
|
if (!_impl) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -24,6 +24,8 @@
|
|||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
|
namespace fs {
|
||||||
|
|
||||||
class File;
|
class File;
|
||||||
class Dir;
|
class Dir;
|
||||||
|
|
||||||
@ -64,6 +66,7 @@ public:
|
|||||||
size_t size() const;
|
size_t size() const;
|
||||||
void close();
|
void close();
|
||||||
operator bool() const;
|
operator bool() const;
|
||||||
|
const char* name() const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
FileImplPtr _p;
|
FileImplPtr _p;
|
||||||
@ -75,6 +78,7 @@ public:
|
|||||||
|
|
||||||
File openFile(const char* mode);
|
File openFile(const char* mode);
|
||||||
String fileName();
|
String fileName();
|
||||||
|
size_t fileSize();
|
||||||
bool next();
|
bool next();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
@ -102,9 +106,18 @@ public:
|
|||||||
|
|
||||||
protected:
|
protected:
|
||||||
FSImplPtr _impl;
|
FSImplPtr _impl;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
} // namespace fs
|
||||||
|
|
||||||
|
using fs::FS;
|
||||||
|
using fs::File;
|
||||||
|
using fs::Dir;
|
||||||
|
using fs::SeekMode;
|
||||||
|
using fs::SeekSet;
|
||||||
|
using fs::SeekCur;
|
||||||
|
using fs::SeekEnd;
|
||||||
|
|
||||||
extern FS SPIFFS;
|
extern FS SPIFFS;
|
||||||
|
|
||||||
#endif //FS_H
|
#endif //FS_H
|
||||||
|
@ -23,6 +23,8 @@
|
|||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
|
namespace fs {
|
||||||
|
|
||||||
class FileImpl {
|
class FileImpl {
|
||||||
public:
|
public:
|
||||||
virtual ~FileImpl() { }
|
virtual ~FileImpl() { }
|
||||||
@ -33,6 +35,7 @@ public:
|
|||||||
virtual size_t position() const = 0;
|
virtual size_t position() const = 0;
|
||||||
virtual size_t size() const = 0;
|
virtual size_t size() const = 0;
|
||||||
virtual void close() = 0;
|
virtual void close() = 0;
|
||||||
|
virtual const char* name() const = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum OpenMode {
|
enum OpenMode {
|
||||||
@ -53,6 +56,7 @@ public:
|
|||||||
virtual ~DirImpl() { }
|
virtual ~DirImpl() { }
|
||||||
virtual FileImplPtr openFile(OpenMode openMode, AccessMode accessMode) = 0;
|
virtual FileImplPtr openFile(OpenMode openMode, AccessMode accessMode) = 0;
|
||||||
virtual const char* fileName() = 0;
|
virtual const char* fileName() = 0;
|
||||||
|
virtual size_t fileSize() = 0;
|
||||||
virtual bool next() = 0;
|
virtual bool next() = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -66,5 +70,6 @@ public:
|
|||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
} // namespace fs
|
||||||
|
|
||||||
#endif //FSIMPL_H
|
#endif //FSIMPL_H
|
||||||
|
@ -35,10 +35,12 @@
|
|||||||
#include "Arduino.h"
|
#include "Arduino.h"
|
||||||
#include "pins_arduino.h"
|
#include "pins_arduino.h"
|
||||||
|
|
||||||
|
/*
|
||||||
static int8_t toneBegin(uint8_t _pin) {
|
static int8_t toneBegin(uint8_t _pin) {
|
||||||
//TODO implement tone
|
//TODO implement tone
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
void tone(uint8_t _pin, unsigned int frequency, unsigned long duration) {
|
void tone(uint8_t _pin, unsigned int frequency, unsigned long duration) {
|
||||||
//TODO implement tone
|
//TODO implement tone
|
||||||
|
@ -108,12 +108,12 @@ class UpdaterClass {
|
|||||||
void _reset();
|
void _reset();
|
||||||
bool _writeBuffer();
|
bool _writeBuffer();
|
||||||
|
|
||||||
|
uint8_t _error;
|
||||||
uint8_t *_buffer;
|
uint8_t *_buffer;
|
||||||
size_t _bufferLen;
|
size_t _bufferLen;
|
||||||
size_t _size;
|
size_t _size;
|
||||||
uint32_t _startAddress;
|
uint32_t _startAddress;
|
||||||
uint32_t _currentAddress;
|
uint32_t _currentAddress;
|
||||||
uint8_t _error;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
extern UpdaterClass Update;
|
extern UpdaterClass Update;
|
||||||
|
@ -70,7 +70,7 @@ class cbuf {
|
|||||||
size_t bytes_available = getSize();
|
size_t bytes_available = getSize();
|
||||||
size_t size_to_read = (size < bytes_available) ? size : bytes_available;
|
size_t size_to_read = (size < bytes_available) ? size : bytes_available;
|
||||||
size_t size_read = size_to_read;
|
size_t size_read = size_to_read;
|
||||||
if(_end < _begin && size_to_read > _bufend - _begin) {
|
if(_end < _begin && size_to_read > (size_t)(_bufend - _begin)) {
|
||||||
size_t top_size = _bufend - _begin;
|
size_t top_size = _bufend - _begin;
|
||||||
memcpy(dst, _begin, top_size);
|
memcpy(dst, _begin, top_size);
|
||||||
_begin = _buf;
|
_begin = _buf;
|
||||||
@ -95,7 +95,7 @@ class cbuf {
|
|||||||
size_t bytes_available = room();
|
size_t bytes_available = room();
|
||||||
size_t size_to_write = (size < bytes_available) ? size : bytes_available;
|
size_t size_to_write = (size < bytes_available) ? size : bytes_available;
|
||||||
size_t size_written = size_to_write;
|
size_t size_written = size_to_write;
|
||||||
if(_end > _begin && size_to_write > _bufend - _end) {
|
if(_end > _begin && size_to_write > (size_t)(_bufend - _end)) {
|
||||||
size_t top_size = _bufend - _end;
|
size_t top_size = _bufend - _end;
|
||||||
memcpy(_end, src, top_size);
|
memcpy(_end, src, top_size);
|
||||||
_end = _buf;
|
_end = _buf;
|
||||||
|
@ -74,7 +74,9 @@ extern "C" void abort() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
extern "C" void esp_yield() {
|
extern "C" void esp_yield() {
|
||||||
cont_yield(&g_cont);
|
if (cont_can_yield(&g_cont)) {
|
||||||
|
cont_yield(&g_cont);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" void esp_schedule() {
|
extern "C" void esp_schedule() {
|
||||||
|
@ -148,7 +148,8 @@ char* ultoa(unsigned long value, char* result, int base) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
char * dtostrf(double number, signed char width, unsigned char prec, char *s) {
|
char * dtostrf(double number, signed char width, unsigned char prec, char *s) {
|
||||||
|
bool negative = false;
|
||||||
|
|
||||||
if (isnan(number)) {
|
if (isnan(number)) {
|
||||||
strcpy(s, "nan");
|
strcpy(s, "nan");
|
||||||
return s;
|
return s;
|
||||||
@ -158,50 +159,65 @@ char * dtostrf(double number, signed char width, unsigned char prec, char *s) {
|
|||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (number > 4294967040.0 || number < -4294967040.0) {
|
|
||||||
strcpy(s, "ovf");
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|
||||||
char* out = s;
|
char* out = s;
|
||||||
int signInt_Part = 1;
|
|
||||||
|
int fillme = width; // how many cells to fill for the integer part
|
||||||
|
if (prec > 0) {
|
||||||
|
fillme -= (prec+1);
|
||||||
|
}
|
||||||
|
|
||||||
// Handle negative numbers
|
// Handle negative numbers
|
||||||
if (number < 0.0) {
|
if (number < 0.0) {
|
||||||
signInt_Part = -1;
|
negative = true;
|
||||||
|
fillme--;
|
||||||
number = -number;
|
number = -number;
|
||||||
}
|
}
|
||||||
|
|
||||||
// calc left over digits
|
|
||||||
if (prec > 0)
|
|
||||||
{
|
|
||||||
width -= (prec + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Round correctly so that print(1.999, 2) prints as "2.00"
|
// Round correctly so that print(1.999, 2) prints as "2.00"
|
||||||
double rounding = 0.5;
|
// I optimized out most of the divisions
|
||||||
|
double rounding = 2.0;
|
||||||
for (uint8_t i = 0; i < prec; ++i)
|
for (uint8_t i = 0; i < prec; ++i)
|
||||||
rounding /= 10.0;
|
rounding *= 10.0;
|
||||||
|
rounding = 1.0 / rounding;
|
||||||
|
|
||||||
number += rounding;
|
number += rounding;
|
||||||
|
|
||||||
// Extract the integer part of the number and print it
|
// Figure out how big our number really is
|
||||||
unsigned long int_part = (unsigned long)number;
|
double tenpow = 1.0;
|
||||||
double remainder = number - (double)int_part;
|
int digitcount = 1;
|
||||||
out += sprintf(out, "%*ld", width, int_part * signInt_Part);
|
while (number >= 10.0 * tenpow) {
|
||||||
|
tenpow *= 10.0;
|
||||||
// Print the decimal point, but only if there are digits beyond
|
digitcount++;
|
||||||
if (prec > 0) {
|
}
|
||||||
*out = '.';
|
|
||||||
++out;
|
number /= tenpow;
|
||||||
|
fillme -= digitcount;
|
||||||
|
|
||||||
for (unsigned char decShift = prec; decShift > 0; decShift--) {
|
// Pad unused cells with spaces
|
||||||
remainder *= 10.0;
|
while (fillme-- > 0) {
|
||||||
}
|
*out++ = ' ';
|
||||||
sprintf(out, "%0*d", prec, (int)remainder);
|
}
|
||||||
|
|
||||||
|
// Handle negative sign
|
||||||
|
if (negative) *out++ = '-';
|
||||||
|
|
||||||
|
// Print the digits, and if necessary, the decimal point
|
||||||
|
digitcount += prec;
|
||||||
|
int8_t digit = 0;
|
||||||
|
while (digitcount-- > 0) {
|
||||||
|
digit = (int8_t)number;
|
||||||
|
if (digit > 9) digit = 9; // insurance
|
||||||
|
*out++ = (char)('0' | digit);
|
||||||
|
if ((digitcount == prec) && (prec > 0)) {
|
||||||
|
*out++ = '.';
|
||||||
|
}
|
||||||
|
number -= digit;
|
||||||
|
number *= 10.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// make sure the string is terminated
|
||||||
|
*out = 0;
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -261,7 +261,10 @@ void user_rf_pre_init() {
|
|||||||
// *((volatile uint32_t*) 0x60000710) = 0;
|
// *((volatile uint32_t*) 0x60000710) = 0;
|
||||||
|
|
||||||
volatile uint32_t* rtc_reg = (volatile uint32_t*) 0x60001000;
|
volatile uint32_t* rtc_reg = (volatile uint32_t*) 0x60001000;
|
||||||
rtc_reg[30] = 0;
|
if((rtc_reg[24] >> 16) > 4) {
|
||||||
|
rtc_reg[24] &= 0xFFFF;
|
||||||
|
rtc_reg[30] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
system_set_os_print(0);
|
system_set_os_print(0);
|
||||||
__run_user_rf_pre_init();
|
__run_user_rf_pre_init();
|
||||||
|
@ -35,7 +35,7 @@ static void uart_write_char_d(char c);
|
|||||||
static void uart0_write_char_d(char c);
|
static void uart0_write_char_d(char c);
|
||||||
static void uart1_write_char_d(char c);
|
static void uart1_write_char_d(char c);
|
||||||
static void print_stack(uint32_t start, uint32_t end);
|
static void print_stack(uint32_t start, uint32_t end);
|
||||||
static void print_pcs(uint32_t start, uint32_t end);
|
//static void print_pcs(uint32_t start, uint32_t end);
|
||||||
|
|
||||||
void __wrap_system_restart_local() {
|
void __wrap_system_restart_local() {
|
||||||
register uint32_t sp asm("a1");
|
register uint32_t sp asm("a1");
|
||||||
@ -108,6 +108,7 @@ static void print_stack(uint32_t start, uint32_t end) {
|
|||||||
ets_printf("<<<stack<<<\n");
|
ets_printf("<<<stack<<<\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
static void print_pcs(uint32_t start, uint32_t end) {
|
static void print_pcs(uint32_t start, uint32_t end) {
|
||||||
uint32_t n = 0;
|
uint32_t n = 0;
|
||||||
ets_printf("\n>>>pc>>>\n");
|
ets_printf("\n>>>pc>>>\n");
|
||||||
@ -122,6 +123,7 @@ static void print_pcs(uint32_t start, uint32_t end) {
|
|||||||
}
|
}
|
||||||
ets_printf("<<<pc<<<\n");
|
ets_printf("<<<pc<<<\n");
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
void uart_write_char_d(char c) {
|
void uart_write_char_d(char c) {
|
||||||
uart0_write_char_d(c);
|
uart0_write_char_d(c);
|
||||||
|
@ -75,8 +75,11 @@ void twi_stop(void){
|
|||||||
|
|
||||||
static void twi_delay(unsigned char v){
|
static void twi_delay(unsigned char v){
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
|
#pragma GCC diagnostic push
|
||||||
|
#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
|
||||||
unsigned int reg;
|
unsigned int reg;
|
||||||
for(i=0;i<v;i++) reg = GPI;
|
for(i=0;i<v;i++) reg = GPI;
|
||||||
|
#pragma GCC diagnostic pop
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool twi_write_start(void) {
|
static bool twi_write_start(void) {
|
||||||
|
@ -32,7 +32,13 @@ static volatile timercallback timer1_user_cb = NULL;
|
|||||||
void timer1_isr_handler(void *para){
|
void timer1_isr_handler(void *para){
|
||||||
if ((T1C & ((1 << TCAR) | (1 << TCIT))) == 0) TEIE &= ~TEIE1;//edge int disable
|
if ((T1C & ((1 << TCAR) | (1 << TCIT))) == 0) TEIE &= ~TEIE1;//edge int disable
|
||||||
T1I = 0;
|
T1I = 0;
|
||||||
if (timer1_user_cb) timer1_user_cb();
|
if (timer1_user_cb) {
|
||||||
|
// to make ISR compatible to Arduino AVR model where interrupts are disabled
|
||||||
|
// we disable them before we call the client ISR
|
||||||
|
uint32_t savedPS = xt_rsil(15); // stop other interrupts
|
||||||
|
timer1_user_cb();
|
||||||
|
xt_wsr_ps(savedPS);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void timer1_isr_init(){
|
void timer1_isr_init(){
|
||||||
@ -72,7 +78,11 @@ static volatile timercallback timer0_user_cb = NULL;
|
|||||||
|
|
||||||
void timer0_isr_handler(void* para){
|
void timer0_isr_handler(void* para){
|
||||||
if (timer0_user_cb) {
|
if (timer0_user_cb) {
|
||||||
|
// to make ISR compatible to Arduino AVR model where interrupts are disabled
|
||||||
|
// we disable them before we call the client ISR
|
||||||
|
uint32_t savedPS = xt_rsil(15); // stop other interrupts
|
||||||
timer0_user_cb();
|
timer0_user_cb();
|
||||||
|
xt_wsr_ps(savedPS);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -123,7 +123,11 @@ void interrupt_handler(void *arg) {
|
|||||||
if (handler->fn &&
|
if (handler->fn &&
|
||||||
(handler->mode == CHANGE ||
|
(handler->mode == CHANGE ||
|
||||||
(handler->mode & 1) == digitalRead(i))) {
|
(handler->mode & 1) == digitalRead(i))) {
|
||||||
|
// to make ISR compatible to Arduino AVR model where interrupts are disabled
|
||||||
|
// we disable them before we call the client ISR
|
||||||
|
uint32_t savedPS = xt_rsil(15); // stop other interrupts
|
||||||
handler->fn();
|
handler->fn();
|
||||||
|
xt_wsr_ps(savedPS);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ETS_GPIO_INTR_ENABLE();
|
ETS_GPIO_INTR_ENABLE();
|
||||||
@ -152,9 +156,6 @@ extern void __detachInterrupt(uint8_t pin) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// stored state for the noInterrupts/interrupts methods
|
|
||||||
uint32_t interruptsState = 0;
|
|
||||||
|
|
||||||
void initPins() {
|
void initPins() {
|
||||||
//Disable UART interrupts
|
//Disable UART interrupts
|
||||||
system_set_os_print(0);
|
system_set_os_print(0);
|
||||||
|
@ -8,23 +8,51 @@ extern "C" {
|
|||||||
#include "ets_sys.h"
|
#include "ets_sys.h"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// these auto classes wrap up xt_rsil so your code can be simplier, but can only be
|
||||||
|
// used in an ino or cpp files.
|
||||||
|
|
||||||
#define xt_disable_interrupts(state, level) __asm__ __volatile__("rsil %0," __STRINGIFY(level) : "=a" (state))
|
// InterruptLock is used when you want to completely disable locks
|
||||||
#define xt_enable_interrupts(state) __asm__ __volatile__("wsr %0,ps; isync" :: "a" (state) : "memory")
|
//{
|
||||||
|
// {
|
||||||
|
// InterruptLock lock;
|
||||||
|
// // do work within interrupt lock here
|
||||||
|
// }
|
||||||
|
// do work outside of interrupt lock here outside its scope
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
|
||||||
class InterruptLock {
|
class InterruptLock {
|
||||||
public:
|
public:
|
||||||
InterruptLock() {
|
InterruptLock() {
|
||||||
xt_disable_interrupts(_state, 15);
|
_state = xt_rsil(15);
|
||||||
}
|
}
|
||||||
|
|
||||||
~InterruptLock() {
|
~InterruptLock() {
|
||||||
xt_enable_interrupts(_state);
|
xt_wsr_ps(_state);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
uint32_t _state;
|
uint32_t _state;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// AutoInterruptLock is when you need to set a specific level, A normal use pattern is like
|
||||||
|
//
|
||||||
|
//{
|
||||||
|
// {
|
||||||
|
// AutoInterruptLock(1); // this routine will allow level 2 and above
|
||||||
|
// // do work within interrupt lock here
|
||||||
|
// }
|
||||||
|
// do work outside of interrupt lock here outside its scope
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
#define AutoInterruptLock(intrLevel) \
|
||||||
|
class _AutoDisableIntr { \
|
||||||
|
public: \
|
||||||
|
_AutoDisableIntr() { _savedPS = xt_rsil(intrLevel); } \
|
||||||
|
~_AutoDisableIntr() { xt_wsr_ps(_savedPS); } \
|
||||||
|
private: \
|
||||||
|
uint32_t _savedPS; \
|
||||||
|
}; \
|
||||||
|
_AutoDisableIntr _autoDisableIntr
|
||||||
|
|
||||||
#endif //INTERRUPTS_H
|
#endif //INTERRUPTS_H
|
||||||
|
@ -215,57 +215,6 @@ char* ICACHE_FLASH_ATTR strdup(const char *str) {
|
|||||||
return cstr;
|
return cstr;
|
||||||
}
|
}
|
||||||
|
|
||||||
long int ICACHE_FLASH_ATTR strtol(const char* str, char** endptr, int base) {
|
|
||||||
long int result = 0;
|
|
||||||
int sign = 1;
|
|
||||||
|
|
||||||
while(isspace(*str)) {
|
|
||||||
str++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(*str == 0x00) {
|
|
||||||
// only space in str?
|
|
||||||
*endptr = (char*) str;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch(base) {
|
|
||||||
case 10:
|
|
||||||
|
|
||||||
if(*str == '-') {
|
|
||||||
sign = -1;
|
|
||||||
str++;
|
|
||||||
} else if(*str == '+') {
|
|
||||||
str++;
|
|
||||||
}
|
|
||||||
|
|
||||||
for(uint8_t i = 0; *str; i++, str++) {
|
|
||||||
int x = *str - '0';
|
|
||||||
if(x < 0 || x > 9) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
result = result * 10 + x;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
for(uint8_t i = 0; *str; i++, str++) {
|
|
||||||
int x = *str - '0';
|
|
||||||
if(x < 0 || x > 1) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
result = result * 2 + x;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 16:
|
|
||||||
default:
|
|
||||||
os_printf("fnk: strtol() only supports base 10 and 2 ATM!\n");
|
|
||||||
break;
|
|
||||||
|
|
||||||
}
|
|
||||||
*endptr = (char*) str;
|
|
||||||
return sign * result;
|
|
||||||
}
|
|
||||||
|
|
||||||
// based on Source:
|
// based on Source:
|
||||||
// https://github.com/anakod/Sming/blob/master/Sming/system/stringconversion.cpp#L93
|
// https://github.com/anakod/Sming/blob/master/Sming/system/stringconversion.cpp#L93
|
||||||
double ICACHE_FLASH_ATTR strtod(const char* str, char** endptr) {
|
double ICACHE_FLASH_ATTR strtod(const char* str, char** endptr) {
|
||||||
@ -280,7 +229,7 @@ double ICACHE_FLASH_ATTR strtod(const char* str, char** endptr) {
|
|||||||
|
|
||||||
if(*str == 0x00) {
|
if(*str == 0x00) {
|
||||||
// only space in str?
|
// only space in str?
|
||||||
*endptr = (char*) str;
|
if (endptr) *endptr = (char*) str;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -310,7 +259,7 @@ double ICACHE_FLASH_ATTR strtod(const char* str, char** endptr) {
|
|||||||
|
|
||||||
str++;
|
str++;
|
||||||
}
|
}
|
||||||
*endptr = (char*) str;
|
if (endptr) *endptr = (char*) str;
|
||||||
return result * factor;
|
return result * factor;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -479,16 +428,189 @@ size_t ICACHE_FLASH_ATTR strlcpy(char* dst, const char* src, size_t size) {
|
|||||||
break;
|
break;
|
||||||
} while (--n != 0);
|
} while (--n != 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (n == 0) {
|
if (n == 0) {
|
||||||
if (size != 0)
|
if (size != 0)
|
||||||
*dst = 0;
|
*dst = 0;
|
||||||
while (*s++);
|
while (*s++);
|
||||||
}
|
}
|
||||||
|
|
||||||
return(s - src - 1);
|
return(s - src - 1);
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
* end of newlib/string/strlcpy.c
|
* end of newlib/string/strlcpy.c
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* strtol() and strtoul() implementations borrowed from newlib:
|
||||||
|
* http://www.sourceware.org/newlib/
|
||||||
|
* newlib/libc/stdlib/strtol.c
|
||||||
|
* newlib/libc/stdlib/strtoul.c
|
||||||
|
*
|
||||||
|
* Adapted for ESP8266 by Kiril Zyapkov <kiril.zyapkov@gmail.com>
|
||||||
|
*
|
||||||
|
* Copyright (c) 1990 The Regents of the University of California.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. All advertising materials mentioning features or use of this software
|
||||||
|
* must display the following acknowledgement:
|
||||||
|
* This product includes software developed by the University of
|
||||||
|
* California, Berkeley and its contributors.
|
||||||
|
* 4. Neither the name of the University nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||||
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||||
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
* SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
long ICACHE_FLASH_ATTR strtol(const char *nptr, char **endptr, int base) {
|
||||||
|
const unsigned char *s = (const unsigned char *)nptr;
|
||||||
|
unsigned long acc;
|
||||||
|
int c;
|
||||||
|
unsigned long cutoff;
|
||||||
|
int neg = 0, any, cutlim;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Skip white space and pick up leading +/- sign if any.
|
||||||
|
* If base is 0, allow 0x for hex and 0 for octal, else
|
||||||
|
* assume decimal; if base is already 16, allow 0x.
|
||||||
|
*/
|
||||||
|
do {
|
||||||
|
c = *s++;
|
||||||
|
} while (isspace(c));
|
||||||
|
if (c == '-') {
|
||||||
|
neg = 1;
|
||||||
|
c = *s++;
|
||||||
|
} else if (c == '+')
|
||||||
|
c = *s++;
|
||||||
|
if ((base == 0 || base == 16) &&
|
||||||
|
c == '0' && (*s == 'x' || *s == 'X')) {
|
||||||
|
c = s[1];
|
||||||
|
s += 2;
|
||||||
|
base = 16;
|
||||||
|
}
|
||||||
|
if (base == 0)
|
||||||
|
base = c == '0' ? 8 : 10;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Compute the cutoff value between legal numbers and illegal
|
||||||
|
* numbers. That is the largest legal value, divided by the
|
||||||
|
* base. An input number that is greater than this value, if
|
||||||
|
* followed by a legal input character, is too big. One that
|
||||||
|
* is equal to this value may be valid or not; the limit
|
||||||
|
* between valid and invalid numbers is then based on the last
|
||||||
|
* digit. For instance, if the range for longs is
|
||||||
|
* [-2147483648..2147483647] and the input base is 10,
|
||||||
|
* cutoff will be set to 214748364 and cutlim to either
|
||||||
|
* 7 (neg==0) or 8 (neg==1), meaning that if we have accumulated
|
||||||
|
* a value > 214748364, or equal but the next digit is > 7 (or 8),
|
||||||
|
* the number is too big, and we will return a range error.
|
||||||
|
*
|
||||||
|
* Set any if any `digits' consumed; make it negative to indicate
|
||||||
|
* overflow.
|
||||||
|
*/
|
||||||
|
cutoff = neg ? -(unsigned long)LONG_MIN : LONG_MAX;
|
||||||
|
cutlim = cutoff % (unsigned long)base;
|
||||||
|
cutoff /= (unsigned long)base;
|
||||||
|
for (acc = 0, any = 0;; c = *s++) {
|
||||||
|
if (isdigit(c))
|
||||||
|
c -= '0';
|
||||||
|
else if (isalpha(c))
|
||||||
|
c -= isupper(c) ? 'A' - 10 : 'a' - 10;
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
if (c >= base)
|
||||||
|
break;
|
||||||
|
if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim))
|
||||||
|
any = -1;
|
||||||
|
else {
|
||||||
|
any = 1;
|
||||||
|
acc *= base;
|
||||||
|
acc += c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (any < 0) {
|
||||||
|
acc = neg ? LONG_MIN : LONG_MAX;
|
||||||
|
errno = ERANGE;
|
||||||
|
} else if (neg)
|
||||||
|
acc = -acc;
|
||||||
|
if (endptr != 0)
|
||||||
|
*endptr = (char *) (any ? (char *)s - 1 : nptr);
|
||||||
|
return (acc);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned long ICACHE_FLASH_ATTR strtoul(const char *nptr, char **endptr, int base)
|
||||||
|
{
|
||||||
|
const unsigned char *s = (const unsigned char *)nptr;
|
||||||
|
unsigned long acc;
|
||||||
|
int c;
|
||||||
|
unsigned long cutoff;
|
||||||
|
int neg = 0, any, cutlim;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* See strtol for comments as to the logic used.
|
||||||
|
*/
|
||||||
|
do {
|
||||||
|
c = *s++;
|
||||||
|
} while (isspace(c));
|
||||||
|
if (c == '-') {
|
||||||
|
neg = 1;
|
||||||
|
c = *s++;
|
||||||
|
} else if (c == '+')
|
||||||
|
c = *s++;
|
||||||
|
if ((base == 0 || base == 16) &&
|
||||||
|
c == '0' && (*s == 'x' || *s == 'X')) {
|
||||||
|
c = s[1];
|
||||||
|
s += 2;
|
||||||
|
base = 16;
|
||||||
|
}
|
||||||
|
if (base == 0)
|
||||||
|
base = c == '0' ? 8 : 10;
|
||||||
|
cutoff = (unsigned long)ULONG_MAX / (unsigned long)base;
|
||||||
|
cutlim = (unsigned long)ULONG_MAX % (unsigned long)base;
|
||||||
|
for (acc = 0, any = 0;; c = *s++) {
|
||||||
|
if (isdigit(c))
|
||||||
|
c -= '0';
|
||||||
|
else if (isalpha(c))
|
||||||
|
c -= isupper(c) ? 'A' - 10 : 'a' - 10;
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
if (c >= base)
|
||||||
|
break;
|
||||||
|
if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim))
|
||||||
|
any = -1;
|
||||||
|
else {
|
||||||
|
any = 1;
|
||||||
|
acc *= base;
|
||||||
|
acc += c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (any < 0) {
|
||||||
|
acc = ULONG_MAX;
|
||||||
|
errno = ERANGE;
|
||||||
|
} else if (neg)
|
||||||
|
acc = -acc;
|
||||||
|
if (endptr != 0)
|
||||||
|
*endptr = (char *) (any ? (char *)s - 1 : nptr);
|
||||||
|
return (acc);
|
||||||
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
SPIFFS (SPI Flash File System)
|
SPIFFS (SPI Flash File System)
|
||||||
V0.3.0
|
V0.3.2
|
||||||
|
|
||||||
Copyright (c) 2013-2015 Peter Andersson (pelleplutt1976<at>gmail.com)
|
Copyright (c) 2013-2015 Peter Andersson (pelleplutt1976<at>gmail.com)
|
||||||
|
|
||||||
@ -58,6 +58,30 @@ For testing and contributions, see the docs/IMPLEMENTING file.
|
|||||||
|
|
||||||
* HISTORY
|
* HISTORY
|
||||||
|
|
||||||
|
0.3.2
|
||||||
|
Limit cache size if too much cache is given (thanks pgeiem)
|
||||||
|
New feature - Controlled erase. #23
|
||||||
|
SPIFFS_rename leaks file descriptors #28 (thanks benpicco)
|
||||||
|
moved dbg print defines in test framework to params_test.h
|
||||||
|
lseek should return the resulting offset (thanks hefloryd)
|
||||||
|
fixed type on dbg ifdefs
|
||||||
|
silence warning about signed/unsigned comparison when spiffs_obj_id is 32 bit (thanks benpicco)
|
||||||
|
Possible error in test_spiffs.c #21 (thanks yihcdaso-yeskela)
|
||||||
|
Cache might writethrough too often #16
|
||||||
|
even moar testrunner updates
|
||||||
|
Test framework update and some added tests
|
||||||
|
Some thoughts for next gen
|
||||||
|
Test sigsevs when having too many sectors #13 (thanks alonewolfx2)
|
||||||
|
GC might be suboptimal #11
|
||||||
|
Fix eternal readdir when objheader at last block, last entry
|
||||||
|
|
||||||
|
New API functions:
|
||||||
|
SPIFFS_gc_quick - call a nonintrusive gc
|
||||||
|
SPIFFS_gc - call a full-scale intrusive gc
|
||||||
|
|
||||||
|
0.3.1
|
||||||
|
Removed two return warnings, was too triggerhappy on release
|
||||||
|
|
||||||
0.3.0
|
0.3.0
|
||||||
Added existing namecheck when creating files
|
Added existing namecheck when creating files
|
||||||
Lots of static analysis bugs #6
|
Lots of static analysis bugs #6
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
|
|
||||||
#ifndef SPIFFS_H_
|
#ifndef SPIFFS_H_
|
||||||
#define SPIFFS_H_
|
#define SPIFFS_H_
|
||||||
#ifdef __cplusplus
|
#if defined(__cplusplus)
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -47,6 +47,9 @@ extern "C" {
|
|||||||
#define SPIFFS_ERR_ERASE_FAIL -10027
|
#define SPIFFS_ERR_ERASE_FAIL -10027
|
||||||
#define SPIFFS_ERR_MAGIC_NOT_POSSIBLE -10028
|
#define SPIFFS_ERR_MAGIC_NOT_POSSIBLE -10028
|
||||||
|
|
||||||
|
#define SPIFFS_ERR_NO_DELETED_BLOCKS -10029
|
||||||
|
|
||||||
|
#define SPIFFS_ERR_FILE_EXISTS -10030
|
||||||
|
|
||||||
#define SPIFFS_ERR_INTERNAL -10050
|
#define SPIFFS_ERR_INTERNAL -10050
|
||||||
|
|
||||||
@ -62,12 +65,25 @@ typedef u16_t spiffs_mode;
|
|||||||
// object type
|
// object type
|
||||||
typedef u8_t spiffs_obj_type;
|
typedef u8_t spiffs_obj_type;
|
||||||
|
|
||||||
|
#if SPIFFS_HAL_CALLBACK_EXTRA
|
||||||
|
struct spiffs_t;
|
||||||
|
|
||||||
|
/* spi read call function type */
|
||||||
|
typedef s32_t (*spiffs_read)(struct spiffs_t *fs, u32_t addr, u32_t size, u8_t *dst);
|
||||||
|
/* spi write call function type */
|
||||||
|
typedef s32_t (*spiffs_write)(struct spiffs_t *fs, u32_t addr, u32_t size, u8_t *src);
|
||||||
|
/* spi erase call function type */
|
||||||
|
typedef s32_t (*spiffs_erase)(struct spiffs_t *fs, u32_t addr, u32_t size);
|
||||||
|
|
||||||
|
#else // SPIFFS_HAL_CALLBACK_EXTRA
|
||||||
|
|
||||||
/* spi read call function type */
|
/* spi read call function type */
|
||||||
typedef s32_t (*spiffs_read)(u32_t addr, u32_t size, u8_t *dst);
|
typedef s32_t (*spiffs_read)(u32_t addr, u32_t size, u8_t *dst);
|
||||||
/* spi write call function type */
|
/* spi write call function type */
|
||||||
typedef s32_t (*spiffs_write)(u32_t addr, u32_t size, u8_t *src);
|
typedef s32_t (*spiffs_write)(u32_t addr, u32_t size, u8_t *src);
|
||||||
/* spi erase call function type */
|
/* spi erase call function type */
|
||||||
typedef s32_t (*spiffs_erase)(u32_t addr, u32_t size);
|
typedef s32_t (*spiffs_erase)(u32_t addr, u32_t size);
|
||||||
|
#endif // SPIFFS_HAL_CALLBACK_EXTRA
|
||||||
|
|
||||||
/* file system check callback report operation */
|
/* file system check callback report operation */
|
||||||
typedef enum {
|
typedef enum {
|
||||||
@ -88,21 +104,26 @@ typedef enum {
|
|||||||
} spiffs_check_report;
|
} spiffs_check_report;
|
||||||
|
|
||||||
/* file system check callback function */
|
/* file system check callback function */
|
||||||
|
#if SPIFFS_HAL_CALLBACK_EXTRA
|
||||||
|
typedef void (*spiffs_check_callback)(struct spiffs_t *fs, spiffs_check_type type, spiffs_check_report report,
|
||||||
|
u32_t arg1, u32_t arg2);
|
||||||
|
#else // SPIFFS_HAL_CALLBACK_EXTRA
|
||||||
typedef void (*spiffs_check_callback)(spiffs_check_type type, spiffs_check_report report,
|
typedef void (*spiffs_check_callback)(spiffs_check_type type, spiffs_check_report report,
|
||||||
u32_t arg1, u32_t arg2);
|
u32_t arg1, u32_t arg2);
|
||||||
|
#endif // SPIFFS_HAL_CALLBACK_EXTRA
|
||||||
|
|
||||||
#ifndef SPIFFS_DBG
|
#ifndef SPIFFS_DBG
|
||||||
#define SPIFFS_DBG(...) \
|
#define SPIFFS_DBG(...) \
|
||||||
print(__VA_ARGS__)
|
print(__VA_ARGS__)
|
||||||
#endif
|
#endif
|
||||||
#ifndef SPIFFS_GC_DBG
|
#ifndef SPIFFS_GC_DBG
|
||||||
#define SPIFFS_GC_DBG(...) c_printf(__VA_ARGS__)
|
#define SPIFFS_GC_DBG(...) printf(__VA_ARGS__)
|
||||||
#endif
|
#endif
|
||||||
#ifndef SPIFFS_CACHE_DBG
|
#ifndef SPIFFS_CACHE_DBG
|
||||||
#define SPIFFS_CACHE_DBG(...) c_printf(__VA_ARGS__)
|
#define SPIFFS_CACHE_DBG(...) printf(__VA_ARGS__)
|
||||||
#endif
|
#endif
|
||||||
#ifndef SPIFFS_CHECK_DBG
|
#ifndef SPIFFS_CHECK_DBG
|
||||||
#define SPIFFS_CHECK_DBG(...) c_printf(__VA_ARGS__)
|
#define SPIFFS_CHECK_DBG(...) printf(__VA_ARGS__)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Any write to the filehandle is appended to end of the file */
|
/* Any write to the filehandle is appended to end of the file */
|
||||||
@ -119,6 +140,8 @@ typedef void (*spiffs_check_callback)(spiffs_check_type type, spiffs_check_repor
|
|||||||
#define SPIFFS_RDWR (SPIFFS_RDONLY | SPIFFS_WRONLY)
|
#define SPIFFS_RDWR (SPIFFS_RDONLY | SPIFFS_WRONLY)
|
||||||
/* Any writes to the filehandle will never be cached */
|
/* Any writes to the filehandle will never be cached */
|
||||||
#define SPIFFS_DIRECT (1<<5)
|
#define SPIFFS_DIRECT (1<<5)
|
||||||
|
/* If SPIFFS_CREAT and SPIFFS_EXCL are set, SPIFFS_open() shall fail if the file exists */
|
||||||
|
#define SPIFFS_EXCL (1<<6)
|
||||||
|
|
||||||
#define SPIFFS_SEEK_SET (0)
|
#define SPIFFS_SEEK_SET (0)
|
||||||
#define SPIFFS_SEEK_CUR (1)
|
#define SPIFFS_SEEK_CUR (1)
|
||||||
@ -166,7 +189,7 @@ typedef struct {
|
|||||||
#endif
|
#endif
|
||||||
} spiffs_config;
|
} spiffs_config;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct spiffs_t {
|
||||||
// file system configuration
|
// file system configuration
|
||||||
spiffs_config cfg;
|
spiffs_config cfg;
|
||||||
// number of logical blocks
|
// number of logical blocks
|
||||||
@ -224,6 +247,8 @@ typedef struct {
|
|||||||
|
|
||||||
// mounted flag
|
// mounted flag
|
||||||
u8_t mounted;
|
u8_t mounted;
|
||||||
|
// user data
|
||||||
|
void *user_data;
|
||||||
// config magic
|
// config magic
|
||||||
u32_t config_magic;
|
u32_t config_magic;
|
||||||
} spiffs;
|
} spiffs;
|
||||||
@ -387,7 +412,7 @@ s32_t SPIFFS_fflush(spiffs *fs, spiffs_file fh);
|
|||||||
* @param fs the file system struct
|
* @param fs the file system struct
|
||||||
* @param fh the filehandle of the file to close
|
* @param fh the filehandle of the file to close
|
||||||
*/
|
*/
|
||||||
void SPIFFS_close(spiffs *fs, spiffs_file fh);
|
s32_t SPIFFS_close(spiffs *fs, spiffs_file fh);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Renames a file
|
* Renames a file
|
||||||
@ -440,7 +465,6 @@ struct spiffs_dirent *SPIFFS_readdir(spiffs_DIR *d, struct spiffs_dirent *e);
|
|||||||
*/
|
*/
|
||||||
s32_t SPIFFS_check(spiffs *fs);
|
s32_t SPIFFS_check(spiffs *fs);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns number of total bytes available and number of used bytes.
|
* Returns number of total bytes available and number of used bytes.
|
||||||
* This is an estimation, and depends on if there a many files with little
|
* This is an estimation, and depends on if there a many files with little
|
||||||
@ -465,27 +489,60 @@ s32_t SPIFFS_info(spiffs *fs, u32_t *total, u32_t *used);
|
|||||||
* SPIFFS_format.
|
* SPIFFS_format.
|
||||||
* If SPIFFS_mount fails, SPIFFS_format can be called directly without calling
|
* If SPIFFS_mount fails, SPIFFS_format can be called directly without calling
|
||||||
* SPIFFS_unmount first.
|
* SPIFFS_unmount first.
|
||||||
|
*
|
||||||
|
* @param fs the file system struct
|
||||||
*/
|
*/
|
||||||
s32_t SPIFFS_format(spiffs *fs);
|
s32_t SPIFFS_format(spiffs *fs);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns nonzero if spiffs is mounted, or zero if unmounted.
|
* Returns nonzero if spiffs is mounted, or zero if unmounted.
|
||||||
|
* @param fs the file system struct
|
||||||
*/
|
*/
|
||||||
u8_t SPIFFS_mounted(spiffs *fs);
|
u8_t SPIFFS_mounted(spiffs *fs);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if EOF reached.
|
* Tries to find a block where most or all pages are deleted, and erase that
|
||||||
* @param fs the file system struct
|
* block if found. Does not care for wear levelling. Will not move pages
|
||||||
* @param fh the filehandle of the file to check
|
* around.
|
||||||
|
* If parameter max_free_pages are set to 0, only blocks with only deleted
|
||||||
|
* pages will be selected.
|
||||||
|
*
|
||||||
|
* NB: the garbage collector is automatically called when spiffs needs free
|
||||||
|
* pages. The reason for this function is to give possibility to do background
|
||||||
|
* tidying when user knows the system is idle.
|
||||||
|
*
|
||||||
|
* Use with care.
|
||||||
|
*
|
||||||
|
* Setting max_free_pages to anything larger than zero will eventually wear
|
||||||
|
* flash more as a block containing free pages can be erased.
|
||||||
|
*
|
||||||
|
* Will set err_no to SPIFFS_OK if a block was found and erased,
|
||||||
|
* SPIFFS_ERR_NO_DELETED_BLOCK if no matching block was found,
|
||||||
|
* or other error.
|
||||||
|
*
|
||||||
|
* @param fs the file system struct
|
||||||
|
* @param max_free_pages maximum number allowed free pages in block
|
||||||
*/
|
*/
|
||||||
s32_t SPIFFS_eof(spiffs *fs, spiffs_file fh);
|
s32_t SPIFFS_gc_quick(spiffs *fs, u16_t max_free_pages);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the current position of the data pointer.
|
* Will try to make room for given amount of bytes in the filesystem by moving
|
||||||
|
* pages and erasing blocks.
|
||||||
|
* If it is physically impossible, err_no will be set to SPIFFS_ERR_FULL. If
|
||||||
|
* there already is this amount (or more) of free space, SPIFFS_gc will
|
||||||
|
* silently return. It is recommended to call SPIFFS_info before invoking
|
||||||
|
* this method in order to determine what amount of bytes to give.
|
||||||
|
*
|
||||||
|
* NB: the garbage collector is automatically called when spiffs needs free
|
||||||
|
* pages. The reason for this function is to give possibility to do background
|
||||||
|
* tidying when user knows the system is idle.
|
||||||
|
*
|
||||||
|
* Use with care.
|
||||||
|
*
|
||||||
* @param fs the file system struct
|
* @param fs the file system struct
|
||||||
* @param fh the filehandle of the open file
|
* @param size amount of bytes that should be freed
|
||||||
*/
|
*/
|
||||||
s32_t SPIFFS_tell(spiffs *fs, spiffs_file fh);
|
s32_t SPIFFS_gc(spiffs *fs, u32_t size);
|
||||||
|
|
||||||
#if SPIFFS_TEST_VISUALISATION
|
#if SPIFFS_TEST_VISUALISATION
|
||||||
/**
|
/**
|
||||||
@ -511,8 +568,9 @@ u32_t SPIFFS_buffer_bytes_for_cache(spiffs *fs, u32_t num_pages);
|
|||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if SPIFFS_CACHE
|
||||||
#ifdef __cplusplus
|
#endif
|
||||||
|
#if defined(__cplusplus)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -20,7 +20,7 @@ static spiffs_cache_page *spiffs_cache_page_get(spiffs *fs, spiffs_page_ix pix)
|
|||||||
if ((cache->cpage_use_map & (1<<i)) &&
|
if ((cache->cpage_use_map & (1<<i)) &&
|
||||||
(cp->flags & SPIFFS_CACHE_FLAG_TYPE_WR) == 0 &&
|
(cp->flags & SPIFFS_CACHE_FLAG_TYPE_WR) == 0 &&
|
||||||
cp->pix == pix ) {
|
cp->pix == pix ) {
|
||||||
SPIFFS_CACHE_DBG("CACHE_GET: have cache page %d for %04x\n", i, pix);
|
SPIFFS_CACHE_DBG("CACHE_GET: have cache page %i for %04x\n", i, pix);
|
||||||
cp->last_access = cache->last_access;
|
cp->last_access = cache->last_access;
|
||||||
return cp;
|
return cp;
|
||||||
}
|
}
|
||||||
@ -39,16 +39,16 @@ static s32_t spiffs_cache_page_free(spiffs *fs, int ix, u8_t write_back) {
|
|||||||
(cp->flags & SPIFFS_CACHE_FLAG_TYPE_WR) == 0 &&
|
(cp->flags & SPIFFS_CACHE_FLAG_TYPE_WR) == 0 &&
|
||||||
(cp->flags & SPIFFS_CACHE_FLAG_DIRTY)) {
|
(cp->flags & SPIFFS_CACHE_FLAG_DIRTY)) {
|
||||||
u8_t *mem = spiffs_get_cache_page(fs, cache, ix);
|
u8_t *mem = spiffs_get_cache_page(fs, cache, ix);
|
||||||
res = fs->cfg.hal_write_f(SPIFFS_PAGE_TO_PADDR(fs, cp->pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), mem);
|
res = SPIFFS_HAL_WRITE(fs, SPIFFS_PAGE_TO_PADDR(fs, cp->pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), mem);
|
||||||
}
|
}
|
||||||
|
|
||||||
cp->flags = 0;
|
cp->flags = 0;
|
||||||
cache->cpage_use_map &= ~(1 << ix);
|
cache->cpage_use_map &= ~(1 << ix);
|
||||||
|
|
||||||
if (cp->flags & SPIFFS_CACHE_FLAG_TYPE_WR) {
|
if (cp->flags & SPIFFS_CACHE_FLAG_TYPE_WR) {
|
||||||
SPIFFS_CACHE_DBG("CACHE_FREE: free cache page %d objid %04x\n", ix, cp->obj_id);
|
SPIFFS_CACHE_DBG("CACHE_FREE: free cache page %i objid %04x\n", ix, cp->obj_id);
|
||||||
} else {
|
} else {
|
||||||
SPIFFS_CACHE_DBG("CACHE_FREE: free cache page %d pix %04x\n", ix, cp->pix);
|
SPIFFS_CACHE_DBG("CACHE_FREE: free cache page %i pix %04x\n", ix, cp->pix);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -98,7 +98,7 @@ static spiffs_cache_page *spiffs_cache_page_allocate(spiffs *fs) {
|
|||||||
spiffs_cache_page *cp = spiffs_get_cache_page_hdr(fs, cache, i);
|
spiffs_cache_page *cp = spiffs_get_cache_page_hdr(fs, cache, i);
|
||||||
cache->cpage_use_map |= (1<<i);
|
cache->cpage_use_map |= (1<<i);
|
||||||
cp->last_access = cache->last_access;
|
cp->last_access = cache->last_access;
|
||||||
SPIFFS_CACHE_DBG("CACHE_ALLO: allocated cache page %d\n", i);
|
SPIFFS_CACHE_DBG("CACHE_ALLO: allocated cache page %i\n", i);
|
||||||
return cp;
|
return cp;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -137,10 +137,7 @@ s32_t spiffs_phys_rd(
|
|||||||
} else {
|
} else {
|
||||||
if ((op & SPIFFS_OP_TYPE_MASK) == SPIFFS_OP_T_OBJ_LU2) {
|
if ((op & SPIFFS_OP_TYPE_MASK) == SPIFFS_OP_T_OBJ_LU2) {
|
||||||
// for second layer lookup functions, we do not cache in order to prevent shredding
|
// for second layer lookup functions, we do not cache in order to prevent shredding
|
||||||
return fs->cfg.hal_read_f(
|
return SPIFFS_HAL_READ(fs, addr, len, dst);
|
||||||
addr ,
|
|
||||||
len,
|
|
||||||
dst);
|
|
||||||
}
|
}
|
||||||
#if SPIFFS_CACHE_STATS
|
#if SPIFFS_CACHE_STATS
|
||||||
fs->cache_misses++;
|
fs->cache_misses++;
|
||||||
@ -151,8 +148,7 @@ s32_t spiffs_phys_rd(
|
|||||||
cp->flags = SPIFFS_CACHE_FLAG_WRTHRU;
|
cp->flags = SPIFFS_CACHE_FLAG_WRTHRU;
|
||||||
cp->pix = SPIFFS_PADDR_TO_PAGE(fs, addr);
|
cp->pix = SPIFFS_PADDR_TO_PAGE(fs, addr);
|
||||||
}
|
}
|
||||||
|
s32_t res2 = SPIFFS_HAL_READ(fs,
|
||||||
s32_t res2 = fs->cfg.hal_read_f(
|
|
||||||
addr - SPIFFS_PADDR_TO_PAGE_OFFSET(fs, addr),
|
addr - SPIFFS_PADDR_TO_PAGE_OFFSET(fs, addr),
|
||||||
SPIFFS_CFG_LOG_PAGE_SZ(fs),
|
SPIFFS_CFG_LOG_PAGE_SZ(fs),
|
||||||
spiffs_get_cache_page(fs, cache, cp->ix));
|
spiffs_get_cache_page(fs, cache, cp->ix));
|
||||||
@ -161,7 +157,7 @@ s32_t spiffs_phys_rd(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
u8_t *mem = spiffs_get_cache_page(fs, cache, cp->ix);
|
u8_t *mem = spiffs_get_cache_page(fs, cache, cp->ix);
|
||||||
c_memcpy(dst, &mem[SPIFFS_PADDR_TO_PAGE_OFFSET(fs, addr)], len);
|
memcpy(dst, &mem[SPIFFS_PADDR_TO_PAGE_OFFSET(fs, addr)], len);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -186,24 +182,24 @@ s32_t spiffs_phys_wr(
|
|||||||
(op & SPIFFS_OP_TYPE_MASK) != SPIFFS_OP_T_OBJ_LU) {
|
(op & SPIFFS_OP_TYPE_MASK) != SPIFFS_OP_T_OBJ_LU) {
|
||||||
// page is being deleted, wipe from cache - unless it is a lookup page
|
// page is being deleted, wipe from cache - unless it is a lookup page
|
||||||
spiffs_cache_page_free(fs, cp->ix, 0);
|
spiffs_cache_page_free(fs, cp->ix, 0);
|
||||||
return fs->cfg.hal_write_f(addr, len, src);
|
return SPIFFS_HAL_WRITE(fs, addr, len, src);
|
||||||
}
|
}
|
||||||
|
|
||||||
u8_t *mem = spiffs_get_cache_page(fs, cache, cp->ix);
|
u8_t *mem = spiffs_get_cache_page(fs, cache, cp->ix);
|
||||||
c_memcpy(&mem[SPIFFS_PADDR_TO_PAGE_OFFSET(fs, addr)], src, len);
|
memcpy(&mem[SPIFFS_PADDR_TO_PAGE_OFFSET(fs, addr)], src, len);
|
||||||
|
|
||||||
cache->last_access++;
|
cache->last_access++;
|
||||||
cp->last_access = cache->last_access;
|
cp->last_access = cache->last_access;
|
||||||
|
|
||||||
if (cp->flags && SPIFFS_CACHE_FLAG_WRTHRU) {
|
if (cp->flags & SPIFFS_CACHE_FLAG_WRTHRU) {
|
||||||
// page is being updated, no write-cache, just pass thru
|
// page is being updated, no write-cache, just pass thru
|
||||||
return fs->cfg.hal_write_f(addr, len, src);
|
return SPIFFS_HAL_WRITE(fs, addr, len, src);
|
||||||
} else {
|
} else {
|
||||||
return SPIFFS_OK;
|
return SPIFFS_OK;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// no cache page, no write cache - just write thru
|
// no cache page, no write cache - just write thru
|
||||||
return fs->cfg.hal_write_f(addr, len, src);
|
return SPIFFS_HAL_WRITE(fs, addr, len, src);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -282,17 +278,17 @@ void spiffs_cache_init(spiffs *fs) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
spiffs_cache cache;
|
spiffs_cache cache;
|
||||||
c_memset(&cache, 0, sizeof(spiffs_cache));
|
memset(&cache, 0, sizeof(spiffs_cache));
|
||||||
cache.cpage_count = cache_entries;
|
cache.cpage_count = cache_entries;
|
||||||
cache.cpages = (u8_t *)((u8_t *)fs->cache + sizeof(spiffs_cache));
|
cache.cpages = (u8_t *)((u8_t *)fs->cache + sizeof(spiffs_cache));
|
||||||
|
|
||||||
cache.cpage_use_map = 0xffffffff;
|
cache.cpage_use_map = 0xffffffff;
|
||||||
cache.cpage_use_mask = cache_mask;
|
cache.cpage_use_mask = cache_mask;
|
||||||
c_memcpy(fs->cache, &cache, sizeof(spiffs_cache));
|
memcpy(fs->cache, &cache, sizeof(spiffs_cache));
|
||||||
|
|
||||||
spiffs_cache *c = spiffs_get_cache(fs);
|
spiffs_cache *c = spiffs_get_cache(fs);
|
||||||
|
|
||||||
c_memset(c->cpages, 0, c->cpage_count * SPIFFS_CACHE_PAGE_SIZE(fs));
|
memset(c->cpages, 0, c->cpage_count * SPIFFS_CACHE_PAGE_SIZE(fs));
|
||||||
|
|
||||||
c->cpage_use_map &= ~(c->cpage_use_mask);
|
c->cpage_use_map &= ~(c->cpage_use_mask);
|
||||||
for (i = 0; i < cache.cpage_count; i++) {
|
for (i = 0; i < cache.cpage_count; i++) {
|
||||||
|
@ -22,6 +22,19 @@
|
|||||||
#include "spiffs.h"
|
#include "spiffs.h"
|
||||||
#include "spiffs_nucleus.h"
|
#include "spiffs_nucleus.h"
|
||||||
|
|
||||||
|
|
||||||
|
#if SPIFFS_HAL_CALLBACK_EXTRA
|
||||||
|
#define CHECK_CB(_fs, _type, _rep, _arg1, _arg2) \
|
||||||
|
do { \
|
||||||
|
if ((_fs)->check_cb_f) (_fs)->check_cb_f((_fs), (_type), (_rep), (_arg1), (_arg2)); \
|
||||||
|
} while (0)
|
||||||
|
#else
|
||||||
|
#define CHECK_CB(_fs, _type, _rep, _arg1, _arg2) \
|
||||||
|
do { \
|
||||||
|
if ((_fs)->check_cb_f) (_fs)->check_cb_f((_type), (_rep), (_arg1), (_arg2)); \
|
||||||
|
} while (0)
|
||||||
|
#endif
|
||||||
|
|
||||||
//---------------------------------------
|
//---------------------------------------
|
||||||
// Look up consistency
|
// Look up consistency
|
||||||
|
|
||||||
@ -190,13 +203,13 @@ static s32_t spiffs_lookup_check_validate(spiffs *fs, spiffs_obj_id lu_obj_id, s
|
|||||||
res = spiffs_rewrite_index(fs, p_hdr->obj_id, p_hdr->span_ix, new_pix, objix_pix);
|
res = spiffs_rewrite_index(fs, p_hdr->obj_id, p_hdr->span_ix, new_pix, objix_pix);
|
||||||
if (res <= _SPIFFS_ERR_CHECK_FIRST && res > _SPIFFS_ERR_CHECK_LAST) {
|
if (res <= _SPIFFS_ERR_CHECK_FIRST && res > _SPIFFS_ERR_CHECK_LAST) {
|
||||||
// index bad also, cannot mend this file
|
// index bad also, cannot mend this file
|
||||||
SPIFFS_CHECK_DBG("LU: FIXUP: index bad %d, cannot mend!\n", res);
|
SPIFFS_CHECK_DBG("LU: FIXUP: index bad %i, cannot mend!\n", res);
|
||||||
res = spiffs_page_delete(fs, new_pix);
|
res = spiffs_page_delete(fs, new_pix);
|
||||||
SPIFFS_CHECK_RES(res);
|
SPIFFS_CHECK_RES(res);
|
||||||
res = spiffs_delete_obj_lazy(fs, p_hdr->obj_id);
|
res = spiffs_delete_obj_lazy(fs, p_hdr->obj_id);
|
||||||
if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_DELETE_BAD_FILE, p_hdr->obj_id, 0);
|
CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_DELETE_BAD_FILE, p_hdr->obj_id, 0);
|
||||||
} else {
|
} else {
|
||||||
if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_FIX_INDEX, p_hdr->obj_id, p_hdr->span_ix);
|
CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_FIX_INDEX, p_hdr->obj_id, p_hdr->span_ix);
|
||||||
}
|
}
|
||||||
SPIFFS_CHECK_RES(res);
|
SPIFFS_CHECK_RES(res);
|
||||||
}
|
}
|
||||||
@ -216,7 +229,7 @@ static s32_t spiffs_lookup_check_validate(spiffs *fs, spiffs_obj_id lu_obj_id, s
|
|||||||
SPIFFS_CHECK_DBG("LU: FIXUP: ix page with data not found elsewhere, rewriting %04x to new page %04x\n", cur_pix, new_pix);
|
SPIFFS_CHECK_DBG("LU: FIXUP: ix page with data not found elsewhere, rewriting %04x to new page %04x\n", cur_pix, new_pix);
|
||||||
SPIFFS_CHECK_RES(res);
|
SPIFFS_CHECK_RES(res);
|
||||||
*reload_lu = 1;
|
*reload_lu = 1;
|
||||||
if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_FIX_LOOKUP, p_hdr->obj_id, p_hdr->span_ix);
|
CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_FIX_LOOKUP, p_hdr->obj_id, p_hdr->span_ix);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
SPIFFS_CHECK_RES(res);
|
SPIFFS_CHECK_RES(res);
|
||||||
@ -249,12 +262,12 @@ static s32_t spiffs_lookup_check_validate(spiffs *fs, spiffs_obj_id lu_obj_id, s
|
|||||||
res = spiffs_rewrite_index(fs, p_hdr->obj_id, p_hdr->span_ix, new_pix, objix_pix);
|
res = spiffs_rewrite_index(fs, p_hdr->obj_id, p_hdr->span_ix, new_pix, objix_pix);
|
||||||
if (res <= _SPIFFS_ERR_CHECK_FIRST && res > _SPIFFS_ERR_CHECK_LAST) {
|
if (res <= _SPIFFS_ERR_CHECK_FIRST && res > _SPIFFS_ERR_CHECK_LAST) {
|
||||||
// index bad also, cannot mend this file
|
// index bad also, cannot mend this file
|
||||||
SPIFFS_CHECK_DBG("LU: FIXUP: index bad %d, cannot mend!\n", res);
|
SPIFFS_CHECK_DBG("LU: FIXUP: index bad %i, cannot mend!\n", res);
|
||||||
res = spiffs_page_delete(fs, new_pix);
|
res = spiffs_page_delete(fs, new_pix);
|
||||||
SPIFFS_CHECK_RES(res);
|
SPIFFS_CHECK_RES(res);
|
||||||
res = spiffs_delete_obj_lazy(fs, p_hdr->obj_id);
|
res = spiffs_delete_obj_lazy(fs, p_hdr->obj_id);
|
||||||
*reload_lu = 1;
|
*reload_lu = 1;
|
||||||
if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_DELETE_BAD_FILE, p_hdr->obj_id, 0);
|
CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_DELETE_BAD_FILE, p_hdr->obj_id, 0);
|
||||||
}
|
}
|
||||||
SPIFFS_CHECK_RES(res);
|
SPIFFS_CHECK_RES(res);
|
||||||
}
|
}
|
||||||
@ -306,7 +319,7 @@ static s32_t spiffs_lookup_check_validate(spiffs *fs, spiffs_obj_id lu_obj_id, s
|
|||||||
new_ph.obj_id = p_hdr->obj_id | SPIFFS_OBJ_ID_IX_FLAG;
|
new_ph.obj_id = p_hdr->obj_id | SPIFFS_OBJ_ID_IX_FLAG;
|
||||||
res = spiffs_rewrite_page(fs, cur_pix, &new_ph, &new_pix);
|
res = spiffs_rewrite_page(fs, cur_pix, &new_ph, &new_pix);
|
||||||
SPIFFS_CHECK_DBG("LU: FIXUP: rewrite page %04x as %04x to pix %04x\n", cur_pix, new_ph.obj_id, new_pix);
|
SPIFFS_CHECK_DBG("LU: FIXUP: rewrite page %04x as %04x to pix %04x\n", cur_pix, new_ph.obj_id, new_pix);
|
||||||
if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_FIX_LOOKUP, p_hdr->obj_id, p_hdr->span_ix);
|
CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_FIX_LOOKUP, p_hdr->obj_id, p_hdr->span_ix);
|
||||||
SPIFFS_CHECK_RES(res);
|
SPIFFS_CHECK_RES(res);
|
||||||
*reload_lu = 1;
|
*reload_lu = 1;
|
||||||
} else if ((objix_pix_ph && data_pix_ph && data_pix_lu && objix_pix_lu == 0) ||
|
} else if ((objix_pix_ph && data_pix_ph && data_pix_lu && objix_pix_lu == 0) ||
|
||||||
@ -315,7 +328,7 @@ static s32_t spiffs_lookup_check_validate(spiffs *fs, spiffs_obj_id lu_obj_id, s
|
|||||||
// rewrite as obj_id_lu
|
// rewrite as obj_id_lu
|
||||||
new_ph.obj_id = lu_obj_id | SPIFFS_OBJ_ID_IX_FLAG;
|
new_ph.obj_id = lu_obj_id | SPIFFS_OBJ_ID_IX_FLAG;
|
||||||
SPIFFS_CHECK_DBG("LU: FIXUP: rewrite page %04x as %04x\n", cur_pix, new_ph.obj_id);
|
SPIFFS_CHECK_DBG("LU: FIXUP: rewrite page %04x as %04x\n", cur_pix, new_ph.obj_id);
|
||||||
if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_FIX_LOOKUP, p_hdr->obj_id, p_hdr->span_ix);
|
CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_FIX_LOOKUP, p_hdr->obj_id, p_hdr->span_ix);
|
||||||
res = spiffs_rewrite_page(fs, cur_pix, &new_ph, &new_pix);
|
res = spiffs_rewrite_page(fs, cur_pix, &new_ph, &new_pix);
|
||||||
SPIFFS_CHECK_RES(res);
|
SPIFFS_CHECK_RES(res);
|
||||||
*reload_lu = 1;
|
*reload_lu = 1;
|
||||||
@ -353,7 +366,7 @@ static s32_t spiffs_lookup_check_validate(spiffs *fs, spiffs_obj_id lu_obj_id, s
|
|||||||
// if only data page exists, make this page index
|
// if only data page exists, make this page index
|
||||||
if (data_pix && objix_pix_d == 0) {
|
if (data_pix && objix_pix_d == 0) {
|
||||||
SPIFFS_CHECK_DBG("LU: FIXUP: other data page exists, make this index\n");
|
SPIFFS_CHECK_DBG("LU: FIXUP: other data page exists, make this index\n");
|
||||||
if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_FIX_INDEX, lu_obj_id, p_hdr->span_ix);
|
CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_FIX_INDEX, lu_obj_id, p_hdr->span_ix);
|
||||||
spiffs_page_header new_ph;
|
spiffs_page_header new_ph;
|
||||||
spiffs_page_ix new_pix;
|
spiffs_page_ix new_pix;
|
||||||
new_ph.flags = 0xff & ~(SPIFFS_PH_FLAG_USED | SPIFFS_PH_FLAG_FINAL | SPIFFS_PH_FLAG_INDEX);
|
new_ph.flags = 0xff & ~(SPIFFS_PH_FLAG_USED | SPIFFS_PH_FLAG_FINAL | SPIFFS_PH_FLAG_INDEX);
|
||||||
@ -369,7 +382,7 @@ static s32_t spiffs_lookup_check_validate(spiffs *fs, spiffs_obj_id lu_obj_id, s
|
|||||||
// if only index exists, make data page
|
// if only index exists, make data page
|
||||||
if (data_pix == 0 && objix_pix_d) {
|
if (data_pix == 0 && objix_pix_d) {
|
||||||
SPIFFS_CHECK_DBG("LU: FIXUP: other index page exists, make this data\n");
|
SPIFFS_CHECK_DBG("LU: FIXUP: other index page exists, make this data\n");
|
||||||
if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_FIX_LOOKUP, lu_obj_id, p_hdr->span_ix);
|
CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_FIX_LOOKUP, lu_obj_id, p_hdr->span_ix);
|
||||||
spiffs_page_header new_ph;
|
spiffs_page_header new_ph;
|
||||||
spiffs_page_ix new_pix;
|
spiffs_page_ix new_pix;
|
||||||
new_ph.flags = 0xff & ~(SPIFFS_PH_FLAG_USED | SPIFFS_PH_FLAG_FINAL);
|
new_ph.flags = 0xff & ~(SPIFFS_PH_FLAG_USED | SPIFFS_PH_FLAG_FINAL);
|
||||||
@ -406,7 +419,7 @@ static s32_t spiffs_lookup_check_validate(spiffs *fs, spiffs_obj_id lu_obj_id, s
|
|||||||
// page referenced by object index but not final
|
// page referenced by object index but not final
|
||||||
// just finalize
|
// just finalize
|
||||||
SPIFFS_CHECK_DBG("LU: FIXUP: unfinalized page is referred, finalizing\n");
|
SPIFFS_CHECK_DBG("LU: FIXUP: unfinalized page is referred, finalizing\n");
|
||||||
if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_FIX_LOOKUP, p_hdr->obj_id, p_hdr->span_ix);
|
CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_FIX_LOOKUP, p_hdr->obj_id, p_hdr->span_ix);
|
||||||
u8_t flags = 0xff & ~SPIFFS_PH_FLAG_FINAL;
|
u8_t flags = 0xff & ~SPIFFS_PH_FLAG_FINAL;
|
||||||
res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_DA | SPIFFS_OP_C_UPDT,
|
res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_DA | SPIFFS_OP_C_UPDT,
|
||||||
0, SPIFFS_PAGE_TO_PADDR(fs, cur_pix) + offsetof(spiffs_page_header, flags),
|
0, SPIFFS_PAGE_TO_PADDR(fs, cur_pix) + offsetof(spiffs_page_header, flags),
|
||||||
@ -418,7 +431,7 @@ static s32_t spiffs_lookup_check_validate(spiffs *fs, spiffs_obj_id lu_obj_id, s
|
|||||||
|
|
||||||
if (delete_page) {
|
if (delete_page) {
|
||||||
SPIFFS_CHECK_DBG("LU: FIXUP: deleting page %04x\n", cur_pix);
|
SPIFFS_CHECK_DBG("LU: FIXUP: deleting page %04x\n", cur_pix);
|
||||||
if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_DELETE_PAGE, cur_pix, 0);
|
CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_DELETE_PAGE, cur_pix, 0);
|
||||||
res = spiffs_page_delete(fs, cur_pix);
|
res = spiffs_page_delete(fs, cur_pix);
|
||||||
SPIFFS_CHECK_RES(res);
|
SPIFFS_CHECK_RES(res);
|
||||||
}
|
}
|
||||||
@ -434,7 +447,7 @@ static s32_t spiffs_lookup_check_v(spiffs *fs, spiffs_obj_id obj_id, spiffs_bloc
|
|||||||
spiffs_page_header p_hdr;
|
spiffs_page_header p_hdr;
|
||||||
spiffs_page_ix cur_pix = SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, cur_block, cur_entry);
|
spiffs_page_ix cur_pix = SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, cur_block, cur_entry);
|
||||||
|
|
||||||
if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_PROGRESS,
|
CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_PROGRESS,
|
||||||
(cur_block * 256)/fs->block_count, 0);
|
(cur_block * 256)/fs->block_count, 0);
|
||||||
|
|
||||||
// load header
|
// load header
|
||||||
@ -460,7 +473,7 @@ s32_t spiffs_lookup_consistency_check(spiffs *fs, u8_t check_all_objects) {
|
|||||||
(void)check_all_objects;
|
(void)check_all_objects;
|
||||||
s32_t res = SPIFFS_OK;
|
s32_t res = SPIFFS_OK;
|
||||||
|
|
||||||
if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_PROGRESS, 0, 0);
|
CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_PROGRESS, 0, 0);
|
||||||
|
|
||||||
res = spiffs_obj_lu_find_entry_visitor(fs, 0, 0, 0, 0, spiffs_lookup_check_v, 0, 0, 0, 0);
|
res = spiffs_obj_lu_find_entry_visitor(fs, 0, 0, 0, 0, spiffs_lookup_check_v, 0, 0, 0, 0);
|
||||||
|
|
||||||
@ -469,10 +482,10 @@ s32_t spiffs_lookup_consistency_check(spiffs *fs, u8_t check_all_objects) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (res != SPIFFS_OK) {
|
if (res != SPIFFS_OK) {
|
||||||
if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_ERROR, res, 0);
|
CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_ERROR, res, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_PROGRESS, 256, 0);
|
CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_PROGRESS, 256, 0);
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
@ -501,19 +514,22 @@ static s32_t spiffs_page_consistency_check_i(spiffs *fs) {
|
|||||||
while (pix_offset < SPIFFS_PAGES_PER_BLOCK(fs) * fs->block_count) {
|
while (pix_offset < SPIFFS_PAGES_PER_BLOCK(fs) * fs->block_count) {
|
||||||
// set this flag to abort all checks and rescan the page range
|
// set this flag to abort all checks and rescan the page range
|
||||||
u8_t restart = 0;
|
u8_t restart = 0;
|
||||||
c_memset(fs->work, 0, SPIFFS_CFG_LOG_PAGE_SZ(fs));
|
memset(fs->work, 0, SPIFFS_CFG_LOG_PAGE_SZ(fs));
|
||||||
|
|
||||||
spiffs_block_ix cur_block = 0;
|
spiffs_block_ix cur_block = 0;
|
||||||
// build consistency bitmap for id range traversing all blocks
|
// build consistency bitmap for id range traversing all blocks
|
||||||
while (!restart && cur_block < fs->block_count) {
|
while (!restart && cur_block < fs->block_count) {
|
||||||
if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_PAGE, SPIFFS_CHECK_PROGRESS,
|
CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_PROGRESS,
|
||||||
(pix_offset*256)/(SPIFFS_PAGES_PER_BLOCK(fs) * fs->block_count) +
|
(pix_offset*256)/(SPIFFS_PAGES_PER_BLOCK(fs) * fs->block_count) +
|
||||||
((((cur_block * pages_per_scan * 256)/ (SPIFFS_PAGES_PER_BLOCK(fs) * fs->block_count))) / fs->block_count),
|
((((cur_block * pages_per_scan * 256)/ (SPIFFS_PAGES_PER_BLOCK(fs) * fs->block_count))) / fs->block_count),
|
||||||
0);
|
0);
|
||||||
|
|
||||||
// traverse each page except for lookup pages
|
// traverse each page except for lookup pages
|
||||||
spiffs_page_ix cur_pix = SPIFFS_OBJ_LOOKUP_PAGES(fs) + SPIFFS_PAGES_PER_BLOCK(fs) * cur_block;
|
spiffs_page_ix cur_pix = SPIFFS_OBJ_LOOKUP_PAGES(fs) + SPIFFS_PAGES_PER_BLOCK(fs) * cur_block;
|
||||||
while (!restart && cur_pix < SPIFFS_PAGES_PER_BLOCK(fs) * (cur_block+1)) {
|
while (!restart && cur_pix < SPIFFS_PAGES_PER_BLOCK(fs) * (cur_block+1)) {
|
||||||
|
//if ((cur_pix & 0xff) == 0)
|
||||||
|
// SPIFFS_CHECK_DBG("PA: processing pix %08x, block %08x of pix %08x, block %08x\n",
|
||||||
|
// cur_pix, cur_block, SPIFFS_PAGES_PER_BLOCK(fs) * fs->block_count, fs->block_count);
|
||||||
|
|
||||||
// read header
|
// read header
|
||||||
spiffs_page_header p_hdr;
|
spiffs_page_header p_hdr;
|
||||||
res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,
|
res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,
|
||||||
@ -597,12 +613,12 @@ static s32_t spiffs_page_consistency_check_i(spiffs *fs) {
|
|||||||
data_spix_offset + i, data_pix, cur_pix);
|
data_spix_offset + i, data_pix, cur_pix);
|
||||||
if (res <= _SPIFFS_ERR_CHECK_FIRST && res > _SPIFFS_ERR_CHECK_LAST) {
|
if (res <= _SPIFFS_ERR_CHECK_FIRST && res > _SPIFFS_ERR_CHECK_LAST) {
|
||||||
// index bad also, cannot mend this file
|
// index bad also, cannot mend this file
|
||||||
SPIFFS_CHECK_DBG("PA: FIXUP: index bad %d, cannot mend - delete object\n", res);
|
SPIFFS_CHECK_DBG("PA: FIXUP: index bad %i, cannot mend - delete object\n", res);
|
||||||
if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_PAGE, SPIFFS_CHECK_DELETE_BAD_FILE, objix_p_hdr->obj_id, 0);
|
CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_DELETE_BAD_FILE, objix_p_hdr->obj_id, 0);
|
||||||
// delete file
|
// delete file
|
||||||
res = spiffs_page_delete(fs, cur_pix);
|
res = spiffs_page_delete(fs, cur_pix);
|
||||||
} else {
|
} else {
|
||||||
if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_PAGE, SPIFFS_CHECK_FIX_INDEX, objix_p_hdr->obj_id, objix_p_hdr->span_ix);
|
CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_FIX_INDEX, objix_p_hdr->obj_id, objix_p_hdr->span_ix);
|
||||||
}
|
}
|
||||||
SPIFFS_CHECK_RES(res);
|
SPIFFS_CHECK_RES(res);
|
||||||
restart = 1;
|
restart = 1;
|
||||||
@ -636,7 +652,7 @@ static s32_t spiffs_page_consistency_check_i(spiffs *fs) {
|
|||||||
if (data_pix == 0) {
|
if (data_pix == 0) {
|
||||||
// not found, this index is badly borked
|
// not found, this index is badly borked
|
||||||
SPIFFS_CHECK_DBG("PA: FIXUP: index bad, delete object id %04x\n", p_hdr.obj_id);
|
SPIFFS_CHECK_DBG("PA: FIXUP: index bad, delete object id %04x\n", p_hdr.obj_id);
|
||||||
if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_PAGE, SPIFFS_CHECK_DELETE_BAD_FILE, p_hdr.obj_id, 0);
|
CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_DELETE_BAD_FILE, p_hdr.obj_id, 0);
|
||||||
res = spiffs_delete_obj_lazy(fs, p_hdr.obj_id);
|
res = spiffs_delete_obj_lazy(fs, p_hdr.obj_id);
|
||||||
SPIFFS_CHECK_RES(res);
|
SPIFFS_CHECK_RES(res);
|
||||||
break;
|
break;
|
||||||
@ -647,11 +663,11 @@ static s32_t spiffs_page_consistency_check_i(spiffs *fs) {
|
|||||||
res = spiffs_rewrite_index(fs, p_hdr.obj_id, data_spix_offset + i, data_pix, cur_pix);
|
res = spiffs_rewrite_index(fs, p_hdr.obj_id, data_spix_offset + i, data_pix, cur_pix);
|
||||||
if (res <= _SPIFFS_ERR_CHECK_FIRST && res > _SPIFFS_ERR_CHECK_LAST) {
|
if (res <= _SPIFFS_ERR_CHECK_FIRST && res > _SPIFFS_ERR_CHECK_LAST) {
|
||||||
// index bad also, cannot mend this file
|
// index bad also, cannot mend this file
|
||||||
SPIFFS_CHECK_DBG("PA: FIXUP: index bad %d, cannot mend!\n", res);
|
SPIFFS_CHECK_DBG("PA: FIXUP: index bad %i, cannot mend!\n", res);
|
||||||
if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_PAGE, SPIFFS_CHECK_DELETE_BAD_FILE, p_hdr.obj_id, 0);
|
CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_DELETE_BAD_FILE, p_hdr.obj_id, 0);
|
||||||
res = spiffs_delete_obj_lazy(fs, p_hdr.obj_id);
|
res = spiffs_delete_obj_lazy(fs, p_hdr.obj_id);
|
||||||
} else {
|
} else {
|
||||||
if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_PAGE, SPIFFS_CHECK_FIX_INDEX, p_hdr.obj_id, p_hdr.span_ix);
|
CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_FIX_INDEX, p_hdr.obj_id, p_hdr.span_ix);
|
||||||
}
|
}
|
||||||
SPIFFS_CHECK_RES(res);
|
SPIFFS_CHECK_RES(res);
|
||||||
restart = 1;
|
restart = 1;
|
||||||
@ -669,7 +685,7 @@ static s32_t spiffs_page_consistency_check_i(spiffs *fs) {
|
|||||||
// the object which is referring to this page
|
// the object which is referring to this page
|
||||||
SPIFFS_CHECK_DBG("PA: FIXUP: removing object %04x and page %04x\n",
|
SPIFFS_CHECK_DBG("PA: FIXUP: removing object %04x and page %04x\n",
|
||||||
p_hdr.obj_id, cur_pix);
|
p_hdr.obj_id, cur_pix);
|
||||||
if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_PAGE, SPIFFS_CHECK_DELETE_BAD_FILE, p_hdr.obj_id, 0);
|
CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_DELETE_BAD_FILE, p_hdr.obj_id, 0);
|
||||||
res = spiffs_delete_obj_lazy(fs, p_hdr.obj_id);
|
res = spiffs_delete_obj_lazy(fs, p_hdr.obj_id);
|
||||||
SPIFFS_CHECK_RES(res);
|
SPIFFS_CHECK_RES(res);
|
||||||
// extra precaution, delete this page also
|
// extra precaution, delete this page also
|
||||||
@ -763,20 +779,20 @@ static s32_t spiffs_page_consistency_check_i(spiffs *fs) {
|
|||||||
res = spiffs_rewrite_index(fs, p_hdr.obj_id, p_hdr.span_ix, cur_pix, objix_pix);
|
res = spiffs_rewrite_index(fs, p_hdr.obj_id, p_hdr.span_ix, cur_pix, objix_pix);
|
||||||
if (res <= _SPIFFS_ERR_CHECK_FIRST && res > _SPIFFS_ERR_CHECK_LAST) {
|
if (res <= _SPIFFS_ERR_CHECK_FIRST && res > _SPIFFS_ERR_CHECK_LAST) {
|
||||||
// index bad also, cannot mend this file
|
// index bad also, cannot mend this file
|
||||||
SPIFFS_CHECK_DBG("PA: FIXUP: index bad %d, cannot mend!\n", res);
|
SPIFFS_CHECK_DBG("PA: FIXUP: index bad %i, cannot mend!\n", res);
|
||||||
if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_PAGE, SPIFFS_CHECK_DELETE_BAD_FILE, p_hdr.obj_id, 0);
|
CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_DELETE_BAD_FILE, p_hdr.obj_id, 0);
|
||||||
res = spiffs_page_delete(fs, cur_pix);
|
res = spiffs_page_delete(fs, cur_pix);
|
||||||
SPIFFS_CHECK_RES(res);
|
SPIFFS_CHECK_RES(res);
|
||||||
res = spiffs_delete_obj_lazy(fs, p_hdr.obj_id);
|
res = spiffs_delete_obj_lazy(fs, p_hdr.obj_id);
|
||||||
} else {
|
} else {
|
||||||
if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_PAGE, SPIFFS_CHECK_FIX_INDEX, p_hdr.obj_id, p_hdr.span_ix);
|
CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_FIX_INDEX, p_hdr.obj_id, p_hdr.span_ix);
|
||||||
}
|
}
|
||||||
SPIFFS_CHECK_RES(res);
|
SPIFFS_CHECK_RES(res);
|
||||||
restart = 1;
|
restart = 1;
|
||||||
continue;
|
continue;
|
||||||
} else if (delete_page) {
|
} else if (delete_page) {
|
||||||
SPIFFS_CHECK_DBG("PA: FIXUP: deleting page %04x\n", cur_pix);
|
SPIFFS_CHECK_DBG("PA: FIXUP: deleting page %04x\n", cur_pix);
|
||||||
if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_PAGE, SPIFFS_CHECK_DELETE_PAGE, cur_pix, 0);
|
CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_DELETE_PAGE, cur_pix, 0);
|
||||||
res = spiffs_page_delete(fs, cur_pix);
|
res = spiffs_page_delete(fs, cur_pix);
|
||||||
}
|
}
|
||||||
SPIFFS_CHECK_RES(res);
|
SPIFFS_CHECK_RES(res);
|
||||||
@ -818,6 +834,8 @@ static s32_t spiffs_page_consistency_check_i(spiffs *fs) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SPIFFS_CHECK_DBG("PA: processed %04x, restart %i\n", pix_offset, restart);
|
||||||
// next page range
|
// next page range
|
||||||
if (!restart) {
|
if (!restart) {
|
||||||
pix_offset += pages_per_scan;
|
pix_offset += pages_per_scan;
|
||||||
@ -828,12 +846,12 @@ static s32_t spiffs_page_consistency_check_i(spiffs *fs) {
|
|||||||
|
|
||||||
// Checks consistency amongst all pages and fixes irregularities
|
// Checks consistency amongst all pages and fixes irregularities
|
||||||
s32_t spiffs_page_consistency_check(spiffs *fs) {
|
s32_t spiffs_page_consistency_check(spiffs *fs) {
|
||||||
if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_PAGE, SPIFFS_CHECK_PROGRESS, 0, 0);
|
CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_PROGRESS, 0, 0);
|
||||||
s32_t res = spiffs_page_consistency_check_i(fs);
|
s32_t res = spiffs_page_consistency_check_i(fs);
|
||||||
if (res != SPIFFS_OK) {
|
if (res != SPIFFS_OK) {
|
||||||
if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_PAGE, SPIFFS_CHECK_ERROR, res, 0);
|
CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_ERROR, res, 0);
|
||||||
}
|
}
|
||||||
if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_PAGE, SPIFFS_CHECK_PROGRESS, 256, 0);
|
CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_PROGRESS, 256, 0);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -862,7 +880,7 @@ static s32_t spiffs_object_index_consistency_check_v(spiffs *fs, spiffs_obj_id o
|
|||||||
u32_t *log_ix = (u32_t *)user_p;
|
u32_t *log_ix = (u32_t *)user_p;
|
||||||
spiffs_obj_id *obj_table = (spiffs_obj_id *)fs->work;
|
spiffs_obj_id *obj_table = (spiffs_obj_id *)fs->work;
|
||||||
|
|
||||||
if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_INDEX, SPIFFS_CHECK_PROGRESS,
|
CHECK_CB(fs, SPIFFS_CHECK_INDEX, SPIFFS_CHECK_PROGRESS,
|
||||||
(cur_block * 256)/fs->block_count, 0);
|
(cur_block * 256)/fs->block_count, 0);
|
||||||
|
|
||||||
if (obj_id != SPIFFS_OBJ_ID_FREE && obj_id != SPIFFS_OBJ_ID_DELETED && (obj_id & SPIFFS_OBJ_ID_IX_FLAG)) {
|
if (obj_id != SPIFFS_OBJ_ID_FREE && obj_id != SPIFFS_OBJ_ID_DELETED && (obj_id & SPIFFS_OBJ_ID_IX_FLAG)) {
|
||||||
@ -879,7 +897,7 @@ static s32_t spiffs_object_index_consistency_check_v(spiffs *fs, spiffs_obj_id o
|
|||||||
(SPIFFS_PH_FLAG_DELET)) {
|
(SPIFFS_PH_FLAG_DELET)) {
|
||||||
SPIFFS_CHECK_DBG("IX: pix %04x, obj id:%04x spix:%04x header not fully deleted - deleting\n",
|
SPIFFS_CHECK_DBG("IX: pix %04x, obj id:%04x spix:%04x header not fully deleted - deleting\n",
|
||||||
cur_pix, obj_id, p_hdr.span_ix);
|
cur_pix, obj_id, p_hdr.span_ix);
|
||||||
if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_INDEX, SPIFFS_CHECK_DELETE_PAGE, cur_pix, obj_id);
|
CHECK_CB(fs, SPIFFS_CHECK_INDEX, SPIFFS_CHECK_DELETE_PAGE, cur_pix, obj_id);
|
||||||
res = spiffs_page_delete(fs, cur_pix);
|
res = spiffs_page_delete(fs, cur_pix);
|
||||||
SPIFFS_CHECK_RES(res);
|
SPIFFS_CHECK_RES(res);
|
||||||
return res_c;
|
return res_c;
|
||||||
@ -935,7 +953,7 @@ static s32_t spiffs_object_index_consistency_check_v(spiffs *fs, spiffs_obj_id o
|
|||||||
if (delete) {
|
if (delete) {
|
||||||
SPIFFS_CHECK_DBG("IX: FIXUP: pix %04x, obj id:%04x spix:%04x is orphan index - deleting\n",
|
SPIFFS_CHECK_DBG("IX: FIXUP: pix %04x, obj id:%04x spix:%04x is orphan index - deleting\n",
|
||||||
cur_pix, obj_id, p_hdr.span_ix);
|
cur_pix, obj_id, p_hdr.span_ix);
|
||||||
if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_INDEX, SPIFFS_CHECK_DELETE_ORPHANED_INDEX, cur_pix, obj_id);
|
CHECK_CB(fs, SPIFFS_CHECK_INDEX, SPIFFS_CHECK_DELETE_ORPHANED_INDEX, cur_pix, obj_id);
|
||||||
res = spiffs_page_delete(fs, cur_pix);
|
res = spiffs_page_delete(fs, cur_pix);
|
||||||
SPIFFS_CHECK_RES(res);
|
SPIFFS_CHECK_RES(res);
|
||||||
}
|
}
|
||||||
@ -956,18 +974,18 @@ s32_t spiffs_object_index_consistency_check(spiffs *fs) {
|
|||||||
// indicating whether they can be reached or not. Acting as a fifo if object ids cannot fit.
|
// indicating whether they can be reached or not. Acting as a fifo if object ids cannot fit.
|
||||||
// In the temporary object index memory, SPIFFS_OBJ_ID_IX_FLAG bit is used to indicate
|
// In the temporary object index memory, SPIFFS_OBJ_ID_IX_FLAG bit is used to indicate
|
||||||
// a reachable/unreachable object id.
|
// a reachable/unreachable object id.
|
||||||
c_memset(fs->work, 0, SPIFFS_CFG_LOG_PAGE_SZ(fs));
|
memset(fs->work, 0, SPIFFS_CFG_LOG_PAGE_SZ(fs));
|
||||||
u32_t obj_id_log_ix = 0;
|
u32_t obj_id_log_ix = 0;
|
||||||
if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_INDEX, SPIFFS_CHECK_PROGRESS, 0, 0);
|
CHECK_CB(fs, SPIFFS_CHECK_INDEX, SPIFFS_CHECK_PROGRESS, 0, 0);
|
||||||
res = spiffs_obj_lu_find_entry_visitor(fs, 0, 0, 0, 0, spiffs_object_index_consistency_check_v, 0, &obj_id_log_ix,
|
res = spiffs_obj_lu_find_entry_visitor(fs, 0, 0, 0, 0, spiffs_object_index_consistency_check_v, 0, &obj_id_log_ix,
|
||||||
0, 0);
|
0, 0);
|
||||||
if (res == SPIFFS_VIS_END) {
|
if (res == SPIFFS_VIS_END) {
|
||||||
res = SPIFFS_OK;
|
res = SPIFFS_OK;
|
||||||
}
|
}
|
||||||
if (res != SPIFFS_OK) {
|
if (res != SPIFFS_OK) {
|
||||||
if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_INDEX, SPIFFS_CHECK_ERROR, res, 0);
|
CHECK_CB(fs, SPIFFS_CHECK_INDEX, SPIFFS_CHECK_ERROR, res, 0);
|
||||||
}
|
}
|
||||||
if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_INDEX, SPIFFS_CHECK_PROGRESS, 256, 0);
|
CHECK_CB(fs, SPIFFS_CHECK_INDEX, SPIFFS_CHECK_PROGRESS, 256, 0);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,7 +9,7 @@ static s32_t spiffs_gc_erase_block(
|
|||||||
spiffs_block_ix bix) {
|
spiffs_block_ix bix) {
|
||||||
s32_t res;
|
s32_t res;
|
||||||
|
|
||||||
SPIFFS_GC_DBG("gc: erase block %d\n", bix);
|
SPIFFS_GC_DBG("gc: erase block %i\n", bix);
|
||||||
res = spiffs_erase_block(fs, bix);
|
res = spiffs_erase_block(fs, bix);
|
||||||
SPIFFS_CHECK_RES(res);
|
SPIFFS_CHECK_RES(res);
|
||||||
|
|
||||||
@ -28,7 +28,7 @@ static s32_t spiffs_gc_erase_block(
|
|||||||
// the block is erased. Compared to the non-quick gc, the quick one ensures
|
// the block is erased. Compared to the non-quick gc, the quick one ensures
|
||||||
// that no updates are needed on existing objects on pages that are erased.
|
// that no updates are needed on existing objects on pages that are erased.
|
||||||
s32_t spiffs_gc_quick(
|
s32_t spiffs_gc_quick(
|
||||||
spiffs *fs) {
|
spiffs *fs, u16_t max_free_pages) {
|
||||||
s32_t res = SPIFFS_OK;
|
s32_t res = SPIFFS_OK;
|
||||||
u32_t blocks = fs->block_count;
|
u32_t blocks = fs->block_count;
|
||||||
spiffs_block_ix cur_block = 0;
|
spiffs_block_ix cur_block = 0;
|
||||||
@ -47,6 +47,7 @@ s32_t spiffs_gc_quick(
|
|||||||
// check each block
|
// check each block
|
||||||
while (res == SPIFFS_OK && blocks--) {
|
while (res == SPIFFS_OK && blocks--) {
|
||||||
u16_t deleted_pages_in_block = 0;
|
u16_t deleted_pages_in_block = 0;
|
||||||
|
u16_t free_pages_in_block = 0;
|
||||||
|
|
||||||
int obj_lookup_page = 0;
|
int obj_lookup_page = 0;
|
||||||
// check each object lookup page
|
// check each object lookup page
|
||||||
@ -63,9 +64,12 @@ s32_t spiffs_gc_quick(
|
|||||||
deleted_pages_in_block++;
|
deleted_pages_in_block++;
|
||||||
} else if (obj_id == SPIFFS_OBJ_ID_FREE) {
|
} else if (obj_id == SPIFFS_OBJ_ID_FREE) {
|
||||||
// kill scan, go for next block
|
// kill scan, go for next block
|
||||||
obj_lookup_page = SPIFFS_OBJ_LOOKUP_PAGES(fs);
|
free_pages_in_block++;
|
||||||
res = 1; // kill object lu loop
|
if (free_pages_in_block > max_free_pages) {
|
||||||
break;
|
obj_lookup_page = SPIFFS_OBJ_LOOKUP_PAGES(fs);
|
||||||
|
res = 1; // kill object lu loop
|
||||||
|
break;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// kill scan, go for next block
|
// kill scan, go for next block
|
||||||
obj_lookup_page = SPIFFS_OBJ_LOOKUP_PAGES(fs);
|
obj_lookup_page = SPIFFS_OBJ_LOOKUP_PAGES(fs);
|
||||||
@ -78,7 +82,9 @@ s32_t spiffs_gc_quick(
|
|||||||
} // per object lookup page
|
} // per object lookup page
|
||||||
if (res == 1) res = SPIFFS_OK;
|
if (res == 1) res = SPIFFS_OK;
|
||||||
|
|
||||||
if (res == SPIFFS_OK && deleted_pages_in_block == SPIFFS_PAGES_PER_BLOCK(fs)-SPIFFS_OBJ_LOOKUP_PAGES(fs)) {
|
if (res == SPIFFS_OK &&
|
||||||
|
deleted_pages_in_block + free_pages_in_block == SPIFFS_PAGES_PER_BLOCK(fs)-SPIFFS_OBJ_LOOKUP_PAGES(fs) &&
|
||||||
|
free_pages_in_block <= max_free_pages) {
|
||||||
// found a fully deleted block
|
// found a fully deleted block
|
||||||
fs->stats_p_deleted -= deleted_pages_in_block;
|
fs->stats_p_deleted -= deleted_pages_in_block;
|
||||||
res = spiffs_gc_erase_block(fs, cur_block);
|
res = spiffs_gc_erase_block(fs, cur_block);
|
||||||
@ -90,10 +96,13 @@ s32_t spiffs_gc_quick(
|
|||||||
cur_block_addr += SPIFFS_CFG_LOG_BLOCK_SZ(fs);
|
cur_block_addr += SPIFFS_CFG_LOG_BLOCK_SZ(fs);
|
||||||
} // per block
|
} // per block
|
||||||
|
|
||||||
|
if (res == SPIFFS_OK) {
|
||||||
|
res = SPIFFS_ERR_NO_DELETED_BLOCKS;
|
||||||
|
}
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Checks if garbaga collecting is necessary. If so a candidate block is found,
|
// Checks if garbage collecting is necessary. If so a candidate block is found,
|
||||||
// cleansed and erased
|
// cleansed and erased
|
||||||
s32_t spiffs_gc_check(
|
s32_t spiffs_gc_check(
|
||||||
spiffs *fs,
|
spiffs *fs,
|
||||||
@ -111,16 +120,16 @@ s32_t spiffs_gc_check(
|
|||||||
|
|
||||||
u32_t needed_pages = (len + SPIFFS_DATA_PAGE_SIZE(fs) - 1) / SPIFFS_DATA_PAGE_SIZE(fs);
|
u32_t needed_pages = (len + SPIFFS_DATA_PAGE_SIZE(fs) - 1) / SPIFFS_DATA_PAGE_SIZE(fs);
|
||||||
// if (fs->free_blocks <= 2 && (s32_t)needed_pages > free_pages) {
|
// if (fs->free_blocks <= 2 && (s32_t)needed_pages > free_pages) {
|
||||||
// SPIFFS_GC_DBG("gc: full freeblk:%d needed:%d free:%d dele:%d\n", fs->free_blocks, needed_pages, free_pages, fs->stats_p_deleted);
|
// SPIFFS_GC_DBG("gc: full freeblk:%i needed:%i free:%i dele:%i\n", fs->free_blocks, needed_pages, free_pages, fs->stats_p_deleted);
|
||||||
// return SPIFFS_ERR_FULL;
|
// return SPIFFS_ERR_FULL;
|
||||||
// }
|
// }
|
||||||
if ((s32_t)needed_pages > (s32_t)(free_pages + fs->stats_p_deleted)) {
|
if ((s32_t)needed_pages > (s32_t)(free_pages + fs->stats_p_deleted)) {
|
||||||
SPIFFS_GC_DBG("gc_check: full freeblk:%d needed:%d free:%d dele:%d\n", fs->free_blocks, needed_pages, free_pages, fs->stats_p_deleted);
|
SPIFFS_GC_DBG("gc_check: full freeblk:%i needed:%i free:%i dele:%i\n", fs->free_blocks, needed_pages, free_pages, fs->stats_p_deleted);
|
||||||
return SPIFFS_ERR_FULL;
|
return SPIFFS_ERR_FULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
do {
|
do {
|
||||||
SPIFFS_GC_DBG("\ngc_check #%d: run gc free_blocks:%d pfree:%d pallo:%d pdele:%d [%d] len:%d of %d\n",
|
SPIFFS_GC_DBG("\ngc_check #%i: run gc free_blocks:%i pfree:%i pallo:%i pdele:%i [%i] len:%i of %i\n",
|
||||||
tries,
|
tries,
|
||||||
fs->free_blocks, free_pages, fs->stats_p_allocated, fs->stats_p_deleted, (free_pages+fs->stats_p_allocated+fs->stats_p_deleted),
|
fs->free_blocks, free_pages, fs->stats_p_allocated, fs->stats_p_deleted, (free_pages+fs->stats_p_allocated+fs->stats_p_deleted),
|
||||||
len, free_pages*SPIFFS_DATA_PAGE_SIZE(fs));
|
len, free_pages*SPIFFS_DATA_PAGE_SIZE(fs));
|
||||||
@ -141,13 +150,13 @@ s32_t spiffs_gc_check(
|
|||||||
#endif
|
#endif
|
||||||
cand = cands[0];
|
cand = cands[0];
|
||||||
fs->cleaning = 1;
|
fs->cleaning = 1;
|
||||||
//c_printf("gcing: cleaning block %d\n", cand);
|
//printf("gcing: cleaning block %i\n", cand);
|
||||||
res = spiffs_gc_clean(fs, cand);
|
res = spiffs_gc_clean(fs, cand);
|
||||||
fs->cleaning = 0;
|
fs->cleaning = 0;
|
||||||
if (res < 0) {
|
if (res < 0) {
|
||||||
SPIFFS_GC_DBG("gc_check: cleaning block %d, result %d\n", cand, res);
|
SPIFFS_GC_DBG("gc_check: cleaning block %i, result %i\n", cand, res);
|
||||||
} else {
|
} else {
|
||||||
SPIFFS_GC_DBG("gc_check: cleaning block %d, result %d\n", cand, res);
|
SPIFFS_GC_DBG("gc_check: cleaning block %i, result %i\n", cand, res);
|
||||||
}
|
}
|
||||||
SPIFFS_CHECK_RES(res);
|
SPIFFS_CHECK_RES(res);
|
||||||
|
|
||||||
@ -177,7 +186,7 @@ s32_t spiffs_gc_check(
|
|||||||
res = SPIFFS_ERR_FULL;
|
res = SPIFFS_ERR_FULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
SPIFFS_GC_DBG("gc_check: finished, %d dirty, blocks %d free, %d pages free, %d tries, res %d\n",
|
SPIFFS_GC_DBG("gc_check: finished, %i dirty, blocks %i free, %i pages free, %i tries, res %i\n",
|
||||||
fs->stats_p_allocated + fs->stats_p_deleted,
|
fs->stats_p_allocated + fs->stats_p_deleted,
|
||||||
fs->free_blocks, free_pages, tries, res);
|
fs->free_blocks, free_pages, tries, res);
|
||||||
|
|
||||||
@ -215,7 +224,7 @@ s32_t spiffs_gc_erase_page_stats(
|
|||||||
} // per entry
|
} // per entry
|
||||||
obj_lookup_page++;
|
obj_lookup_page++;
|
||||||
} // per object lookup page
|
} // per object lookup page
|
||||||
SPIFFS_GC_DBG("gc_check: wipe pallo:%d pdele:%d\n", allo, dele);
|
SPIFFS_GC_DBG("gc_check: wipe pallo:%i pdele:%i\n", allo, dele);
|
||||||
fs->stats_p_allocated -= allo;
|
fs->stats_p_allocated -= allo;
|
||||||
fs->stats_p_deleted -= dele;
|
fs->stats_p_deleted -= dele;
|
||||||
return res;
|
return res;
|
||||||
@ -237,13 +246,18 @@ s32_t spiffs_gc_find_candidate(
|
|||||||
// using fs->work area as sorted candidate memory, (spiffs_block_ix)cand_bix/(s32_t)score
|
// using fs->work area as sorted candidate memory, (spiffs_block_ix)cand_bix/(s32_t)score
|
||||||
int max_candidates = MIN(fs->block_count, (SPIFFS_CFG_LOG_PAGE_SZ(fs)-8)/(sizeof(spiffs_block_ix) + sizeof(s32_t)));
|
int max_candidates = MIN(fs->block_count, (SPIFFS_CFG_LOG_PAGE_SZ(fs)-8)/(sizeof(spiffs_block_ix) + sizeof(s32_t)));
|
||||||
*candidate_count = 0;
|
*candidate_count = 0;
|
||||||
c_memset(fs->work, 0xff, SPIFFS_CFG_LOG_PAGE_SZ(fs));
|
memset(fs->work, 0xff, SPIFFS_CFG_LOG_PAGE_SZ(fs));
|
||||||
|
|
||||||
// divide up work area into block indices and scores
|
// divide up work area into block indices and scores
|
||||||
// todo alignment?
|
|
||||||
spiffs_block_ix *cand_blocks = (spiffs_block_ix *)fs->work;
|
spiffs_block_ix *cand_blocks = (spiffs_block_ix *)fs->work;
|
||||||
s32_t *cand_scores = (s32_t *)(fs->work + max_candidates * sizeof(spiffs_block_ix));
|
s32_t *cand_scores = (s32_t *)(fs->work + max_candidates * sizeof(spiffs_block_ix));
|
||||||
|
|
||||||
|
// align cand_scores on s32_t boundary
|
||||||
|
#pragma GCC diagnostic push
|
||||||
|
#pragma GCC diagnostic ignored "-Wpointer-to-int-cast"
|
||||||
|
cand_scores = (s32_t*)(((u32_t)cand_scores + sizeof(s32_t) - 1) & ~(sizeof(s32_t) - 1));
|
||||||
|
#pragma GCC diagnostic pop
|
||||||
|
|
||||||
*block_candidates = cand_blocks;
|
*block_candidates = cand_blocks;
|
||||||
|
|
||||||
int entries_per_page = (SPIFFS_CFG_LOG_PAGE_SZ(fs) / sizeof(spiffs_obj_id));
|
int entries_per_page = (SPIFFS_CFG_LOG_PAGE_SZ(fs) / sizeof(spiffs_obj_id));
|
||||||
@ -301,7 +315,7 @@ s32_t spiffs_gc_find_candidate(
|
|||||||
used_pages_in_block * SPIFFS_GC_HEUR_W_USED +
|
used_pages_in_block * SPIFFS_GC_HEUR_W_USED +
|
||||||
erase_age * (fs_crammed ? 0 : SPIFFS_GC_HEUR_W_ERASE_AGE);
|
erase_age * (fs_crammed ? 0 : SPIFFS_GC_HEUR_W_ERASE_AGE);
|
||||||
int cand_ix = 0;
|
int cand_ix = 0;
|
||||||
SPIFFS_GC_DBG("gc_check: bix:%d del:%d use:%d score:%d\n", cur_block, deleted_pages_in_block, used_pages_in_block, score);
|
SPIFFS_GC_DBG("gc_check: bix:%i del:%i use:%i score:%i\n", cur_block, deleted_pages_in_block, used_pages_in_block, score);
|
||||||
while (cand_ix < max_candidates) {
|
while (cand_ix < max_candidates) {
|
||||||
if (cand_blocks[cand_ix] == (spiffs_block_ix)-1) {
|
if (cand_blocks[cand_ix] == (spiffs_block_ix)-1) {
|
||||||
cand_blocks[cand_ix] = cur_block;
|
cand_blocks[cand_ix] = cur_block;
|
||||||
@ -370,20 +384,20 @@ s32_t spiffs_gc_clean(spiffs *fs, spiffs_block_ix bix) {
|
|||||||
spiffs_page_object_ix_header *objix_hdr = (spiffs_page_object_ix_header *)fs->work;
|
spiffs_page_object_ix_header *objix_hdr = (spiffs_page_object_ix_header *)fs->work;
|
||||||
spiffs_page_object_ix *objix = (spiffs_page_object_ix *)fs->work;
|
spiffs_page_object_ix *objix = (spiffs_page_object_ix *)fs->work;
|
||||||
|
|
||||||
SPIFFS_GC_DBG("gc_clean: cleaning block %d\n", bix);
|
SPIFFS_GC_DBG("gc_clean: cleaning block %i\n", bix);
|
||||||
|
|
||||||
c_memset(&gc, 0, sizeof(spiffs_gc));
|
memset(&gc, 0, sizeof(spiffs_gc));
|
||||||
gc.state = FIND_OBJ_DATA;
|
gc.state = FIND_OBJ_DATA;
|
||||||
|
|
||||||
if (fs->free_cursor_block_ix == bix) {
|
if (fs->free_cursor_block_ix == bix) {
|
||||||
// move free cursor to next block, cannot use free pages from the block we want to clean
|
// move free cursor to next block, cannot use free pages from the block we want to clean
|
||||||
fs->free_cursor_block_ix = (bix+1)%fs->block_count;
|
fs->free_cursor_block_ix = (bix+1)%fs->block_count;
|
||||||
fs->free_cursor_obj_lu_entry = 0;
|
fs->free_cursor_obj_lu_entry = 0;
|
||||||
SPIFFS_GC_DBG("gc_clean: move free cursor to block %d\n", fs->free_cursor_block_ix);
|
SPIFFS_GC_DBG("gc_clean: move free cursor to block %i\n", fs->free_cursor_block_ix);
|
||||||
}
|
}
|
||||||
|
|
||||||
while (res == SPIFFS_OK && gc.state != FINISHED) {
|
while (res == SPIFFS_OK && gc.state != FINISHED) {
|
||||||
SPIFFS_GC_DBG("gc_clean: state = %d entry:%d\n", gc.state, cur_entry);
|
SPIFFS_GC_DBG("gc_clean: state = %i entry:%i\n", gc.state, cur_entry);
|
||||||
gc.obj_id_found = 0;
|
gc.obj_id_found = 0;
|
||||||
|
|
||||||
// scan through lookup pages
|
// scan through lookup pages
|
||||||
@ -406,7 +420,7 @@ s32_t spiffs_gc_clean(spiffs *fs, spiffs_block_ix bix) {
|
|||||||
case FIND_OBJ_DATA:
|
case FIND_OBJ_DATA:
|
||||||
if (obj_id != SPIFFS_OBJ_ID_DELETED && obj_id != SPIFFS_OBJ_ID_FREE &&
|
if (obj_id != SPIFFS_OBJ_ID_DELETED && obj_id != SPIFFS_OBJ_ID_FREE &&
|
||||||
((obj_id & SPIFFS_OBJ_ID_IX_FLAG) == 0)) {
|
((obj_id & SPIFFS_OBJ_ID_IX_FLAG) == 0)) {
|
||||||
SPIFFS_GC_DBG("gc_clean: FIND_DATA state:%d - found obj id %04x\n", gc.state, obj_id);
|
SPIFFS_GC_DBG("gc_clean: FIND_DATA state:%i - found obj id %04x\n", gc.state, obj_id);
|
||||||
gc.obj_id_found = 1;
|
gc.obj_id_found = 1;
|
||||||
gc.cur_obj_id = obj_id;
|
gc.cur_obj_id = obj_id;
|
||||||
scan = 0;
|
scan = 0;
|
||||||
@ -550,9 +564,10 @@ s32_t spiffs_gc_clean(spiffs *fs, spiffs_block_ix bix) {
|
|||||||
cur_entry = 0;
|
cur_entry = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
SPIFFS_GC_DBG("gc_clean: state-> %d\n", gc.state);
|
SPIFFS_GC_DBG("gc_clean: state-> %i\n", gc.state);
|
||||||
} // while state != FINISHED
|
} // while state != FINISHED
|
||||||
|
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,7 +8,9 @@
|
|||||||
#include "spiffs.h"
|
#include "spiffs.h"
|
||||||
#include "spiffs_nucleus.h"
|
#include "spiffs_nucleus.h"
|
||||||
|
|
||||||
|
#if SPIFFS_CACHE == 1
|
||||||
static s32_t spiffs_fflush_cache(spiffs *fs, spiffs_file fh);
|
static s32_t spiffs_fflush_cache(spiffs *fs, spiffs_file fh);
|
||||||
|
#endif
|
||||||
|
|
||||||
#if SPIFFS_BUFFER_HELP
|
#if SPIFFS_BUFFER_HELP
|
||||||
u32_t SPIFFS_buffer_bytes_for_filedescs(spiffs *fs, u32_t num_descs) {
|
u32_t SPIFFS_buffer_bytes_for_filedescs(spiffs *fs, u32_t num_descs) {
|
||||||
@ -56,12 +58,12 @@ s32_t SPIFFS_mount(spiffs *fs, spiffs_config *config, u8_t *work,
|
|||||||
void *cache, u32_t cache_size,
|
void *cache, u32_t cache_size,
|
||||||
spiffs_check_callback check_cb_f) {
|
spiffs_check_callback check_cb_f) {
|
||||||
SPIFFS_LOCK(fs);
|
SPIFFS_LOCK(fs);
|
||||||
c_memset(fs, 0, sizeof(spiffs));
|
memset(fs, 0, sizeof(spiffs));
|
||||||
c_memcpy(&fs->cfg, config, sizeof(spiffs_config));
|
memcpy(&fs->cfg, config, sizeof(spiffs_config));
|
||||||
fs->block_count = SPIFFS_CFG_PHYS_SZ(fs) / SPIFFS_CFG_LOG_BLOCK_SZ(fs);
|
fs->block_count = SPIFFS_CFG_PHYS_SZ(fs) / SPIFFS_CFG_LOG_BLOCK_SZ(fs);
|
||||||
fs->work = &work[0];
|
fs->work = &work[0];
|
||||||
fs->lu_work = &work[SPIFFS_CFG_LOG_PAGE_SZ(fs)];
|
fs->lu_work = &work[SPIFFS_CFG_LOG_PAGE_SZ(fs)];
|
||||||
c_memset(fd_space, 0, fd_space_size);
|
memset(fd_space, 0, fd_space_size);
|
||||||
// align fd_space pointer to pointer size byte boundary, below is safe
|
// align fd_space pointer to pointer size byte boundary, below is safe
|
||||||
u8_t ptr_size = sizeof(void*);
|
u8_t ptr_size = sizeof(void*);
|
||||||
#pragma GCC diagnostic push
|
#pragma GCC diagnostic push
|
||||||
@ -89,9 +91,10 @@ s32_t SPIFFS_mount(spiffs *fs, spiffs_config *config, u8_t *work,
|
|||||||
if (cache_size & (ptr_size-1)) {
|
if (cache_size & (ptr_size-1)) {
|
||||||
cache_size -= (cache_size & (ptr_size-1));
|
cache_size -= (cache_size & (ptr_size-1));
|
||||||
}
|
}
|
||||||
|
|
||||||
#if SPIFFS_CACHE
|
#if SPIFFS_CACHE
|
||||||
fs->cache = cache;
|
fs->cache = cache;
|
||||||
fs->cache_size = cache_size;
|
fs->cache_size = (cache_size > (SPIFFS_CFG_LOG_PAGE_SZ(fs)*32)) ? SPIFFS_CFG_LOG_PAGE_SZ(fs)*32 : cache_size;
|
||||||
spiffs_cache_init(fs);
|
spiffs_cache_init(fs);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -107,14 +110,14 @@ s32_t SPIFFS_mount(spiffs *fs, spiffs_config *config, u8_t *work,
|
|||||||
res = spiffs_obj_lu_scan(fs);
|
res = spiffs_obj_lu_scan(fs);
|
||||||
SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
|
SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
|
||||||
|
|
||||||
SPIFFS_DBG("page index byte len: %d\n", SPIFFS_CFG_LOG_PAGE_SZ(fs));
|
SPIFFS_DBG("page index byte len: %i\n", SPIFFS_CFG_LOG_PAGE_SZ(fs));
|
||||||
SPIFFS_DBG("object lookup pages: %d\n", SPIFFS_OBJ_LOOKUP_PAGES(fs));
|
SPIFFS_DBG("object lookup pages: %i\n", SPIFFS_OBJ_LOOKUP_PAGES(fs));
|
||||||
SPIFFS_DBG("page pages per block: %d\n", SPIFFS_PAGES_PER_BLOCK(fs));
|
SPIFFS_DBG("page pages per block: %i\n", SPIFFS_PAGES_PER_BLOCK(fs));
|
||||||
SPIFFS_DBG("page header length: %d\n", sizeof(spiffs_page_header));
|
SPIFFS_DBG("page header length: %i\n", sizeof(spiffs_page_header));
|
||||||
SPIFFS_DBG("object header index entries: %d\n", SPIFFS_OBJ_HDR_IX_LEN(fs));
|
SPIFFS_DBG("object header index entries: %i\n", SPIFFS_OBJ_HDR_IX_LEN(fs));
|
||||||
SPIFFS_DBG("object index entries: %d\n", SPIFFS_OBJ_IX_LEN(fs));
|
SPIFFS_DBG("object index entries: %i\n", SPIFFS_OBJ_IX_LEN(fs));
|
||||||
SPIFFS_DBG("available file descriptors: %d\n", fs->fd_count);
|
SPIFFS_DBG("available file descriptors: %i\n", fs->fd_count);
|
||||||
SPIFFS_DBG("free blocks: %d\n", fs->free_blocks);
|
SPIFFS_DBG("free blocks: %i\n", fs->free_blocks);
|
||||||
|
|
||||||
fs->check_cb_f = check_cb_f;
|
fs->check_cb_f = check_cb_f;
|
||||||
|
|
||||||
@ -188,6 +191,14 @@ spiffs_file SPIFFS_open(spiffs *fs, char *path, spiffs_flags flags, spiffs_mode
|
|||||||
SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
|
SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (res == SPIFFS_OK &&
|
||||||
|
(flags & (SPIFFS_CREAT | SPIFFS_EXCL)) == (SPIFFS_CREAT | SPIFFS_EXCL)) {
|
||||||
|
// creat and excl and file exists - fail
|
||||||
|
res = SPIFFS_ERR_FILE_EXISTS;
|
||||||
|
spiffs_fd_return(fs, fd->file_nbr);
|
||||||
|
SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
|
||||||
|
}
|
||||||
|
|
||||||
if ((flags & SPIFFS_CREAT) && res == SPIFFS_ERR_NOT_FOUND) {
|
if ((flags & SPIFFS_CREAT) && res == SPIFFS_ERR_NOT_FOUND) {
|
||||||
spiffs_obj_id obj_id;
|
spiffs_obj_id obj_id;
|
||||||
// no need to enter conflicting name here, already looked for it above
|
// no need to enter conflicting name here, already looked for it above
|
||||||
@ -377,7 +388,7 @@ s32_t SPIFFS_write(spiffs *fs, spiffs_file fh, void *buf, s32_t len) {
|
|||||||
offset + len > fd->cache_page->offset + SPIFFS_CFG_LOG_PAGE_SZ(fs)) // writing beyond cache page
|
offset + len > fd->cache_page->offset + SPIFFS_CFG_LOG_PAGE_SZ(fs)) // writing beyond cache page
|
||||||
{
|
{
|
||||||
// boundary violation, write back cache first and allocate new
|
// boundary violation, write back cache first and allocate new
|
||||||
SPIFFS_CACHE_DBG("CACHE_WR_DUMP: dumping cache page %d for fd %d:%04x, boundary viol, offs:%d size:%d\n",
|
SPIFFS_CACHE_DBG("CACHE_WR_DUMP: dumping cache page %i for fd %i:%04x, boundary viol, offs:%i size:%i\n",
|
||||||
fd->cache_page->ix, fd->file_nbr, fd->obj_id, fd->cache_page->offset, fd->cache_page->size);
|
fd->cache_page->ix, fd->file_nbr, fd->obj_id, fd->cache_page->offset, fd->cache_page->size);
|
||||||
res = spiffs_hydro_write(fs, fd,
|
res = spiffs_hydro_write(fs, fd,
|
||||||
spiffs_get_cache_page(fs, spiffs_get_cache(fs), fd->cache_page->ix),
|
spiffs_get_cache_page(fs, spiffs_get_cache(fs), fd->cache_page->ix),
|
||||||
@ -395,19 +406,19 @@ s32_t SPIFFS_write(spiffs *fs, spiffs_file fh, void *buf, s32_t len) {
|
|||||||
if (fd->cache_page) {
|
if (fd->cache_page) {
|
||||||
fd->cache_page->offset = offset;
|
fd->cache_page->offset = offset;
|
||||||
fd->cache_page->size = 0;
|
fd->cache_page->size = 0;
|
||||||
SPIFFS_CACHE_DBG("CACHE_WR_ALLO: allocating cache page %d for fd %d:%04x\n",
|
SPIFFS_CACHE_DBG("CACHE_WR_ALLO: allocating cache page %i for fd %i:%04x\n",
|
||||||
fd->cache_page->ix, fd->file_nbr, fd->obj_id);
|
fd->cache_page->ix, fd->file_nbr, fd->obj_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fd->cache_page) {
|
if (fd->cache_page) {
|
||||||
u32_t offset_in_cpage = offset - fd->cache_page->offset;
|
u32_t offset_in_cpage = offset - fd->cache_page->offset;
|
||||||
SPIFFS_CACHE_DBG("CACHE_WR_WRITE: storing to cache page %d for fd %d:%04x, offs %d:%d len %d\n",
|
SPIFFS_CACHE_DBG("CACHE_WR_WRITE: storing to cache page %i for fd %i:%04x, offs %i:%i len %i\n",
|
||||||
fd->cache_page->ix, fd->file_nbr, fd->obj_id,
|
fd->cache_page->ix, fd->file_nbr, fd->obj_id,
|
||||||
offset, offset_in_cpage, len);
|
offset, offset_in_cpage, len);
|
||||||
spiffs_cache *cache = spiffs_get_cache(fs);
|
spiffs_cache *cache = spiffs_get_cache(fs);
|
||||||
u8_t *cpage_data = spiffs_get_cache_page(fs, cache, fd->cache_page->ix);
|
u8_t *cpage_data = spiffs_get_cache_page(fs, cache, fd->cache_page->ix);
|
||||||
c_memcpy(&cpage_data[offset_in_cpage], buf, len);
|
memcpy(&cpage_data[offset_in_cpage], buf, len);
|
||||||
fd->cache_page->size = MAX(fd->cache_page->size, offset_in_cpage + len);
|
fd->cache_page->size = MAX(fd->cache_page->size, offset_in_cpage + len);
|
||||||
fd->fdoffset += len;
|
fd->fdoffset += len;
|
||||||
SPIFFS_UNLOCK(fs);
|
SPIFFS_UNLOCK(fs);
|
||||||
@ -423,7 +434,7 @@ s32_t SPIFFS_write(spiffs *fs, spiffs_file fh, void *buf, s32_t len) {
|
|||||||
// big write, no need to cache it - but first check if there is a cached write already
|
// big write, no need to cache it - but first check if there is a cached write already
|
||||||
if (fd->cache_page) {
|
if (fd->cache_page) {
|
||||||
// write back cache first
|
// write back cache first
|
||||||
SPIFFS_CACHE_DBG("CACHE_WR_DUMP: dumping cache page %d for fd %d:%04x, big write, offs:%d size:%d\n",
|
SPIFFS_CACHE_DBG("CACHE_WR_DUMP: dumping cache page %i for fd %i:%04x, big write, offs:%i size:%i\n",
|
||||||
fd->cache_page->ix, fd->file_nbr, fd->obj_id, fd->cache_page->offset, fd->cache_page->size);
|
fd->cache_page->ix, fd->file_nbr, fd->obj_id, fd->cache_page->offset, fd->cache_page->size);
|
||||||
res = spiffs_hydro_write(fs, fd,
|
res = spiffs_hydro_write(fs, fd,
|
||||||
spiffs_get_cache_page(fs, spiffs_get_cache(fs), fd->cache_page->ix),
|
spiffs_get_cache_page(fs, spiffs_get_cache(fs), fd->cache_page->ix),
|
||||||
@ -488,7 +499,7 @@ s32_t SPIFFS_lseek(spiffs *fs, spiffs_file fh, s32_t offs, int whence) {
|
|||||||
|
|
||||||
SPIFFS_UNLOCK(fs);
|
SPIFFS_UNLOCK(fs);
|
||||||
|
|
||||||
return 0;
|
return offs;
|
||||||
}
|
}
|
||||||
|
|
||||||
s32_t SPIFFS_remove(spiffs *fs, char *path) {
|
s32_t SPIFFS_remove(spiffs *fs, char *path) {
|
||||||
@ -554,6 +565,7 @@ s32_t SPIFFS_fremove(spiffs *fs, spiffs_file fh) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static s32_t spiffs_stat_pix(spiffs *fs, spiffs_page_ix pix, spiffs_file fh, spiffs_stat *s) {
|
static s32_t spiffs_stat_pix(spiffs *fs, spiffs_page_ix pix, spiffs_file fh, spiffs_stat *s) {
|
||||||
|
(void)fh;
|
||||||
spiffs_page_object_ix_header objix_hdr;
|
spiffs_page_object_ix_header objix_hdr;
|
||||||
spiffs_obj_id obj_id;
|
spiffs_obj_id obj_id;
|
||||||
s32_t res =_spiffs_rd(fs, SPIFFS_OP_T_OBJ_IX | SPIFFS_OP_C_READ, fh,
|
s32_t res =_spiffs_rd(fs, SPIFFS_OP_T_OBJ_IX | SPIFFS_OP_C_READ, fh,
|
||||||
@ -616,7 +628,10 @@ s32_t SPIFFS_fstat(spiffs *fs, spiffs_file fh, spiffs_stat *s) {
|
|||||||
|
|
||||||
// Checks if there are any cached writes for the object id associated with
|
// Checks if there are any cached writes for the object id associated with
|
||||||
// given filehandle. If so, these writes are flushed.
|
// given filehandle. If so, these writes are flushed.
|
||||||
|
#if SPIFFS_CACHE == 1
|
||||||
static s32_t spiffs_fflush_cache(spiffs *fs, spiffs_file fh) {
|
static s32_t spiffs_fflush_cache(spiffs *fs, spiffs_file fh) {
|
||||||
|
(void)fs;
|
||||||
|
(void)fh;
|
||||||
s32_t res = SPIFFS_OK;
|
s32_t res = SPIFFS_OK;
|
||||||
#if SPIFFS_CACHE_WR
|
#if SPIFFS_CACHE_WR
|
||||||
|
|
||||||
@ -630,7 +645,7 @@ static s32_t spiffs_fflush_cache(spiffs *fs, spiffs_file fh) {
|
|||||||
fd->cache_page = spiffs_cache_page_get_by_fd(fs, fd);
|
fd->cache_page = spiffs_cache_page_get_by_fd(fs, fd);
|
||||||
}
|
}
|
||||||
if (fd->cache_page) {
|
if (fd->cache_page) {
|
||||||
SPIFFS_CACHE_DBG("CACHE_WR_DUMP: dumping cache page %d for fd %d:%04x, flush, offs:%d size:%d\n",
|
SPIFFS_CACHE_DBG("CACHE_WR_DUMP: dumping cache page %i for fd %i:%04x, flush, offs:%i size:%i\n",
|
||||||
fd->cache_page->ix, fd->file_nbr, fd->obj_id, fd->cache_page->offset, fd->cache_page->size);
|
fd->cache_page->ix, fd->file_nbr, fd->obj_id, fd->cache_page->offset, fd->cache_page->size);
|
||||||
res = spiffs_hydro_write(fs, fd,
|
res = spiffs_hydro_write(fs, fd,
|
||||||
spiffs_get_cache_page(fs, spiffs_get_cache(fs), fd->cache_page->ix),
|
spiffs_get_cache_page(fs, spiffs_get_cache(fs), fd->cache_page->ix),
|
||||||
@ -645,8 +660,10 @@ static s32_t spiffs_fflush_cache(spiffs *fs, spiffs_file fh) {
|
|||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
s32_t SPIFFS_fflush(spiffs *fs, spiffs_file fh) {
|
s32_t SPIFFS_fflush(spiffs *fs, spiffs_file fh) {
|
||||||
|
(void)fh;
|
||||||
SPIFFS_API_CHECK_CFG(fs);
|
SPIFFS_API_CHECK_CFG(fs);
|
||||||
SPIFFS_API_CHECK_MOUNT(fs);
|
SPIFFS_API_CHECK_MOUNT(fs);
|
||||||
s32_t res = SPIFFS_OK;
|
s32_t res = SPIFFS_OK;
|
||||||
@ -660,24 +677,23 @@ s32_t SPIFFS_fflush(spiffs *fs, spiffs_file fh) {
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SPIFFS_close(spiffs *fs, spiffs_file fh) {
|
s32_t SPIFFS_close(spiffs *fs, spiffs_file fh) {
|
||||||
if (!SPIFFS_CHECK_CFG((fs))) {
|
SPIFFS_API_CHECK_CFG(fs);
|
||||||
(fs)->err_code = SPIFFS_ERR_NOT_CONFIGURED;
|
SPIFFS_API_CHECK_MOUNT(fs);
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!SPIFFS_CHECK_MOUNT(fs)) {
|
s32_t res = SPIFFS_OK;
|
||||||
fs->err_code = SPIFFS_ERR_NOT_MOUNTED;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
SPIFFS_LOCK(fs);
|
SPIFFS_LOCK(fs);
|
||||||
|
|
||||||
#if SPIFFS_CACHE
|
#if SPIFFS_CACHE
|
||||||
spiffs_fflush_cache(fs, fh);
|
res = spiffs_fflush_cache(fs, fh);
|
||||||
|
SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
|
||||||
#endif
|
#endif
|
||||||
spiffs_fd_return(fs, fh);
|
res = spiffs_fd_return(fs, fh);
|
||||||
|
SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
|
||||||
|
|
||||||
SPIFFS_UNLOCK(fs);
|
SPIFFS_UNLOCK(fs);
|
||||||
|
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
s32_t SPIFFS_rename(spiffs *fs, char *old, char *new) {
|
s32_t SPIFFS_rename(spiffs *fs, char *old, char *new) {
|
||||||
@ -711,9 +727,8 @@ s32_t SPIFFS_rename(spiffs *fs, char *old, char *new) {
|
|||||||
res = spiffs_object_update_index_hdr(fs, fd, fd->obj_id, fd->objix_hdr_pix, 0, (u8_t*)new,
|
res = spiffs_object_update_index_hdr(fs, fd, fd->obj_id, fd->objix_hdr_pix, 0, (u8_t*)new,
|
||||||
0, &pix_dummy);
|
0, &pix_dummy);
|
||||||
|
|
||||||
if (res != SPIFFS_OK) {
|
spiffs_fd_return(fs, fd->file_nbr);
|
||||||
spiffs_fd_return(fs, fd->file_nbr);
|
|
||||||
}
|
|
||||||
SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
|
SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
|
||||||
|
|
||||||
SPIFFS_UNLOCK(fs);
|
SPIFFS_UNLOCK(fs);
|
||||||
@ -780,7 +795,7 @@ struct spiffs_dirent *SPIFFS_readdir(spiffs_DIR *d, struct spiffs_dirent *e) {
|
|||||||
d->fs->err_code = SPIFFS_ERR_NOT_MOUNTED;
|
d->fs->err_code = SPIFFS_ERR_NOT_MOUNTED;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
SPIFFS_LOCK(fs);
|
SPIFFS_LOCK(d->fs);
|
||||||
|
|
||||||
spiffs_block_ix bix;
|
spiffs_block_ix bix;
|
||||||
int entry;
|
int entry;
|
||||||
@ -804,7 +819,7 @@ struct spiffs_dirent *SPIFFS_readdir(spiffs_DIR *d, struct spiffs_dirent *e) {
|
|||||||
} else {
|
} else {
|
||||||
d->fs->err_code = res;
|
d->fs->err_code = res;
|
||||||
}
|
}
|
||||||
SPIFFS_UNLOCK(fs);
|
SPIFFS_UNLOCK(d->fs);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -856,46 +871,34 @@ s32_t SPIFFS_info(spiffs *fs, u32_t *total, u32_t *used) {
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
s32_t SPIFFS_eof(spiffs *fs, spiffs_file fh) {
|
s32_t SPIFFS_gc_quick(spiffs *fs, u16_t max_free_pages) {
|
||||||
|
s32_t res;
|
||||||
SPIFFS_API_CHECK_CFG(fs);
|
SPIFFS_API_CHECK_CFG(fs);
|
||||||
SPIFFS_API_CHECK_MOUNT(fs);
|
SPIFFS_API_CHECK_MOUNT(fs);
|
||||||
SPIFFS_LOCK(fs);
|
SPIFFS_LOCK(fs);
|
||||||
|
|
||||||
spiffs_fd *fd;
|
res = spiffs_gc_quick(fs, max_free_pages);
|
||||||
s32_t res;
|
|
||||||
res = spiffs_fd_get(fs, fh, &fd);
|
|
||||||
SPIFFS_API_CHECK_RES(fs, res);
|
|
||||||
|
|
||||||
#if SPIFFS_CACHE_WR
|
|
||||||
spiffs_fflush_cache(fs, fh);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
res = (fd->fdoffset == fd->size);
|
|
||||||
|
|
||||||
|
SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
|
||||||
SPIFFS_UNLOCK(fs);
|
SPIFFS_UNLOCK(fs);
|
||||||
return res;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
s32_t SPIFFS_tell(spiffs *fs, spiffs_file fh) {
|
|
||||||
|
s32_t SPIFFS_gc(spiffs *fs, u32_t size) {
|
||||||
|
s32_t res;
|
||||||
SPIFFS_API_CHECK_CFG(fs);
|
SPIFFS_API_CHECK_CFG(fs);
|
||||||
SPIFFS_API_CHECK_MOUNT(fs);
|
SPIFFS_API_CHECK_MOUNT(fs);
|
||||||
SPIFFS_LOCK(fs);
|
SPIFFS_LOCK(fs);
|
||||||
|
|
||||||
spiffs_fd *fd;
|
res = spiffs_gc_check(fs, size);
|
||||||
s32_t res;
|
|
||||||
res = spiffs_fd_get(fs, fh, &fd);
|
|
||||||
SPIFFS_API_CHECK_RES(fs, res);
|
|
||||||
|
|
||||||
#if SPIFFS_CACHE_WR
|
|
||||||
spiffs_fflush_cache(fs, fh);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
res = fd->fdoffset;
|
|
||||||
|
|
||||||
|
SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
|
||||||
SPIFFS_UNLOCK(fs);
|
SPIFFS_UNLOCK(fs);
|
||||||
return res;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#if SPIFFS_TEST_VISUALISATION
|
#if SPIFFS_TEST_VISUALISATION
|
||||||
s32_t SPIFFS_vis(spiffs *fs) {
|
s32_t SPIFFS_vis(spiffs *fs) {
|
||||||
s32_t res = SPIFFS_OK;
|
s32_t res = SPIFFS_OK;
|
||||||
@ -949,7 +952,7 @@ s32_t SPIFFS_vis(spiffs *fs) {
|
|||||||
SPIFFS_CHECK_RES(res);
|
SPIFFS_CHECK_RES(res);
|
||||||
|
|
||||||
if (erase_count != (spiffs_obj_id)-1) {
|
if (erase_count != (spiffs_obj_id)-1) {
|
||||||
spiffs_printf("\tera_cnt: %d\n", erase_count);
|
spiffs_printf("\tera_cnt: %i\n", erase_count);
|
||||||
} else {
|
} else {
|
||||||
spiffs_printf("\tera_cnt: N/A\n");
|
spiffs_printf("\tera_cnt: N/A\n");
|
||||||
}
|
}
|
||||||
@ -957,15 +960,15 @@ s32_t SPIFFS_vis(spiffs *fs) {
|
|||||||
bix++;
|
bix++;
|
||||||
} // per block
|
} // per block
|
||||||
|
|
||||||
spiffs_printf("era_cnt_max: %d\n", fs->max_erase_count);
|
spiffs_printf("era_cnt_max: %i\n", fs->max_erase_count);
|
||||||
spiffs_printf("last_errno: %d\n", fs->err_code);
|
spiffs_printf("last_errno: %i\n", fs->err_code);
|
||||||
spiffs_printf("blocks: %d\n", fs->block_count);
|
spiffs_printf("blocks: %i\n", fs->block_count);
|
||||||
spiffs_printf("free_blocks: %d\n", fs->free_blocks);
|
spiffs_printf("free_blocks: %i\n", fs->free_blocks);
|
||||||
spiffs_printf("page_alloc: %d\n", fs->stats_p_allocated);
|
spiffs_printf("page_alloc: %i\n", fs->stats_p_allocated);
|
||||||
spiffs_printf("page_delet: %d\n", fs->stats_p_deleted);
|
spiffs_printf("page_delet: %i\n", fs->stats_p_deleted);
|
||||||
u32_t total, used;
|
u32_t total, used;
|
||||||
SPIFFS_info(fs, &total, &used);
|
SPIFFS_info(fs, &total, &used);
|
||||||
spiffs_printf("used: %d of %d\n", used, total);
|
spiffs_printf("used: %i of %i\n", used, total);
|
||||||
|
|
||||||
SPIFFS_UNLOCK(fs);
|
SPIFFS_UNLOCK(fs);
|
||||||
return res;
|
return res;
|
||||||
|
@ -64,7 +64,7 @@ s32_t spiffs_phys_rd(
|
|||||||
u32_t addr,
|
u32_t addr,
|
||||||
u32_t len,
|
u32_t len,
|
||||||
u8_t *dst) {
|
u8_t *dst) {
|
||||||
return fs->cfg.hal_read_f(addr, len, dst);
|
return SPIFFS_HAL_READ(fs, addr, len, dst);
|
||||||
}
|
}
|
||||||
|
|
||||||
s32_t spiffs_phys_wr(
|
s32_t spiffs_phys_wr(
|
||||||
@ -72,7 +72,7 @@ s32_t spiffs_phys_wr(
|
|||||||
u32_t addr,
|
u32_t addr,
|
||||||
u32_t len,
|
u32_t len,
|
||||||
u8_t *src) {
|
u8_t *src) {
|
||||||
return fs->cfg.hal_write_f(addr, len, src);
|
return SPIFFS_HAL_WRITE(fs, addr, len, src);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@ -83,6 +83,7 @@ s32_t spiffs_phys_cpy(
|
|||||||
u32_t dst,
|
u32_t dst,
|
||||||
u32_t src,
|
u32_t src,
|
||||||
u32_t len) {
|
u32_t len) {
|
||||||
|
(void)fh;
|
||||||
s32_t res;
|
s32_t res;
|
||||||
u8_t b[SPIFFS_COPY_BUFFER_STACK];
|
u8_t b[SPIFFS_COPY_BUFFER_STACK];
|
||||||
while (len > 0) {
|
while (len > 0) {
|
||||||
@ -227,7 +228,8 @@ s32_t spiffs_erase_block(
|
|||||||
// here we ignore res, just try erasing the block
|
// here we ignore res, just try erasing the block
|
||||||
while (size > 0) {
|
while (size > 0) {
|
||||||
SPIFFS_DBG("erase %08x:%08x\n", addr, SPIFFS_CFG_PHYS_ERASE_SZ(fs));
|
SPIFFS_DBG("erase %08x:%08x\n", addr, SPIFFS_CFG_PHYS_ERASE_SZ(fs));
|
||||||
(void)fs->cfg.hal_erase_f(addr, SPIFFS_CFG_PHYS_ERASE_SZ(fs));
|
SPIFFS_HAL_ERASE(fs, addr, SPIFFS_CFG_PHYS_ERASE_SZ(fs));
|
||||||
|
|
||||||
addr += SPIFFS_CFG_PHYS_ERASE_SZ(fs);
|
addr += SPIFFS_CFG_PHYS_ERASE_SZ(fs);
|
||||||
size -= SPIFFS_CFG_PHYS_ERASE_SZ(fs);
|
size -= SPIFFS_CFG_PHYS_ERASE_SZ(fs);
|
||||||
}
|
}
|
||||||
@ -347,7 +349,7 @@ s32_t spiffs_obj_lu_scan(
|
|||||||
#if SPIFFS_USE_MAGIC
|
#if SPIFFS_USE_MAGIC
|
||||||
if (unerased_bix != (spiffs_block_ix)-1) {
|
if (unerased_bix != (spiffs_block_ix)-1) {
|
||||||
// found one unerased block, remedy
|
// found one unerased block, remedy
|
||||||
SPIFFS_DBG("mount: erase block %d\n", bix);
|
SPIFFS_DBG("mount: erase block %i\n", bix);
|
||||||
res = spiffs_erase_block(fs, unerased_bix);
|
res = spiffs_erase_block(fs, unerased_bix);
|
||||||
SPIFFS_CHECK_RES(res);
|
SPIFFS_CHECK_RES(res);
|
||||||
}
|
}
|
||||||
@ -389,7 +391,10 @@ s32_t spiffs_obj_lu_find_free(
|
|||||||
int *lu_entry) {
|
int *lu_entry) {
|
||||||
s32_t res;
|
s32_t res;
|
||||||
if (!fs->cleaning && fs->free_blocks < 2) {
|
if (!fs->cleaning && fs->free_blocks < 2) {
|
||||||
res = spiffs_gc_quick(fs);
|
res = spiffs_gc_quick(fs, 0);
|
||||||
|
if (res == SPIFFS_ERR_NO_DELETED_BLOCKS) {
|
||||||
|
res = SPIFFS_OK;
|
||||||
|
}
|
||||||
SPIFFS_CHECK_RES(res);
|
SPIFFS_CHECK_RES(res);
|
||||||
if (fs->free_blocks < 2) {
|
if (fs->free_blocks < 2) {
|
||||||
return SPIFFS_ERR_FULL;
|
return SPIFFS_ERR_FULL;
|
||||||
@ -701,7 +706,7 @@ s32_t spiffs_object_create(
|
|||||||
// find free entry
|
// find free entry
|
||||||
res = spiffs_obj_lu_find_free(fs, fs->free_cursor_block_ix, fs->free_cursor_obj_lu_entry, &bix, &entry);
|
res = spiffs_obj_lu_find_free(fs, fs->free_cursor_block_ix, fs->free_cursor_obj_lu_entry, &bix, &entry);
|
||||||
SPIFFS_CHECK_RES(res);
|
SPIFFS_CHECK_RES(res);
|
||||||
SPIFFS_DBG("create: found free page @ %04x bix:%d entry:%d\n", SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, bix, entry), bix, entry);
|
SPIFFS_DBG("create: found free page @ %04x bix:%i entry:%i\n", SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, bix, entry), bix, entry);
|
||||||
|
|
||||||
// occupy page in object lookup
|
// occupy page in object lookup
|
||||||
res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_UPDT,
|
res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_UPDT,
|
||||||
@ -806,7 +811,7 @@ void spiffs_cb_object_event(
|
|||||||
if (cur_fd->file_nbr == 0 || (cur_fd->obj_id & ~SPIFFS_OBJ_ID_IX_FLAG) != obj_id) continue;
|
if (cur_fd->file_nbr == 0 || (cur_fd->obj_id & ~SPIFFS_OBJ_ID_IX_FLAG) != obj_id) continue;
|
||||||
if (spix == 0) {
|
if (spix == 0) {
|
||||||
if (ev == SPIFFS_EV_IX_NEW || ev == SPIFFS_EV_IX_UPD) {
|
if (ev == SPIFFS_EV_IX_NEW || ev == SPIFFS_EV_IX_UPD) {
|
||||||
SPIFFS_DBG(" callback: setting fd %d:%04x objix_hdr_pix to %04x, size:%d\n", cur_fd->file_nbr, cur_fd->obj_id, new_pix, new_size);
|
SPIFFS_DBG(" callback: setting fd %i:%04x objix_hdr_pix to %04x, size:%i\n", cur_fd->file_nbr, cur_fd->obj_id, new_pix, new_size);
|
||||||
cur_fd->objix_hdr_pix = new_pix;
|
cur_fd->objix_hdr_pix = new_pix;
|
||||||
if (new_size != 0) {
|
if (new_size != 0) {
|
||||||
cur_fd->size = new_size;
|
cur_fd->size = new_size;
|
||||||
@ -818,7 +823,7 @@ void spiffs_cb_object_event(
|
|||||||
}
|
}
|
||||||
if (cur_fd->cursor_objix_spix == spix) {
|
if (cur_fd->cursor_objix_spix == spix) {
|
||||||
if (ev == SPIFFS_EV_IX_NEW || ev == SPIFFS_EV_IX_UPD) {
|
if (ev == SPIFFS_EV_IX_NEW || ev == SPIFFS_EV_IX_UPD) {
|
||||||
SPIFFS_DBG(" callback: setting fd %d:%04x span:%04x objix_pix to %04x\n", cur_fd->file_nbr, cur_fd->obj_id, spix, new_pix);
|
SPIFFS_DBG(" callback: setting fd %i:%04x span:%04x objix_pix to %04x\n", cur_fd->file_nbr, cur_fd->obj_id, spix, new_pix);
|
||||||
cur_fd->cursor_objix_pix = new_pix;
|
cur_fd->cursor_objix_pix = new_pix;
|
||||||
} else {
|
} else {
|
||||||
cur_fd->cursor_objix_pix = 0;
|
cur_fd->cursor_objix_pix = 0;
|
||||||
@ -878,7 +883,7 @@ s32_t spiffs_object_open_by_page(
|
|||||||
|
|
||||||
SPIFFS_VALIDATE_OBJIX(oix_hdr.p_hdr, fd->obj_id, 0);
|
SPIFFS_VALIDATE_OBJIX(oix_hdr.p_hdr, fd->obj_id, 0);
|
||||||
|
|
||||||
SPIFFS_DBG("open: fd %d is obj id %04x\n", fd->file_nbr, fd->obj_id);
|
SPIFFS_DBG("open: fd %i is obj id %04x\n", fd->file_nbr, fd->obj_id);
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
@ -890,7 +895,7 @@ s32_t spiffs_object_append(spiffs_fd *fd, u32_t offset, u8_t *data, u32_t len) {
|
|||||||
s32_t res = SPIFFS_OK;
|
s32_t res = SPIFFS_OK;
|
||||||
u32_t written = 0;
|
u32_t written = 0;
|
||||||
|
|
||||||
SPIFFS_DBG("append: %d bytes @ offs %d of size %d\n", len, offset, fd->size);
|
SPIFFS_DBG("append: %i bytes @ offs %i of size %i\n", len, offset, fd->size);
|
||||||
|
|
||||||
if (offset > fd->size) {
|
if (offset > fd->size) {
|
||||||
SPIFFS_DBG("append: offset reversed to size\n");
|
SPIFFS_DBG("append: offset reversed to size\n");
|
||||||
@ -899,7 +904,7 @@ s32_t spiffs_object_append(spiffs_fd *fd, u32_t offset, u8_t *data, u32_t len) {
|
|||||||
|
|
||||||
res = spiffs_gc_check(fs, len + SPIFFS_DATA_PAGE_SIZE(fs)); // add an extra page of data worth for meta
|
res = spiffs_gc_check(fs, len + SPIFFS_DATA_PAGE_SIZE(fs)); // add an extra page of data worth for meta
|
||||||
if (res != SPIFFS_OK) {
|
if (res != SPIFFS_OK) {
|
||||||
SPIFFS_DBG("append: gc check fail %d\n", res);
|
SPIFFS_DBG("append: gc check fail %i\n", res);
|
||||||
}
|
}
|
||||||
SPIFFS_CHECK_RES(res);
|
SPIFFS_CHECK_RES(res);
|
||||||
|
|
||||||
@ -927,7 +932,7 @@ s32_t spiffs_object_append(spiffs_fd *fd, u32_t offset, u8_t *data, u32_t len) {
|
|||||||
// within this clause we return directly if something fails, object index mess-up
|
// within this clause we return directly if something fails, object index mess-up
|
||||||
if (written > 0) {
|
if (written > 0) {
|
||||||
// store previous object index page, unless first pass
|
// store previous object index page, unless first pass
|
||||||
SPIFFS_DBG("append: %04x store objix %04x:%04x, written %d\n", fd->obj_id,
|
SPIFFS_DBG("append: %04x store objix %04x:%04x, written %i\n", fd->obj_id,
|
||||||
cur_objix_pix, prev_objix_spix, written);
|
cur_objix_pix, prev_objix_spix, written);
|
||||||
if (prev_objix_spix == 0) {
|
if (prev_objix_spix == 0) {
|
||||||
// this is an update to object index header page
|
// this is an update to object index header page
|
||||||
@ -944,7 +949,7 @@ s32_t spiffs_object_append(spiffs_fd *fd, u32_t offset, u8_t *data, u32_t len) {
|
|||||||
res = spiffs_object_update_index_hdr(fs, fd, fd->obj_id,
|
res = spiffs_object_update_index_hdr(fs, fd, fd->obj_id,
|
||||||
fd->objix_hdr_pix, fs->work, 0, offset+written, &new_objix_hdr_page);
|
fd->objix_hdr_pix, fs->work, 0, offset+written, &new_objix_hdr_page);
|
||||||
SPIFFS_CHECK_RES(res);
|
SPIFFS_CHECK_RES(res);
|
||||||
SPIFFS_DBG("append: %04x store new objix_hdr, %04x:%04x, written %d\n", fd->obj_id,
|
SPIFFS_DBG("append: %04x store new objix_hdr, %04x:%04x, written %i\n", fd->obj_id,
|
||||||
new_objix_hdr_page, 0, written);
|
new_objix_hdr_page, 0, written);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -960,7 +965,7 @@ s32_t spiffs_object_append(spiffs_fd *fd, u32_t offset, u8_t *data, u32_t len) {
|
|||||||
res = spiffs_object_update_index_hdr(fs, fd, fd->obj_id,
|
res = spiffs_object_update_index_hdr(fs, fd, fd->obj_id,
|
||||||
fd->objix_hdr_pix, 0, 0, offset+written, &new_objix_hdr_page);
|
fd->objix_hdr_pix, 0, 0, offset+written, &new_objix_hdr_page);
|
||||||
SPIFFS_CHECK_RES(res);
|
SPIFFS_CHECK_RES(res);
|
||||||
SPIFFS_DBG("append: %04x store new size I %d in objix_hdr, %04x:%04x, written %d\n", fd->obj_id,
|
SPIFFS_DBG("append: %04x store new size I %i in objix_hdr, %04x:%04x, written %i\n", fd->obj_id,
|
||||||
offset+written, new_objix_hdr_page, 0, written);
|
offset+written, new_objix_hdr_page, 0, written);
|
||||||
}
|
}
|
||||||
fd->size = offset+written;
|
fd->size = offset+written;
|
||||||
@ -987,9 +992,9 @@ s32_t spiffs_object_append(spiffs_fd *fd, u32_t offset, u8_t *data, u32_t len) {
|
|||||||
SPIFFS_CHECK_RES(res);
|
SPIFFS_CHECK_RES(res);
|
||||||
spiffs_cb_object_event(fs, fd, SPIFFS_EV_IX_NEW, fd->obj_id, cur_objix_spix, cur_objix_pix, 0);
|
spiffs_cb_object_event(fs, fd, SPIFFS_EV_IX_NEW, fd->obj_id, cur_objix_spix, cur_objix_pix, 0);
|
||||||
// quick "load" of new object index page
|
// quick "load" of new object index page
|
||||||
c_memset(fs->work, 0xff, SPIFFS_CFG_LOG_PAGE_SZ(fs));
|
memset(fs->work, 0xff, SPIFFS_CFG_LOG_PAGE_SZ(fs));
|
||||||
c_memcpy(fs->work, &p_hdr, sizeof(spiffs_page_header));
|
memcpy(fs->work, &p_hdr, sizeof(spiffs_page_header));
|
||||||
SPIFFS_DBG("append: %04x create objix page, %04x:%04x, written %d\n", fd->obj_id
|
SPIFFS_DBG("append: %04x create objix page, %04x:%04x, written %i\n", fd->obj_id
|
||||||
, cur_objix_pix, cur_objix_spix, written);
|
, cur_objix_pix, cur_objix_spix, written);
|
||||||
} else {
|
} else {
|
||||||
// on first pass, we load existing object index page
|
// on first pass, we load existing object index page
|
||||||
@ -1001,7 +1006,7 @@ s32_t spiffs_object_append(spiffs_fd *fd, u32_t offset, u8_t *data, u32_t len) {
|
|||||||
res = spiffs_obj_lu_find_id_and_span(fs, fd->obj_id | SPIFFS_OBJ_ID_IX_FLAG, cur_objix_spix, 0, &pix);
|
res = spiffs_obj_lu_find_id_and_span(fs, fd->obj_id | SPIFFS_OBJ_ID_IX_FLAG, cur_objix_spix, 0, &pix);
|
||||||
SPIFFS_CHECK_RES(res);
|
SPIFFS_CHECK_RES(res);
|
||||||
}
|
}
|
||||||
SPIFFS_DBG("append: %04x found object index at page %04x [fd size %d]\n", fd->obj_id, pix, fd->size);
|
SPIFFS_DBG("append: %04x found object index at page %04x [fd size %i]\n", fd->obj_id, pix, fd->size);
|
||||||
res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_IX | SPIFFS_OP_C_READ,
|
res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_IX | SPIFFS_OP_C_READ,
|
||||||
fd->file_nbr, SPIFFS_PAGE_TO_PADDR(fs, pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->work);
|
fd->file_nbr, SPIFFS_PAGE_TO_PADDR(fs, pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->work);
|
||||||
SPIFFS_CHECK_RES(res);
|
SPIFFS_CHECK_RES(res);
|
||||||
@ -1025,7 +1030,7 @@ s32_t spiffs_object_append(spiffs_fd *fd, u32_t offset, u8_t *data, u32_t len) {
|
|||||||
p_hdr.flags = 0xff & ~(SPIFFS_PH_FLAG_FINAL); // finalize immediately
|
p_hdr.flags = 0xff & ~(SPIFFS_PH_FLAG_FINAL); // finalize immediately
|
||||||
res = spiffs_page_allocate_data(fs, fd->obj_id & ~SPIFFS_OBJ_ID_IX_FLAG,
|
res = spiffs_page_allocate_data(fs, fd->obj_id & ~SPIFFS_OBJ_ID_IX_FLAG,
|
||||||
&p_hdr, &data[written], to_write, page_offs, 1, &data_page);
|
&p_hdr, &data[written], to_write, page_offs, 1, &data_page);
|
||||||
SPIFFS_DBG("append: %04x store new data page, %04x:%04x offset:%d, len %d, written %d\n", fd->obj_id,
|
SPIFFS_DBG("append: %04x store new data page, %04x:%04x offset:%i, len %i, written %i\n", fd->obj_id,
|
||||||
data_page, data_spix, page_offs, to_write, written);
|
data_page, data_spix, page_offs, to_write, written);
|
||||||
} else {
|
} else {
|
||||||
// append to existing page, fill out free data in existing page
|
// append to existing page, fill out free data in existing page
|
||||||
@ -1042,7 +1047,7 @@ s32_t spiffs_object_append(spiffs_fd *fd, u32_t offset, u8_t *data, u32_t len) {
|
|||||||
|
|
||||||
res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_DA | SPIFFS_OP_C_UPDT,
|
res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_DA | SPIFFS_OP_C_UPDT,
|
||||||
fd->file_nbr, SPIFFS_PAGE_TO_PADDR(fs, data_page) + sizeof(spiffs_page_header) + page_offs, to_write, &data[written]);
|
fd->file_nbr, SPIFFS_PAGE_TO_PADDR(fs, data_page) + sizeof(spiffs_page_header) + page_offs, to_write, &data[written]);
|
||||||
SPIFFS_DBG("append: %04x store to existing data page, %04x:%04x offset:%d, len %d, written %d\n", fd->obj_id
|
SPIFFS_DBG("append: %04x store to existing data page, %04x:%04x offset:%i, len %i, written %i\n", fd->obj_id
|
||||||
, data_page, data_spix, page_offs, to_write, written);
|
, data_page, data_spix, page_offs, to_write, written);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1078,7 +1083,7 @@ s32_t spiffs_object_append(spiffs_fd *fd, u32_t offset, u8_t *data, u32_t len) {
|
|||||||
if (cur_objix_spix != 0) {
|
if (cur_objix_spix != 0) {
|
||||||
// wrote beyond object index header page
|
// wrote beyond object index header page
|
||||||
// write last modified object index page, unless object header index page
|
// write last modified object index page, unless object header index page
|
||||||
SPIFFS_DBG("append: %04x store objix page, %04x:%04x, written %d\n", fd->obj_id,
|
SPIFFS_DBG("append: %04x store objix page, %04x:%04x, written %i\n", fd->obj_id,
|
||||||
cur_objix_pix, cur_objix_spix, written);
|
cur_objix_pix, cur_objix_spix, written);
|
||||||
|
|
||||||
res2 = spiffs_page_index_check(fs, fd, cur_objix_pix, cur_objix_spix);
|
res2 = spiffs_page_index_check(fs, fd, cur_objix_pix, cur_objix_spix);
|
||||||
@ -1092,7 +1097,7 @@ s32_t spiffs_object_append(spiffs_fd *fd, u32_t offset, u8_t *data, u32_t len) {
|
|||||||
// update size in object header index page
|
// update size in object header index page
|
||||||
res2 = spiffs_object_update_index_hdr(fs, fd, fd->obj_id,
|
res2 = spiffs_object_update_index_hdr(fs, fd, fd->obj_id,
|
||||||
fd->objix_hdr_pix, 0, 0, offset+written, &new_objix_hdr_page);
|
fd->objix_hdr_pix, 0, 0, offset+written, &new_objix_hdr_page);
|
||||||
SPIFFS_DBG("append: %04x store new size II %d in objix_hdr, %04x:%04x, written %d, res %d\n", fd->obj_id
|
SPIFFS_DBG("append: %04x store new size II %i in objix_hdr, %04x:%04x, written %i, res %i\n", fd->obj_id
|
||||||
, offset+written, new_objix_hdr_page, 0, written, res2);
|
, offset+written, new_objix_hdr_page, 0, written, res2);
|
||||||
SPIFFS_CHECK_RES(res2);
|
SPIFFS_CHECK_RES(res2);
|
||||||
} else {
|
} else {
|
||||||
@ -1100,7 +1105,7 @@ s32_t spiffs_object_append(spiffs_fd *fd, u32_t offset, u8_t *data, u32_t len) {
|
|||||||
if (offset == 0) {
|
if (offset == 0) {
|
||||||
// wrote to empty object - simply update size and write whole page
|
// wrote to empty object - simply update size and write whole page
|
||||||
objix_hdr->size = offset+written;
|
objix_hdr->size = offset+written;
|
||||||
SPIFFS_DBG("append: %04x store fresh objix_hdr page, %04x:%04x, written %d\n", fd->obj_id
|
SPIFFS_DBG("append: %04x store fresh objix_hdr page, %04x:%04x, written %i\n", fd->obj_id
|
||||||
, cur_objix_pix, cur_objix_spix, written);
|
, cur_objix_pix, cur_objix_spix, written);
|
||||||
|
|
||||||
res2 = spiffs_page_index_check(fs, fd, cur_objix_pix, cur_objix_spix);
|
res2 = spiffs_page_index_check(fs, fd, cur_objix_pix, cur_objix_spix);
|
||||||
@ -1115,7 +1120,7 @@ s32_t spiffs_object_append(spiffs_fd *fd, u32_t offset, u8_t *data, u32_t len) {
|
|||||||
// modifying object index header page, update size and make new copy
|
// modifying object index header page, update size and make new copy
|
||||||
res2 = spiffs_object_update_index_hdr(fs, fd, fd->obj_id,
|
res2 = spiffs_object_update_index_hdr(fs, fd, fd->obj_id,
|
||||||
fd->objix_hdr_pix, fs->work, 0, offset+written, &new_objix_hdr_page);
|
fd->objix_hdr_pix, fs->work, 0, offset+written, &new_objix_hdr_page);
|
||||||
SPIFFS_DBG("append: %04x store modified objix_hdr page, %04x:%04x, written %d\n", fd->obj_id
|
SPIFFS_DBG("append: %04x store modified objix_hdr page, %04x:%04x, written %i\n", fd->obj_id
|
||||||
, new_objix_hdr_page, 0, written);
|
, new_objix_hdr_page, 0, written);
|
||||||
SPIFFS_CHECK_RES(res2);
|
SPIFFS_CHECK_RES(res2);
|
||||||
}
|
}
|
||||||
@ -1163,7 +1168,7 @@ s32_t spiffs_object_modify(spiffs_fd *fd, u32_t offset, u8_t *data, u32_t len) {
|
|||||||
// store previous object index header page
|
// store previous object index header page
|
||||||
res = spiffs_object_update_index_hdr(fs, fd, fd->obj_id,
|
res = spiffs_object_update_index_hdr(fs, fd, fd->obj_id,
|
||||||
fd->objix_hdr_pix, fs->work, 0, 0, &new_objix_hdr_pix);
|
fd->objix_hdr_pix, fs->work, 0, 0, &new_objix_hdr_pix);
|
||||||
SPIFFS_DBG("modify: store modified objix_hdr page, %04x:%04x, written %d\n", new_objix_hdr_pix, 0, written);
|
SPIFFS_DBG("modify: store modified objix_hdr page, %04x:%04x, written %i\n", new_objix_hdr_pix, 0, written);
|
||||||
SPIFFS_CHECK_RES(res);
|
SPIFFS_CHECK_RES(res);
|
||||||
} else {
|
} else {
|
||||||
// store new version of previous object index page
|
// store new version of previous object index page
|
||||||
@ -1173,7 +1178,7 @@ s32_t spiffs_object_modify(spiffs_fd *fd, u32_t offset, u8_t *data, u32_t len) {
|
|||||||
SPIFFS_CHECK_RES(res);
|
SPIFFS_CHECK_RES(res);
|
||||||
|
|
||||||
res = spiffs_page_move(fs, fd->file_nbr, (u8_t*)objix, fd->obj_id, 0, cur_objix_pix, &new_objix_pix);
|
res = spiffs_page_move(fs, fd->file_nbr, (u8_t*)objix, fd->obj_id, 0, cur_objix_pix, &new_objix_pix);
|
||||||
SPIFFS_DBG("modify: store previous modified objix page, %04x:%04x, written %d\n", new_objix_pix, objix->p_hdr.span_ix, written);
|
SPIFFS_DBG("modify: store previous modified objix page, %04x:%04x, written %i\n", new_objix_pix, objix->p_hdr.span_ix, written);
|
||||||
SPIFFS_CHECK_RES(res);
|
SPIFFS_CHECK_RES(res);
|
||||||
spiffs_cb_object_event(fs, fd, SPIFFS_EV_IX_UPD, fd->obj_id, objix->p_hdr.span_ix, new_objix_pix, 0);
|
spiffs_cb_object_event(fs, fd, SPIFFS_EV_IX_UPD, fd->obj_id, objix->p_hdr.span_ix, new_objix_pix, 0);
|
||||||
}
|
}
|
||||||
@ -1228,7 +1233,7 @@ s32_t spiffs_object_modify(spiffs_fd *fd, u32_t offset, u8_t *data, u32_t len) {
|
|||||||
// a full page, allocate and write a new page of data
|
// a full page, allocate and write a new page of data
|
||||||
res = spiffs_page_allocate_data(fs, fd->obj_id & ~SPIFFS_OBJ_ID_IX_FLAG,
|
res = spiffs_page_allocate_data(fs, fd->obj_id & ~SPIFFS_OBJ_ID_IX_FLAG,
|
||||||
&p_hdr, &data[written], to_write, page_offs, 1, &data_pix);
|
&p_hdr, &data[written], to_write, page_offs, 1, &data_pix);
|
||||||
SPIFFS_DBG("modify: store new data page, %04x:%04x offset:%d, len %d, written %d\n", data_pix, data_spix, page_offs, to_write, written);
|
SPIFFS_DBG("modify: store new data page, %04x:%04x offset:%i, len %i, written %i\n", data_pix, data_spix, page_offs, to_write, written);
|
||||||
} else {
|
} else {
|
||||||
// write to existing page, allocate new and copy unmodified data
|
// write to existing page, allocate new and copy unmodified data
|
||||||
|
|
||||||
@ -1269,7 +1274,7 @@ s32_t spiffs_object_modify(spiffs_fd *fd, u32_t offset, u8_t *data, u32_t len) {
|
|||||||
(u8_t *)&p_hdr.flags);
|
(u8_t *)&p_hdr.flags);
|
||||||
if (res != SPIFFS_OK) break;
|
if (res != SPIFFS_OK) break;
|
||||||
|
|
||||||
SPIFFS_DBG("modify: store to existing data page, src:%04x, dst:%04x:%04x offset:%d, len %d, written %d\n", orig_data_pix, data_pix, data_spix, page_offs, to_write, written);
|
SPIFFS_DBG("modify: store to existing data page, src:%04x, dst:%04x:%04x offset:%i, len %i, written %i\n", orig_data_pix, data_pix, data_spix, page_offs, to_write, written);
|
||||||
}
|
}
|
||||||
|
|
||||||
// delete original data page
|
// delete original data page
|
||||||
@ -1308,7 +1313,7 @@ s32_t spiffs_object_modify(spiffs_fd *fd, u32_t offset, u8_t *data, u32_t len) {
|
|||||||
SPIFFS_CHECK_RES(res2);
|
SPIFFS_CHECK_RES(res2);
|
||||||
|
|
||||||
res2 = spiffs_page_move(fs, fd->file_nbr, (u8_t*)objix, fd->obj_id, 0, cur_objix_pix, &new_objix_pix);
|
res2 = spiffs_page_move(fs, fd->file_nbr, (u8_t*)objix, fd->obj_id, 0, cur_objix_pix, &new_objix_pix);
|
||||||
SPIFFS_DBG("modify: store modified objix page, %04x:%04x, written %d\n", new_objix_pix, cur_objix_spix, written);
|
SPIFFS_DBG("modify: store modified objix page, %04x:%04x, written %i\n", new_objix_pix, cur_objix_spix, written);
|
||||||
fd->cursor_objix_pix = new_objix_pix;
|
fd->cursor_objix_pix = new_objix_pix;
|
||||||
fd->cursor_objix_spix = cur_objix_spix;
|
fd->cursor_objix_spix = cur_objix_spix;
|
||||||
SPIFFS_CHECK_RES(res2);
|
SPIFFS_CHECK_RES(res2);
|
||||||
@ -1318,7 +1323,7 @@ s32_t spiffs_object_modify(spiffs_fd *fd, u32_t offset, u8_t *data, u32_t len) {
|
|||||||
// wrote within object index header page
|
// wrote within object index header page
|
||||||
res2 = spiffs_object_update_index_hdr(fs, fd, fd->obj_id,
|
res2 = spiffs_object_update_index_hdr(fs, fd, fd->obj_id,
|
||||||
fd->objix_hdr_pix, fs->work, 0, 0, &new_objix_hdr_pix);
|
fd->objix_hdr_pix, fs->work, 0, 0, &new_objix_hdr_pix);
|
||||||
SPIFFS_DBG("modify: store modified objix_hdr page, %04x:%04x, written %d\n", new_objix_hdr_pix, 0, written);
|
SPIFFS_DBG("modify: store modified objix_hdr page, %04x:%04x, written %i\n", new_objix_hdr_pix, 0, written);
|
||||||
SPIFFS_CHECK_RES(res2);
|
SPIFFS_CHECK_RES(res2);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1438,7 +1443,7 @@ s32_t spiffs_object_truncate(
|
|||||||
spiffs_cb_object_event(fs, fd, SPIFFS_EV_IX_DEL, fd->obj_id, objix->p_hdr.span_ix, objix_pix, 0);
|
spiffs_cb_object_event(fs, fd, SPIFFS_EV_IX_DEL, fd->obj_id, objix->p_hdr.span_ix, objix_pix, 0);
|
||||||
if (prev_objix_spix > 0) {
|
if (prev_objix_spix > 0) {
|
||||||
// update object index header page
|
// update object index header page
|
||||||
SPIFFS_DBG("truncate: update objix hdr page %04x:%04x to size %d\n", fd->objix_hdr_pix, prev_objix_spix, cur_size);
|
SPIFFS_DBG("truncate: update objix hdr page %04x:%04x to size %i\n", fd->objix_hdr_pix, prev_objix_spix, cur_size);
|
||||||
res = spiffs_object_update_index_hdr(fs, fd, fd->obj_id,
|
res = spiffs_object_update_index_hdr(fs, fd, fd->obj_id,
|
||||||
fd->objix_hdr_pix, 0, 0, cur_size, &new_objix_hdr_pix);
|
fd->objix_hdr_pix, 0, 0, cur_size, &new_objix_hdr_pix);
|
||||||
SPIFFS_CHECK_RES(res);
|
SPIFFS_CHECK_RES(res);
|
||||||
@ -1481,14 +1486,14 @@ s32_t spiffs_object_truncate(
|
|||||||
// delete full data page
|
// delete full data page
|
||||||
res = spiffs_page_data_check(fs, fd, data_pix, data_spix);
|
res = spiffs_page_data_check(fs, fd, data_pix, data_spix);
|
||||||
if (res != SPIFFS_ERR_DELETED && res != SPIFFS_OK && res != SPIFFS_ERR_INDEX_REF_FREE) {
|
if (res != SPIFFS_ERR_DELETED && res != SPIFFS_OK && res != SPIFFS_ERR_INDEX_REF_FREE) {
|
||||||
SPIFFS_DBG("truncate: err validating data pix %d\n", res);
|
SPIFFS_DBG("truncate: err validating data pix %i\n", res);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (res == SPIFFS_OK) {
|
if (res == SPIFFS_OK) {
|
||||||
res = spiffs_page_delete(fs, data_pix);
|
res = spiffs_page_delete(fs, data_pix);
|
||||||
if (res != SPIFFS_OK) {
|
if (res != SPIFFS_OK) {
|
||||||
SPIFFS_DBG("truncate: err deleting data pix %d\n", res);
|
SPIFFS_DBG("truncate: err deleting data pix %i\n", res);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else if (res == SPIFFS_ERR_DELETED || res == SPIFFS_ERR_INDEX_REF_FREE) {
|
} else if (res == SPIFFS_ERR_DELETED || res == SPIFFS_ERR_INDEX_REF_FREE) {
|
||||||
@ -1503,13 +1508,13 @@ s32_t spiffs_object_truncate(
|
|||||||
}
|
}
|
||||||
fd->size = cur_size;
|
fd->size = cur_size;
|
||||||
fd->offset = cur_size;
|
fd->offset = cur_size;
|
||||||
SPIFFS_DBG("truncate: delete data page %04x for data spix:%04x, cur_size:%d\n", data_pix, data_spix, cur_size);
|
SPIFFS_DBG("truncate: delete data page %04x for data spix:%04x, cur_size:%i\n", data_pix, data_spix, cur_size);
|
||||||
} else {
|
} else {
|
||||||
// delete last page, partially
|
// delete last page, partially
|
||||||
spiffs_page_header p_hdr;
|
spiffs_page_header p_hdr;
|
||||||
spiffs_page_ix new_data_pix;
|
spiffs_page_ix new_data_pix;
|
||||||
u32_t bytes_to_remove = SPIFFS_DATA_PAGE_SIZE(fs) - (new_size % SPIFFS_DATA_PAGE_SIZE(fs));
|
u32_t bytes_to_remove = SPIFFS_DATA_PAGE_SIZE(fs) - (new_size % SPIFFS_DATA_PAGE_SIZE(fs));
|
||||||
SPIFFS_DBG("truncate: delete %d bytes from data page %04x for data spix:%04x, cur_size:%d\n", bytes_to_remove, data_pix, data_spix, cur_size);
|
SPIFFS_DBG("truncate: delete %i bytes from data page %04x for data spix:%04x, cur_size:%i\n", bytes_to_remove, data_pix, data_spix, cur_size);
|
||||||
|
|
||||||
res = spiffs_page_data_check(fs, fd, data_pix, data_spix);
|
res = spiffs_page_data_check(fs, fd, data_pix, data_spix);
|
||||||
if (res != SPIFFS_OK) break;
|
if (res != SPIFFS_OK) break;
|
||||||
@ -1572,7 +1577,7 @@ s32_t spiffs_object_truncate(
|
|||||||
} else {
|
} else {
|
||||||
// make uninitialized object
|
// make uninitialized object
|
||||||
SPIFFS_DBG("truncate: reset objix_hdr page %04x\n", objix_pix);
|
SPIFFS_DBG("truncate: reset objix_hdr page %04x\n", objix_pix);
|
||||||
c_memset(fs->work + sizeof(spiffs_page_object_ix_header), 0xff,
|
memset(fs->work + sizeof(spiffs_page_object_ix_header), 0xff,
|
||||||
SPIFFS_CFG_LOG_PAGE_SZ(fs) - sizeof(spiffs_page_object_ix_header));
|
SPIFFS_CFG_LOG_PAGE_SZ(fs) - sizeof(spiffs_page_object_ix_header));
|
||||||
res = spiffs_object_update_index_hdr(fs, fd, fd->obj_id,
|
res = spiffs_object_update_index_hdr(fs, fd, fd->obj_id,
|
||||||
objix_pix, fs->work, 0, SPIFFS_UNDEFINED_LEN, &new_objix_hdr_pix);
|
objix_pix, fs->work, 0, SPIFFS_UNDEFINED_LEN, &new_objix_hdr_pix);
|
||||||
@ -1664,7 +1669,7 @@ s32_t spiffs_object_read(
|
|||||||
len_to_read = MIN(len_to_read, SPIFFS_DATA_PAGE_SIZE(fs) - (cur_offset % SPIFFS_DATA_PAGE_SIZE(fs)));
|
len_to_read = MIN(len_to_read, SPIFFS_DATA_PAGE_SIZE(fs) - (cur_offset % SPIFFS_DATA_PAGE_SIZE(fs)));
|
||||||
// remaining data in file
|
// remaining data in file
|
||||||
len_to_read = MIN(len_to_read, fd->size);
|
len_to_read = MIN(len_to_read, fd->size);
|
||||||
SPIFFS_DBG("read: offset:%d rd:%d data spix:%04x is data_pix:%04x addr:%08x\n", cur_offset, len_to_read, data_spix, data_pix,
|
SPIFFS_DBG("read: offset:%i rd:%i data spix:%04x is data_pix:%04x addr:%08x\n", cur_offset, len_to_read, data_spix, data_pix,
|
||||||
SPIFFS_PAGE_TO_PADDR(fs, data_pix) + sizeof(spiffs_page_header) + (cur_offset % SPIFFS_DATA_PAGE_SIZE(fs)));
|
SPIFFS_PAGE_TO_PADDR(fs, data_pix) + sizeof(spiffs_page_header) + (cur_offset % SPIFFS_DATA_PAGE_SIZE(fs)));
|
||||||
if (len_to_read <= 0) {
|
if (len_to_read <= 0) {
|
||||||
res = SPIFFS_ERR_END_OF_OBJECT;
|
res = SPIFFS_ERR_END_OF_OBJECT;
|
||||||
@ -1750,7 +1755,7 @@ static s32_t spiffs_obj_lu_find_free_obj_id_compact_v(spiffs *fs, spiffs_obj_id
|
|||||||
if (id >= state->min_obj_id && id <= state->max_obj_id) {
|
if (id >= state->min_obj_id && id <= state->max_obj_id) {
|
||||||
u8_t *map = (u8_t *)fs->work;
|
u8_t *map = (u8_t *)fs->work;
|
||||||
int ix = (id - state->min_obj_id) / state->compaction;
|
int ix = (id - state->min_obj_id) / state->compaction;
|
||||||
//SPIFFS_DBG("free_obj_id: add ix %d for id %04x min:%04x max%04x comp:%d\n", ix, id, state->min_obj_id, state->max_obj_id, state->compaction);
|
//SPIFFS_DBG("free_obj_id: add ix %i for id %04x min:%04x max%04x comp:%i\n", ix, id, state->min_obj_id, state->max_obj_id, state->compaction);
|
||||||
map[ix]++;
|
map[ix]++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1780,7 +1785,7 @@ s32_t spiffs_obj_lu_find_free_obj_id(spiffs *fs, spiffs_obj_id *obj_id, u8_t *co
|
|||||||
u32_t i, j;
|
u32_t i, j;
|
||||||
SPIFFS_DBG("free_obj_id: BITM min:%04x max:%04x\n", state.min_obj_id, state.max_obj_id);
|
SPIFFS_DBG("free_obj_id: BITM min:%04x max:%04x\n", state.min_obj_id, state.max_obj_id);
|
||||||
|
|
||||||
c_memset(fs->work, 0, SPIFFS_CFG_LOG_PAGE_SZ(fs));
|
memset(fs->work, 0, SPIFFS_CFG_LOG_PAGE_SZ(fs));
|
||||||
res = spiffs_obj_lu_find_entry_visitor(fs, 0, 0, 0, 0, spiffs_obj_lu_find_free_obj_id_bitmap_v, state.min_obj_id,
|
res = spiffs_obj_lu_find_entry_visitor(fs, 0, 0, 0, 0, spiffs_obj_lu_find_free_obj_id_bitmap_v, state.min_obj_id,
|
||||||
conflicting_name, 0, 0);
|
conflicting_name, 0, 0);
|
||||||
if (res == SPIFFS_VIS_END) res = SPIFFS_OK;
|
if (res == SPIFFS_VIS_END) res = SPIFFS_OK;
|
||||||
@ -1823,7 +1828,7 @@ s32_t spiffs_obj_lu_find_free_obj_id(spiffs *fs, spiffs_obj_id *obj_id, u8_t *co
|
|||||||
return SPIFFS_ERR_FULL;
|
return SPIFFS_ERR_FULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
SPIFFS_DBG("free_obj_id: COMP select index:%d min_count:%d min:%04x max:%04x compact:%d\n", min_i, min_count, state.min_obj_id, state.max_obj_id, state.compaction);
|
SPIFFS_DBG("free_obj_id: COMP select index:%i min_count:%i min:%04x max:%04x compact:%i\n", min_i, min_count, state.min_obj_id, state.max_obj_id, state.compaction);
|
||||||
|
|
||||||
if (min_count == 0) {
|
if (min_count == 0) {
|
||||||
// no id in this range, skip compacting and use directly
|
// no id in this range, skip compacting and use directly
|
||||||
@ -1843,9 +1848,9 @@ s32_t spiffs_obj_lu_find_free_obj_id(spiffs *fs, spiffs_obj_id *obj_id, u8_t *co
|
|||||||
// in a work memory of log_page_size bytes, we may fit in log_page_size ids
|
// in a work memory of log_page_size bytes, we may fit in log_page_size ids
|
||||||
// todo what if compaction is > 255 - then we cannot fit it in a byte
|
// todo what if compaction is > 255 - then we cannot fit it in a byte
|
||||||
state.compaction = (state.max_obj_id-state.min_obj_id) / ((SPIFFS_CFG_LOG_PAGE_SZ(fs) / sizeof(u8_t)));
|
state.compaction = (state.max_obj_id-state.min_obj_id) / ((SPIFFS_CFG_LOG_PAGE_SZ(fs) / sizeof(u8_t)));
|
||||||
SPIFFS_DBG("free_obj_id: COMP min:%04x max:%04x compact:%d\n", state.min_obj_id, state.max_obj_id, state.compaction);
|
SPIFFS_DBG("free_obj_id: COMP min:%04x max:%04x compact:%i\n", state.min_obj_id, state.max_obj_id, state.compaction);
|
||||||
|
|
||||||
c_memset(fs->work, 0, SPIFFS_CFG_LOG_PAGE_SZ(fs));
|
memset(fs->work, 0, SPIFFS_CFG_LOG_PAGE_SZ(fs));
|
||||||
res = spiffs_obj_lu_find_entry_visitor(fs, 0, 0, 0, 0, spiffs_obj_lu_find_free_obj_id_compact_v, 0, &state, 0, 0);
|
res = spiffs_obj_lu_find_entry_visitor(fs, 0, 0, 0, 0, spiffs_obj_lu_find_free_obj_id_compact_v, 0, &state, 0, 0);
|
||||||
if (res == SPIFFS_VIS_END) res = SPIFFS_OK;
|
if (res == SPIFFS_VIS_END) res = SPIFFS_OK;
|
||||||
SPIFFS_CHECK_RES(res);
|
SPIFFS_CHECK_RES(res);
|
||||||
|
@ -124,7 +124,7 @@
|
|||||||
#define SPIFFS_EV_IX_NEW 1
|
#define SPIFFS_EV_IX_NEW 1
|
||||||
#define SPIFFS_EV_IX_DEL 2
|
#define SPIFFS_EV_IX_DEL 2
|
||||||
|
|
||||||
#define SPIFFS_OBJ_ID_IX_FLAG (1<<(8*sizeof(spiffs_obj_id)-1))
|
#define SPIFFS_OBJ_ID_IX_FLAG ((spiffs_obj_id)(1<<(8*sizeof(spiffs_obj_id)-1)))
|
||||||
|
|
||||||
#define SPIFFS_UNDEFINED_LEN (u32_t)(-1)
|
#define SPIFFS_UNDEFINED_LEN (u32_t)(-1)
|
||||||
|
|
||||||
@ -311,6 +311,26 @@
|
|||||||
// stop searching at end of all look up pages
|
// stop searching at end of all look up pages
|
||||||
#define SPIFFS_VIS_NO_WRAP (1<<2)
|
#define SPIFFS_VIS_NO_WRAP (1<<2)
|
||||||
|
|
||||||
|
#if SPIFFS_HAL_CALLBACK_EXTRA
|
||||||
|
|
||||||
|
#define SPIFFS_HAL_WRITE(_fs, _paddr, _len, _src) \
|
||||||
|
(_fs)->cfg.hal_write_f((_fs), (_paddr), (_len), (_src))
|
||||||
|
#define SPIFFS_HAL_READ(_fs, _paddr, _len, _dst) \
|
||||||
|
(_fs)->cfg.hal_read_f((_fs), (_paddr), (_len), (_dst))
|
||||||
|
#define SPIFFS_HAL_ERASE(_fs, _paddr, _len) \
|
||||||
|
(_fs)->cfg.hal_erase_f((_fs), (_paddr), (_len))
|
||||||
|
|
||||||
|
#else // SPIFFS_HAL_CALLBACK_EXTRA
|
||||||
|
|
||||||
|
#define SPIFFS_HAL_WRITE(_fs, _paddr, _len, _src) \
|
||||||
|
(_fs)->cfg.hal_write_f((_paddr), (_len), (_src))
|
||||||
|
#define SPIFFS_HAL_READ(_fs, _paddr, _len, _dst) \
|
||||||
|
(_fs)->cfg.hal_read_f((_paddr), (_len), (_dst))
|
||||||
|
#define SPIFFS_HAL_ERASE(_fs, _paddr, _len) \
|
||||||
|
(_fs)->cfg.hal_erase_f((_paddr), (_len))
|
||||||
|
|
||||||
|
#endif // SPIFFS_HAL_CALLBACK_EXTRA
|
||||||
|
|
||||||
#if SPIFFS_CACHE
|
#if SPIFFS_CACHE
|
||||||
|
|
||||||
#define SPIFFS_CACHE_FLAG_DIRTY (1<<0)
|
#define SPIFFS_CACHE_FLAG_DIRTY (1<<0)
|
||||||
@ -423,7 +443,7 @@ typedef struct __attribute(( packed ))
|
|||||||
// common page header
|
// common page header
|
||||||
spiffs_page_header p_hdr;
|
spiffs_page_header p_hdr;
|
||||||
// alignment
|
// alignment
|
||||||
u8_t _align[4 - (sizeof(spiffs_page_header)&3)==0 ? 4 : (sizeof(spiffs_page_header)&3)];
|
u8_t _align[4 - ((sizeof(spiffs_page_header)&3)==0 ? 4 : (sizeof(spiffs_page_header)&3))];
|
||||||
// size of object
|
// size of object
|
||||||
u32_t size;
|
u32_t size;
|
||||||
// type of object
|
// type of object
|
||||||
@ -435,7 +455,7 @@ typedef struct __attribute(( packed ))
|
|||||||
// object index page header
|
// object index page header
|
||||||
typedef struct __attribute(( packed )) {
|
typedef struct __attribute(( packed )) {
|
||||||
spiffs_page_header p_hdr;
|
spiffs_page_header p_hdr;
|
||||||
u8_t _align[4 - (sizeof(spiffs_page_header)&3)==0 ? 4 : (sizeof(spiffs_page_header)&3)];
|
u8_t _align[4 - ((sizeof(spiffs_page_header)&3)==0 ? 4 : (sizeof(spiffs_page_header)&3))];
|
||||||
} spiffs_page_object_ix;
|
} spiffs_page_object_ix;
|
||||||
|
|
||||||
// callback func for object lookup visitor
|
// callback func for object lookup visitor
|
||||||
@ -665,7 +685,7 @@ s32_t spiffs_gc_clean(
|
|||||||
spiffs_block_ix bix);
|
spiffs_block_ix bix);
|
||||||
|
|
||||||
s32_t spiffs_gc_quick(
|
s32_t spiffs_gc_quick(
|
||||||
spiffs *fs);
|
spiffs *fs, u16_t max_free_pages);
|
||||||
|
|
||||||
// ---------------
|
// ---------------
|
||||||
|
|
||||||
|
@ -32,6 +32,8 @@ extern "C" {
|
|||||||
#include "spi_flash.h"
|
#include "spi_flash.h"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
using namespace fs;
|
||||||
|
|
||||||
extern int32_t spiffs_hal_write(uint32_t addr, uint32_t size, uint8_t *src);
|
extern int32_t spiffs_hal_write(uint32_t addr, uint32_t size, uint8_t *src);
|
||||||
extern int32_t spiffs_hal_erase(uint32_t addr, uint32_t size);
|
extern int32_t spiffs_hal_erase(uint32_t addr, uint32_t size);
|
||||||
extern int32_t spiffs_hal_read(uint32_t addr, uint32_t size, uint8_t *dst);
|
extern int32_t spiffs_hal_read(uint32_t addr, uint32_t size, uint8_t *dst);
|
||||||
@ -237,7 +239,7 @@ public:
|
|||||||
size_t position() const override {
|
size_t position() const override {
|
||||||
CHECKFD();
|
CHECKFD();
|
||||||
|
|
||||||
auto result = SPIFFS_tell(_fs->getFs(), _fd);
|
auto result = SPIFFS_lseek(_fs->getFs(), _fd, 0, SPIFFS_SEEK_CUR);
|
||||||
if (result < 0) {
|
if (result < 0) {
|
||||||
DEBUGV("SPIFFS_tell rc=%d\r\n", result);
|
DEBUGV("SPIFFS_tell rc=%d\r\n", result);
|
||||||
return 0;
|
return 0;
|
||||||
@ -259,6 +261,12 @@ public:
|
|||||||
DEBUGV("SPIFFS_close: fd=%d\r\n", _fd);
|
DEBUGV("SPIFFS_close: fd=%d\r\n", _fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char* name() const override {
|
||||||
|
CHECKFD();
|
||||||
|
|
||||||
|
return (const char*) _stat.name;
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
SPIFFSImpl* _fs;
|
SPIFFSImpl* _fs;
|
||||||
spiffs_file _fd;
|
spiffs_file _fd;
|
||||||
@ -283,10 +291,11 @@ public:
|
|||||||
return FileImplPtr();
|
return FileImplPtr();
|
||||||
}
|
}
|
||||||
int mode = getSpiffsMode(openMode, accessMode);
|
int mode = getSpiffsMode(openMode, accessMode);
|
||||||
spiffs_file fd = SPIFFS_open_by_dirent(_fs->getFs(), &_dirent, mode, 0);
|
auto fs = _fs->getFs();
|
||||||
|
spiffs_file fd = SPIFFS_open_by_dirent(fs, &_dirent, mode, 0);
|
||||||
if (fd < 0) {
|
if (fd < 0) {
|
||||||
DEBUGV("SPIFFSDirImpl::openFile: fd=%d path=`%s` openMode=%d accessMode=%d err=%d\r\n",
|
DEBUGV("SPIFFSDirImpl::openFile: fd=%d path=`%s` openMode=%d accessMode=%d err=%d\r\n",
|
||||||
fd, _dirent.name, openMode, accessMode, _fs.err_code);
|
fd, _dirent.name, openMode, accessMode, fs->err_code);
|
||||||
return FileImplPtr();
|
return FileImplPtr();
|
||||||
}
|
}
|
||||||
return std::make_shared<SPIFFSFileImpl>(_fs, fd);
|
return std::make_shared<SPIFFSFileImpl>(_fs, fd);
|
||||||
@ -299,6 +308,13 @@ public:
|
|||||||
return (const char*) _dirent.name;
|
return (const char*) _dirent.name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t fileSize() override {
|
||||||
|
if (!_valid)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return _dirent.size;
|
||||||
|
}
|
||||||
|
|
||||||
bool next() override {
|
bool next() override {
|
||||||
spiffs_dirent* result = SPIFFS_readdir(&_dir, &_dirent);
|
spiffs_dirent* result = SPIFFS_readdir(&_dir, &_dirent);
|
||||||
_valid = (result != nullptr);
|
_valid = (result != nullptr);
|
||||||
|
@ -5,6 +5,7 @@ title: Supported Hardware
|
|||||||
- [Adafruit HUZZAH ESP8266 (ESP-12)](#adafruit-huzzah-esp8266-esp-12)
|
- [Adafruit HUZZAH ESP8266 (ESP-12)](#adafruit-huzzah-esp8266-esp-12)
|
||||||
- [NodeMCU 0.9](#nodemcu-0-9)
|
- [NodeMCU 0.9](#nodemcu-0-9)
|
||||||
- [NodeMCU 1.0](#nodemcu-1-0)
|
- [NodeMCU 1.0](#nodemcu-1-0)
|
||||||
|
- [Olimex MOD-WIFI-ESP8266-DEV](#olimex-mod-wifi-esp8266-dev)
|
||||||
- [Olimex MOD-WIFI-ESP8266](#olimex-mod-wifi-esp8266)
|
- [Olimex MOD-WIFI-ESP8266](#olimex-mod-wifi-esp8266)
|
||||||
- [SparkFun ESP8266 Thing](#sparkfun-esp8266-thing)
|
- [SparkFun ESP8266 Thing](#sparkfun-esp8266-thing)
|
||||||
- [SweetPea ESP-210](#sweetpea-esp-210)
|
- [SweetPea ESP-210](#sweetpea-esp-210)
|
||||||
@ -38,11 +39,33 @@ If you want to use NodeMCU pin 5, use D5 for pin number, and it will be translat
|
|||||||
|
|
||||||
### NodeMCU 1.0 <a name="nodemcu-1-0"></a>
|
### NodeMCU 1.0 <a name="nodemcu-1-0"></a>
|
||||||
|
|
||||||
*TODO: add notes*
|
This module is sold under many names for around $6.50 on AliExpress and it's one of the cheapest, fully integrated ESP8266 solutions.
|
||||||
|
|
||||||
|
It's an open hardware design with an ESP-12E core and 4 MB of SPI flash.
|
||||||
|
|
||||||
|
Acording to the manufacturer, "with a micro USB cable, you can connect NodeMCU devkit to your laptop and flash it without any trouble". This is more or less true: the board comes with a CP2102 onboard USB to serial adapter which just works, well, the majority of the time. Sometimes flashing fails and you have to reset the board by holding down FLASH + RST, then releasing FLASH, then releasing RST. This forces the CP2102 device to power cycle and to be re-numbered by Linux.
|
||||||
|
|
||||||
|
The board also features a NCP1117 voltage regulator, a blue LED on GPIO16 and a 220k/100k Ohm voltage divider on the ADC input pin.
|
||||||
|
|
||||||
|
Full pinout and PDF schematics can be found [here](https://github.com/nodemcu/nodemcu-devkit-v1.0)
|
||||||
|
|
||||||
|
### Olimex MOD-WIFI-ESP8266-DEV
|
||||||
|
|
||||||
|
This board comes with 2 MB of SPI flash and optional accessories (e.g. evaluation board ESP8266-EVB or BAT-BOX for batteries).
|
||||||
|
|
||||||
|
The basic module has three solder jumpers that allow you to switch the operating mode between SDIO, UART and FLASH.
|
||||||
|
|
||||||
|
The board is shipped for FLASH operation mode, with jumpers TD0JP=0, IO0JP=1, IO2JP=1.
|
||||||
|
|
||||||
|
Since jumper IO0JP is tied to GPIO0, which is PIN 21, you'll have to ground it before programming with a USB to serial adapter and reset the board by power cycling it.
|
||||||
|
|
||||||
|
UART pins for programming and serial I/O are GPIO1 (TXD, pin 3) and GPIO3 (RXD, pin 4).
|
||||||
|
|
||||||
|
Get the board schematics [here](https://github.com/OLIMEX/ESP8266/blob/master/HARDWARE/MOD-WIFI-ESP8266-DEV/MOD-WIFI-ESP8266-DEV_schematic.pdf)
|
||||||
|
|
||||||
### Olimex MOD-WIFI-ESP8266
|
### Olimex MOD-WIFI-ESP8266
|
||||||
|
|
||||||
*TODO: add notes*
|
This is a stripped down version of the above. Behaves identically in terms of jumpers but has less pins readily available for I/O. Still 2 MB of SPI flash.
|
||||||
|
|
||||||
### SparkFun ESP8266 Thing ###
|
### SparkFun ESP8266 Thing ###
|
||||||
|
|
||||||
|
@ -6,18 +6,30 @@ title: Change log
|
|||||||
|
|
||||||
### Core
|
### Core
|
||||||
|
|
||||||
- Add first batch of file system APIs
|
- Add file system APIs and documentation
|
||||||
|
- Add ConfigFile example
|
||||||
- Allow user to run code in user_rf_pre_init
|
- Allow user to run code in user_rf_pre_init
|
||||||
|
- Add strtoul and strtol, fix strtod
|
||||||
|
- Update documentation for NodeMCU and Olimex boards
|
||||||
|
- Disable interrupts inside ESP.getVcc (#567)
|
||||||
|
- Erase RTC RAM only if RF mode looks invalid (#619)
|
||||||
|
|
||||||
|
|
||||||
### Libraries
|
### Libraries
|
||||||
|
|
||||||
- ESP8266WebServer: support for sending of PROGMEM strings
|
- ESP8266WebServer: support for sending of PROGMEM strings
|
||||||
|
- ESP8266WebServer: support for serving files from file system
|
||||||
- ESP8266WiFi: fix mode selection (#529)
|
- ESP8266WiFi: fix mode selection (#529)
|
||||||
|
- ESP8266mDNS: allow to work on SoftAP interface
|
||||||
|
- EEPROM: round requested size to 4 bytes (#659)
|
||||||
|
- Add ESP8266AVRISP library
|
||||||
|
|
||||||
### Tools
|
### Tools
|
||||||
|
|
||||||
- Update SDK to 1.2.0_15_07_13_p4
|
- Update SDK to 1.3.0_15_08_10_p1
|
||||||
|
- Update esptool to 0.4.6
|
||||||
|
- Bump toolchain version to force libm update on Windows
|
||||||
|
- ESP8266FS tool update
|
||||||
|
|
||||||
---
|
---
|
||||||
## 1.6.5-947-g39819f0
|
## 1.6.5-947-g39819f0
|
||||||
|
BIN
doc/esp12.png
Normal file
BIN
doc/esp12.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 44 KiB |
175
doc/reference.md
175
doc/reference.md
@ -11,7 +11,7 @@ Pin 16 can be `INPUT`, `OUTPUT` or `INPUT_PULLDOWN_16`. At startup, pins are con
|
|||||||
|
|
||||||
Pins may also serve other functions, like Serial, I2C, SPI. These functions are normally activated by the corresponding library. The diagram below shows pin mapping for the popular ESP-12 module.
|
Pins may also serve other functions, like Serial, I2C, SPI. These functions are normally activated by the corresponding library. The diagram below shows pin mapping for the popular ESP-12 module.
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
Digital pins 6—11 are not shown on this diagram because they are used to connect flash memory chip on most modules. Trying to use these pins as IOs will likely cause the program to crash.
|
Digital pins 6—11 are not shown on this diagram because they are used to connect flash memory chip on most modules. Trying to use these pins as IOs will likely cause the program to crash.
|
||||||
|
|
||||||
@ -103,17 +103,184 @@ const char HTTP[] PROGMEM = "http:";
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## File system
|
||||||
|
|
||||||
|
Even though file system is stored on the same flash chip as the program, programming new sketch will not modify file system contents. This allows to use file system to store sketch data, configuration files, or content for Web server.
|
||||||
|
|
||||||
|
The following diagram illustrates flash layout used in Arduino environment:
|
||||||
|
|
||||||
|
|--------------|-------|---------------|--|--|--|--|--|
|
||||||
|
^ ^ ^ ^ ^
|
||||||
|
Sketch OTA update File system EEPROM WiFi config (SDK)
|
||||||
|
|
||||||
|
File system size depends on the flash chip size. Depending on the board which is selected in IDE, you have the following options for flash size:
|
||||||
|
|
||||||
|
Board | Flash chip size, bytes | File system size, bytes
|
||||||
|
------|-----------------|-----------------
|
||||||
|
Generic module | 512k | 64k
|
||||||
|
Generic module | 1M | 64k, 128k, 256k, 512k
|
||||||
|
Generic module | 2M | 1M
|
||||||
|
Generic module | 4M | 3M
|
||||||
|
Adafruit HUZZAH | 4M | 3M
|
||||||
|
NodeMCU 0.9 | 4M | 3M
|
||||||
|
NodeMCU 1.0 | 4M | 3M
|
||||||
|
Olimex MOD-WIFI-ESP8266(-DEV)| 2M | 1M
|
||||||
|
SparkFun Thing | 512k | 64k
|
||||||
|
SweetPea ESP-210 | 4M | 3M
|
||||||
|
|
||||||
|
**Note:** to use any of file system functions in the sketch, add the following include to the sketch:
|
||||||
|
|
||||||
|
```c++
|
||||||
|
#include "FS.h"
|
||||||
|
```
|
||||||
|
|
||||||
|
### File system object (SPIFFS)
|
||||||
|
|
||||||
|
#### begin
|
||||||
|
|
||||||
|
```c++
|
||||||
|
SPIFFS.begin()
|
||||||
|
```
|
||||||
|
|
||||||
|
This method mounts SPIFFS file system. It must be called before any other
|
||||||
|
FS APIs are used. Returns *true* if file system was mounted successfully, false
|
||||||
|
otherwise.
|
||||||
|
|
||||||
|
#### open
|
||||||
|
|
||||||
|
```c++
|
||||||
|
SPIFFS.open(path, mode)
|
||||||
|
```
|
||||||
|
|
||||||
|
Opens a file. `path` should be an absolute path starting with a slash
|
||||||
|
(e.g. `/dir/filename.txt`). `mode` is a string specifying access mode. It can be
|
||||||
|
one of "r", "w", "a", "r+", "w+", "a+". Meaning of these modes is the same as
|
||||||
|
for `fopen` C function.
|
||||||
|
|
||||||
|
Returns *File* object. To check whether the file was opened successfully, use
|
||||||
|
the boolean operator.
|
||||||
|
|
||||||
|
```c++
|
||||||
|
File f = SPIFFS.open("/f.txt", "w");
|
||||||
|
if (!f) {
|
||||||
|
Serial.println("file open failed");
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### openDir
|
||||||
|
|
||||||
|
```c++
|
||||||
|
SPIFFS.openDir(path)
|
||||||
|
```
|
||||||
|
|
||||||
|
Opens a directory given its absolute path. Returns a *Dir* object. To check if
|
||||||
|
directory was opened successfully, use the boolean operator, similar to opening
|
||||||
|
a file.
|
||||||
|
|
||||||
|
#### remove
|
||||||
|
|
||||||
|
```c++
|
||||||
|
SPIFFS.remove(path)
|
||||||
|
```
|
||||||
|
|
||||||
|
Deletes the file given its absolute path. Returns *true* if file was deleted successfully.
|
||||||
|
|
||||||
|
#### rename
|
||||||
|
|
||||||
|
```c++
|
||||||
|
SPIFFS.rename(pathFrom, pathTo)
|
||||||
|
```
|
||||||
|
|
||||||
|
Renames file from `pathFrom` to `pathTo`. Paths must be absolute. Returns *true*
|
||||||
|
if file was renamed successfully.
|
||||||
|
|
||||||
|
### Directory object (Dir)
|
||||||
|
|
||||||
|
The purpose of *Dir* object is to iterate over files inside a directory.
|
||||||
|
It provides three methods: `next()`, `fileName()`, and `openFile(mode)`.
|
||||||
|
|
||||||
|
The following example shows how it should be used:
|
||||||
|
|
||||||
|
```c++
|
||||||
|
Dir dir = SPIFFS.openDir("/data");
|
||||||
|
while (dir.next()) {
|
||||||
|
Serial.print(dir.fileName());
|
||||||
|
File f = dir.openFile("r");
|
||||||
|
Serial.println(f.size());
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
`dir.next()` returns true while there are files in the directory to iterate over.
|
||||||
|
It must be called before calling `fileName` and `openFile` functions.
|
||||||
|
|
||||||
|
`openFile` method takes *mode* argument which has the same meaning as for `SPIFFS.open` function.
|
||||||
|
|
||||||
|
### File object
|
||||||
|
|
||||||
|
`SPIFFS.open` and `dir.openFile` functions return a *File* object. This object
|
||||||
|
supports all the functions of *Stream*, so you can use `readBytes`, `findUntil`,
|
||||||
|
`parseInt`, `println`, and all other *Stream* methods.
|
||||||
|
|
||||||
|
There are also some functions which are specific to *File* object.
|
||||||
|
|
||||||
|
#### seek
|
||||||
|
|
||||||
|
```c++
|
||||||
|
file.seek(offset, mode)
|
||||||
|
```
|
||||||
|
|
||||||
|
This function behaves like `fseek` C function. Depending on the value of `mode`,
|
||||||
|
it moves current position in a file as follows:
|
||||||
|
|
||||||
|
- if `mode` is `SeekSet`, position is set to `offset` bytes from the beginning.
|
||||||
|
- if `mode` is `SeekCur`, current position is moved by `offset` bytes.
|
||||||
|
- if `mode` is `SeekEnd`, position is set to `offset` bytes from the end of the
|
||||||
|
file.
|
||||||
|
|
||||||
|
Returns *true* if position was set successfully.
|
||||||
|
|
||||||
|
#### position
|
||||||
|
|
||||||
|
```c++
|
||||||
|
file.position()
|
||||||
|
```
|
||||||
|
|
||||||
|
Returns the current position inside the file, in bytes.
|
||||||
|
|
||||||
|
#### size
|
||||||
|
|
||||||
|
```c++
|
||||||
|
file.size()
|
||||||
|
```
|
||||||
|
|
||||||
|
Returns file size, in bytes.
|
||||||
|
|
||||||
|
|
||||||
|
#### name
|
||||||
|
|
||||||
|
```c++
|
||||||
|
String name = file.name();
|
||||||
|
```
|
||||||
|
|
||||||
|
Returns file name, as `const char*`. Convert it to *String* for storage.
|
||||||
|
|
||||||
|
#### close
|
||||||
|
|
||||||
|
```c++
|
||||||
|
file.close()
|
||||||
|
```
|
||||||
|
|
||||||
|
Close the file. No other operations should be performed on *File* object after `close` function was called.
|
||||||
|
|
||||||
## WiFi(ESP8266WiFi library)
|
## WiFi(ESP8266WiFi library)
|
||||||
|
|
||||||
This is mostly similar to WiFi shield library. Differences include:
|
This is mostly similar to WiFi shield library. Differences include:
|
||||||
|
|
||||||
- `WiFi.mode(m)`: set mode to `WIFI_AP`, `WIFI_STA`, or `WIFI_AP_STA`.
|
- `WiFi.mode(m)`: set mode to `WIFI_AP`, `WIFI_STA`, `WIFI_AP_STA` or `WIFI_OFF`.
|
||||||
- call `WiFi.softAP(ssid)` to set up an open network
|
- call `WiFi.softAP(ssid)` to set up an open network
|
||||||
- call `WiFi.softAP(ssid, password)` to set up a WPA2-PSK network (password should be at least 8 characters)
|
- call `WiFi.softAP(ssid, password)` to set up a WPA2-PSK network (password should be at least 8 characters)
|
||||||
- `WiFi.macAddress(mac)` is for STA, `WiFi.softAPmacAddress(mac)` is for AP.
|
- `WiFi.macAddress(mac)` is for STA, `WiFi.softAPmacAddress(mac)` is for AP.
|
||||||
- `WiFi.localIP()` is for STA, `WiFi.softAPIP()` is for AP.
|
- `WiFi.localIP()` is for STA, `WiFi.softAPIP()` is for AP.
|
||||||
- `WiFi.RSSI()` doesn't work
|
|
||||||
- `WiFi.printDiag(Serial)` will print out some diagnostic info
|
- `WiFi.printDiag(Serial)` will print out some diagnostic info
|
||||||
- `WiFiUDP` class supports sending and receiving multicast packets on STA interface.
|
- `WiFiUDP` class supports sending and receiving multicast packets on STA interface.
|
||||||
When sending a multicast packet, replace `udp.beginPacket(addr, port)` with
|
When sending a multicast packet, replace `udp.beginPacket(addr, port)` with
|
||||||
@ -122,7 +289,6 @@ When listening to multicast packets, replace `udp.begin(port)` with
|
|||||||
`udp.beginMulticast(WiFi.localIP(), multicast_ip_addr, port)`.
|
`udp.beginMulticast(WiFi.localIP(), multicast_ip_addr, port)`.
|
||||||
You can use `udp.destinationIP()` to tell whether the packet received was
|
You can use `udp.destinationIP()` to tell whether the packet received was
|
||||||
sent to the multicast or unicast address.
|
sent to the multicast or unicast address.
|
||||||
Also note that multicast doesn't work on softAP interface.
|
|
||||||
|
|
||||||
`WiFiServer`, `WiFiClient`, and `WiFiUDP` behave mostly the same way as with WiFi shield library.
|
`WiFiServer`, `WiFiClient`, and `WiFiUDP` behave mostly the same way as with WiFi shield library.
|
||||||
Four samples are provided for this library.
|
Four samples are provided for this library.
|
||||||
@ -205,7 +371,6 @@ instead of the one that comes with this package.
|
|||||||
## mDNS and DNS-SD responder (ESP8266mDNS library)
|
## mDNS and DNS-SD responder (ESP8266mDNS library)
|
||||||
|
|
||||||
Allows the sketch to respond to multicast DNS queries for domain names like "foo.local", and DNS-SD (service dicovery) queries.
|
Allows the sketch to respond to multicast DNS queries for domain names like "foo.local", and DNS-SD (service dicovery) queries.
|
||||||
Currently the library only works on STA interface, AP interface is not supported.
|
|
||||||
See attached example for details.
|
See attached example for details.
|
||||||
|
|
||||||
## SSDP responder (ESP8266SSDP)
|
## SSDP responder (ESP8266SSDP)
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
/*
|
/*
|
||||||
EEPROM.cpp - esp8266 EEPROM emulation
|
EEPROM.cpp - esp8266 EEPROM emulation
|
||||||
|
|
||||||
Copyright (c) 2014 Ivan Grokhotkov. All rights reserved.
|
Copyright (c) 2014 Ivan Grokhotkov. All rights reserved.
|
||||||
This file is part of the esp8266 core for Arduino environment.
|
This file is part of the esp8266 core for Arduino environment.
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
This library is free software; you can redistribute it and/or
|
||||||
modify it under the terms of the GNU Lesser General Public
|
modify it under the terms of the GNU Lesser General Public
|
||||||
License as published by the Free Software Foundation; either
|
License as published by the Free Software Foundation; either
|
||||||
@ -34,7 +34,7 @@ EEPROMClass::EEPROMClass(uint32_t sector)
|
|||||||
: _sector(sector)
|
: _sector(sector)
|
||||||
, _data(0)
|
, _data(0)
|
||||||
, _size(0)
|
, _size(0)
|
||||||
, _dirty(false)
|
, _dirty(false)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -44,6 +44,8 @@ void EEPROMClass::begin(size_t size) {
|
|||||||
if (size > SPI_FLASH_SEC_SIZE)
|
if (size > SPI_FLASH_SEC_SIZE)
|
||||||
size = SPI_FLASH_SEC_SIZE;
|
size = SPI_FLASH_SEC_SIZE;
|
||||||
|
|
||||||
|
size = (size + 3) & (~3);
|
||||||
|
|
||||||
if (_data) {
|
if (_data) {
|
||||||
delete[] _data;
|
delete[] _data;
|
||||||
}
|
}
|
||||||
|
57
libraries/ESP8266AVRISP/README.md
Normal file
57
libraries/ESP8266AVRISP/README.md
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
# AVR In-System Programming over WiFi for ESP8266
|
||||||
|
|
||||||
|
This library allows an ESP8266 module with the HSPI port available to become
|
||||||
|
an AVR In-System Programmer.
|
||||||
|
|
||||||
|
## Hardware
|
||||||
|
|
||||||
|
The ESP8266 module connects to the AVR target chip via the standard 6-pin
|
||||||
|
AVR "Recommended In-System Programming Interface Connector Layout" as seen
|
||||||
|
in [AVR910](http://www.atmel.com/images/doc0943.pdf) among other places.
|
||||||
|
|
||||||
|
If the AVR target is powered by a different Vcc than what powers your ESP8266
|
||||||
|
chip, you **must provide voltage level shifting** or some other form of buffers.
|
||||||
|
Exposing the pins of ESP8266 to anything larger than 3.6V will damage it.
|
||||||
|
|
||||||
|
Connections are as follows:
|
||||||
|
|
||||||
|
ESP8266 | AVR / SPI
|
||||||
|
--------|------------
|
||||||
|
GPIO12 | MISO
|
||||||
|
GPIO13 | MOSI
|
||||||
|
GPIO14 | SCK
|
||||||
|
any* | RESET
|
||||||
|
|
||||||
|
For RESET use a GPIO other than 0, 2 and 15 (bootselect pins), and apply an
|
||||||
|
external pullup/down so that the target is normally running.
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
See the included example. In short:
|
||||||
|
|
||||||
|
```arduino
|
||||||
|
|
||||||
|
// Create the programmer object
|
||||||
|
ESP8266AVRISP avrprog(PORT, RESET_PIN)
|
||||||
|
// ... with custom SPI frequency
|
||||||
|
ESP8266AVRISP avrprog(PORT, RESET_PIN, 4e6)
|
||||||
|
|
||||||
|
// Check current connection state, but don't perform any actions
|
||||||
|
AVRISPState_t state = avrprog.update();
|
||||||
|
|
||||||
|
// Serve the pending connection, execute STK500 commands
|
||||||
|
AVRISPState_t state = avrprog.serve();
|
||||||
|
```
|
||||||
|
|
||||||
|
### License and Authors
|
||||||
|
|
||||||
|
This library started off from the source of ArduinoISP "sketch" included with
|
||||||
|
the Arduino IDE:
|
||||||
|
|
||||||
|
ArduinoISP version 04m3
|
||||||
|
Copyright (c) 2008-2011 Randall Bohn
|
||||||
|
If you require a license, see
|
||||||
|
http://www.opensource.org/licenses/bsd-license.php
|
||||||
|
|
||||||
|
Support for TCP on ESP8266
|
||||||
|
Copyright (c) Kiril Zyapkov <kiril@robotev.com>.
|
@ -0,0 +1,67 @@
|
|||||||
|
#include <SPI.h>
|
||||||
|
#include <ESP8266WiFi.h>
|
||||||
|
#include <ESP8266mDNS.h>
|
||||||
|
#include <ESP8266AVRISP.h>
|
||||||
|
|
||||||
|
const char* host = "esp8266-avrisp";
|
||||||
|
const char* ssid = "**********";
|
||||||
|
const char* pass = "**********";
|
||||||
|
const uint16_t port = 328;
|
||||||
|
const uint8_t reset_pin = 5;
|
||||||
|
|
||||||
|
ESP8266AVRISP avrprog(port, reset_pin);
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
Serial.begin(115200);
|
||||||
|
Serial.println("");
|
||||||
|
Serial.println("Arduino AVR-ISP over TCP");
|
||||||
|
avrprog.setReset(false); // let the AVR run
|
||||||
|
|
||||||
|
WiFi.begin(ssid, pass);
|
||||||
|
while (WiFi.waitForConnectResult() != WL_CONNECTED);
|
||||||
|
|
||||||
|
MDNS.begin(host);
|
||||||
|
MDNS.addService("avrisp", "tcp", port);
|
||||||
|
|
||||||
|
IPAddress local_ip = WiFi.localIP();
|
||||||
|
Serial.print("IP address: ");
|
||||||
|
Serial.println(local_ip);
|
||||||
|
Serial.println("Use your avrdude:");
|
||||||
|
Serial.print("avrdude -c arduino -p <device> -P net:");
|
||||||
|
Serial.print(local_ip);
|
||||||
|
Serial.print(":");
|
||||||
|
Serial.print(port);
|
||||||
|
Serial.println(" -t # or -U ...");
|
||||||
|
|
||||||
|
// listen for avrdudes
|
||||||
|
avrprog.begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
static AVRISPState_t last_state = AVRISP_STATE_IDLE;
|
||||||
|
AVRISPState_t new_state = avrprog.update();
|
||||||
|
if (last_state != new_state) {
|
||||||
|
switch (new_state) {
|
||||||
|
case AVRISP_STATE_IDLE: {
|
||||||
|
Serial.printf("[AVRISP] now idle\r\n");
|
||||||
|
// Use the SPI bus for other purposes
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case AVRISP_STATE_PENDING: {
|
||||||
|
Serial.printf("[AVRISP] connection pending\r\n");
|
||||||
|
// Clean up your other purposes and prepare for programming mode
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case AVRISP_STATE_ACTIVE: {
|
||||||
|
Serial.printf("[AVRISP] programming mode\r\n");
|
||||||
|
// Stand by for completion
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
last_state = new_state;
|
||||||
|
}
|
||||||
|
// Serve the client
|
||||||
|
if (last_state != AVRISP_STATE_IDLE) {
|
||||||
|
avrprog.serve();
|
||||||
|
}
|
||||||
|
}
|
9
libraries/ESP8266AVRISP/library.properties
Normal file
9
libraries/ESP8266AVRISP/library.properties
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
name=ESP8266AVRISP
|
||||||
|
version=1.0
|
||||||
|
author=Kiril Zyapkov
|
||||||
|
maintainer=Kiril Zyapkov <kiril@robotev.com>
|
||||||
|
sentence=AVR In-System Programming over WiFi for ESP8266
|
||||||
|
paragraph=This library allows programming 8-bit AVR ICSP targets via TCP over WiFi with ESP8266.
|
||||||
|
category=Communication
|
||||||
|
url=
|
||||||
|
architectures=esp8266
|
541
libraries/ESP8266AVRISP/src/ESP8266AVRISP.cpp
Normal file
541
libraries/ESP8266AVRISP/src/ESP8266AVRISP.cpp
Normal file
@ -0,0 +1,541 @@
|
|||||||
|
/*
|
||||||
|
AVR In-System Programming over WiFi for ESP8266
|
||||||
|
Copyright (c) Kiril Zyapkov <kiril@robotev.com>
|
||||||
|
|
||||||
|
Original version:
|
||||||
|
ArduinoISP version 04m3
|
||||||
|
Copyright (c) 2008-2011 Randall Bohn
|
||||||
|
If you require a license, see
|
||||||
|
http://www.opensource.org/licenses/bsd-license.php
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
#include <SPI.h>
|
||||||
|
#include <pgmspace.h>
|
||||||
|
#include <ESP8266WiFi.h>
|
||||||
|
|
||||||
|
#include "ESP8266AVRISP.h"
|
||||||
|
#include "command.h"
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
#include "user_interface.h"
|
||||||
|
#include "mem.h"
|
||||||
|
}
|
||||||
|
|
||||||
|
#define malloc os_malloc
|
||||||
|
#define free os_free
|
||||||
|
|
||||||
|
#ifdef AVRISP_ACTIVE_HIGH_RESET
|
||||||
|
#define AVRISP_RESET_ON HIGH
|
||||||
|
#define AVRISP_RESET_OFF LOW
|
||||||
|
#else
|
||||||
|
#define AVRISP_RESET_ON LOW
|
||||||
|
#define AVRISP_RESET_OFF HIGH
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
// #define AVRISP_DEBUG(fmt, ...) os_printf("[AVRP] " fmt "\r\n", ##__VA_ARGS__ )
|
||||||
|
#define AVRISP_DEBUG(...)
|
||||||
|
|
||||||
|
#define AVRISP_HWVER 2
|
||||||
|
#define AVRISP_SWMAJ 1
|
||||||
|
#define AVRISP_SWMIN 18
|
||||||
|
#define AVRISP_PTIME 10
|
||||||
|
|
||||||
|
#define EECHUNK (32)
|
||||||
|
|
||||||
|
#define beget16(addr) (*addr * 256 + *(addr+1))
|
||||||
|
|
||||||
|
ESP8266AVRISP::ESP8266AVRISP(uint16_t port, uint8_t reset_pin, uint32_t spi_freq, bool reset_state):
|
||||||
|
_reset_pin(reset_pin), _reset_state(reset_state), _spi_freq(spi_freq),
|
||||||
|
_server(WiFiServer(port)), _state(AVRISP_STATE_IDLE)
|
||||||
|
{
|
||||||
|
pinMode(_reset_pin, OUTPUT);
|
||||||
|
setReset(_reset_state);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ESP8266AVRISP::begin() {
|
||||||
|
_server.begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ESP8266AVRISP::setSpiFrequency(uint32_t freq) {
|
||||||
|
_spi_freq = freq;
|
||||||
|
if (_state == AVRISP_STATE_ACTIVE) {
|
||||||
|
SPI.setFrequency(freq);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ESP8266AVRISP::setReset(bool rst) {
|
||||||
|
_reset_state = rst;
|
||||||
|
if (_reset_state) {
|
||||||
|
digitalWrite(_reset_pin, AVRISP_RESET_ON);
|
||||||
|
} else {
|
||||||
|
digitalWrite(_reset_pin, AVRISP_RESET_OFF);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AVRISPState_t ESP8266AVRISP::update() {
|
||||||
|
switch (_state) {
|
||||||
|
case AVRISP_STATE_IDLE: {
|
||||||
|
if (_server.hasClient()) {
|
||||||
|
_client = _server.available();
|
||||||
|
_client.setNoDelay(true);
|
||||||
|
ip_addr_t lip;
|
||||||
|
lip.addr = _client.remoteIP();
|
||||||
|
AVRISP_DEBUG("client connect %d.%d.%d.%d:%d", IP2STR(&lip), _client.remotePort());
|
||||||
|
_client.setTimeout(100); // for getch()
|
||||||
|
_state = AVRISP_STATE_PENDING;
|
||||||
|
_reject_incoming();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case AVRISP_STATE_PENDING:
|
||||||
|
case AVRISP_STATE_ACTIVE: {
|
||||||
|
// handle disconnect
|
||||||
|
if (!_client.connected()) {
|
||||||
|
_client.stop();
|
||||||
|
AVRISP_DEBUG("client disconnect");
|
||||||
|
if (pmode) {
|
||||||
|
SPI.end();
|
||||||
|
pmode = 0;
|
||||||
|
}
|
||||||
|
setReset(_reset_state);
|
||||||
|
_state = AVRISP_STATE_IDLE;
|
||||||
|
} else {
|
||||||
|
_reject_incoming();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return _state;
|
||||||
|
}
|
||||||
|
|
||||||
|
AVRISPState_t ESP8266AVRISP::serve() {
|
||||||
|
switch (update()) {
|
||||||
|
case AVRISP_STATE_IDLE:
|
||||||
|
// should not be called when idle, error?
|
||||||
|
break;
|
||||||
|
case AVRISP_STATE_PENDING: {
|
||||||
|
_state = AVRISP_STATE_ACTIVE;
|
||||||
|
// fallthrough
|
||||||
|
}
|
||||||
|
case AVRISP_STATE_ACTIVE: {
|
||||||
|
while (_client.available()) {
|
||||||
|
avrisp();
|
||||||
|
}
|
||||||
|
return update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return _state;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void ESP8266AVRISP::_reject_incoming(void) {
|
||||||
|
while (_server.hasClient()) _server.available().stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t ESP8266AVRISP::getch() {
|
||||||
|
while (!_client.available()) yield();
|
||||||
|
uint8_t b = (uint8_t)_client.read();
|
||||||
|
// AVRISP_DEBUG("< %02x", b);
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ESP8266AVRISP::fill(int n) {
|
||||||
|
// AVRISP_DEBUG("fill(%u)", n);
|
||||||
|
for (int x = 0; x < n; x++) {
|
||||||
|
buff[x] = getch();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t ESP8266AVRISP::spi_transaction(uint8_t a, uint8_t b, uint8_t c, uint8_t d) {
|
||||||
|
uint8_t n;
|
||||||
|
SPI.transfer(a);
|
||||||
|
n = SPI.transfer(b);
|
||||||
|
n = SPI.transfer(c);
|
||||||
|
return SPI.transfer(d);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ESP8266AVRISP::empty_reply() {
|
||||||
|
if (Sync_CRC_EOP == getch()) {
|
||||||
|
_client.print((char)Resp_STK_INSYNC);
|
||||||
|
_client.print((char)Resp_STK_OK);
|
||||||
|
} else {
|
||||||
|
error++;
|
||||||
|
_client.print((char)Resp_STK_NOSYNC);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ESP8266AVRISP::breply(uint8_t b) {
|
||||||
|
if (Sync_CRC_EOP == getch()) {
|
||||||
|
uint8_t resp[3];
|
||||||
|
resp[0] = Resp_STK_INSYNC;
|
||||||
|
resp[1] = b;
|
||||||
|
resp[2] = Resp_STK_OK;
|
||||||
|
_client.write((const uint8_t *)resp, (size_t)3);
|
||||||
|
} else {
|
||||||
|
error++;
|
||||||
|
_client.print((char)Resp_STK_NOSYNC);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void ESP8266AVRISP::get_parameter(uint8_t c) {
|
||||||
|
switch (c) {
|
||||||
|
case 0x80:
|
||||||
|
breply(AVRISP_HWVER);
|
||||||
|
break;
|
||||||
|
case 0x81:
|
||||||
|
breply(AVRISP_SWMAJ);
|
||||||
|
break;
|
||||||
|
case 0x82:
|
||||||
|
breply(AVRISP_SWMIN);
|
||||||
|
break;
|
||||||
|
case 0x93:
|
||||||
|
breply('S'); // serial programmer
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
breply(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ESP8266AVRISP::set_parameters() {
|
||||||
|
// call this after reading paramter packet into buff[]
|
||||||
|
param.devicecode = buff[0];
|
||||||
|
param.revision = buff[1];
|
||||||
|
param.progtype = buff[2];
|
||||||
|
param.parmode = buff[3];
|
||||||
|
param.polling = buff[4];
|
||||||
|
param.selftimed = buff[5];
|
||||||
|
param.lockbytes = buff[6];
|
||||||
|
param.fusebytes = buff[7];
|
||||||
|
param.flashpoll = buff[8];
|
||||||
|
// ignore buff[9] (= buff[8])
|
||||||
|
// following are 16 bits (big endian)
|
||||||
|
param.eeprompoll = beget16(&buff[10]);
|
||||||
|
param.pagesize = beget16(&buff[12]);
|
||||||
|
param.eepromsize = beget16(&buff[14]);
|
||||||
|
|
||||||
|
// 32 bits flashsize (big endian)
|
||||||
|
param.flashsize = buff[16] * 0x01000000
|
||||||
|
+ buff[17] * 0x00010000
|
||||||
|
+ buff[18] * 0x00000100
|
||||||
|
+ buff[19];
|
||||||
|
}
|
||||||
|
|
||||||
|
void ESP8266AVRISP::start_pmode() {
|
||||||
|
SPI.begin();
|
||||||
|
SPI.setFrequency(_spi_freq);
|
||||||
|
SPI.setHwCs(false);
|
||||||
|
|
||||||
|
// try to sync the bus
|
||||||
|
SPI.transfer(0x00);
|
||||||
|
digitalWrite(_reset_pin, AVRISP_RESET_OFF);
|
||||||
|
delayMicroseconds(50);
|
||||||
|
digitalWrite(_reset_pin, AVRISP_RESET_ON);
|
||||||
|
delay(30);
|
||||||
|
|
||||||
|
spi_transaction(0xAC, 0x53, 0x00, 0x00);
|
||||||
|
pmode = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ESP8266AVRISP::end_pmode() {
|
||||||
|
SPI.end();
|
||||||
|
setReset(_reset_state);
|
||||||
|
pmode = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ESP8266AVRISP::universal() {
|
||||||
|
int w;
|
||||||
|
uint8_t ch;
|
||||||
|
|
||||||
|
fill(4);
|
||||||
|
ch = spi_transaction(buff[0], buff[1], buff[2], buff[3]);
|
||||||
|
breply(ch);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ESP8266AVRISP::flash(uint8_t hilo, int addr, uint8_t data) {
|
||||||
|
spi_transaction(0x40 + 8 * hilo,
|
||||||
|
addr >> 8 & 0xFF,
|
||||||
|
addr & 0xFF,
|
||||||
|
data);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ESP8266AVRISP::commit(int addr) {
|
||||||
|
spi_transaction(0x4C, (addr >> 8) & 0xFF, addr & 0xFF, 0);
|
||||||
|
delay(AVRISP_PTIME);
|
||||||
|
}
|
||||||
|
|
||||||
|
//#define _addr_page(x) (here & 0xFFFFE0)
|
||||||
|
int ESP8266AVRISP::addr_page(int addr) {
|
||||||
|
if (param.pagesize == 32) return addr & 0xFFFFFFF0;
|
||||||
|
if (param.pagesize == 64) return addr & 0xFFFFFFE0;
|
||||||
|
if (param.pagesize == 128) return addr & 0xFFFFFFC0;
|
||||||
|
if (param.pagesize == 256) return addr & 0xFFFFFF80;
|
||||||
|
AVRISP_DEBUG("unknown page size: %d", param.pagesize);
|
||||||
|
return addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void ESP8266AVRISP::write_flash(int length) {
|
||||||
|
uint32_t started = millis();
|
||||||
|
|
||||||
|
fill(length);
|
||||||
|
|
||||||
|
if (Sync_CRC_EOP == getch()) {
|
||||||
|
_client.print((char) Resp_STK_INSYNC);
|
||||||
|
_client.print((char) write_flash_pages(length));
|
||||||
|
} else {
|
||||||
|
error++;
|
||||||
|
_client.print((char) Resp_STK_NOSYNC);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t ESP8266AVRISP::write_flash_pages(int length) {
|
||||||
|
int x = 0;
|
||||||
|
int page = addr_page(here);
|
||||||
|
while (x < length) {
|
||||||
|
yield();
|
||||||
|
if (page != addr_page(here)) {
|
||||||
|
commit(page);
|
||||||
|
page = addr_page(here);
|
||||||
|
}
|
||||||
|
flash(LOW, here, buff[x++]);
|
||||||
|
flash(HIGH, here, buff[x++]);
|
||||||
|
here++;
|
||||||
|
}
|
||||||
|
commit(page);
|
||||||
|
return Resp_STK_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t ESP8266AVRISP::write_eeprom(int length) {
|
||||||
|
// here is a word address, get the byte address
|
||||||
|
int start = here * 2;
|
||||||
|
int remaining = length;
|
||||||
|
if (length > param.eepromsize) {
|
||||||
|
error++;
|
||||||
|
return Resp_STK_FAILED;
|
||||||
|
}
|
||||||
|
while (remaining > EECHUNK) {
|
||||||
|
write_eeprom_chunk(start, EECHUNK);
|
||||||
|
start += EECHUNK;
|
||||||
|
remaining -= EECHUNK;
|
||||||
|
}
|
||||||
|
write_eeprom_chunk(start, remaining);
|
||||||
|
return Resp_STK_OK;
|
||||||
|
}
|
||||||
|
// write (length) bytes, (start) is a byte address
|
||||||
|
uint8_t ESP8266AVRISP::write_eeprom_chunk(int start, int length) {
|
||||||
|
// this writes byte-by-byte,
|
||||||
|
// page writing may be faster (4 bytes at a time)
|
||||||
|
fill(length);
|
||||||
|
// prog_lamp(LOW);
|
||||||
|
for (int x = 0; x < length; x++) {
|
||||||
|
int addr = start + x;
|
||||||
|
spi_transaction(0xC0, (addr >> 8) & 0xFF, addr & 0xFF, buff[x]);
|
||||||
|
delay(45);
|
||||||
|
}
|
||||||
|
// prog_lamp(HIGH);
|
||||||
|
return Resp_STK_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ESP8266AVRISP::program_page() {
|
||||||
|
char result = (char) Resp_STK_FAILED;
|
||||||
|
int length = 256 * getch();
|
||||||
|
length += getch();
|
||||||
|
char memtype = getch();
|
||||||
|
char buf[100];
|
||||||
|
// flash memory @here, (length) bytes
|
||||||
|
if (memtype == 'F') {
|
||||||
|
write_flash(length);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (memtype == 'E') {
|
||||||
|
result = (char)write_eeprom(length);
|
||||||
|
if (Sync_CRC_EOP == getch()) {
|
||||||
|
_client.print((char) Resp_STK_INSYNC);
|
||||||
|
_client.print(result);
|
||||||
|
} else {
|
||||||
|
error++;
|
||||||
|
_client.print((char) Resp_STK_NOSYNC);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_client.print((char)Resp_STK_FAILED);
|
||||||
|
return;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t ESP8266AVRISP::flash_read(uint8_t hilo, int addr) {
|
||||||
|
return spi_transaction(0x20 + hilo * 8,
|
||||||
|
(addr >> 8) & 0xFF,
|
||||||
|
addr & 0xFF,
|
||||||
|
0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ESP8266AVRISP::flash_read_page(int length) {
|
||||||
|
uint8_t *data = (uint8_t *) malloc(length + 1);
|
||||||
|
for (int x = 0; x < length; x += 2) {
|
||||||
|
*(data + x) = flash_read(LOW, here);
|
||||||
|
*(data + x + 1) = flash_read(HIGH, here);
|
||||||
|
here++;
|
||||||
|
}
|
||||||
|
*(data + length) = Resp_STK_OK;
|
||||||
|
_client.write((const uint8_t *)data, (size_t)(length + 1));
|
||||||
|
free(data);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ESP8266AVRISP::eeprom_read_page(int length) {
|
||||||
|
// here again we have a word address
|
||||||
|
uint8_t *data = (uint8_t *) malloc(length + 1);
|
||||||
|
int start = here * 2;
|
||||||
|
for (int x = 0; x < length; x++) {
|
||||||
|
int addr = start + x;
|
||||||
|
uint8_t ee = spi_transaction(0xA0, (addr >> 8) & 0xFF, addr & 0xFF, 0xFF);
|
||||||
|
*(data + x) = ee;
|
||||||
|
}
|
||||||
|
*(data + length) = Resp_STK_OK;
|
||||||
|
_client.write((const uint8_t *)data, (size_t)(length + 1));
|
||||||
|
free(data);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ESP8266AVRISP::read_page() {
|
||||||
|
char result = (char)Resp_STK_FAILED;
|
||||||
|
int length = 256 * getch();
|
||||||
|
length += getch();
|
||||||
|
char memtype = getch();
|
||||||
|
if (Sync_CRC_EOP != getch()) {
|
||||||
|
error++;
|
||||||
|
_client.print((char) Resp_STK_NOSYNC);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_client.print((char) Resp_STK_INSYNC);
|
||||||
|
if (memtype == 'F') flash_read_page(length);
|
||||||
|
if (memtype == 'E') eeprom_read_page(length);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ESP8266AVRISP::read_signature() {
|
||||||
|
if (Sync_CRC_EOP != getch()) {
|
||||||
|
error++;
|
||||||
|
_client.print((char) Resp_STK_NOSYNC);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_client.print((char) Resp_STK_INSYNC);
|
||||||
|
|
||||||
|
uint8_t high = spi_transaction(0x30, 0x00, 0x00, 0x00);
|
||||||
|
_client.print((char) high);
|
||||||
|
uint8_t middle = spi_transaction(0x30, 0x00, 0x01, 0x00);
|
||||||
|
_client.print((char) middle);
|
||||||
|
uint8_t low = spi_transaction(0x30, 0x00, 0x02, 0x00);
|
||||||
|
_client.print((char) low);
|
||||||
|
_client.print((char) Resp_STK_OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
// It seems ArduinoISP is based on the original STK500 (not v2)
|
||||||
|
// but implements only a subset of the commands.
|
||||||
|
int ESP8266AVRISP::avrisp() {
|
||||||
|
uint8_t data, low, high;
|
||||||
|
uint8_t ch = getch();
|
||||||
|
// AVRISP_DEBUG("CMD 0x%02x", ch);
|
||||||
|
switch (ch) {
|
||||||
|
case Cmnd_STK_GET_SYNC:
|
||||||
|
error = 0;
|
||||||
|
empty_reply();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Cmnd_STK_GET_SIGN_ON:
|
||||||
|
if (getch() == Sync_CRC_EOP) {
|
||||||
|
_client.print((char) Resp_STK_INSYNC);
|
||||||
|
_client.print(F("AVR ISP")); // AVR061 says "AVR STK"?
|
||||||
|
_client.print((char) Resp_STK_OK);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Cmnd_STK_GET_PARAMETER:
|
||||||
|
get_parameter(getch());
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Cmnd_STK_SET_DEVICE:
|
||||||
|
fill(20);
|
||||||
|
set_parameters();
|
||||||
|
empty_reply();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Cmnd_STK_SET_DEVICE_EXT: // ignored
|
||||||
|
fill(5);
|
||||||
|
empty_reply();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Cmnd_STK_ENTER_PROGMODE:
|
||||||
|
start_pmode();
|
||||||
|
empty_reply();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Cmnd_STK_LOAD_ADDRESS:
|
||||||
|
here = getch();
|
||||||
|
here += 256 * getch();
|
||||||
|
// AVRISP_DEBUG("here=0x%04x", here);
|
||||||
|
empty_reply();
|
||||||
|
break;
|
||||||
|
|
||||||
|
// XXX: not implemented!
|
||||||
|
case Cmnd_STK_PROG_FLASH:
|
||||||
|
low = getch();
|
||||||
|
high = getch();
|
||||||
|
empty_reply();
|
||||||
|
break;
|
||||||
|
|
||||||
|
// XXX: not implemented!
|
||||||
|
case Cmnd_STK_PROG_DATA:
|
||||||
|
data = getch();
|
||||||
|
empty_reply();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Cmnd_STK_PROG_PAGE:
|
||||||
|
program_page();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Cmnd_STK_READ_PAGE:
|
||||||
|
read_page();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Cmnd_STK_UNIVERSAL:
|
||||||
|
universal();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Cmnd_STK_LEAVE_PROGMODE:
|
||||||
|
error = 0;
|
||||||
|
end_pmode();
|
||||||
|
empty_reply();
|
||||||
|
delay(5);
|
||||||
|
// if (_client && _client.connected())
|
||||||
|
_client.stop();
|
||||||
|
// AVRISP_DEBUG("left progmode");
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Cmnd_STK_READ_SIGN:
|
||||||
|
read_signature();
|
||||||
|
break;
|
||||||
|
// expecting a command, not Sync_CRC_EOP
|
||||||
|
// this is how we can get back in sync
|
||||||
|
case Sync_CRC_EOP: // 0x20, space
|
||||||
|
error++;
|
||||||
|
_client.print((char) Resp_STK_NOSYNC);
|
||||||
|
break;
|
||||||
|
|
||||||
|
// anything else we will return STK_UNKNOWN
|
||||||
|
default:
|
||||||
|
AVRISP_DEBUG("??!?");
|
||||||
|
error++;
|
||||||
|
if (Sync_CRC_EOP == getch()) {
|
||||||
|
_client.print((char)Resp_STK_UNKNOWN);
|
||||||
|
} else {
|
||||||
|
_client.print((char)Resp_STK_NOSYNC);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
125
libraries/ESP8266AVRISP/src/ESP8266AVRISP.h
Normal file
125
libraries/ESP8266AVRISP/src/ESP8266AVRISP.h
Normal file
@ -0,0 +1,125 @@
|
|||||||
|
/*
|
||||||
|
AVR In-System Programming over WiFi for ESP8266
|
||||||
|
Copyright (c) Kiril Zyapkov <kiril@robotev.com>
|
||||||
|
|
||||||
|
Original version:
|
||||||
|
ArduinoISP version 04m3
|
||||||
|
Copyright (c) 2008-2011 Randall Bohn
|
||||||
|
If you require a license, see
|
||||||
|
http://www.opensource.org/licenses/bsd-license.php
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _ESP8266AVRISP_H
|
||||||
|
#define _ESP8266AVRISP_H
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
|
||||||
|
// uncomment if you use an n-mos to level-shift the reset line
|
||||||
|
// #define AVRISP_ACTIVE_HIGH_RESET
|
||||||
|
|
||||||
|
// SPI clock frequency in Hz
|
||||||
|
#define AVRISP_SPI_FREQ 300e3
|
||||||
|
|
||||||
|
// programmer states
|
||||||
|
typedef enum {
|
||||||
|
AVRISP_STATE_IDLE = 0, // no active TCP session
|
||||||
|
AVRISP_STATE_PENDING, // TCP connected, pending SPI activation
|
||||||
|
AVRISP_STATE_ACTIVE // programmer is active and owns the SPI bus
|
||||||
|
} AVRISPState_t;
|
||||||
|
|
||||||
|
// stk500 parameters
|
||||||
|
typedef struct {
|
||||||
|
uint8_t devicecode;
|
||||||
|
uint8_t revision;
|
||||||
|
uint8_t progtype;
|
||||||
|
uint8_t parmode;
|
||||||
|
uint8_t polling;
|
||||||
|
uint8_t selftimed;
|
||||||
|
uint8_t lockbytes;
|
||||||
|
uint8_t fusebytes;
|
||||||
|
int flashpoll;
|
||||||
|
int eeprompoll;
|
||||||
|
int pagesize;
|
||||||
|
int eepromsize;
|
||||||
|
int flashsize;
|
||||||
|
} AVRISP_parameter_t;
|
||||||
|
|
||||||
|
|
||||||
|
class ESP8266AVRISP {
|
||||||
|
public:
|
||||||
|
ESP8266AVRISP(uint16_t port, uint8_t reset_pin, uint32_t spi_freq=AVRISP_SPI_FREQ, bool reset_state=false);
|
||||||
|
|
||||||
|
void begin();
|
||||||
|
|
||||||
|
// set the SPI clock frequency
|
||||||
|
void setSpiFrequency(uint32_t);
|
||||||
|
|
||||||
|
// control the state of the RESET pin of the target
|
||||||
|
// see AVRISP_ACTIVE_HIGH_RESET
|
||||||
|
void setReset(bool);
|
||||||
|
|
||||||
|
// check for pending clients if IDLE, check for disconnect otherwise
|
||||||
|
// returns the updated state
|
||||||
|
AVRISPState_t update();
|
||||||
|
|
||||||
|
// transition to ACTIVE if PENDING
|
||||||
|
// serve STK500 commands from buffer if ACTIVE
|
||||||
|
// returns the updated state
|
||||||
|
AVRISPState_t serve();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
inline void _reject_incoming(void); // reject any incoming tcp connections
|
||||||
|
|
||||||
|
int avrisp(void); // handle incoming STK500 commands
|
||||||
|
|
||||||
|
uint8_t getch(void); // retrieve a character from the remote end
|
||||||
|
uint8_t spi_transaction(uint8_t, uint8_t, uint8_t, uint8_t);
|
||||||
|
void empty_reply(void);
|
||||||
|
void breply(uint8_t);
|
||||||
|
|
||||||
|
void get_parameter(uint8_t);
|
||||||
|
void set_parameters(void);
|
||||||
|
int addr_page(int);
|
||||||
|
void flash(uint8_t, int, uint8_t);
|
||||||
|
void write_flash(int);
|
||||||
|
uint8_t write_flash_pages(int length);
|
||||||
|
uint8_t write_eeprom(int length);
|
||||||
|
uint8_t write_eeprom_chunk(int start, int length);
|
||||||
|
void commit(int addr);
|
||||||
|
void program_page();
|
||||||
|
uint8_t flash_read(uint8_t hilo, int addr);
|
||||||
|
void flash_read_page(int length);
|
||||||
|
void eeprom_read_page(int length);
|
||||||
|
void read_page();
|
||||||
|
void read_signature();
|
||||||
|
|
||||||
|
void universal(void);
|
||||||
|
|
||||||
|
void fill(int); // fill the buffer with n bytes
|
||||||
|
void start_pmode(void); // enter program mode
|
||||||
|
void end_pmode(void); // exit program mode
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
uint32_t _spi_freq;
|
||||||
|
WiFiServer _server;
|
||||||
|
WiFiClient _client;
|
||||||
|
AVRISPState_t _state;
|
||||||
|
uint8_t _reset_pin;
|
||||||
|
bool _reset_state;
|
||||||
|
|
||||||
|
// programmer settings, set by remote end
|
||||||
|
AVRISP_parameter_t param;
|
||||||
|
// page buffer
|
||||||
|
uint8_t buff[256];
|
||||||
|
|
||||||
|
int error = 0;
|
||||||
|
bool pmode = 0;
|
||||||
|
|
||||||
|
// address for reading and writing, set by 'U' command
|
||||||
|
int here;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // _ESP8266AVRISP_H
|
108
libraries/ESP8266AVRISP/src/command.h
Normal file
108
libraries/ESP8266AVRISP/src/command.h
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
//**** ATMEL AVR - A P P L I C A T I O N N O T E ************************
|
||||||
|
//*
|
||||||
|
//* Title: AVR061 - STK500 Communication Protocol
|
||||||
|
//* Filename: command.h
|
||||||
|
//* Version: 1.0
|
||||||
|
//* Last updated: 09.09.2002
|
||||||
|
//*
|
||||||
|
//* Support E-mail: avr@atmel.com
|
||||||
|
//*
|
||||||
|
//**************************************************************************
|
||||||
|
|
||||||
|
// *****************[ STK Message constants ]***************************
|
||||||
|
|
||||||
|
#define STK_SIGN_ON_MESSAGE "AVR STK" // Sign on string for Cmnd_STK_GET_SIGN_ON
|
||||||
|
|
||||||
|
// *****************[ STK Response constants ]***************************
|
||||||
|
|
||||||
|
#define Resp_STK_OK 0x10 // ' '
|
||||||
|
#define Resp_STK_FAILED 0x11 // ' '
|
||||||
|
#define Resp_STK_UNKNOWN 0x12 // ' '
|
||||||
|
#define Resp_STK_NODEVICE 0x13 // ' '
|
||||||
|
#define Resp_STK_INSYNC 0x14 // ' '
|
||||||
|
#define Resp_STK_NOSYNC 0x15 // ' '
|
||||||
|
|
||||||
|
#define Resp_ADC_CHANNEL_ERROR 0x16 // ' '
|
||||||
|
#define Resp_ADC_MEASURE_OK 0x17 // ' '
|
||||||
|
#define Resp_PWM_CHANNEL_ERROR 0x18 // ' '
|
||||||
|
#define Resp_PWM_ADJUST_OK 0x19 // ' '
|
||||||
|
|
||||||
|
// *****************[ STK Special constants ]***************************
|
||||||
|
|
||||||
|
#define Sync_CRC_EOP 0x20 // 'SPACE'
|
||||||
|
|
||||||
|
// *****************[ STK Command constants ]***************************
|
||||||
|
|
||||||
|
#define Cmnd_STK_GET_SYNC 0x30 // ' '
|
||||||
|
#define Cmnd_STK_GET_SIGN_ON 0x31 // ' '
|
||||||
|
#define Cmnd_STK_RESET 0x32 // ' '
|
||||||
|
#define Cmnd_STK_SINGLE_CLOCK 0x33 // ' '
|
||||||
|
#define Cmnd_STK_STORE_PARAMETERS 0x34 // ' '
|
||||||
|
|
||||||
|
#define Cmnd_STK_SET_PARAMETER 0x40 // ' '
|
||||||
|
#define Cmnd_STK_GET_PARAMETER 0x41 // ' '
|
||||||
|
#define Cmnd_STK_SET_DEVICE 0x42 // ' '
|
||||||
|
#define Cmnd_STK_GET_DEVICE 0x43 // ' '
|
||||||
|
#define Cmnd_STK_GET_STATUS 0x44 // ' '
|
||||||
|
#define Cmnd_STK_SET_DEVICE_EXT 0x45 // ' '
|
||||||
|
|
||||||
|
#define Cmnd_STK_ENTER_PROGMODE 0x50 // ' '
|
||||||
|
#define Cmnd_STK_LEAVE_PROGMODE 0x51 // ' '
|
||||||
|
#define Cmnd_STK_CHIP_ERASE 0x52 // ' '
|
||||||
|
#define Cmnd_STK_CHECK_AUTOINC 0x53 // ' '
|
||||||
|
#define Cmnd_STK_CHECK_DEVICE 0x54 // ' '
|
||||||
|
#define Cmnd_STK_LOAD_ADDRESS 0x55 // ' '
|
||||||
|
#define Cmnd_STK_UNIVERSAL 0x56 // ' '
|
||||||
|
|
||||||
|
#define Cmnd_STK_PROG_FLASH 0x60 // ' '
|
||||||
|
#define Cmnd_STK_PROG_DATA 0x61 // ' '
|
||||||
|
#define Cmnd_STK_PROG_FUSE 0x62 // ' '
|
||||||
|
#define Cmnd_STK_PROG_LOCK 0x63 // ' '
|
||||||
|
#define Cmnd_STK_PROG_PAGE 0x64 // ' '
|
||||||
|
#define Cmnd_STK_PROG_FUSE_EXT 0x65 // ' '
|
||||||
|
|
||||||
|
#define Cmnd_STK_READ_FLASH 0x70 // ' '
|
||||||
|
#define Cmnd_STK_READ_DATA 0x71 // ' '
|
||||||
|
#define Cmnd_STK_READ_FUSE 0x72 // ' '
|
||||||
|
#define Cmnd_STK_READ_LOCK 0x73 // ' '
|
||||||
|
#define Cmnd_STK_READ_PAGE 0x74 // ' '
|
||||||
|
#define Cmnd_STK_READ_SIGN 0x75 // ' '
|
||||||
|
#define Cmnd_STK_READ_OSCCAL 0x76 // ' '
|
||||||
|
#define Cmnd_STK_READ_FUSE_EXT 0x77 // ' '
|
||||||
|
#define Cmnd_STK_READ_OSCCAL_EXT 0x78 // ' '
|
||||||
|
|
||||||
|
// *****************[ STK Parameter constants ]***************************
|
||||||
|
|
||||||
|
#define Parm_STK_HW_VER 0x80 // ' ' - R
|
||||||
|
#define Parm_STK_SW_MAJOR 0x81 // ' ' - R
|
||||||
|
#define Parm_STK_SW_MINOR 0x82 // ' ' - R
|
||||||
|
#define Parm_STK_LEDS 0x83 // ' ' - R/W
|
||||||
|
#define Parm_STK_VTARGET 0x84 // ' ' - R/W
|
||||||
|
#define Parm_STK_VADJUST 0x85 // ' ' - R/W
|
||||||
|
#define Parm_STK_OSC_PSCALE 0x86 // ' ' - R/W
|
||||||
|
#define Parm_STK_OSC_CMATCH 0x87 // ' ' - R/W
|
||||||
|
#define Parm_STK_RESET_DURATION 0x88 // ' ' - R/W
|
||||||
|
#define Parm_STK_SCK_DURATION 0x89 // ' ' - R/W
|
||||||
|
|
||||||
|
#define Parm_STK_BUFSIZEL 0x90 // ' ' - R/W, Range {0..255}
|
||||||
|
#define Parm_STK_BUFSIZEH 0x91 // ' ' - R/W, Range {0..255}
|
||||||
|
#define Parm_STK_DEVICE 0x92 // ' ' - R/W, Range {0..255}
|
||||||
|
#define Parm_STK_PROGMODE 0x93 // ' ' - 'P' or 'S'
|
||||||
|
#define Parm_STK_PARAMODE 0x94 // ' ' - TRUE or FALSE
|
||||||
|
#define Parm_STK_POLLING 0x95 // ' ' - TRUE or FALSE
|
||||||
|
#define Parm_STK_SELFTIMED 0x96 // ' ' - TRUE or FALSE
|
||||||
|
|
||||||
|
|
||||||
|
// *****************[ STK status bit definitions ]***************************
|
||||||
|
|
||||||
|
#define Stat_STK_INSYNC 0x01 // INSYNC status bit, '1' - INSYNC
|
||||||
|
#define Stat_STK_PROGMODE 0x02 // Programming mode, '1' - PROGMODE
|
||||||
|
#define Stat_STK_STANDALONE 0x04 // Standalone mode, '1' - SM mode
|
||||||
|
#define Stat_STK_RESET 0x08 // RESET button, '1' - Pushed
|
||||||
|
#define Stat_STK_PROGRAM 0x10 // Program button, ' 1' - Pushed
|
||||||
|
#define Stat_STK_LEDG 0x20 // Green LED status, '1' - Lit
|
||||||
|
#define Stat_STK_LEDR 0x40 // Red LED status, '1' - Lit
|
||||||
|
#define Stat_STK_LEDBLINK 0x80 // LED blink ON/OFF, '1' - Blink
|
||||||
|
|
||||||
|
|
||||||
|
// *****************************[ End Of COMMAND.H ]**************************
|
@ -1,9 +1,9 @@
|
|||||||
/*
|
/*
|
||||||
ESP8266WebServer.cpp - Dead simple web-server.
|
ESP8266WebServer.cpp - Dead simple web-server.
|
||||||
Supports only one simultaneous client, knows how to handle GET and POST.
|
Supports only one simultaneous client, knows how to handle GET and POST.
|
||||||
|
|
||||||
Copyright (c) 2014 Ivan Grokhotkov. All rights reserved.
|
Copyright (c) 2014 Ivan Grokhotkov. All rights reserved.
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
This library is free software; you can redistribute it and/or
|
||||||
modify it under the terms of the GNU Lesser General Public
|
modify it under the terms of the GNU Lesser General Public
|
||||||
License as published by the Free Software Foundation; either
|
License as published by the Free Software Foundation; either
|
||||||
@ -25,25 +25,11 @@
|
|||||||
#include "WiFiServer.h"
|
#include "WiFiServer.h"
|
||||||
#include "WiFiClient.h"
|
#include "WiFiClient.h"
|
||||||
#include "ESP8266WebServer.h"
|
#include "ESP8266WebServer.h"
|
||||||
|
#include "FS.h"
|
||||||
|
#include "detail/RequestHandler.h"
|
||||||
// #define DEBUG
|
// #define DEBUG
|
||||||
#define DEBUG_OUTPUT Serial
|
#define DEBUG_OUTPUT Serial
|
||||||
|
|
||||||
struct ESP8266WebServer::RequestHandler {
|
|
||||||
RequestHandler(ESP8266WebServer::THandlerFunction fn, const char* uri, HTTPMethod method)
|
|
||||||
: fn(fn)
|
|
||||||
, uri(uri)
|
|
||||||
, method(method)
|
|
||||||
, next(NULL)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
ESP8266WebServer::THandlerFunction fn;
|
|
||||||
String uri;
|
|
||||||
HTTPMethod method;
|
|
||||||
RequestHandler* next;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
ESP8266WebServer::ESP8266WebServer(int port)
|
ESP8266WebServer::ESP8266WebServer(int port)
|
||||||
: _server(port)
|
: _server(port)
|
||||||
@ -78,15 +64,22 @@ void ESP8266WebServer::on(const char* uri, ESP8266WebServer::THandlerFunction ha
|
|||||||
|
|
||||||
void ESP8266WebServer::on(const char* uri, HTTPMethod method, ESP8266WebServer::THandlerFunction fn)
|
void ESP8266WebServer::on(const char* uri, HTTPMethod method, ESP8266WebServer::THandlerFunction fn)
|
||||||
{
|
{
|
||||||
RequestHandler* handler = new RequestHandler(fn, uri, method);
|
_addRequestHandler(new FunctionRequestHandler(fn, uri, method));
|
||||||
if (!_lastHandler) {
|
}
|
||||||
_firstHandler = handler;
|
|
||||||
_lastHandler = handler;
|
void ESP8266WebServer::_addRequestHandler(RequestHandler* handler) {
|
||||||
}
|
if (!_lastHandler) {
|
||||||
else {
|
_firstHandler = handler;
|
||||||
_lastHandler->next = handler;
|
_lastHandler = handler;
|
||||||
_lastHandler = handler;
|
}
|
||||||
}
|
else {
|
||||||
|
_lastHandler->next = handler;
|
||||||
|
_lastHandler = handler;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ESP8266WebServer::serveStatic(const char* uri, FS& fs, const char* path) {
|
||||||
|
_addRequestHandler(new StaticRequestHandler(fs, uri));
|
||||||
}
|
}
|
||||||
|
|
||||||
void ESP8266WebServer::handleClient()
|
void ESP8266WebServer::handleClient()
|
||||||
@ -185,17 +178,18 @@ void ESP8266WebServer::send(int code, const String& content_type, const String&
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ESP8266WebServer::sendContent(const String& content) {
|
void ESP8266WebServer::sendContent(const String& content) {
|
||||||
|
const size_t unit_size = HTTP_DOWNLOAD_UNIT_SIZE;
|
||||||
size_t size_to_send = content.length();
|
size_t size_to_send = content.length();
|
||||||
size_t size_sent = 0;
|
const char* send_start = content.c_str();
|
||||||
while(size_to_send) {
|
|
||||||
const size_t unit_size = HTTP_DOWNLOAD_UNIT_SIZE;
|
while (size_to_send) {
|
||||||
size_t will_send = (size_to_send < unit_size) ? size_to_send : unit_size;
|
size_t will_send = (size_to_send < unit_size) ? size_to_send : unit_size;
|
||||||
size_t sent = _currentClient.write(content.c_str() + size_sent, will_send);
|
size_t sent = _currentClient.write(send_start, will_send);
|
||||||
size_to_send -= sent;
|
|
||||||
size_sent += sent;
|
|
||||||
if (sent == 0) {
|
if (sent == 0) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
size_to_send -= sent;
|
||||||
|
send_start += sent;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -269,16 +263,9 @@ void ESP8266WebServer::onNotFound(THandlerFunction fn) {
|
|||||||
|
|
||||||
void ESP8266WebServer::_handleRequest() {
|
void ESP8266WebServer::_handleRequest() {
|
||||||
RequestHandler* handler;
|
RequestHandler* handler;
|
||||||
for (handler = _firstHandler; handler; handler = handler->next)
|
for (handler = _firstHandler; handler; handler = handler->next) {
|
||||||
{
|
if (handler->handle(*this, _currentMethod, _currentUri))
|
||||||
if (handler->method != HTTP_ANY && handler->method != _currentMethod)
|
break;
|
||||||
continue;
|
|
||||||
|
|
||||||
if (handler->uri != _currentUri)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
handler->fn();
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!handler){
|
if (!handler){
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
/*
|
/*
|
||||||
ESP8266WebServer.h - Dead simple web-server.
|
ESP8266WebServer.h - Dead simple web-server.
|
||||||
Supports only one simultaneous client, knows how to handle GET and POST.
|
Supports only one simultaneous client, knows how to handle GET and POST.
|
||||||
|
|
||||||
Copyright (c) 2014 Ivan Grokhotkov. All rights reserved.
|
Copyright (c) 2014 Ivan Grokhotkov. All rights reserved.
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
This library is free software; you can redistribute it and/or
|
||||||
modify it under the terms of the GNU Lesser General Public
|
modify it under the terms of the GNU Lesser General Public
|
||||||
License as published by the Free Software Foundation; either
|
License as published by the Free Software Foundation; either
|
||||||
@ -37,6 +37,12 @@ enum HTTPUploadStatus { UPLOAD_FILE_START, UPLOAD_FILE_WRITE, UPLOAD_FILE_END };
|
|||||||
#define CONTENT_LENGTH_UNKNOWN ((size_t) -1)
|
#define CONTENT_LENGTH_UNKNOWN ((size_t) -1)
|
||||||
#define CONTENT_LENGTH_NOT_SET ((size_t) -2)
|
#define CONTENT_LENGTH_NOT_SET ((size_t) -2)
|
||||||
|
|
||||||
|
class RequestHandler;
|
||||||
|
|
||||||
|
namespace fs {
|
||||||
|
class FS;
|
||||||
|
}
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
HTTPUploadStatus status;
|
HTTPUploadStatus status;
|
||||||
String filename;
|
String filename;
|
||||||
@ -59,6 +65,7 @@ public:
|
|||||||
typedef std::function<void(void)> THandlerFunction;
|
typedef std::function<void(void)> THandlerFunction;
|
||||||
void on(const char* uri, THandlerFunction handler);
|
void on(const char* uri, THandlerFunction handler);
|
||||||
void on(const char* uri, HTTPMethod method, THandlerFunction fn);
|
void on(const char* uri, HTTPMethod method, THandlerFunction fn);
|
||||||
|
void serveStatic(const char* uri, fs::FS& fs, const char* path);
|
||||||
void onNotFound(THandlerFunction fn); //called when handler is not assigned
|
void onNotFound(THandlerFunction fn); //called when handler is not assigned
|
||||||
void onFileUpload(THandlerFunction fn); //handle file uploads
|
void onFileUpload(THandlerFunction fn); //handle file uploads
|
||||||
|
|
||||||
@ -66,13 +73,13 @@ public:
|
|||||||
HTTPMethod method() { return _currentMethod; }
|
HTTPMethod method() { return _currentMethod; }
|
||||||
WiFiClient client() { return _currentClient; }
|
WiFiClient client() { return _currentClient; }
|
||||||
HTTPUpload& upload() { return _currentUpload; }
|
HTTPUpload& upload() { return _currentUpload; }
|
||||||
|
|
||||||
String arg(const char* name); // get request argument value by name
|
String arg(const char* name); // get request argument value by name
|
||||||
String arg(int i); // get request argument value by number
|
String arg(int i); // get request argument value by number
|
||||||
String argName(int i); // get request argument name by number
|
String argName(int i); // get request argument name by number
|
||||||
int args(); // get arguments count
|
int args(); // get arguments count
|
||||||
bool hasArg(const char* name); // check if argument exists
|
bool hasArg(const char* name); // check if argument exists
|
||||||
|
|
||||||
// send response to the client
|
// send response to the client
|
||||||
// code - HTTP response code, can be 200 or 404
|
// code - HTTP response code, can be 200 or 404
|
||||||
// content_type - HTTP content type, like "text/plain" or "image/png"
|
// content_type - HTTP content type, like "text/plain" or "image/png"
|
||||||
@ -89,7 +96,7 @@ public:
|
|||||||
|
|
||||||
template<typename T> size_t streamFile(T &file, const String& contentType){
|
template<typename T> size_t streamFile(T &file, const String& contentType){
|
||||||
setContentLength(file.size());
|
setContentLength(file.size());
|
||||||
if (String(file.name()).endsWith(".gz") &&
|
if (String(file.name()).endsWith(".gz") &&
|
||||||
contentType != "application/x-gzip" &&
|
contentType != "application/x-gzip" &&
|
||||||
contentType != "application/octet-stream"){
|
contentType != "application/octet-stream"){
|
||||||
sendHeader("Content-Encoding", "gzip");
|
sendHeader("Content-Encoding", "gzip");
|
||||||
@ -97,8 +104,9 @@ template<typename T> size_t streamFile(T &file, const String& contentType){
|
|||||||
send(200, contentType, "");
|
send(200, contentType, "");
|
||||||
return _currentClient.write(file, HTTP_DOWNLOAD_UNIT_SIZE);
|
return _currentClient.write(file, HTTP_DOWNLOAD_UNIT_SIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
void _addRequestHandler(RequestHandler* handler);
|
||||||
void _handleRequest();
|
void _handleRequest();
|
||||||
bool _parseRequest(WiFiClient& client);
|
bool _parseRequest(WiFiClient& client);
|
||||||
void _parseArguments(String data);
|
void _parseArguments(String data);
|
||||||
@ -108,7 +116,6 @@ protected:
|
|||||||
uint8_t _uploadReadByte(WiFiClient& client);
|
uint8_t _uploadReadByte(WiFiClient& client);
|
||||||
void _prepareHeader(String& response, int code, const char* content_type, size_t contentLength);
|
void _prepareHeader(String& response, int code, const char* content_type, size_t contentLength);
|
||||||
|
|
||||||
struct RequestHandler;
|
|
||||||
struct RequestArgument {
|
struct RequestArgument {
|
||||||
String key;
|
String key;
|
||||||
String value;
|
String value;
|
||||||
|
96
libraries/ESP8266WebServer/src/detail/RequestHandler.h
Normal file
96
libraries/ESP8266WebServer/src/detail/RequestHandler.h
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
#ifndef REQUESTHANDLER_H
|
||||||
|
#define REQUESTHANDLER_H
|
||||||
|
|
||||||
|
class RequestHandler {
|
||||||
|
public:
|
||||||
|
RequestHandler(const char* uri, HTTPMethod method)
|
||||||
|
: uri(uri)
|
||||||
|
, method(method)
|
||||||
|
, next(NULL)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool handle(ESP8266WebServer& server, HTTPMethod requestMethod, String requestUri) = 0;
|
||||||
|
|
||||||
|
RequestHandler* next;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
String uri;
|
||||||
|
HTTPMethod method;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class FunctionRequestHandler : public RequestHandler {
|
||||||
|
typedef RequestHandler base;
|
||||||
|
|
||||||
|
public:
|
||||||
|
FunctionRequestHandler(ESP8266WebServer::THandlerFunction fn, const char* uri, HTTPMethod method)
|
||||||
|
: fn(fn)
|
||||||
|
, base(uri, method)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool handle(ESP8266WebServer& server, HTTPMethod requestMethod, String requestUri) override {
|
||||||
|
if (method != HTTP_ANY && method != requestMethod)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (requestUri != uri)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
fn();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
ESP8266WebServer::THandlerFunction fn;
|
||||||
|
};
|
||||||
|
|
||||||
|
class StaticRequestHandler : public RequestHandler {
|
||||||
|
typedef RequestHandler base;
|
||||||
|
|
||||||
|
public:
|
||||||
|
StaticRequestHandler(FS& fs, const char* uri)
|
||||||
|
: fs(fs)
|
||||||
|
, base(uri, HTTP_GET)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool handle(ESP8266WebServer& server, HTTPMethod requestMethod, String requestUri) override {
|
||||||
|
if (requestMethod != method)
|
||||||
|
return false;
|
||||||
|
DEBUGV("StaticRequestHandler::handle: %s\r\n", requestUri.c_str());
|
||||||
|
if (!requestUri.startsWith(uri))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
auto prefixLength = uri.length() - 1;
|
||||||
|
String path = requestUri.substring(prefixLength);
|
||||||
|
DEBUGV("StaticRequestHandler::handle: %d %s\r\n", prefixLength, path.c_str());
|
||||||
|
File f = fs.open(path, "r");
|
||||||
|
if (!f)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
server.streamFile(f, getContentType(path));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static String getContentType(const String& path) {
|
||||||
|
if (path.endsWith(".html")) return "text/html";
|
||||||
|
else if (path.endsWith(".htm")) return "text/html";
|
||||||
|
else if (path.endsWith(".css")) return "text/css";
|
||||||
|
else if (path.endsWith(".txt")) return "text/plain";
|
||||||
|
else if (path.endsWith(".js")) return "application/javascript";
|
||||||
|
else if (path.endsWith(".png")) return "image/png";
|
||||||
|
else if (path.endsWith(".gif")) return "image/gif";
|
||||||
|
else if (path.endsWith(".jpg")) return "image/jpeg";
|
||||||
|
else if (path.endsWith(".ico")) return "image/x-icon";
|
||||||
|
else if (path.endsWith(".xml")) return "text/xml";
|
||||||
|
else if (path.endsWith(".pdf")) return "application/pdf";
|
||||||
|
else if (path.endsWith(".zip")) return "application/zip";
|
||||||
|
return "text/plain";
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
FS fs;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif //REQUESTHANDLER_H
|
@ -666,7 +666,7 @@ bool ESP8266WiFiClass::hostname(String aHostname) {
|
|||||||
|
|
||||||
//--------------------------------------------------------------
|
//--------------------------------------------------------------
|
||||||
|
|
||||||
void wifi_wps_status_cb(WPS_CB_STATUS_t status)
|
void wifi_wps_status_cb(wps_cb_status status)
|
||||||
{
|
{
|
||||||
DEBUGV("wps cb status: %d\r\n", status);
|
DEBUGV("wps cb status: %d\r\n", status);
|
||||||
switch (status) {
|
switch (status) {
|
||||||
@ -682,6 +682,9 @@ void wifi_wps_status_cb(WPS_CB_STATUS_t status)
|
|||||||
case WPS_CB_ST_TIMEOUT:
|
case WPS_CB_ST_TIMEOUT:
|
||||||
DEBUGV("wps TIMEOUT\n");
|
DEBUGV("wps TIMEOUT\n");
|
||||||
break;
|
break;
|
||||||
|
case WPS_CB_ST_WEP:
|
||||||
|
DEBUGV("wps WEP\n");
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
// todo user function to get status
|
// todo user function to get status
|
||||||
|
|
||||||
@ -715,7 +718,7 @@ bool ESP8266WiFiClass::beginWPSConfig(void) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!wifi_set_wps_cb(&wifi_wps_status_cb)) {
|
if(!wifi_set_wps_cb((wps_st_cb_t) &wifi_wps_status_cb)) {
|
||||||
DEBUGV("wps cb faild\n");
|
DEBUGV("wps cb faild\n");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -44,7 +44,7 @@ public:
|
|||||||
ESP8266WiFiClass();
|
ESP8266WiFiClass();
|
||||||
|
|
||||||
void mode(WiFiMode);
|
void mode(WiFiMode);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Start Wifi connection
|
* Start Wifi connection
|
||||||
* if passphrase is set the most secure supported mode will be automatically selected
|
* if passphrase is set the most secure supported mode will be automatically selected
|
||||||
@ -95,7 +95,7 @@ public:
|
|||||||
* param dns: Defined DNS
|
* param dns: Defined DNS
|
||||||
*/
|
*/
|
||||||
void config(IPAddress local_ip, IPAddress gateway, IPAddress subnet, IPAddress dns);
|
void config(IPAddress local_ip, IPAddress gateway, IPAddress subnet, IPAddress dns);
|
||||||
|
|
||||||
/* Configure access point
|
/* Configure access point
|
||||||
*
|
*
|
||||||
* param local_ip: access point IP
|
* param local_ip: access point IP
|
||||||
@ -336,19 +336,19 @@ public:
|
|||||||
/*
|
/*
|
||||||
* Start SmartConfig
|
* Start SmartConfig
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
void beginSmartConfig();
|
void beginSmartConfig();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Query SmartConfig status, to decide when stop config
|
* Query SmartConfig status, to decide when stop config
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
bool smartConfigDone();
|
bool smartConfigDone();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Stop SmartConfig
|
* Stop SmartConfig
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
void stopSmartConfig();
|
void stopSmartConfig();
|
||||||
|
|
||||||
friend class WiFiClient;
|
friend class WiFiClient;
|
||||||
@ -366,7 +366,7 @@ protected:
|
|||||||
bool _useApMode;
|
bool _useApMode;
|
||||||
bool _useClientMode;
|
bool _useClientMode;
|
||||||
bool _useStaticIp;
|
bool _useStaticIp;
|
||||||
|
|
||||||
static bool _scanAsync;
|
static bool _scanAsync;
|
||||||
static bool _scanStarted;
|
static bool _scanStarted;
|
||||||
static bool _scanComplete;
|
static bool _scanComplete;
|
||||||
|
@ -36,7 +36,7 @@ License (MIT license):
|
|||||||
|
|
||||||
#include "ESP8266mDNS.h"
|
#include "ESP8266mDNS.h"
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
@ -88,28 +88,28 @@ static const int MDNS_PORT = 5353;
|
|||||||
MDNSResponder::MDNSResponder() : _conn(0) { _services = 0; }
|
MDNSResponder::MDNSResponder() : _conn(0) { _services = 0; }
|
||||||
MDNSResponder::~MDNSResponder() {}
|
MDNSResponder::~MDNSResponder() {}
|
||||||
|
|
||||||
bool MDNSResponder::begin(const char* domain){
|
bool MDNSResponder::begin(const char* domain){
|
||||||
// Open the MDNS socket if it isn't already open.
|
// Open the MDNS socket if it isn't already open.
|
||||||
|
|
||||||
size_t n = strlen(domain);
|
size_t n = strlen(domain);
|
||||||
if (n > 255) { // Can only handle domains that are 255 chars in length.
|
if (n > 255) { // Can only handle domains that are 255 chars in length.
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copy in domain characters as lowercase
|
// Copy in domain characters as lowercase
|
||||||
for (int i = 0; i < n; ++i)
|
for (int i = 0; i < n; ++i)
|
||||||
_hostName[i] = tolower(domain[i]);
|
_hostName[i] = tolower(domain[i]);
|
||||||
_hostName[n] = '\0';
|
_hostName[n] = '\0';
|
||||||
|
|
||||||
os_strcpy(_boardName, ARDUINO_BOARD);
|
os_strcpy(_boardName, ARDUINO_BOARD);
|
||||||
|
|
||||||
// Open the MDNS socket if it isn't already open.
|
// Open the MDNS socket if it isn't already open.
|
||||||
if (!_conn) {
|
if (!_conn) {
|
||||||
uint32_t ourIp = _getOurIp();
|
uint32_t ourIp = _getOurIp();
|
||||||
if(ourIp == 0){
|
if(ourIp == 0){
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
ip_addr_t ifaddr;
|
ip_addr_t ifaddr;
|
||||||
ifaddr.addr = ourIp;
|
ifaddr.addr = ourIp;
|
||||||
ip_addr_t multicast_addr;
|
ip_addr_t multicast_addr;
|
||||||
@ -135,7 +135,7 @@ bool MDNSResponder::begin(const char* domain){
|
|||||||
|
|
||||||
void MDNSResponder::update() {
|
void MDNSResponder::update() {
|
||||||
if (!_conn->next()) {
|
if (!_conn->next()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
_parsePacket();
|
_parsePacket();
|
||||||
}
|
}
|
||||||
@ -163,15 +163,21 @@ uint16_t MDNSResponder::_getServicePort(char *name, char *proto){
|
|||||||
}
|
}
|
||||||
|
|
||||||
uint32_t MDNSResponder::_getOurIp(){
|
uint32_t MDNSResponder::_getOurIp(){
|
||||||
if(wifi_get_opmode() & STATION_MODE){
|
int mode = wifi_get_opmode();
|
||||||
|
if(mode & STATION_MODE){
|
||||||
struct ip_info staIpInfo;
|
struct ip_info staIpInfo;
|
||||||
wifi_get_ip_info(STATION_IF, &staIpInfo);
|
wifi_get_ip_info(STATION_IF, &staIpInfo);
|
||||||
return staIpInfo.ip.addr;
|
return staIpInfo.ip.addr;
|
||||||
}
|
} else if (mode & SOFTAP_MODE) {
|
||||||
|
struct ip_info staIpInfo;
|
||||||
|
wifi_get_ip_info(SOFTAP_IF, &staIpInfo);
|
||||||
|
return staIpInfo.ip.addr;
|
||||||
|
} else {
|
||||||
#ifdef MDNS_DEBUG_ERR
|
#ifdef MDNS_DEBUG_ERR
|
||||||
os_printf("ERR_NO_LOCAL_IP\n");
|
os_printf("ERR_NO_LOCAL_IP\n");
|
||||||
#endif
|
#endif
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MDNSResponder::_parsePacket(){
|
void MDNSResponder::_parsePacket(){
|
||||||
@ -180,39 +186,39 @@ void MDNSResponder::_parsePacket(){
|
|||||||
bool serviceParsed = false;
|
bool serviceParsed = false;
|
||||||
bool protoParsed = false;
|
bool protoParsed = false;
|
||||||
bool localParsed = false;
|
bool localParsed = false;
|
||||||
|
|
||||||
char hostName[255];
|
char hostName[255];
|
||||||
uint8_t hostNameLen;
|
uint8_t hostNameLen;
|
||||||
|
|
||||||
char serviceName[32];
|
char serviceName[32];
|
||||||
uint8_t serviceNameLen;
|
uint8_t serviceNameLen;
|
||||||
uint16_t servicePort;
|
uint16_t servicePort;
|
||||||
|
|
||||||
char protoName[32];
|
char protoName[32];
|
||||||
uint8_t protoNameLen;
|
uint8_t protoNameLen;
|
||||||
|
|
||||||
uint16_t packetHeader[6];
|
uint16_t packetHeader[6];
|
||||||
|
|
||||||
for(i=0; i<6; i++) packetHeader[i] = _conn_read16();
|
for(i=0; i<6; i++) packetHeader[i] = _conn_read16();
|
||||||
|
|
||||||
if((packetHeader[1] & 0x8000) != 0){ //not parsing responses yet
|
if((packetHeader[1] & 0x8000) != 0){ //not parsing responses yet
|
||||||
_conn->flush();
|
_conn->flush();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// PARSE REQUEST NAME
|
// PARSE REQUEST NAME
|
||||||
|
|
||||||
hostNameLen = _conn_read8();
|
hostNameLen = _conn_read8();
|
||||||
_conn_readS(hostName, hostNameLen);
|
_conn_readS(hostName, hostNameLen);
|
||||||
hostName[hostNameLen] = '\0';
|
hostName[hostNameLen] = '\0';
|
||||||
|
|
||||||
if(hostName[0] == '_'){
|
if(hostName[0] == '_'){
|
||||||
serviceParsed = true;
|
serviceParsed = true;
|
||||||
memcpy(serviceName, hostName+1, hostNameLen);
|
memcpy(serviceName, hostName+1, hostNameLen);
|
||||||
serviceNameLen = hostNameLen-1;
|
serviceNameLen = hostNameLen-1;
|
||||||
hostNameLen = 0;
|
hostNameLen = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(hostNameLen > 0 && strcmp(_hostName, hostName) != 0){
|
if(hostNameLen > 0 && strcmp(_hostName, hostName) != 0){
|
||||||
#ifdef MDNS_DEBUG_ERR
|
#ifdef MDNS_DEBUG_ERR
|
||||||
os_printf("ERR_NO_HOST: %s\n", hostName);
|
os_printf("ERR_NO_HOST: %s\n", hostName);
|
||||||
@ -220,12 +226,12 @@ void MDNSResponder::_parsePacket(){
|
|||||||
_conn->flush();
|
_conn->flush();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!serviceParsed){
|
if(!serviceParsed){
|
||||||
serviceNameLen = _conn_read8();
|
serviceNameLen = _conn_read8();
|
||||||
_conn_readS(serviceName, serviceNameLen);
|
_conn_readS(serviceName, serviceNameLen);
|
||||||
serviceName[serviceNameLen] = '\0';
|
serviceName[serviceNameLen] = '\0';
|
||||||
|
|
||||||
if(serviceName[0] == '_'){
|
if(serviceName[0] == '_'){
|
||||||
memcpy(serviceName, serviceName+1, serviceNameLen);
|
memcpy(serviceName, serviceName+1, serviceNameLen);
|
||||||
serviceNameLen--;
|
serviceNameLen--;
|
||||||
@ -253,7 +259,7 @@ void MDNSResponder::_parsePacket(){
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!protoParsed){
|
if(!protoParsed){
|
||||||
protoNameLen = _conn_read8();
|
protoNameLen = _conn_read8();
|
||||||
_conn_readS(protoName, protoNameLen);
|
_conn_readS(protoName, protoNameLen);
|
||||||
@ -270,7 +276,7 @@ void MDNSResponder::_parsePacket(){
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!localParsed){
|
if(!localParsed){
|
||||||
char localName[32];
|
char localName[32];
|
||||||
uint8_t localNameLen = _conn_read8();
|
uint8_t localNameLen = _conn_read8();
|
||||||
@ -287,7 +293,7 @@ void MDNSResponder::_parsePacket(){
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(serviceNameLen > 0 && protoNameLen > 0){
|
if(serviceNameLen > 0 && protoNameLen > 0){
|
||||||
servicePort = _getServicePort(serviceName, protoName);
|
servicePort = _getServicePort(serviceName, protoName);
|
||||||
if(servicePort == 0){
|
if(servicePort == 0){
|
||||||
@ -304,16 +310,16 @@ void MDNSResponder::_parsePacket(){
|
|||||||
_conn->flush();
|
_conn->flush();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// RESPOND
|
// RESPOND
|
||||||
|
|
||||||
#ifdef MDNS_DEBUG_RX
|
#ifdef MDNS_DEBUG_RX
|
||||||
os_printf("RX: REQ, ID:%u, Q:%u, A:%u, NS:%u, ADD:%u\n", packetHeader[0], packetHeader[2], packetHeader[3], packetHeader[4], packetHeader[5]);
|
os_printf("RX: REQ, ID:%u, Q:%u, A:%u, NS:%u, ADD:%u\n", packetHeader[0], packetHeader[2], packetHeader[3], packetHeader[4], packetHeader[5]);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
uint16_t currentType;
|
uint16_t currentType;
|
||||||
uint16_t currentClass;
|
uint16_t currentClass;
|
||||||
|
|
||||||
int numQuestions = packetHeader[2];
|
int numQuestions = packetHeader[2];
|
||||||
if(numQuestions > 4) numQuestions = 4;
|
if(numQuestions > 4) numQuestions = 4;
|
||||||
uint16_t questions[4];
|
uint16_t questions[4];
|
||||||
@ -326,21 +332,21 @@ void MDNSResponder::_parsePacket(){
|
|||||||
}
|
}
|
||||||
currentClass = _conn_read16();
|
currentClass = _conn_read16();
|
||||||
if(currentClass & MDNS_CLASS_IN) questions[question++] = currentType;
|
if(currentClass & MDNS_CLASS_IN) questions[question++] = currentType;
|
||||||
|
|
||||||
if(numQuestions > 0){
|
if(numQuestions > 0){
|
||||||
if(_conn_read16() != 0xC00C){//new question but for another host/service
|
if(_conn_read16() != 0xC00C){//new question but for another host/service
|
||||||
_conn->flush();
|
_conn->flush();
|
||||||
numQuestions = 0;
|
numQuestions = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef MDNS_DEBUG_RX
|
#ifdef MDNS_DEBUG_RX
|
||||||
os_printf("REQ: ");
|
os_printf("REQ: ");
|
||||||
if(hostNameLen > 0) os_printf("%s.", hostName);
|
if(hostNameLen > 0) os_printf("%s.", hostName);
|
||||||
if(serviceNameLen > 0) os_printf("_%s.", serviceName);
|
if(serviceNameLen > 0) os_printf("_%s.", serviceName);
|
||||||
if(protoNameLen > 0) os_printf("_%s.", protoName);
|
if(protoNameLen > 0) os_printf("_%s.", protoName);
|
||||||
os_printf("local. ");
|
os_printf("local. ");
|
||||||
|
|
||||||
if(currentType == MDNS_TYPE_AAAA) os_printf(" AAAA ");
|
if(currentType == MDNS_TYPE_AAAA) os_printf(" AAAA ");
|
||||||
else if(currentType == MDNS_TYPE_A) os_printf(" A ");
|
else if(currentType == MDNS_TYPE_A) os_printf(" A ");
|
||||||
else if(currentType == MDNS_TYPE_PTR) os_printf(" PTR ");
|
else if(currentType == MDNS_TYPE_PTR) os_printf(" PTR ");
|
||||||
@ -351,7 +357,7 @@ void MDNSResponder::_parsePacket(){
|
|||||||
if(currentClass == MDNS_CLASS_IN) os_printf(" IN ");
|
if(currentClass == MDNS_CLASS_IN) os_printf(" IN ");
|
||||||
else if(currentClass == MDNS_CLASS_IN_FLUSH_CACHE) os_printf(" IN[F] ");
|
else if(currentClass == MDNS_CLASS_IN_FLUSH_CACHE) os_printf(" IN[F] ");
|
||||||
else os_printf(" 0x%04X ", currentClass);
|
else os_printf(" 0x%04X ", currentClass);
|
||||||
|
|
||||||
os_printf("\n");
|
os_printf("\n");
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@ -362,7 +368,7 @@ void MDNSResponder::_parsePacket(){
|
|||||||
else if(questions[i] == MDNS_TYPE_TXT) responseMask |= 0x4;
|
else if(questions[i] == MDNS_TYPE_TXT) responseMask |= 0x4;
|
||||||
else if(questions[i] == MDNS_TYPE_PTR) responseMask |= 0xF;
|
else if(questions[i] == MDNS_TYPE_PTR) responseMask |= 0xF;
|
||||||
}
|
}
|
||||||
|
|
||||||
return _reply(responseMask, (serviceName), (protoName), servicePort);
|
return _reply(responseMask, (serviceName), (protoName), servicePort);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -371,14 +377,14 @@ void MDNSResponder::_parsePacket(){
|
|||||||
void MDNSResponder::_reply(uint8_t replyMask, char * service, char *proto, uint16_t port){
|
void MDNSResponder::_reply(uint8_t replyMask, char * service, char *proto, uint16_t port){
|
||||||
int i;
|
int i;
|
||||||
if(replyMask == 0) return;
|
if(replyMask == 0) return;
|
||||||
|
|
||||||
#ifdef MDNS_DEBUG_TX
|
#ifdef MDNS_DEBUG_TX
|
||||||
os_printf("TX: mask:%01X, service:%s, proto:%s, port:%u\n", replyMask, service, proto, port);
|
os_printf("TX: mask:%01X, service:%s, proto:%s, port:%u\n", replyMask, service, proto, port);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
char nameLen = os_strlen(_hostName);
|
char nameLen = os_strlen(_hostName);
|
||||||
size_t serviceLen = os_strlen(service);
|
size_t serviceLen = os_strlen(service);
|
||||||
|
|
||||||
uint8_t answerCount = 0;
|
uint8_t answerCount = 0;
|
||||||
for(i=0;i<4;i++){
|
for(i=0;i<4;i++){
|
||||||
if(replyMask & (1 << i)) answerCount++;
|
if(replyMask & (1 << i)) answerCount++;
|
||||||
@ -394,12 +400,12 @@ void MDNSResponder::_reply(uint8_t replyMask, char * service, char *proto, uint1
|
|||||||
0x00, 0x00, //Additional records
|
0x00, 0x00, //Additional records
|
||||||
};
|
};
|
||||||
_conn->append(reinterpret_cast<const char*>(head), 12);
|
_conn->append(reinterpret_cast<const char*>(head), 12);
|
||||||
|
|
||||||
if((replyMask & 0x8) == 0){
|
if((replyMask & 0x8) == 0){
|
||||||
_conn->append(reinterpret_cast<const char*>(&nameLen), 1);
|
_conn->append(reinterpret_cast<const char*>(&nameLen), 1);
|
||||||
_conn->append(reinterpret_cast<const char*>(_hostName), nameLen);
|
_conn->append(reinterpret_cast<const char*>(_hostName), nameLen);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(replyMask & 0xE){
|
if(replyMask & 0xE){
|
||||||
uint8_t servHead[2] = {(uint8_t)(serviceLen+1), '_'};
|
uint8_t servHead[2] = {(uint8_t)(serviceLen+1), '_'};
|
||||||
uint8_t protoHead[2] = {0x4, '_'};
|
uint8_t protoHead[2] = {0x4, '_'};
|
||||||
@ -408,14 +414,14 @@ void MDNSResponder::_reply(uint8_t replyMask, char * service, char *proto, uint1
|
|||||||
_conn->append(reinterpret_cast<const char*>(protoHead), 2);
|
_conn->append(reinterpret_cast<const char*>(protoHead), 2);
|
||||||
_conn->append(reinterpret_cast<const char*>(proto), 3);
|
_conn->append(reinterpret_cast<const char*>(proto), 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t local[7] = {
|
uint8_t local[7] = {
|
||||||
0x05, //strlen(_local)
|
0x05, //strlen(_local)
|
||||||
0x6C, 0x6F, 0x63, 0x61, 0x6C, //local
|
0x6C, 0x6F, 0x63, 0x61, 0x6C, //local
|
||||||
0x00, //End of domain
|
0x00, //End of domain
|
||||||
};
|
};
|
||||||
_conn->append(reinterpret_cast<const char*>(local), 7);
|
_conn->append(reinterpret_cast<const char*>(local), 7);
|
||||||
|
|
||||||
// PTR Response
|
// PTR Response
|
||||||
if(replyMask & 0x8){
|
if(replyMask & 0x8){
|
||||||
uint8_t ptr[10] = {
|
uint8_t ptr[10] = {
|
||||||
@ -430,16 +436,16 @@ void MDNSResponder::_reply(uint8_t replyMask, char * service, char *proto, uint1
|
|||||||
uint8_t ptrTail[2] = {0xC0, 0x0C};
|
uint8_t ptrTail[2] = {0xC0, 0x0C};
|
||||||
_conn->append(reinterpret_cast<const char*>(ptrTail), 2);
|
_conn->append(reinterpret_cast<const char*>(ptrTail), 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TXT Response
|
// TXT Response
|
||||||
if(replyMask & 0x4){
|
if(replyMask & 0x4){
|
||||||
if(replyMask & 0x8){//send the name
|
if(replyMask & 0x8){//send the name
|
||||||
uint8_t txtHead[2] = {0xC0, (uint8_t)(36 + serviceLen)};
|
uint8_t txtHead[2] = {0xC0, (uint8_t)(36 + serviceLen)};
|
||||||
_conn->append(reinterpret_cast<const char*>(txtHead), 2);
|
_conn->append(reinterpret_cast<const char*>(txtHead), 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t boardNameLen = os_strlen(_boardName);
|
uint8_t boardNameLen = os_strlen(_boardName);
|
||||||
|
|
||||||
uint8_t txt[24] = {
|
uint8_t txt[24] = {
|
||||||
0x00, 0x10, //Type TXT
|
0x00, 0x10, //Type TXT
|
||||||
0x80, 0x01, //Class IN, with cache flush
|
0x80, 0x01, //Class IN, with cache flush
|
||||||
@ -450,9 +456,9 @@ void MDNSResponder::_reply(uint8_t replyMask, char * service, char *proto, uint1
|
|||||||
};
|
};
|
||||||
_conn->append(reinterpret_cast<const char*>(txt), 17);
|
_conn->append(reinterpret_cast<const char*>(txt), 17);
|
||||||
_conn->append(reinterpret_cast<const char*>(_boardName), boardNameLen);
|
_conn->append(reinterpret_cast<const char*>(_boardName), boardNameLen);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// SRV Response
|
// SRV Response
|
||||||
if(replyMask & 0x2){
|
if(replyMask & 0x2){
|
||||||
if(replyMask & 0xC){//send the name
|
if(replyMask & 0xC){//send the name
|
||||||
@ -461,7 +467,7 @@ void MDNSResponder::_reply(uint8_t replyMask, char * service, char *proto, uint1
|
|||||||
srvHead[1] = 36 + serviceLen;
|
srvHead[1] = 36 + serviceLen;
|
||||||
_conn->append(reinterpret_cast<const char*>(srvHead), 2);
|
_conn->append(reinterpret_cast<const char*>(srvHead), 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t srv[16] = {
|
uint8_t srv[16] = {
|
||||||
0x00, 0x21, //Type SRV
|
0x00, 0x21, //Type SRV
|
||||||
0x80, 0x01, //Class IN, with cache flush
|
0x80, 0x01, //Class IN, with cache flush
|
||||||
@ -479,7 +485,7 @@ void MDNSResponder::_reply(uint8_t replyMask, char * service, char *proto, uint1
|
|||||||
srvTail[1] = 19 + serviceLen;
|
srvTail[1] = 19 + serviceLen;
|
||||||
_conn->append(reinterpret_cast<const char*>(srvTail), 2);
|
_conn->append(reinterpret_cast<const char*>(srvTail), 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
// A Response
|
// A Response
|
||||||
if(replyMask & 0x1){
|
if(replyMask & 0x1){
|
||||||
uint32_t ip = _getOurIp();
|
uint32_t ip = _getOurIp();
|
||||||
@ -488,7 +494,7 @@ void MDNSResponder::_reply(uint8_t replyMask, char * service, char *proto, uint1
|
|||||||
_conn->append(reinterpret_cast<const char*>(_hostName), nameLen);
|
_conn->append(reinterpret_cast<const char*>(_hostName), nameLen);
|
||||||
_conn->append(reinterpret_cast<const char*>(local), 7);
|
_conn->append(reinterpret_cast<const char*>(local), 7);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t aaa[14] = {
|
uint8_t aaa[14] = {
|
||||||
0x00, 0x01, //TYPE A
|
0x00, 0x01, //TYPE A
|
||||||
0x80, 0x01, //Class IN, with cache flush
|
0x80, 0x01, //Class IN, with cache flush
|
||||||
|
@ -13,10 +13,9 @@ Requirements:
|
|||||||
|
|
||||||
Usage:
|
Usage:
|
||||||
- Include the ESP8266 Multicast DNS library in the sketch.
|
- Include the ESP8266 Multicast DNS library in the sketch.
|
||||||
- Create an instance of the MDNSResponder class.
|
|
||||||
- Call the begin method in the sketch's setup and provide a domain name (without
|
- Call the begin method in the sketch's setup and provide a domain name (without
|
||||||
the '.local' suffix, i.e. just provide 'foo' to resolve 'foo.local'), and the
|
the '.local' suffix, i.e. just provide 'foo' to resolve 'foo.local'), and the
|
||||||
Adafruit CC3000 class instance. Optionally provide a time to live (in seconds)
|
Adafruit CC3000 class instance. Optionally provide a time to live (in seconds)
|
||||||
for the DNS record--the default is 1 hour.
|
for the DNS record--the default is 1 hour.
|
||||||
- Call the update method in each iteration of the sketch's loop function.
|
- Call the update method in each iteration of the sketch's loop function.
|
||||||
|
|
||||||
@ -70,7 +69,7 @@ public:
|
|||||||
return begin(hostName);
|
return begin(hostName);
|
||||||
}
|
}
|
||||||
void update();
|
void update();
|
||||||
|
|
||||||
void addService(char *service, char *proto, uint16_t port);
|
void addService(char *service, char *proto, uint16_t port);
|
||||||
void addService(const char *service, const char *proto, uint16_t port){
|
void addService(const char *service, const char *proto, uint16_t port){
|
||||||
addService((char *)service, (char *)proto, port);
|
addService((char *)service, (char *)proto, port);
|
||||||
@ -78,7 +77,7 @@ public:
|
|||||||
void addService(String service, String proto, uint16_t port){
|
void addService(String service, String proto, uint16_t port){
|
||||||
addService(service.c_str(), proto.c_str(), port);
|
addService(service.c_str(), proto.c_str(), port);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct MDNSService * _services;
|
struct MDNSService * _services;
|
||||||
UdpContext* _conn;
|
UdpContext* _conn;
|
||||||
|
@ -59,8 +59,6 @@ static uint8_t s_servoCount = 0; // the total number of attached s_se
|
|||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
template <class T> void Servo_Handler(T* timer)
|
template <class T> void Servo_Handler(T* timer)
|
||||||
{
|
{
|
||||||
noInterrupts();
|
|
||||||
|
|
||||||
uint8_t servoIndex;
|
uint8_t servoIndex;
|
||||||
|
|
||||||
// clear interrupt
|
// clear interrupt
|
||||||
@ -101,8 +99,6 @@ template <class T> void Servo_Handler(T* timer)
|
|||||||
|
|
||||||
timer->setEndOfCycle();
|
timer->setEndOfCycle();
|
||||||
}
|
}
|
||||||
|
|
||||||
interrupts();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void initISR(ServoTimerSequence timerId)
|
static void initISR(ServoTimerSequence timerId)
|
||||||
|
97
libraries/esp8266/examples/ConfigFile/ConfigFile.ino
Normal file
97
libraries/esp8266/examples/ConfigFile/ConfigFile.ino
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
// Example: storing JSON configuration file in flash file system
|
||||||
|
//
|
||||||
|
// Uses ArduinoJson library by Benoit Blanchon.
|
||||||
|
// https://github.com/bblanchon/ArduinoJson
|
||||||
|
//
|
||||||
|
// Created Aug 10, 2015 by Ivan Grokhotkov.
|
||||||
|
//
|
||||||
|
// This example code is in the public domain.
|
||||||
|
|
||||||
|
#include <ArduinoJson.h>
|
||||||
|
#include "FS.h"
|
||||||
|
|
||||||
|
bool loadConfig() {
|
||||||
|
File configFile = SPIFFS.open("/config.json", "r");
|
||||||
|
if (!configFile) {
|
||||||
|
Serial.println("Failed to open config file");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t size = configFile.size();
|
||||||
|
if (size > 1024) {
|
||||||
|
Serial.println("Config file size is too large");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allocate a buffer to store contents of the file.
|
||||||
|
std::unique_ptr<char[]> buf(new char[size]);
|
||||||
|
|
||||||
|
// We don't use String here because ArduinoJson library requires the input
|
||||||
|
// buffer to be mutable. If you don't use ArduinoJson, you may as well
|
||||||
|
// use configFile.readString instead.
|
||||||
|
configFile.readBytes(buf.get(), size);
|
||||||
|
|
||||||
|
StaticJsonBuffer<200> jsonBuffer;
|
||||||
|
JsonObject& json = jsonBuffer.parseObject(buf.get());
|
||||||
|
|
||||||
|
if (!json.success()) {
|
||||||
|
Serial.println("Failed to parse config file");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* serverName = json["serverName"];
|
||||||
|
const char* accessToken = json["accessToken"];
|
||||||
|
|
||||||
|
// Real world application would store these values in some variables for
|
||||||
|
// later use.
|
||||||
|
|
||||||
|
Serial.print("Loaded serverName: ");
|
||||||
|
Serial.println(serverName);
|
||||||
|
Serial.print("Loaded accessToken: ");
|
||||||
|
Serial.println(accessToken);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool saveConfig() {
|
||||||
|
StaticJsonBuffer<200> jsonBuffer;
|
||||||
|
JsonObject& json = jsonBuffer.createObject();
|
||||||
|
json["serverName"] = "api.example.com";
|
||||||
|
json["accessToken"] = "128du9as8du12eoue8da98h123ueh9h98";
|
||||||
|
|
||||||
|
File configFile = SPIFFS.open("/config.json", "w");
|
||||||
|
if (!configFile) {
|
||||||
|
Serial.println("Failed to open config file for writing");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
json.printTo(configFile);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
Serial.begin(115200);
|
||||||
|
Serial.println("");
|
||||||
|
delay(1000);
|
||||||
|
Serial.println("Mounting FS...");
|
||||||
|
|
||||||
|
if (!SPIFFS.begin()) {
|
||||||
|
Serial.println("Failed to mount file system");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (!saveConfig()) {
|
||||||
|
Serial.println("Failed to save config");
|
||||||
|
} else {
|
||||||
|
Serial.println("Config saved");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!loadConfig()) {
|
||||||
|
Serial.println("Failed to load config");
|
||||||
|
} else {
|
||||||
|
Serial.println("Config loaded");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
}
|
@ -20,3 +20,14 @@ function build_sketches()
|
|||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function install_libraries()
|
||||||
|
{
|
||||||
|
mkdir -p $HOME/Arduino/libraries
|
||||||
|
pushd $HOME/Arduino/libraries
|
||||||
|
|
||||||
|
# install ArduinoJson library
|
||||||
|
wget https://github.com/bblanchon/ArduinoJson/releases/download/v4.6.1/ArduinoJson-v4.6.1.zip && unzip ArduinoJson-v4.6.1.zip
|
||||||
|
|
||||||
|
popd
|
||||||
|
}
|
||||||
|
@ -1,7 +1,65 @@
|
|||||||
esp_iot_sdk_v1.2.0_15_07_13_p4 Release Note
|
esp_iot_sdk_v1.3.0_15_08_10_p1 Release Note
|
||||||
|
----------------------------------------
|
||||||
|
|
||||||
|
Here is a patch based on esp_iot_sdk_v1.3.0 (non-OS SDK) resolved issue that if there are 2 connections, one is normal TCP connection, the other is SSL connection, it may cause memory leak.
|
||||||
|
|
||||||
|
Download and unzip the attachment, replace the lib in esp_iot_sdk/lib folder.
|
||||||
|
|
||||||
|
Please do not set the same priority for two different tasks when using system_os_task.
|
||||||
|
|
||||||
|
Sorry for the inconvenience.
|
||||||
|
|
||||||
|
|
||||||
|
esp_iot_sdk_v1.3.0_15_08_08 Release Note
|
||||||
|
----------------------------------------
|
||||||
|
|
||||||
|
Resolved Issues(Bugs below are eligible for Bug Bounty Program):
|
||||||
|
1.Device can't connect to router after it gets ssid and password when using ESPTOUCH with router's ssid hidden. [冯智]
|
||||||
|
2.Format string of os_random can't be supported by atoi. [杨朝位]
|
||||||
|
3.Optimized os_printf seems to have an issue on 4 bytes aligned and other valuable suggestions. [Andrey Filimonov]
|
||||||
|
4.SmartConfig can’t get IP address after connected to router. [孙大明]
|
||||||
|
|
||||||
|
Optimization:
|
||||||
|
1.Memory optimization to save 12KBytes.
|
||||||
|
2.Optimize RF calibration to short the booting time,more details in documentation "2A-ESP8266__IOT_SDK_User_Manual" chapter "Appendix".
|
||||||
|
3.Optimize Wi-Fi function to solve issue that ESP8266 may fail to connect to a special router.
|
||||||
|
4.Optimize software timer to solve the a connecting problem.Please do not call "os_delay_us" or "while" or "for" to occupy CPU more than 10 ms in timer callback.
|
||||||
|
5.Optimize system_get_rst_info to obtain more accurate information about the start-up.
|
||||||
|
6.Optimize function of Wi-Fi scanning to be more reliable.
|
||||||
|
7.Optimize function of changing Wi-Fi mode to be more reliable.
|
||||||
|
8.Optimize WPS to improve connectivity.And WPS does not support WEP, it will return status "WPS_CB_ST_WEP".
|
||||||
|
9.Optimize Wi-Fi function to solve softAP multiple stations DHCP issue.
|
||||||
|
10.Optimize TCP in LAST_ACK status.
|
||||||
|
11.Optimize TLS to support SHA256, SHA384, SHA512.
|
||||||
|
12.Memory optimization during TLS hand-shaking.
|
||||||
|
13.Optimize OTA funtion to download big chunk of data.
|
||||||
|
14.Add CRC32 in OTA function.Folder "tools" in esp_iot_sdk has to be updated, otherwise OTA will fail.
|
||||||
|
15.Optimize mDNS to support both softAP and station interfaces.
|
||||||
|
16.Optimize ESP-NOW, more details in "Add APIs"
|
||||||
|
17.Update SmartConfig to version 2.4.7
|
||||||
|
18.Remove "-O2" from makefile.
|
||||||
|
19.Optimize header files to improve compatibility, will not affect compilation.
|
||||||
|
|
||||||
|
Add APIs:
|
||||||
|
1.system_soft_wdt_feed : feed software watchdog
|
||||||
|
2.wifi_softap_get_dhcps_lease:get IP range of ESP8266 softAP DHCP server
|
||||||
|
3.ESP-NOW APIs
|
||||||
|
esp_now_set_kok: set the secure key to encrypt ESP-NOW communication key
|
||||||
|
esp_now_register_send_cb: register ESP-NOW send callback
|
||||||
|
esp_now_unregister_send_cb: unregister ESP-NOW send callback
|
||||||
|
|
||||||
|
AT_v0.40 Release Note:
|
||||||
|
Note: For AT firmware to support FOTA, flash size need to be 1024KB or more than that.
|
||||||
|
|
||||||
|
1.Add parameter <max conn> in command "AT+CWSAP" to set the maximum number of connections allowed.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
esp_iot_sdk_v1.2.0_15_07_13_p4 Release Note
|
||||||
-------------------------------------------
|
-------------------------------------------
|
||||||
|
|
||||||
Here is a patch of memory optimization based on SDK_v1.2.0
|
Here is a patch of memory optimization based on SDK_v1.2.0
|
||||||
1. It saved about 8KBytes memory.
|
1. It saved about 8KBytes memory.
|
||||||
2. It revised problem that change mode may cause memory leak.
|
2. It revised problem that change mode may cause memory leak.
|
||||||
3. Update SmartConfig to version 2.4.3
|
3. Update SmartConfig to version 2.4.3
|
||||||
@ -13,7 +71,7 @@ Thanks for your interest in Espressif Systems and ESP8266 !
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
esp_iot_sdk_v1.2.0_15_07_09_p3 Release Note
|
esp_iot_sdk_v1.2.0_15_07_09_p3 Release Note
|
||||||
-------------------------------------------
|
-------------------------------------------
|
||||||
|
|
||||||
Here is a patch based on SDK_v1.2.0 solved problem that if AP’s SSID is hidden,ESPTOUCH may get wrong BSSID of AP and cause connection fail.
|
Here is a patch based on SDK_v1.2.0 solved problem that if AP’s SSID is hidden,ESPTOUCH may get wrong BSSID of AP and cause connection fail.
|
||||||
@ -24,7 +82,7 @@ Sorry for the inconvenience.
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
esp_iot_sdk_v1.2.0_15_07_09_p2 Release Note
|
esp_iot_sdk_v1.2.0_15_07_09_p2 Release Note
|
||||||
-------------------------------------------
|
-------------------------------------------
|
||||||
|
|
||||||
Updated libssl again. To support SHA-256 and SHA-512.
|
Updated libssl again. To support SHA-256 and SHA-512.
|
||||||
@ -34,7 +92,7 @@ Thanks for your interest in Espressif Systems and ESP8266 !
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
esp_iot_sdk_v1.2.0_15_07_08_p1 Release Note
|
esp_iot_sdk_v1.2.0_15_07_08_p1 Release Note
|
||||||
-------------------------------------------
|
-------------------------------------------
|
||||||
|
|
||||||
Here is a patch based on SDK_v1.2.0 solved problem that abnormal SSL disconnection may cause reset.
|
Here is a patch based on SDK_v1.2.0 solved problem that abnormal SSL disconnection may cause reset.
|
||||||
@ -45,7 +103,7 @@ Sorry for the inconvenience.
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
esp_iot_sdk_v1.2.0_15_07_03 Release Note
|
esp_iot_sdk_v1.2.0_15_07_03 Release Note
|
||||||
-------------------------------------------
|
-------------------------------------------
|
||||||
Resolved Issues(Bugs below are eligible for Bug Bounty Program):
|
Resolved Issues(Bugs below are eligible for Bug Bounty Program):
|
||||||
1.TLS server disconnect to ESP8266 may cause crash. [孙新虎]
|
1.TLS server disconnect to ESP8266 may cause crash. [孙新虎]
|
||||||
@ -77,10 +135,10 @@ esp_now_add_peer: add an ESP-NOW peer
|
|||||||
esp_now_del_peer: delete an ESP-NOW peer
|
esp_now_del_peer: delete an ESP-NOW peer
|
||||||
esp_now_set_self_role: set ESP-NOW role of device itself
|
esp_now_set_self_role: set ESP-NOW role of device itself
|
||||||
esp_now_get_self_role: get ESP-NOW role of device itself
|
esp_now_get_self_role: get ESP-NOW role of device itself
|
||||||
esp_now_set_peer_role: set ESP-NOW role about another device
|
esp_now_set_peer_role: set ESP-NOW role about another device
|
||||||
esp_now_get_peer_role: get ESP-NOW role about another device
|
esp_now_get_peer_role: get ESP-NOW role about another device
|
||||||
esp_now_set_peer_key: set ESP-NOW key of a device
|
esp_now_set_peer_key: set ESP-NOW key of a device
|
||||||
esp_now_get_peer_key: get ESP-NOW key of a device
|
esp_now_get_peer_key: get ESP-NOW key of a device
|
||||||
|
|
||||||
2. WPS APIs
|
2. WPS APIs
|
||||||
wifi_wps_enable : enable WPS function
|
wifi_wps_enable : enable WPS function
|
||||||
@ -92,9 +150,9 @@ wifi_set_wps_cb: set WPS callback
|
|||||||
system_soft_wdt_stop: stop software watchdog
|
system_soft_wdt_stop: stop software watchdog
|
||||||
system_soft_wdt_restart: restart software watchdog
|
system_soft_wdt_restart: restart software watchdog
|
||||||
|
|
||||||
4.sntp_get_timezone: get SNTP timezone
|
4.sntp_get_timezone: get SNTP timezone
|
||||||
|
|
||||||
AT_v0.30 Release Note:
|
AT_v0.30 Release Note:
|
||||||
Note: For AT firmware to support FOTA, flash size need to be 1024KB or more than that.
|
Note: For AT firmware to support FOTA, flash size need to be 1024KB or more than that.
|
||||||
|
|
||||||
1.Command "AT+CWSTARTSMART" need not parameter any more, SmartConfig type can be got automatically.
|
1.Command "AT+CWSTARTSMART" need not parameter any more, SmartConfig type can be got automatically.
|
||||||
@ -104,15 +162,15 @@ Note: For AT firmware to support FOTA, flash size need to be 1024KB or more than
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
esp_iot_sdk_1.1.2_15_06_25_p2 Release Note
|
esp_iot_sdk_1.1.2_15_06_25_p2 Release Note
|
||||||
-------------------------------------------
|
-------------------------------------------
|
||||||
|
|
||||||
Here is a patch based on SDK_v1.1.2 solved problem of abnormal current during modem-sleep.
|
Here is a patch based on SDK_v1.1.2 solved problem of abnormal current during modem-sleep.
|
||||||
Please replace the lib in \esp_iot_sdk_v1.1.2\lib
|
Please replace the lib in \esp_iot_sdk_v1.1.2\lib
|
||||||
|
|
||||||
Sorry for the inconvenience.
|
Sorry for the inconvenience.
|
||||||
|
|
||||||
esp_iot_sdk_v1.1.2_15_06_24_p1.1 Release Note
|
esp_iot_sdk_v1.1.2_15_06_24_p1.1 Release Note
|
||||||
-------------------------------------------
|
-------------------------------------------
|
||||||
|
|
||||||
Here is a patch for AT firmware based on SDK_v1.1.2 resolved issue that AT user parameter area was located in wrong address,it may cause WiFi configuration goes wrong.
|
Here is a patch for AT firmware based on SDK_v1.1.2 resolved issue that AT user parameter area was located in wrong address,it may cause WiFi configuration goes wrong.
|
||||||
@ -133,7 +191,7 @@ can not FOTA upgrade,please don‘t call “AT+CIPUPDATE”
|
|||||||
|
|
||||||
So sorry for the inconvenience.
|
So sorry for the inconvenience.
|
||||||
|
|
||||||
esp_iot_sdk_v1.1.2_15_06_16_p1 Release Note
|
esp_iot_sdk_v1.1.2_15_06_16_p1 Release Note
|
||||||
-------------------------------------------
|
-------------------------------------------
|
||||||
Here is a patch based on SDK_v1.1.2 resolved issue that "wifi_station_scan" cause loss of wireless connectivity.
|
Here is a patch based on SDK_v1.1.2 resolved issue that "wifi_station_scan" cause loss of wireless connectivity.
|
||||||
|
|
||||||
@ -144,7 +202,7 @@ Sorry for the inconvenience.
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
esp_iot_sdk_v1.1.2_15_06_12 Release Note
|
esp_iot_sdk_v1.1.2_15_06_12 Release Note
|
||||||
-------------------------------------------
|
-------------------------------------------
|
||||||
|
|
||||||
Optimization:
|
Optimization:
|
||||||
@ -165,7 +223,7 @@ Add Documentation:
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
esp_iot_sdk_v1.1.1_15_06_05 Release Note
|
esp_iot_sdk_v1.1.1_15_06_05 Release Note
|
||||||
-------------------------------------------
|
-------------------------------------------
|
||||||
|
|
||||||
Resolved Issues(Bugs below are eligible for Bug Bounty Program):
|
Resolved Issues(Bugs below are eligible for Bug Bounty Program):
|
||||||
@ -175,7 +233,7 @@ Resolved Issues(Bugs below are eligible for Bug Bounty Program):
|
|||||||
|
|
||||||
Optimization:
|
Optimization:
|
||||||
1.Update JSON parser to handle with illegal parameter and illegal calling progress.
|
1.Update JSON parser to handle with illegal parameter and illegal calling progress.
|
||||||
2.Add parameter of user_esp_platform_check_ip in user_websever.c which in IOT_Demo.
|
2.Add parameter of user_esp_platform_check_ip in user_websever.c which in IOT_Demo.
|
||||||
3.Update UART driver to solve the problem that if send data through UART while ESP8266 startup may cause UART invalid.
|
3.Update UART driver to solve the problem that if send data through UART while ESP8266 startup may cause UART invalid.
|
||||||
4.Update smartconfig to version 2.2, corresponding phone APP v0.3.2. And update the description and example of smartconfig_start in document "2C_ESP8266__Programming Guide"
|
4.Update smartconfig to version 2.2, corresponding phone APP v0.3.2. And update the description and example of smartconfig_start in document "2C_ESP8266__Programming Guide"
|
||||||
5.Update code in iram to solve the problem that space for text is not enough.
|
5.Update code in iram to solve the problem that space for text is not enough.
|
||||||
@ -185,12 +243,12 @@ Optimization:
|
|||||||
9.Remove useless driver code in IOT_Demo
|
9.Remove useless driver code in IOT_Demo
|
||||||
10.Update IOT_Demo to use the latest PWM driver in light demo.
|
10.Update IOT_Demo to use the latest PWM driver in light demo.
|
||||||
11.Provide liblwip_536.a of which MSS size is 536
|
11.Provide liblwip_536.a of which MSS size is 536
|
||||||
12.Revised issue that boot may fail when 80Mhz SPI clock selected
|
12.Revised issue that boot may fail when 80Mhz SPI clock selected
|
||||||
13.Update esp_init_data_default.bin about RF option in \esp_iot_sdk\bin
|
13.Update esp_init_data_default.bin about RF option in \esp_iot_sdk\bin
|
||||||
|
|
||||||
Added APIs:
|
Added APIs:
|
||||||
1.PWM APIs:
|
1.PWM APIs:
|
||||||
Updated: pwm_init,add parameter to set PWM channel and GPIO pin
|
Updated: pwm_init,add parameter to set PWM channel and GPIO pin
|
||||||
Added:
|
Added:
|
||||||
(1)get_pwm_version:get version information of PWM driver
|
(1)get_pwm_version:get version information of PWM driver
|
||||||
(2)pwm_set_period:set PWM period
|
(2)pwm_set_period:set PWM period
|
||||||
@ -200,23 +258,23 @@ Deleted:
|
|||||||
(2)pwm_get_freq:get PWM frequency
|
(2)pwm_get_freq:get PWM frequency
|
||||||
2.Read/write flash with protection
|
2.Read/write flash with protection
|
||||||
(1)system_param_save_with_protect:write data into flash with backup protection
|
(1)system_param_save_with_protect:write data into flash with backup protection
|
||||||
(2)system_param_load:read data which saved into flash with backup protection
|
(2)system_param_load:read data which saved into flash with backup protection
|
||||||
3.system_get_rst_info:get information about current startup,it is a normal startup or watch dog reset
|
3.system_get_rst_info:get information about current startup,it is a normal startup or watch dog reset
|
||||||
4.at_response:set AT response
|
4.at_response:set AT response
|
||||||
5.at_register_response_func:register a callback for user-define AT response.
|
5.at_register_response_func:register a callback for user-define AT response.
|
||||||
6.Update document "2C_ESP8266__Programming Guide" to add description of interrupt definition in ets_sys.h
|
6.Update document "2C_ESP8266__Programming Guide" to add description of interrupt definition in ets_sys.h
|
||||||
|
|
||||||
AT_v0.25 Release Note:
|
AT_v0.25 Release Note:
|
||||||
Note: For AT firmware to support FOTA, flash size need to be 1024KB or more than that.
|
Note: For AT firmware to support FOTA, flash size need to be 1024KB or more than that.
|
||||||
Optimization:
|
Optimization:
|
||||||
1.Add parameter about UDP local port in command "AT+SAVETRANSLINK"
|
1.Add parameter about UDP local port in command "AT+SAVETRANSLINK"
|
||||||
|
|
||||||
Added AT command:
|
Added AT command:
|
||||||
1.AT+CIPDINFO:set configuration whether show remote IP and remote port with “+IPD” or not
|
1.AT+CIPDINFO:set configuration whether show remote IP and remote port with “+IPD” or not
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
esp_iot_sdk_v1.1.0_15_05_27_p1 Release Note
|
esp_iot_sdk_v1.1.0_15_05_27_p1 Release Note
|
||||||
-------------------------------------------
|
-------------------------------------------
|
||||||
|
|
||||||
Here is a patch based on SDK_v1.1.0 resolved issues below:
|
Here is a patch based on SDK_v1.1.0 resolved issues below:
|
||||||
@ -226,7 +284,7 @@ Here is a patch based on SDK_v1.1.0 resolved issues below:
|
|||||||
|
|
||||||
Sorry for the inconvenience.
|
Sorry for the inconvenience.
|
||||||
|
|
||||||
esp_iot_sdk_v1.1.0_15_05_22 Release Note
|
esp_iot_sdk_v1.1.0_15_05_22 Release Note
|
||||||
----------------------------------------
|
----------------------------------------
|
||||||
Resolved Issues(Bugs below are eligible for Bug Bounty Program):
|
Resolved Issues(Bugs below are eligible for Bug Bounty Program):
|
||||||
1.Predictable TLS random values leads to insecure connections [projectgus]
|
1.Predictable TLS random values leads to insecure connections [projectgus]
|
||||||
@ -257,26 +315,26 @@ Added APIs:
|
|||||||
3.system_uart_de_swap : disable UART0 swap
|
3.system_uart_de_swap : disable UART0 swap
|
||||||
4.system_get_flash_size_map: get flash size and flash map
|
4.system_get_flash_size_map: get flash size and flash map
|
||||||
5.system_phy_set_max_tpw : set maximum RF TX power
|
5.system_phy_set_max_tpw : set maximum RF TX power
|
||||||
6.system_phy_set_tpw_via_vdd33 :set RF TX power according to VDD33
|
6.system_phy_set_tpw_via_vdd33 :set RF TX power according to VDD33
|
||||||
7.system_phy_set_rfoption : set RF option
|
7.system_phy_set_rfoption : set RF option
|
||||||
8.wifi_station_get_rssi:get rssi of AP which ESP8266 station connected to
|
8.wifi_station_get_rssi:get rssi of AP which ESP8266 station connected to
|
||||||
9.wifi_softap_get_station_num :get number count of stations connected to ESP8266 soft-AP
|
9.wifi_softap_get_station_num :get number count of stations connected to ESP8266 soft-AP
|
||||||
|
|
||||||
AT_v0.24 Release Note:
|
AT_v0.24 Release Note:
|
||||||
Note: For AT firmware to support FOTA, flash size need to be 1024KB or more than that.
|
Note: For AT firmware to support FOTA, flash size need to be 1024KB or more than that.
|
||||||
Optimization:
|
Optimization:
|
||||||
1.Disable data echo of command "AT+CIPSEND"
|
1.Disable data echo of command "AT+CIPSEND"
|
||||||
2.Optimized "AT+CWJAP?" to get channel and rssi
|
2.Optimized "AT+CWJAP?" to get channel and rssi
|
||||||
3.ESP8266 station IP can only be got and inquiried after ESP8266 station connected to AP
|
3.ESP8266 station IP can only be got and inquiried after ESP8266 station connected to AP
|
||||||
|
|
||||||
Added AT command:
|
Added AT command:
|
||||||
1.AT+RFPOWER :set maximum RF TX power
|
1.AT+RFPOWER :set maximum RF TX power
|
||||||
2.AT+RFVDD : set RF TX power according to VDD33
|
2.AT+RFVDD : set RF TX power according to VDD33
|
||||||
|
|
||||||
|
|
||||||
自从乐鑫信息科技于 2015-03-20 启动 Bug 赏金计划以来,我们收到了一些重要问题反馈及建议,感谢世界各地的开发者对 ESP8266的关注,推动我们的软件更进一步,技术支持团队也得到迅速地成长。我们将在如下发布日志中点名感谢您的帮助。
|
自从乐鑫信息科技于 2015-03-20 启动 Bug 赏金计划以来,我们收到了一些重要问题反馈及建议,感谢世界各地的开发者对 ESP8266的关注,推动我们的软件更进一步,技术支持团队也得到迅速地成长。我们将在如下发布日志中点名感谢您的帮助。
|
||||||
|
|
||||||
esp_iot_sdk_v1.1.0_15_05_22 Release Note
|
esp_iot_sdk_v1.1.0_15_05_22 Release Note
|
||||||
修正问题(符合乐鑫 Bug 赏金计划):
|
修正问题(符合乐鑫 Bug 赏金计划):
|
||||||
1.随机值的生成可以被预测,完善随机数的产生机制 [projectgus]
|
1.随机值的生成可以被预测,完善随机数的产生机制 [projectgus]
|
||||||
2.softAP+station 模式下,可能连接 ESP8266 soft-AP 失败 [智捷通]
|
2.softAP+station 模式下,可能连接 ESP8266 soft-AP 失败 [智捷通]
|
||||||
@ -307,11 +365,11 @@ esp_iot_sdk_v1.1.0_15_05_22 Release Note
|
|||||||
4.system_get_flash_size_map: 查询 flash size 和 flash map
|
4.system_get_flash_size_map: 查询 flash size 和 flash map
|
||||||
5.system_phy_set_max_tpw : 设置 RF TX power 最大值
|
5.system_phy_set_max_tpw : 设置 RF TX power 最大值
|
||||||
6.system_phy_set_tpw_via_vdd33 :根据 VDD33 设置 RF TX power
|
6.system_phy_set_tpw_via_vdd33 :根据 VDD33 设置 RF TX power
|
||||||
7.system_phy_set_rfoption : 设置 RF
|
7.system_phy_set_rfoption : 设置 RF
|
||||||
8.wifi_station_get_rssi:查询 ESP8266 station 连接的 AP 的信号强度
|
8.wifi_station_get_rssi:查询 ESP8266 station 连接的 AP 的信号强度
|
||||||
9.wifi_softap_get_station_num :查询连接到 ESP8266 soft-AP 的 station 数目
|
9.wifi_softap_get_station_num :查询连接到 ESP8266 soft-AP 的 station 数目
|
||||||
|
|
||||||
AT_v0.24 Release Note:
|
AT_v0.24 Release Note:
|
||||||
注意:运行 AT 固件,支持云端升级,请使用 1024KB 或以上容量的 flash
|
注意:运行 AT 固件,支持云端升级,请使用 1024KB 或以上容量的 flash
|
||||||
|
|
||||||
优化:
|
优化:
|
||||||
@ -319,7 +377,7 @@ AT_v0.24 Release Note:
|
|||||||
2.优化"AT+CWJAP?" 可获得信道和信号强度
|
2.优化"AT+CWJAP?" 可获得信道和信号强度
|
||||||
3.必须在 ESP8266 station 连接到 AP 后,才能查询到 ESP8266 station IP
|
3.必须在 ESP8266 station 连接到 AP 后,才能查询到 ESP8266 station IP
|
||||||
|
|
||||||
新增 AT command:
|
新增 AT command:
|
||||||
1.AT+RFPOWER :设置 RF TX power 最大值
|
1.AT+RFPOWER :设置 RF TX power 最大值
|
||||||
2.AT+RFVDD : 根据 VDD33 设置 RF TX power
|
2.AT+RFVDD : 根据 VDD33 设置 RF TX power
|
||||||
|
|
||||||
@ -327,68 +385,68 @@ Thanks for your interest in ESP8266 !
|
|||||||
|
|
||||||
esp_iot_sdk_v1.0.1_15_05_04_p1
|
esp_iot_sdk_v1.0.1_15_05_04_p1
|
||||||
-------------------------------------------
|
-------------------------------------------
|
||||||
Here is a patch for station+softAP issue that users may have, based on SDK_v1.0.1,
|
Here is a patch for station+softAP issue that users may have, based on SDK_v1.0.1,
|
||||||
solved problem that connect to ESP8266 softAP may fail in station+softAP mode.
|
solved problem that connect to ESP8266 softAP may fail in station+softAP mode.
|
||||||
|
|
||||||
Sorry for the inconvenience.
|
Sorry for the inconvenience.
|
||||||
|
|
||||||
esp_iot_sdk_v1.0.1_15_04_24 Release Note
|
esp_iot_sdk_v1.0.1_15_04_24 Release Note
|
||||||
-------------------------------------------
|
-------------------------------------------
|
||||||
|
|
||||||
Resolved Issues(Bugs below are eligible for Bug Bounty Program):
|
Resolved Issues(Bugs below are eligible for Bug Bounty Program):
|
||||||
1. SSL connection may fail if SSL packet size larger than 2kBytes [PeteW ]
|
1. SSL connection may fail if SSL packet size larger than 2kBytes [PeteW ]
|
||||||
2. UDP remote IP to be 0.0.0.0 may cause reset [Jerry S]
|
2. UDP remote IP to be 0.0.0.0 may cause reset [Jerry S]
|
||||||
3. Optimize wifi_get_ip_info to fix loss of wireless connectivity problem
|
3. Optimize wifi_get_ip_info to fix loss of wireless connectivity problem
|
||||||
4. Air-Kiss restart [Orgmar]
|
4. Air-Kiss restart [Orgmar]
|
||||||
|
|
||||||
Optimization:
|
Optimization:
|
||||||
1. Optimized IOT_Espressif_EspTouch.APK (apply for access from Espressif) for improved compatibility. [???]
|
1. Optimized IOT_Espressif_EspTouch.APK (apply for access from Espressif) for improved compatibility. [???]
|
||||||
2. TCP server can not open again immediately with the same port [624908539]
|
2. TCP server can not open again immediately with the same port [624908539]
|
||||||
3. Update UART driver for parity bit value may be incorrect [1062583993]
|
3. Update UART driver for parity bit value may be incorrect [1062583993]
|
||||||
4. Add define of “ICACHE_RODATA_ATTR” for Symbol 'ICACHE_RODATA_ATTR' could not be resolved. [???]
|
4. Add define of “ICACHE_RODATA_ATTR” for Symbol 'ICACHE_RODATA_ATTR' could not be resolved. [???]
|
||||||
5. Add API wifi_softap_dhcps_set_offer_option to enable/disable ESP8266 softAP DHCP server default gateway. [xyz769]
|
5. Add API wifi_softap_dhcps_set_offer_option to enable/disable ESP8266 softAP DHCP server default gateway. [xyz769]
|
||||||
6. AT register_uart_rx_intr may enter callback twice. [???]
|
6. AT register_uart_rx_intr may enter callback twice. [???]
|
||||||
7.optimize document that WPA password length range : 8 ~ 64 bytes [785057041]
|
7.optimize document that WPA password length range : 8 ~ 64 bytes [785057041]
|
||||||
8. ESP8266 softAP DHCP server record 8 DHCP client's IP at most [ygjeon]
|
8. ESP8266 softAP DHCP server record 8 DHCP client's IP at most [ygjeon]
|
||||||
9. To set static IP (wifi_set_ip_info) has to disable DHCP first(wifi_softap_dhcps_stop or wifi_station_dhcpc_stop)
|
9. To set static IP (wifi_set_ip_info) has to disable DHCP first(wifi_softap_dhcps_stop or wifi_station_dhcpc_stop)
|
||||||
10.Add example of wifi_softap_set_dhcps_lease
|
10.Add example of wifi_softap_set_dhcps_lease
|
||||||
11. smartconfig_start can only be called in ESP8266 station mode
|
11. smartconfig_start can only be called in ESP8266 station mode
|
||||||
|
|
||||||
Added APIs:
|
Added APIs:
|
||||||
1. Wi-Fi related APIs:
|
1. Wi-Fi related APIs:
|
||||||
wifi_station_set_reconnect_policy: enable/disable reconnect when ESP8266 disconnect from router,default to be enable reconnect.
|
wifi_station_set_reconnect_policy: enable/disable reconnect when ESP8266 disconnect from router,default to be enable reconnect.
|
||||||
wifi_set_event_handler_cb: set event handler of ESP8266 softAP or station status change.
|
wifi_set_event_handler_cb: set event handler of ESP8266 softAP or station status change.
|
||||||
wifi_softap_dhcps_set_offer_option: enable/disable get router information from ESP8266 softAP, default to be enable.
|
wifi_softap_dhcps_set_offer_option: enable/disable get router information from ESP8266 softAP, default to be enable.
|
||||||
2. SNTP APIs:
|
2. SNTP APIs:
|
||||||
sntp_get_current_timestamp: get current timestamp from Jan 01, 1970, 00:00 (GMT)
|
sntp_get_current_timestamp: get current timestamp from Jan 01, 1970, 00:00 (GMT)
|
||||||
sntp_get_real_time: char,get real time (GTM + 8 time zone)
|
sntp_get_real_time: char,get real time (GTM + 8 time zone)
|
||||||
sntp_init: initialize SNTP
|
sntp_init: initialize SNTP
|
||||||
sntp_stop: stop SNTP
|
sntp_stop: stop SNTP
|
||||||
sntp_setserver: set SNTP server by IP
|
sntp_setserver: set SNTP server by IP
|
||||||
sntp_getserver: get SNTP server IP
|
sntp_getserver: get SNTP server IP
|
||||||
sntp_setservername: set SNTP server by domain name
|
sntp_setservername: set SNTP server by domain name
|
||||||
sntp_getservername: get domain name of SNTP server set by sntp_setservername
|
sntp_getservername: get domain name of SNTP server set by sntp_setservername
|
||||||
3. MDNS APIs:
|
3. MDNS APIs:
|
||||||
espconn_mdns_init: initialize mDNS
|
espconn_mdns_init: initialize mDNS
|
||||||
espconn_mdns_close: close mDNS
|
espconn_mdns_close: close mDNS
|
||||||
espconn_mdns_server_register: register mDNS server
|
espconn_mdns_server_register: register mDNS server
|
||||||
espconn_mdns_server_unregister: unregister mDNS server
|
espconn_mdns_server_unregister: unregister mDNS server
|
||||||
espconn_mdns_get_servername: get mDNS server name
|
espconn_mdns_get_servername: get mDNS server name
|
||||||
espconn_mdns_set_servername: set mDNS server name
|
espconn_mdns_set_servername: set mDNS server name
|
||||||
espconn_mdns_set_hostname: get mDNS host name
|
espconn_mdns_set_hostname: get mDNS host name
|
||||||
espconn_mdns_get_hostname: set mDNS host name
|
espconn_mdns_get_hostname: set mDNS host name
|
||||||
espconn_mdns_disable: disable mDNS
|
espconn_mdns_disable: disable mDNS
|
||||||
espconn_mdns_enable: endisable mDNS
|
espconn_mdns_enable: endisable mDNS
|
||||||
|
|
||||||
AT_v0.23 Release Note:
|
AT_v0.23 Release Note:
|
||||||
Optimized:
|
Optimized:
|
||||||
1.AT+CWJAP add parameter "bssid", for several APs may have the same SSID
|
1.AT+CWJAP add parameter "bssid", for several APs may have the same SSID
|
||||||
|
|
||||||
New AT commands:
|
New AT commands:
|
||||||
1. AT+CIPSENDBUF: write data into TCP-send-buffer; non-blocking. Background task automatically handles transmission. Has much higher throughput.
|
1. AT+CIPSENDBUF: write data into TCP-send-buffer; non-blocking. Background task automatically handles transmission. Has much higher throughput.
|
||||||
2. AT+CIPBUFRESET: resets segment count in TCP-send-buffer
|
2. AT+CIPBUFRESET: resets segment count in TCP-send-buffer
|
||||||
3. AT+CIPBUFSTATUS: checks status of TCP-send-buffer
|
3. AT+CIPBUFSTATUS: checks status of TCP-send-buffer
|
||||||
4. AT+CIPCHECKSEGID: checks if a specific segment in TCP-send-buffer has sent successfully
|
4. AT+CIPCHECKSEGID: checks if a specific segment in TCP-send-buffer has sent successfully
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -396,7 +454,7 @@ esp_iot_sdk_v1.0.1_b2_15_04_10 release note
|
|||||||
-------------------------------------------
|
-------------------------------------------
|
||||||
|
|
||||||
Fix bugs:
|
Fix bugs:
|
||||||
1.Call espconn_sent to send UDP packet in user_init cause reset.[BBP#2 reporter (????)]
|
1.Call espconn_sent to send UDP packet in user_init cause reset.[BBP#2 reporter (????)]
|
||||||
2.UART & FlowControl issue: send data to FIFO without CTS flag will cause WDT [BBP#11 reporter (pvxx)]
|
2.UART & FlowControl issue: send data to FIFO without CTS flag will cause WDT [BBP#11 reporter (pvxx)]
|
||||||
3.SSL issue,add an API (espconn_secure_set_size) to set SSL buffer size [BBP#29 reporter (PeteW)]
|
3.SSL issue,add an API (espconn_secure_set_size) to set SSL buffer size [BBP#29 reporter (PeteW)]
|
||||||
4.UDP broadcast issue in WEP
|
4.UDP broadcast issue in WEP
|
||||||
@ -485,21 +543,21 @@ Add AT commands:
|
|||||||
XXX_DEF: default, set configuration and save it to Flash
|
XXX_DEF: default, set configuration and save it to Flash
|
||||||
2. Add SmartConfig in AT:
|
2. Add SmartConfig in AT:
|
||||||
AT+CWSTARTSMART/AT+CWSTOPSMART: start / stop SmartConfig
|
AT+CWSTARTSMART/AT+CWSTOPSMART: start / stop SmartConfig
|
||||||
Notice: please refer to the document, call "AT+CWSTOPSMART" to stop SmartConfig first since "AT+CWSTARTSMART", then call other AT commands. Don't call any other AT commands during SmartConfig.
|
Notice: please refer to the document, call "AT+CWSTOPSMART" to stop SmartConfig first since "AT+CWSTARTSMART", then call other AT commands. Don't call any other AT commands during SmartConfig.
|
||||||
2. AT+SAVETRANSLINK: save transparent transmission link to Flash;
|
2. AT+SAVETRANSLINK: save transparent transmission link to Flash;
|
||||||
Note:AT+CIPMODE=1 set to enter transparent transmission mode, won't save to Flash.
|
Note:AT+CIPMODE=1 set to enter transparent transmission mode, won't save to Flash.
|
||||||
|
|
||||||
|
|
||||||
Add AT APIs
|
Add AT APIs
|
||||||
1. at_customLinkMax: set the max link that allowed, most can be 10; if you want to set it, please set it before at_init; if you didn't set it, the max link allowed is 5 by default.
|
1. at_customLinkMax: set the max link that allowed, most can be 10; if you want to set it, please set it before at_init; if you didn't set it, the max link allowed is 5 by default.
|
||||||
2. at_enter_special_state/ at_leave_special_state:Enter/leave AT processing state. In processing state, AT core will return "busy" for any further AT commands.
|
2. at_enter_special_state/ at_leave_special_state:Enter/leave AT processing state. In processing state, AT core will return "busy" for any further AT commands.
|
||||||
3. at_set_custom_info:set custom version information of AT which can be got by AT+GMR;
|
3. at_set_custom_info:set custom version information of AT which can be got by AT+GMR;
|
||||||
4. at_get_version:get version information of AT lib .
|
4. at_get_version:get version information of AT lib .
|
||||||
|
|
||||||
Optimize
|
Optimize
|
||||||
1. Add UDP remote ip and remote port is allowed to be parameters of "AT+CIPSEND"
|
1. Add UDP remote ip and remote port is allowed to be parameters of "AT+CIPSEND"
|
||||||
2. Move "AT+CIUPDATE" from lib to AT "demo\esp_iot_sdk\examples\at", AT demo shows how to upgrade AT firmware from a local server. Notice that AT upgrade the bin files name have to be "user1.bin" and "user2.bin".
|
2. Move "AT+CIUPDATE" from lib to AT "demo\esp_iot_sdk\examples\at", AT demo shows how to upgrade AT firmware from a local server. Notice that AT upgrade the bin files name have to be "user1.bin" and "user2.bin".
|
||||||
3. Optimize "AT+CIPSTA", add gateway and netmask as parameters
|
3. Optimize "AT+CIPSTA", add gateway and netmask as parameters
|
||||||
4. Optimize transparent transmission.
|
4. Optimize transparent transmission.
|
||||||
|
|
||||||
esp_iot_sdk_v0.9.5_15_01_22 Release Note
|
esp_iot_sdk_v0.9.5_15_01_22 Release Note
|
||||||
@ -532,7 +590,7 @@ Optimize:
|
|||||||
6. update to boot v1.2 to support new format user.bin;
|
6. update to boot v1.2 to support new format user.bin;
|
||||||
7. update ARP
|
7. update ARP
|
||||||
8. update SSL
|
8. update SSL
|
||||||
9. revised system_deep_sleep,system_deep_sleep(0),set no wake up timer,connect a GPIO to pin RST, the chip will wake up by a falling-edge on pin RST
|
9. revised system_deep_sleep,system_deep_sleep(0),set no wake up timer,connect a GPIO to pin RST, the chip will wake up by a falling-edge on pin RST
|
||||||
|
|
||||||
esp_iot_sdk_v0.9.4_14_12_19 Release Note
|
esp_iot_sdk_v0.9.4_14_12_19 Release Note
|
||||||
----------------------------------------
|
----------------------------------------
|
||||||
|
@ -24,7 +24,7 @@ typedef void (* espconn_reconnect_callback)(void *arg, sint8 err);
|
|||||||
#define ESPCONN_ISCONN -15 /* Already connected. */
|
#define ESPCONN_ISCONN -15 /* Already connected. */
|
||||||
|
|
||||||
#define ESPCONN_HANDSHAKE -28 /* ssl handshake failed */
|
#define ESPCONN_HANDSHAKE -28 /* ssl handshake failed */
|
||||||
#define ESPCONN_PROTO_MSG -61 /* ssl application invalid */
|
#define ESPCONN_SSL_INVALID_DATA -61 /* ssl application invalid */
|
||||||
|
|
||||||
/** Protocol family and type of the espconn */
|
/** Protocol family and type of the espconn */
|
||||||
enum espconn_type {
|
enum espconn_type {
|
||||||
@ -267,6 +267,17 @@ sint8 espconn_regist_sentcb(struct espconn *espconn, espconn_sent_callback sent_
|
|||||||
|
|
||||||
sint8 espconn_regist_write_finish(struct espconn *espconn, espconn_connect_callback write_finish_fn);
|
sint8 espconn_regist_write_finish(struct espconn *espconn, espconn_connect_callback write_finish_fn);
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
* FunctionName : espconn_send
|
||||||
|
* Description : sent data for client or server
|
||||||
|
* Parameters : espconn -- espconn to set for client or server
|
||||||
|
* psent -- data to send
|
||||||
|
* length -- length of data to send
|
||||||
|
* Returns : none
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
|
sint8 espconn_send(struct espconn *espconn, uint8 *psent, uint16 length);
|
||||||
|
|
||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
* FunctionName : espconn_sent
|
* FunctionName : espconn_sent
|
||||||
* Description : sent data for client or server
|
* Description : sent data for client or server
|
||||||
@ -426,6 +437,17 @@ sint8 espconn_secure_connect(struct espconn *espconn);
|
|||||||
|
|
||||||
sint8 espconn_secure_disconnect(struct espconn *espconn);
|
sint8 espconn_secure_disconnect(struct espconn *espconn);
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
* FunctionName : espconn_secure_send
|
||||||
|
* Description : sent data for client or server
|
||||||
|
* Parameters : espconn -- espconn to set for client or server
|
||||||
|
* psent -- data to send
|
||||||
|
* length -- length of data to send
|
||||||
|
* Returns : none
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
|
sint8 espconn_secure_send(struct espconn *espconn, uint8 *psent, uint16 length);
|
||||||
|
|
||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
* FunctionName : espconn_encry_sent
|
* FunctionName : espconn_encry_sent
|
||||||
* Description : sent data for client or server
|
* Description : sent data for client or server
|
||||||
|
@ -13,12 +13,16 @@ enum esp_now_role {
|
|||||||
ESP_NOW_ROLE_MAX,
|
ESP_NOW_ROLE_MAX,
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef void (*esp_now_cb_t)(u8 *mac_addr, u8 *data, u8 len);
|
typedef void (*esp_now_recv_cb_t)(u8 *mac_addr, u8 *data, u8 len);
|
||||||
|
typedef void (*esp_now_send_cb_t)(u8 *mac_addr, u8 status);
|
||||||
|
|
||||||
int esp_now_init(void);
|
int esp_now_init(void);
|
||||||
int esp_now_deinit(void);
|
int esp_now_deinit(void);
|
||||||
|
|
||||||
int esp_now_register_recv_cb(esp_now_cb_t cb);
|
int esp_now_register_send_cb(esp_now_send_cb_t cb);
|
||||||
|
int esp_now_unregister_send_cb(void);
|
||||||
|
|
||||||
|
int esp_now_register_recv_cb(esp_now_recv_cb_t cb);
|
||||||
int esp_now_unregister_recv_cb(void);
|
int esp_now_unregister_recv_cb(void);
|
||||||
|
|
||||||
int esp_now_send(u8 *da, u8 *data, int len);
|
int esp_now_send(u8 *da, u8 *data, int len);
|
||||||
@ -44,4 +48,6 @@ int esp_now_is_peer_exist(u8 *mac_addr);
|
|||||||
|
|
||||||
int esp_now_get_cnt_info(u8 *all_cnt, u8 *encrypt_cnt);
|
int esp_now_get_cnt_info(u8 *all_cnt, u8 *encrypt_cnt);
|
||||||
|
|
||||||
|
int esp_now_set_kok(u8 *key, u8 len);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -65,8 +65,8 @@ inline bool ETS_INTR_WITHINISR()
|
|||||||
{
|
{
|
||||||
uint32_t ps;
|
uint32_t ps;
|
||||||
__asm__ __volatile__("rsr %0,ps":"=a" (ps));
|
__asm__ __volatile__("rsr %0,ps":"=a" (ps));
|
||||||
// PS.EXCM bit check
|
// PS.INTLEVEL check
|
||||||
return ((ps & (1 << 4)) != 0);
|
return ((ps & 0x0f) != 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline uint32_t ETS_INTR_ENABLED(void)
|
inline uint32_t ETS_INTR_ENABLED(void)
|
||||||
|
@ -23,7 +23,7 @@ typedef enum {
|
|||||||
} GPIO_INT_TYPE;
|
} GPIO_INT_TYPE;
|
||||||
|
|
||||||
#define GPIO_OUTPUT_SET(gpio_no, bit_value) \
|
#define GPIO_OUTPUT_SET(gpio_no, bit_value) \
|
||||||
gpio_output_set(bit_value<<gpio_no, ((~bit_value)&0x01)<<gpio_no, 1<<gpio_no,0)
|
gpio_output_set((bit_value)<<gpio_no, ((~(bit_value))&0x01)<<gpio_no, 1<<gpio_no,0)
|
||||||
#define GPIO_DIS_OUTPUT(gpio_no) gpio_output_set(0,0,0, 1<<gpio_no)
|
#define GPIO_DIS_OUTPUT(gpio_no) gpio_output_set(0,0,0, 1<<gpio_no)
|
||||||
#define GPIO_INPUT_GET(gpio_no) ((gpio_input_get()>>gpio_no)&BIT0)
|
#define GPIO_INPUT_GET(gpio_no) ((gpio_input_get()>>gpio_no)&BIT0)
|
||||||
|
|
||||||
|
0
tools/sdk/include/json/json.h
Executable file → Normal file
0
tools/sdk/include/json/json.h
Executable file → Normal file
0
tools/sdk/include/json/jsonparse.h
Executable file → Normal file
0
tools/sdk/include/json/jsonparse.h
Executable file → Normal file
0
tools/sdk/include/json/jsontree.h
Executable file → Normal file
0
tools/sdk/include/json/jsontree.h
Executable file → Normal file
5
tools/sdk/include/upgrade.h
Executable file → Normal file
5
tools/sdk/include/upgrade.h
Executable file → Normal file
@ -2,6 +2,7 @@
|
|||||||
#define __UPGRADE_H__
|
#define __UPGRADE_H__
|
||||||
|
|
||||||
#define SPI_FLASH_SEC_SIZE 4096
|
#define SPI_FLASH_SEC_SIZE 4096
|
||||||
|
#define LIMIT_ERASE_SIZE 0x10000
|
||||||
|
|
||||||
#define USER_BIN1 0x00
|
#define USER_BIN1 0x00
|
||||||
#define USER_BIN2 0x01
|
#define USER_BIN2 0x01
|
||||||
@ -37,14 +38,12 @@ struct upgrade_server_info {
|
|||||||
#define UPGRADE_FLAG_START 0x01
|
#define UPGRADE_FLAG_START 0x01
|
||||||
#define UPGRADE_FLAG_FINISH 0x02
|
#define UPGRADE_FLAG_FINISH 0x02
|
||||||
|
|
||||||
//bool system_upgrade_start(struct upgrade_server_info *server);
|
|
||||||
bool system_upgrade_start_ssl(struct upgrade_server_info *server);
|
|
||||||
void system_upgrade_init();
|
void system_upgrade_init();
|
||||||
void system_upgrade_deinit();
|
void system_upgrade_deinit();
|
||||||
bool system_upgrade(uint8 *data, uint16 len);
|
bool system_upgrade(uint8 *data, uint16 len);
|
||||||
|
|
||||||
#ifdef UPGRADE_SSL_ENABLE
|
#ifdef UPGRADE_SSL_ENABLE
|
||||||
bool system_upgrade_start_ssl(struct upgrade_server_info *server);
|
bool system_upgrade_start_ssl(struct upgrade_server_info *server); // not supported now
|
||||||
#else
|
#else
|
||||||
bool system_upgrade_start(struct upgrade_server_info *server);
|
bool system_upgrade_start(struct upgrade_server_info *server);
|
||||||
#endif
|
#endif
|
||||||
|
@ -28,10 +28,11 @@ enum rst_reason {
|
|||||||
REASON_EXCEPTION_RST = 2,
|
REASON_EXCEPTION_RST = 2,
|
||||||
REASON_SOFT_WDT_RST = 3,
|
REASON_SOFT_WDT_RST = 3,
|
||||||
REASON_SOFT_RESTART = 4,
|
REASON_SOFT_RESTART = 4,
|
||||||
REASON_DEEP_SLEEP_AWAKE = 5
|
REASON_DEEP_SLEEP_AWAKE = 5,
|
||||||
|
REASON_EXT_SYS_RST = 6
|
||||||
};
|
};
|
||||||
|
|
||||||
struct rst_info {
|
struct rst_info{
|
||||||
uint32 reason;
|
uint32 reason;
|
||||||
uint32 exccause;
|
uint32 exccause;
|
||||||
uint32 epc1;
|
uint32 epc1;
|
||||||
@ -137,6 +138,7 @@ bool system_param_load(uint16 start_sec, uint16 offset, void *param, uint16 len)
|
|||||||
|
|
||||||
void system_soft_wdt_stop(void);
|
void system_soft_wdt_stop(void);
|
||||||
void system_soft_wdt_restart(void);
|
void system_soft_wdt_restart(void);
|
||||||
|
void system_soft_wdt_feed(void);
|
||||||
|
|
||||||
#define NULL_MODE 0x00
|
#define NULL_MODE 0x00
|
||||||
#define STATION_MODE 0x01
|
#define STATION_MODE 0x01
|
||||||
@ -283,6 +285,7 @@ void wifi_softap_free_station_info(void);
|
|||||||
bool wifi_softap_dhcps_start(void);
|
bool wifi_softap_dhcps_start(void);
|
||||||
bool wifi_softap_dhcps_stop(void);
|
bool wifi_softap_dhcps_stop(void);
|
||||||
bool wifi_softap_set_dhcps_lease(struct dhcps_lease *please);
|
bool wifi_softap_set_dhcps_lease(struct dhcps_lease *please);
|
||||||
|
bool wifi_softap_get_dhcps_lease(struct dhcps_lease *please);
|
||||||
enum dhcp_status wifi_softap_dhcps_status(void);
|
enum dhcp_status wifi_softap_dhcps_status(void);
|
||||||
bool wifi_softap_set_dhcps_offer_option(uint8 level, void* optarg);
|
bool wifi_softap_set_dhcps_offer_option(uint8 level, void* optarg);
|
||||||
|
|
||||||
@ -430,17 +433,18 @@ typedef enum wps_type {
|
|||||||
WPS_TYPE_MAX
|
WPS_TYPE_MAX
|
||||||
} WPS_TYPE_t;
|
} WPS_TYPE_t;
|
||||||
|
|
||||||
typedef enum wps_cb_status {
|
enum wps_cb_status {
|
||||||
WPS_CB_ST_SUCCESS = 0,
|
WPS_CB_ST_SUCCESS = 0,
|
||||||
WPS_CB_ST_FAILED,
|
WPS_CB_ST_FAILED,
|
||||||
WPS_CB_ST_TIMEOUT
|
WPS_CB_ST_TIMEOUT,
|
||||||
} WPS_CB_STATUS_t;
|
WPS_CB_ST_WEP,
|
||||||
|
};
|
||||||
|
|
||||||
bool wifi_wps_enable(WPS_TYPE_t wps_type);
|
bool wifi_wps_enable(WPS_TYPE_t wps_type);
|
||||||
bool wifi_wps_disable(void);
|
bool wifi_wps_disable(void);
|
||||||
bool wifi_wps_start(void);
|
bool wifi_wps_start(void);
|
||||||
|
|
||||||
typedef void (*wps_st_cb_t)(WPS_CB_STATUS_t status);
|
typedef void (*wps_st_cb_t)(int status);
|
||||||
bool wifi_set_wps_cb(wps_st_cb_t cb);
|
bool wifi_set_wps_cb(wps_st_cb_t cb);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -1 +1 @@
|
|||||||
1.2.0_15_07_13_p4
|
1.3.0_15_08_10_p1
|
Loading…
x
Reference in New Issue
Block a user