mirror of
https://github.com/esp8266/Arduino.git
synced 2025-04-21 10:26:06 +03:00
Merge remote-tracking branch 'esp8266/master'
This commit is contained in:
commit
5edcaa0eed
@ -814,6 +814,7 @@ wifinfo.build.f_cpu=80000000L
|
|||||||
wifinfo.build.core=esp8266
|
wifinfo.build.core=esp8266
|
||||||
wifinfo.build.variant=wifinfo
|
wifinfo.build.variant=wifinfo
|
||||||
wifinfo.build.flash_mode=qio
|
wifinfo.build.flash_mode=qio
|
||||||
|
wifinfo.build.board=ESP8266_ESP12
|
||||||
wifinfo.build.spiffs_pagesize=256
|
wifinfo.build.spiffs_pagesize=256
|
||||||
|
|
||||||
#wifinfo.menu.ESPModule.ESP07512=ESP07 (1M/512K SPIFFS)
|
#wifinfo.menu.ESPModule.ESP07512=ESP07 (1M/512K SPIFFS)
|
||||||
|
@ -177,26 +177,7 @@ uint32_t EspClass::getFlashChipSize(void)
|
|||||||
uint8_t * bytes = (uint8_t *) &data;
|
uint8_t * bytes = (uint8_t *) &data;
|
||||||
// read first 4 byte (magic byte + flash config)
|
// read first 4 byte (magic byte + flash config)
|
||||||
if(spi_flash_read(0x0000, &data, 4) == SPI_FLASH_RESULT_OK) {
|
if(spi_flash_read(0x0000, &data, 4) == SPI_FLASH_RESULT_OK) {
|
||||||
switch((bytes[3] & 0xf0) >> 4) {
|
return magicFlashChipSize((bytes[3] & 0xf0) >> 4);
|
||||||
case 0x0: // 4 Mbit (512KB)
|
|
||||||
return (512_kB);
|
|
||||||
case 0x1: // 2 MBit (256KB)
|
|
||||||
return (256_kB);
|
|
||||||
case 0x2: // 8 MBit (1MB)
|
|
||||||
return (1_MB);
|
|
||||||
case 0x3: // 16 MBit (2MB)
|
|
||||||
return (2_MB);
|
|
||||||
case 0x4: // 32 MBit (4MB)
|
|
||||||
return (4_MB);
|
|
||||||
case 0x5: // 64 MBit (8MB)
|
|
||||||
return (8_MB);
|
|
||||||
case 0x6: // 128 MBit (16MB)
|
|
||||||
return (16_MB);
|
|
||||||
case 0x7: // 256 MBit (32MB)
|
|
||||||
return (32_MB);
|
|
||||||
default: // fail?
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -207,18 +188,7 @@ uint32_t EspClass::getFlashChipSpeed(void)
|
|||||||
uint8_t * bytes = (uint8_t *) &data;
|
uint8_t * bytes = (uint8_t *) &data;
|
||||||
// read first 4 byte (magic byte + flash config)
|
// read first 4 byte (magic byte + flash config)
|
||||||
if(spi_flash_read(0x0000, &data, 4) == SPI_FLASH_RESULT_OK) {
|
if(spi_flash_read(0x0000, &data, 4) == SPI_FLASH_RESULT_OK) {
|
||||||
switch(bytes[3] & 0x0F) {
|
return magicFlashChipSpeed(bytes[3] & 0x0F);
|
||||||
case 0x0: // 40 MHz
|
|
||||||
return (40_MHz);
|
|
||||||
case 0x1: // 26 MHz
|
|
||||||
return (26_MHz);
|
|
||||||
case 0x2: // 20 MHz
|
|
||||||
return (20_MHz);
|
|
||||||
case 0xf: // 80 MHz
|
|
||||||
return (80_MHz);
|
|
||||||
default: // fail?
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -230,10 +200,53 @@ FlashMode_t EspClass::getFlashChipMode(void)
|
|||||||
uint8_t * bytes = (uint8_t *) &data;
|
uint8_t * bytes = (uint8_t *) &data;
|
||||||
// read first 4 byte (magic byte + flash config)
|
// read first 4 byte (magic byte + flash config)
|
||||||
if(spi_flash_read(0x0000, &data, 4) == SPI_FLASH_RESULT_OK) {
|
if(spi_flash_read(0x0000, &data, 4) == SPI_FLASH_RESULT_OK) {
|
||||||
mode = (FlashMode_t) bytes[2];
|
mode = magicFlashChipMode(bytes[2]);
|
||||||
if(mode > FM_DOUT) {
|
}
|
||||||
mode = FM_UNKNOWN;
|
return mode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint32_t EspClass::magicFlashChipSize(uint8_t byte) {
|
||||||
|
switch(byte & 0x0F) {
|
||||||
|
case 0x0: // 4 Mbit (512KB)
|
||||||
|
return (512_kB);
|
||||||
|
case 0x1: // 2 MBit (256KB)
|
||||||
|
return (256_kB);
|
||||||
|
case 0x2: // 8 MBit (1MB)
|
||||||
|
return (1_MB);
|
||||||
|
case 0x3: // 16 MBit (2MB)
|
||||||
|
return (2_MB);
|
||||||
|
case 0x4: // 32 MBit (4MB)
|
||||||
|
return (4_MB);
|
||||||
|
case 0x5: // 64 MBit (8MB)
|
||||||
|
return (8_MB);
|
||||||
|
case 0x6: // 128 MBit (16MB)
|
||||||
|
return (16_MB);
|
||||||
|
case 0x7: // 256 MBit (32MB)
|
||||||
|
return (32_MB);
|
||||||
|
default: // fail?
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t EspClass::magicFlashChipSpeed(uint8_t byte) {
|
||||||
|
switch(byte & 0x0F) {
|
||||||
|
case 0x0: // 40 MHz
|
||||||
|
return (40_MHz);
|
||||||
|
case 0x1: // 26 MHz
|
||||||
|
return (26_MHz);
|
||||||
|
case 0x2: // 20 MHz
|
||||||
|
return (20_MHz);
|
||||||
|
case 0xf: // 80 MHz
|
||||||
|
return (80_MHz);
|
||||||
|
default: // fail?
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FlashMode_t EspClass::magicFlashChipMode(uint8_t byte) {
|
||||||
|
FlashMode_t mode = (FlashMode_t) byte;
|
||||||
|
if(mode > FM_DOUT) {
|
||||||
|
mode = FM_UNKNOWN;
|
||||||
}
|
}
|
||||||
return mode;
|
return mode;
|
||||||
}
|
}
|
||||||
@ -298,6 +311,24 @@ uint32_t EspClass::getFlashChipSizeByChipId(void) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* check the Flash settings from IDE against the Real flash size
|
||||||
|
* @param needsEquals (return only true it equals)
|
||||||
|
* @return ok or not
|
||||||
|
*/
|
||||||
|
bool EspClass::checkFlashConfig(bool needsEquals) {
|
||||||
|
if(needsEquals) {
|
||||||
|
if(getFlashChipRealSize() == getFlashChipSize()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if(getFlashChipRealSize() >= getFlashChipSize()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
String EspClass::getResetInfo(void) {
|
String EspClass::getResetInfo(void) {
|
||||||
if(resetInfo.reason != 0) {
|
if(resetInfo.reason != 0) {
|
||||||
char buff[200];
|
char buff[200];
|
||||||
|
@ -117,6 +117,12 @@ class EspClass {
|
|||||||
FlashMode_t getFlashChipMode();
|
FlashMode_t getFlashChipMode();
|
||||||
uint32_t getFlashChipSizeByChipId();
|
uint32_t getFlashChipSizeByChipId();
|
||||||
|
|
||||||
|
uint32_t magicFlashChipSize(uint8_t byte);
|
||||||
|
uint32_t magicFlashChipSpeed(uint8_t byte);
|
||||||
|
FlashMode_t magicFlashChipMode(uint8_t byte);
|
||||||
|
|
||||||
|
bool checkFlashConfig(bool needsEquals = false);
|
||||||
|
|
||||||
bool flashEraseSector(uint32_t sector);
|
bool flashEraseSector(uint32_t sector);
|
||||||
bool flashWrite(uint32_t offset, uint32_t *data, size_t size);
|
bool flashWrite(uint32_t offset, uint32_t *data, size_t size);
|
||||||
bool flashRead(uint32_t offset, uint32_t *data, size_t size);
|
bool flashRead(uint32_t offset, uint32_t *data, size_t size);
|
||||||
|
@ -57,6 +57,14 @@ bool UpdaterClass::begin(size_t size, int command) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(!ESP.checkFlashConfig(false)) {
|
||||||
|
_error = UPDATE_ERROR_FLASH_CONFIG;
|
||||||
|
#ifdef DEBUG_UPDATER
|
||||||
|
printError(DEBUG_UPDATER);
|
||||||
|
#endif
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
_reset();
|
_reset();
|
||||||
_error = 0;
|
_error = 0;
|
||||||
|
|
||||||
@ -116,9 +124,13 @@ bool UpdaterClass::begin(size_t size, int command) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void UpdaterClass::setMD5(const char * expected_md5){
|
bool UpdaterClass::setMD5(const char * expected_md5){
|
||||||
if(strlen(expected_md5) != 32) return;
|
if(strlen(expected_md5) != 32)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
_target_md5 = expected_md5;
|
_target_md5 = expected_md5;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool UpdaterClass::end(bool evenIfRemaining){
|
bool UpdaterClass::end(bool evenIfRemaining){
|
||||||
@ -152,6 +164,7 @@ bool UpdaterClass::end(bool evenIfRemaining){
|
|||||||
#ifdef DEBUG_UPDATER
|
#ifdef DEBUG_UPDATER
|
||||||
DEBUG_UPDATER.printf("MD5 Failed: expected:%s, calculated:%s\n", _target_md5.c_str(), _md5.toString().c_str());
|
DEBUG_UPDATER.printf("MD5 Failed: expected:%s, calculated:%s\n", _target_md5.c_str(), _md5.toString().c_str());
|
||||||
#endif
|
#endif
|
||||||
|
_reset();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
#ifdef DEBUG_UPDATER
|
#ifdef DEBUG_UPDATER
|
||||||
@ -159,6 +172,14 @@ bool UpdaterClass::end(bool evenIfRemaining){
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(!_verifyEnd()) {
|
||||||
|
#ifdef DEBUG_UPDATER
|
||||||
|
printError(DEBUG_UPDATER);
|
||||||
|
#endif
|
||||||
|
_reset();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (_command == U_FLASH) {
|
if (_command == U_FLASH) {
|
||||||
eboot_command ebcmd;
|
eboot_command ebcmd;
|
||||||
ebcmd.action = ACTION_COPY_RAW;
|
ebcmd.action = ACTION_COPY_RAW;
|
||||||
@ -233,12 +254,70 @@ size_t UpdaterClass::write(uint8_t *data, size_t len) {
|
|||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool UpdaterClass::_verifyHeader(uint8_t data) {
|
||||||
|
if(_command == U_FLASH) {
|
||||||
|
// check for valid first magic byte (is always 0xE9)
|
||||||
|
if(data != 0xE9) {
|
||||||
|
_error = UPDATE_ERROR_MAGIC_BYTE;
|
||||||
|
_currentAddress = (_startAddress + _size);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
} else if(_command == U_SPIFFS) {
|
||||||
|
// no check of SPIFFS possible with first byte.
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool UpdaterClass::_verifyEnd() {
|
||||||
|
if(_command == U_FLASH) {
|
||||||
|
|
||||||
|
uint8_t buf[4];
|
||||||
|
if(!ESP.flashRead(_startAddress, (uint32_t *) &buf[0], 4)) {
|
||||||
|
_error = UPDATE_ERROR_READ;
|
||||||
|
_currentAddress = (_startAddress);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// check for valid first magic byte
|
||||||
|
if(buf[0] != 0xE9) {
|
||||||
|
_error = UPDATE_ERROR_MAGIC_BYTE;
|
||||||
|
_currentAddress = (_startAddress);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t bin_flash_size = ESP.magicFlashChipSize((buf[3] & 0xf0) >> 4);
|
||||||
|
|
||||||
|
// check if new bin fits to SPI flash
|
||||||
|
if(bin_flash_size > ESP.getFlashChipRealSize()) {
|
||||||
|
_error = UPDATE_ERROR_NEW_FLASH_CONFIG;
|
||||||
|
_currentAddress = (_startAddress);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
} else if(_command == U_SPIFFS) {
|
||||||
|
// SPIFFS is already over written checks make no sense any more.
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
size_t UpdaterClass::writeStream(Stream &data) {
|
size_t UpdaterClass::writeStream(Stream &data) {
|
||||||
size_t written = 0;
|
size_t written = 0;
|
||||||
size_t toRead = 0;
|
size_t toRead = 0;
|
||||||
if(hasError() || !isRunning())
|
if(hasError() || !isRunning())
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
if(!_verifyHeader(data.peek())) {
|
||||||
|
#ifdef DEBUG_UPDATER
|
||||||
|
printError(DEBUG_UPDATER);
|
||||||
|
#endif
|
||||||
|
_reset();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
while(remaining()) {
|
while(remaining()) {
|
||||||
toRead = data.readBytes(_buffer + _bufferLen, (FLASH_SECTOR_SIZE - _bufferLen));
|
toRead = data.readBytes(_buffer + _bufferLen, (FLASH_SECTOR_SIZE - _bufferLen));
|
||||||
if(toRead == 0) { //Timeout
|
if(toRead == 0) { //Timeout
|
||||||
@ -250,8 +329,9 @@ size_t UpdaterClass::writeStream(Stream &data) {
|
|||||||
#ifdef DEBUG_UPDATER
|
#ifdef DEBUG_UPDATER
|
||||||
printError(DEBUG_UPDATER);
|
printError(DEBUG_UPDATER);
|
||||||
#endif
|
#endif
|
||||||
|
_reset();
|
||||||
|
return written;
|
||||||
}
|
}
|
||||||
return written;
|
|
||||||
}
|
}
|
||||||
_bufferLen += toRead;
|
_bufferLen += toRead;
|
||||||
if((_bufferLen == remaining() || _bufferLen == FLASH_SECTOR_SIZE) && !_writeBuffer())
|
if((_bufferLen == remaining() || _bufferLen == FLASH_SECTOR_SIZE) && !_writeBuffer())
|
||||||
@ -270,6 +350,8 @@ void UpdaterClass::printError(Stream &out){
|
|||||||
out.println("Flash Write Failed");
|
out.println("Flash Write Failed");
|
||||||
} else if(_error == UPDATE_ERROR_ERASE){
|
} else if(_error == UPDATE_ERROR_ERASE){
|
||||||
out.println("Flash Erase Failed");
|
out.println("Flash Erase Failed");
|
||||||
|
} else if(_error == UPDATE_ERROR_READ){
|
||||||
|
out.println("Flash Read Failed");
|
||||||
} else if(_error == UPDATE_ERROR_SPACE){
|
} else if(_error == UPDATE_ERROR_SPACE){
|
||||||
out.println("Not Enough Space");
|
out.println("Not Enough Space");
|
||||||
} else if(_error == UPDATE_ERROR_SIZE){
|
} else if(_error == UPDATE_ERROR_SIZE){
|
||||||
@ -278,6 +360,12 @@ void UpdaterClass::printError(Stream &out){
|
|||||||
out.println("Stream Read Timeout");
|
out.println("Stream Read Timeout");
|
||||||
} else if(_error == UPDATE_ERROR_MD5){
|
} else if(_error == UPDATE_ERROR_MD5){
|
||||||
out.println("MD5 Check Failed");
|
out.println("MD5 Check Failed");
|
||||||
|
} else if(_error == UPDATE_ERROR_FLASH_CONFIG){
|
||||||
|
out.printf("Flash config wrong real: %d IDE: %d\n", ESP.getFlashChipRealSize(), ESP.getFlashChipSize());
|
||||||
|
} else if(_error == UPDATE_ERROR_NEW_FLASH_CONFIG){
|
||||||
|
out.printf("new Flash config wrong real: %d\n", ESP.getFlashChipRealSize());
|
||||||
|
} else if(_error == UPDATE_ERROR_MAGIC_BYTE){
|
||||||
|
out.println("Magic byte is wrong, not 0xE9");
|
||||||
} else {
|
} else {
|
||||||
out.println("UNKNOWN");
|
out.println("UNKNOWN");
|
||||||
}
|
}
|
||||||
|
@ -5,13 +5,18 @@
|
|||||||
#include "flash_utils.h"
|
#include "flash_utils.h"
|
||||||
#include "MD5Builder.h"
|
#include "MD5Builder.h"
|
||||||
|
|
||||||
#define UPDATE_ERROR_OK 0
|
#define UPDATE_ERROR_OK (0)
|
||||||
#define UPDATE_ERROR_WRITE 1
|
#define UPDATE_ERROR_WRITE (1)
|
||||||
#define UPDATE_ERROR_ERASE 2
|
#define UPDATE_ERROR_ERASE (2)
|
||||||
#define UPDATE_ERROR_SPACE 3
|
#define UPDATE_ERROR_READ (3)
|
||||||
#define UPDATE_ERROR_SIZE 4
|
#define UPDATE_ERROR_SPACE (4)
|
||||||
#define UPDATE_ERROR_STREAM 5
|
#define UPDATE_ERROR_SIZE (5)
|
||||||
#define UPDATE_ERROR_MD5 6
|
#define UPDATE_ERROR_STREAM (6)
|
||||||
|
#define UPDATE_ERROR_MD5 (7)
|
||||||
|
#define UPDATE_ERROR_FLASH_CONFIG (8)
|
||||||
|
#define UPDATE_ERROR_NEW_FLASH_CONFIG (9)
|
||||||
|
#define UPDATE_ERROR_MAGIC_BYTE (10)
|
||||||
|
|
||||||
|
|
||||||
#define U_FLASH 0
|
#define U_FLASH 0
|
||||||
#define U_SPIFFS 100
|
#define U_SPIFFS 100
|
||||||
@ -63,7 +68,7 @@ class UpdaterClass {
|
|||||||
/*
|
/*
|
||||||
sets the expected MD5 for the firmware (hexString)
|
sets the expected MD5 for the firmware (hexString)
|
||||||
*/
|
*/
|
||||||
void setMD5(const char * expected_md5);
|
bool setMD5(const char * expected_md5);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
returns the MD5 String of the sucessfully ended firmware
|
returns the MD5 String of the sucessfully ended firmware
|
||||||
@ -131,6 +136,9 @@ class UpdaterClass {
|
|||||||
void _reset();
|
void _reset();
|
||||||
bool _writeBuffer();
|
bool _writeBuffer();
|
||||||
|
|
||||||
|
bool _verifyHeader(uint8_t data);
|
||||||
|
bool _verifyEnd();
|
||||||
|
|
||||||
uint8_t _error;
|
uint8_t _error;
|
||||||
uint8_t *_buffer;
|
uint8_t *_buffer;
|
||||||
size_t _bufferLen;
|
size_t _bufferLen;
|
||||||
|
@ -31,7 +31,7 @@ extern "C" {
|
|||||||
#include "user_interface.h"
|
#include "user_interface.h"
|
||||||
#include "cont.h"
|
#include "cont.h"
|
||||||
}
|
}
|
||||||
#define LOOP_TASK_PRIORITY 0
|
#define LOOP_TASK_PRIORITY 1
|
||||||
#define LOOP_QUEUE_SIZE 1
|
#define LOOP_QUEUE_SIZE 1
|
||||||
|
|
||||||
#define OPTIMISTIC_YIELD_TIME_US 16000
|
#define OPTIMISTIC_YIELD_TIME_US 16000
|
||||||
@ -73,7 +73,7 @@ extern "C" void esp_yield() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
extern "C" void esp_schedule() {
|
extern "C" void esp_schedule() {
|
||||||
system_os_post(LOOP_TASK_PRIORITY, 0, 0);
|
ets_post(LOOP_TASK_PRIORITY, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" void __yield() {
|
extern "C" void __yield() {
|
||||||
@ -144,7 +144,7 @@ extern "C" void user_init(void) {
|
|||||||
|
|
||||||
cont_init(&g_cont);
|
cont_init(&g_cont);
|
||||||
|
|
||||||
system_os_task(loop_task,
|
ets_task(loop_task,
|
||||||
LOOP_TASK_PRIORITY, g_loop_queue,
|
LOOP_TASK_PRIORITY, g_loop_queue,
|
||||||
LOOP_QUEUE_SIZE);
|
LOOP_QUEUE_SIZE);
|
||||||
|
|
||||||
|
@ -231,6 +231,13 @@ static uint8_t phy_init_data[128] =
|
|||||||
// force_freq_offset
|
// force_freq_offset
|
||||||
// signed, unit is 8kHz
|
// signed, unit is 8kHz
|
||||||
[113] = 0,
|
[113] = 0,
|
||||||
|
|
||||||
|
// rf_cal_use_flash
|
||||||
|
// 0: RF init no RF CAL, using all RF CAL data in flash, it takes about 2ms for RF init
|
||||||
|
// 1: RF init only do TX power control CAL, others using RF CAL data in flash , it takes about 20ms for RF init
|
||||||
|
// 2: RF init no RF CAL, using all RF CAL data in flash, it takes about 2ms for RF init (same as 0?!)
|
||||||
|
// 3: RF init do all RF CAL, it takes about 200ms for RF init
|
||||||
|
[114] = 2
|
||||||
};
|
};
|
||||||
|
|
||||||
extern int __real_register_chipv6_phy(uint8_t* init_data);
|
extern int __real_register_chipv6_phy(uint8_t* init_data);
|
||||||
|
@ -19,17 +19,24 @@ platformio boards espressif
|
|||||||
# --------------------------------------------------------------------------------------------------------
|
# --------------------------------------------------------------------------------------------------------
|
||||||
# Type MCU Frequency Flash RAM Name
|
# Type MCU Frequency Flash RAM Name
|
||||||
# --------------------------------------------------------------------------------------------------------
|
# --------------------------------------------------------------------------------------------------------
|
||||||
# esp01 esp8266 80Mhz 512Kb 32Kb Espressif ESP8266 ESP-01 board
|
# huzzah esp8266 80Mhz 1024Kb 80Kb Adafruit HUZZAH ESP8266
|
||||||
# esp01_1m esp8266 80Mhz 1024Kb 32Kb Espressif ESP8266 ESP-01-1MB board
|
# espino esp8266 80Mhz 1024Kb 80Kb ESPino
|
||||||
# esp12e esp8266 80Mhz 4096Kb 32Kb Espressif ESP8266 ESP-12E board (NodeMCU)
|
# esp12e esp8266 80Mhz 1024Kb 80Kb Espressif ESP8266 ESP-12E
|
||||||
|
# esp01 esp8266 80Mhz 512Kb 80Kb Espressif Generic ESP8266 ESP-01
|
||||||
|
# nodemcu esp8266 80Mhz 1024Kb 80Kb NodeMCU 0.9 & 1.0
|
||||||
|
# modwifi esp8266 80Mhz 1024Kb 80Kb Olimex MOD-WIFI-ESP8266(-DEV)
|
||||||
|
# thing esp8266 80Mhz 512Kb 80Kb SparkFun ESP8266 Thing
|
||||||
|
# esp210 esp8266 80Mhz 1024Kb 80Kb SweetPea ESP-210
|
||||||
|
# d1 esp8266 80Mhz 1024Kb 80Kb WeMos D1
|
||||||
|
# d1_mini esp8266 80Mhz 1024Kb 80Kb WeMos D1 mini
|
||||||
# ...
|
# ...
|
||||||
|
|
||||||
#
|
#
|
||||||
# Initialise base project
|
# Initialise base project
|
||||||
#
|
#
|
||||||
platformio init --board %TYPE%(see above)
|
platformio init --board %TYPE%(see above)
|
||||||
# for example, initialise project for ESP8266 ESP-12E board (NodeMCU)
|
# for example, initialise project for Espressif Generic ESP8266 ESP-01
|
||||||
platformio init --board esp12e
|
platformio init --board esp01
|
||||||
|
|
||||||
# The next files/directories will be created in myproject
|
# The next files/directories will be created in myproject
|
||||||
# platformio.ini - Project Configuration File. |-> PLEASE EDIT ME <-|
|
# platformio.ini - Project Configuration File. |-> PLEASE EDIT ME <-|
|
||||||
@ -49,43 +56,14 @@ platformio run
|
|||||||
platformio run --target upload
|
platformio run --target upload
|
||||||
```
|
```
|
||||||
|
|
||||||
## OTA firmware uploading
|
## Advanced documentation
|
||||||
|
|
||||||
There are 2 options:
|
- [OTA update](http://docs.platformio.org/en/latest/platforms/espressif.html#ota-update)
|
||||||
|
* [Authentication and upload options](http://docs.platformio.org/en/latest/platforms/espressif.html#authentication-and-upload-options)
|
||||||
|
- [Custom CPU Frequency and Upload Speed](http://docs.platformio.org/en/latest/platforms/espressif.html#custom-cpu-frequency-and-upload-speed)
|
||||||
|
- [Custom Flash Size](http://docs.platformio.org/en/latest/platforms/espressif.html#custom-flash-size)
|
||||||
|
- [IDE Integration](http://docs.platformio.org/en/latest/ide.html) (Atom, CLion, Eclipse, Qt Creator, Sublime Text, VIM, Visual Studio)
|
||||||
|
- [Project Examples](http://docs.platformio.org/en/latest/platforms/espressif.html#examples)
|
||||||
|
|
||||||
- Directly specify `--upoad-port` in command line
|
## Demo of OTA update
|
||||||
```bash
|
|
||||||
platformio run --target upload --upload-port IP_ADDRESS_HERE
|
|
||||||
```
|
|
||||||
- Specify [upload_port](http://docs.platformio.org/en/latest/projectconf.html#upload-port) option in `platformio.ini`
|
|
||||||
```ini
|
|
||||||
[env:***]
|
|
||||||
...
|
|
||||||
upload_port = IP_ADDRESS_HERE
|
|
||||||
```
|
|
||||||
|
|
||||||
### Authentication and upload options
|
|
||||||
|
|
||||||
You can pass additional options/flags to OTA uploader using [upload_flags](http://docs.platformio.org/en/latest/projectconf.html#upload-flags) option in `platformio.ini`
|
|
||||||
```ini
|
|
||||||
[env:***]
|
|
||||||
upload_flags = --port=8266
|
|
||||||
```
|
|
||||||
|
|
||||||
Availalbe flags
|
|
||||||
- `--port=ESP_PORT` ESP8266 ota Port. Default 8266
|
|
||||||
- `--auth=AUTH` Set authentication password
|
|
||||||
- `--spiffs` Use this option to transmit a SPIFFS image and do not flash the module
|
|
||||||
|
|
||||||
For the full list with availalbe options please run this command `~/.platformio/packages/framework-arduinoespressif/tools/espota.py -h`.
|
|
||||||
|
|
||||||
|
|
||||||
## IDE Integration
|
|
||||||
In addition, PlatformIO [can be integrated into the popular IDEs](http://docs.platformio.org/en/latest/ide.html). For example, initialise project for Espressif ESP8266 ESP-01 board and Eclipse IDE
|
|
||||||
```
|
|
||||||
platformio init --board esp01 --ide eclipse
|
|
||||||
```
|
|
||||||
Then [import project](http://docs.platformio.org/en/latest/ide/eclipse.html) using `Eclipse Menu: File > Import... > General > Existing Projects into Workspace`.
|
|
||||||
|
|
||||||
## Demo of OTA firmware uploading
|
|
||||||
[](http://www.youtube.com/watch?v=W8wWjvQ8ZQs "PlatformIO and OTA firmware uploading to Espressif ESP8266 ESP-01")
|
[](http://www.youtube.com/watch?v=W8wWjvQ8ZQs "PlatformIO and OTA firmware uploading to Espressif ESP8266 ESP-01")
|
||||||
|
@ -153,7 +153,7 @@ class HTTPClient {
|
|||||||
int writeToStream(Stream * stream);
|
int writeToStream(Stream * stream);
|
||||||
String getString(void);
|
String getString(void);
|
||||||
|
|
||||||
String errorToString(int error);
|
static String errorToString(int error);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
|
@ -239,6 +239,27 @@ int WiFiClient::peek()
|
|||||||
return _client->peek();
|
return _client->peek();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t WiFiClient::peekBytes(uint8_t *buffer, size_t length) {
|
||||||
|
size_t count = 0;
|
||||||
|
|
||||||
|
if(!_client) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
_startMillis = millis();
|
||||||
|
while((available() < (int) length) && ((millis() - _startMillis) < _timeout)) {
|
||||||
|
yield();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(available() < (int) length) {
|
||||||
|
count = available();
|
||||||
|
} else {
|
||||||
|
count = length;
|
||||||
|
}
|
||||||
|
|
||||||
|
return _client->peekBytes((char *)buffer, count);
|
||||||
|
}
|
||||||
|
|
||||||
void WiFiClient::flush()
|
void WiFiClient::flush()
|
||||||
{
|
{
|
||||||
if (_client)
|
if (_client)
|
||||||
|
@ -56,6 +56,10 @@ public:
|
|||||||
virtual int read();
|
virtual int read();
|
||||||
virtual int read(uint8_t *buf, size_t size);
|
virtual int read(uint8_t *buf, size_t size);
|
||||||
virtual int peek();
|
virtual int peek();
|
||||||
|
virtual size_t peekBytes(uint8_t *buffer, size_t length);
|
||||||
|
size_t peekBytes(char *buffer, size_t length) {
|
||||||
|
return peekBytes((uint8_t *) buffer, length);
|
||||||
|
}
|
||||||
virtual void flush();
|
virtual void flush();
|
||||||
virtual void stop();
|
virtual void stop();
|
||||||
virtual uint8_t connected();
|
virtual uint8_t connected();
|
||||||
|
@ -133,6 +133,17 @@ public:
|
|||||||
return _read_ptr[0];
|
return _read_ptr[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t peekBytes(char *dst, size_t size) {
|
||||||
|
if(!_available) {
|
||||||
|
if(!_readAll())
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t will_copy = (_available < size) ? _available : size;
|
||||||
|
memcpy(dst, _read_ptr, will_copy);
|
||||||
|
return will_copy;
|
||||||
|
}
|
||||||
|
|
||||||
int available() {
|
int available() {
|
||||||
auto cb = _available;
|
auto cb = _available;
|
||||||
if (cb == 0) {
|
if (cb == 0) {
|
||||||
@ -278,6 +289,27 @@ int WiFiClientSecure::peek() {
|
|||||||
return _ssl->peek();
|
return _ssl->peek();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t WiFiClientSecure::peekBytes(uint8_t *buffer, size_t length) {
|
||||||
|
size_t count = 0;
|
||||||
|
|
||||||
|
if(!_ssl) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
_startMillis = millis();
|
||||||
|
while((available() < (int) length) && ((millis() - _startMillis) < _timeout)) {
|
||||||
|
yield();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(available() < (int) length) {
|
||||||
|
count = available();
|
||||||
|
} else {
|
||||||
|
count = length;
|
||||||
|
}
|
||||||
|
|
||||||
|
return _ssl->peekBytes((char *)buffer, count);
|
||||||
|
}
|
||||||
|
|
||||||
int WiFiClientSecure::available() {
|
int WiFiClientSecure::available() {
|
||||||
if (!_ssl)
|
if (!_ssl)
|
||||||
return 0;
|
return 0;
|
||||||
@ -327,7 +359,7 @@ bool WiFiClientSecure::verify(const char* fp, const char* url) {
|
|||||||
int len = strlen(fp);
|
int len = strlen(fp);
|
||||||
int pos = 0;
|
int pos = 0;
|
||||||
for (size_t i = 0; i < sizeof(sha1); ++i) {
|
for (size_t i = 0; i < sizeof(sha1); ++i) {
|
||||||
while (pos < len && fp[pos] == ' ') {
|
while (pos < len && ((fp[pos] == ' ') || (fp[pos] == ':'))) {
|
||||||
++pos;
|
++pos;
|
||||||
}
|
}
|
||||||
if (pos > len - 2) {
|
if (pos > len - 2) {
|
||||||
|
@ -46,6 +46,7 @@ public:
|
|||||||
int available() override;
|
int available() override;
|
||||||
int read() override;
|
int read() override;
|
||||||
int peek() override;
|
int peek() override;
|
||||||
|
size_t peekBytes(uint8_t *buffer, size_t length) override;
|
||||||
void stop() override;
|
void stop() override;
|
||||||
|
|
||||||
void setCertificate(const uint8_t* cert_data, size_t size);
|
void setCertificate(const uint8_t* cert_data, size_t size);
|
||||||
|
@ -179,6 +179,20 @@ class ClientContext {
|
|||||||
return reinterpret_cast<char*>(_rx_buf->payload)[_rx_buf_offset];
|
return reinterpret_cast<char*>(_rx_buf->payload)[_rx_buf_offset];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t peekBytes(char *dst, size_t size) {
|
||||||
|
if(!_rx_buf) return 0;
|
||||||
|
|
||||||
|
size_t max_size = _rx_buf->tot_len - _rx_buf_offset;
|
||||||
|
size = (size < max_size) ? size : max_size;
|
||||||
|
|
||||||
|
DEBUGV(":pd %d, %d, %d\r\n", size, _rx_buf->tot_len, _rx_buf_offset);
|
||||||
|
size_t buf_size = _rx_buf->len - _rx_buf_offset;
|
||||||
|
size_t copy_size = (size < buf_size) ? size : buf_size;
|
||||||
|
DEBUGV(":rpi %d, %d\r\n", buf_size, copy_size);
|
||||||
|
os_memcpy(dst, reinterpret_cast<char*>(_rx_buf->payload) + _rx_buf_offset, copy_size);
|
||||||
|
return copy_size;
|
||||||
|
}
|
||||||
|
|
||||||
void flush() {
|
void flush() {
|
||||||
if(!_rx_buf) {
|
if(!_rx_buf) {
|
||||||
return;
|
return;
|
||||||
|
@ -51,19 +51,19 @@ typedef size_t mem_size_t;
|
|||||||
* allow these defines to be overridden.
|
* allow these defines to be overridden.
|
||||||
*/
|
*/
|
||||||
#ifndef mem_free
|
#ifndef mem_free
|
||||||
#define mem_free vPortFree
|
#define mem_free(p) vPortFree(p, "", 0)
|
||||||
#endif
|
#endif
|
||||||
#ifndef mem_malloc
|
#ifndef mem_malloc
|
||||||
#define mem_malloc pvPortMalloc
|
#define mem_malloc(s) pvPortMalloc(s, "", 0)
|
||||||
#endif
|
#endif
|
||||||
#ifndef mem_calloc
|
#ifndef mem_calloc
|
||||||
#define mem_calloc pvPortCalloc
|
#define mem_calloc(s) pvPortCalloc(s, "", 0)
|
||||||
#endif
|
#endif
|
||||||
#ifndef mem_realloc
|
#ifndef mem_realloc
|
||||||
#define mem_realloc pvPortRealloc
|
#define mem_realloc(p, s) pvPortRealloc(p, s, "", 0)
|
||||||
#endif
|
#endif
|
||||||
#ifndef mem_zalloc
|
#ifndef mem_zalloc
|
||||||
#define mem_zalloc pvPortZalloc
|
#define mem_zalloc(s) pvPortZalloc(s, "", 0)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef os_malloc
|
#ifndef os_malloc
|
||||||
|
@ -45,7 +45,7 @@ void loop() {
|
|||||||
|
|
||||||
switch(ret) {
|
switch(ret) {
|
||||||
case HTTP_UPDATE_FAILED:
|
case HTTP_UPDATE_FAILED:
|
||||||
USE_SERIAL.println("HTTP_UPDATE_FAILD");
|
USE_SERIAL.printf("HTTP_UPDATE_FAILD Error (%d): %s", ESPhttpUpdate.getLastError(), ESPhttpUpdate.getLastErrorString().c_str());
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case HTTP_UPDATE_NO_UPDATES:
|
case HTTP_UPDATE_NO_UPDATES:
|
||||||
|
@ -48,7 +48,7 @@ void loop() {
|
|||||||
|
|
||||||
switch(ret) {
|
switch(ret) {
|
||||||
case HTTP_UPDATE_FAILED:
|
case HTTP_UPDATE_FAILED:
|
||||||
USE_SERIAL.println("HTTP_UPDATE_FAILD");
|
USE_SERIAL.printf("HTTP_UPDATE_FAILD Error (%d): %s", ESPhttpUpdate.getLastError(), ESPhttpUpdate.getLastErrorString().c_str());
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case HTTP_UPDATE_NO_UPDATES:
|
case HTTP_UPDATE_NO_UPDATES:
|
||||||
|
@ -82,6 +82,60 @@ t_httpUpdate_return ESP8266HTTPUpdate::update(String host, uint16_t port, String
|
|||||||
return handleUpdate(&http, current_version.c_str(), reboot, false);
|
return handleUpdate(&http, current_version.c_str(), reboot, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* return error code as int
|
||||||
|
* @return int error code
|
||||||
|
*/
|
||||||
|
int ESP8266HTTPUpdate::getLastError(void){
|
||||||
|
return lastError;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* return error code as String
|
||||||
|
* @return String error
|
||||||
|
*/
|
||||||
|
String ESP8266HTTPUpdate::getLastErrorString(void) {
|
||||||
|
|
||||||
|
if(lastError == 0) {
|
||||||
|
return String(); // no error
|
||||||
|
}
|
||||||
|
|
||||||
|
// error from Update class
|
||||||
|
if(lastError > 0) {
|
||||||
|
StreamString error;
|
||||||
|
Update.printError(error);
|
||||||
|
error.trim(); // remove line ending
|
||||||
|
return "Update error: " + error;
|
||||||
|
}
|
||||||
|
|
||||||
|
// error from http client
|
||||||
|
if(lastError > -100) {
|
||||||
|
return "HTTP error: " + HTTPClient::errorToString(lastError);
|
||||||
|
}
|
||||||
|
|
||||||
|
switch(lastError) {
|
||||||
|
case HTTP_UE_TOO_LESS_SPACE:
|
||||||
|
return String("To less space");
|
||||||
|
case HTTP_UE_SERVER_NOT_REPORT_SIZE:
|
||||||
|
return String("Server not Report Size");
|
||||||
|
case HTTP_UE_SERVER_FILE_NOT_FOUND:
|
||||||
|
return String("File not Found (404)");
|
||||||
|
case HTTP_UE_SERVER_FORBIDDEN:
|
||||||
|
return String("Forbidden (403)");
|
||||||
|
case HTTP_UE_SERVER_WRONG_HTTP_CODE:
|
||||||
|
return String("Wrong HTTP code");
|
||||||
|
case HTTP_UE_SERVER_FAULTY_MD5:
|
||||||
|
return String("Faulty MD5");
|
||||||
|
case HTTP_UE_BIN_VERIFY_HEADER_FAILED:
|
||||||
|
return String("Verify bin header failed");
|
||||||
|
case HTTP_UE_BIN_FOR_WRONG_FLASH:
|
||||||
|
return String("bin for wrong flash size");
|
||||||
|
}
|
||||||
|
|
||||||
|
return String();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param http HTTPClient *
|
* @param http HTTPClient *
|
||||||
@ -122,10 +176,12 @@ t_httpUpdate_return ESP8266HTTPUpdate::handleUpdate(HTTPClient * http, const cha
|
|||||||
|
|
||||||
if(code <= 0) {
|
if(code <= 0) {
|
||||||
DEBUG_HTTP_UPDATE("[httpUpdate] HTTP error: %s\n", http->errorToString(code).c_str());
|
DEBUG_HTTP_UPDATE("[httpUpdate] HTTP error: %s\n", http->errorToString(code).c_str());
|
||||||
|
lastError = code;
|
||||||
http->end();
|
http->end();
|
||||||
return HTTP_UPDATE_FAILED;
|
return HTTP_UPDATE_FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
DEBUG_HTTP_UPDATE("[httpUpdate] Header read fin.\n");
|
DEBUG_HTTP_UPDATE("[httpUpdate] Header read fin.\n");
|
||||||
DEBUG_HTTP_UPDATE("[httpUpdate] Server header:\n");
|
DEBUG_HTTP_UPDATE("[httpUpdate] Server header:\n");
|
||||||
DEBUG_HTTP_UPDATE("[httpUpdate] - code: %d\n", code);
|
DEBUG_HTTP_UPDATE("[httpUpdate] - code: %d\n", code);
|
||||||
@ -161,6 +217,7 @@ t_httpUpdate_return ESP8266HTTPUpdate::handleUpdate(HTTPClient * http, const cha
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(!startUpdate) {
|
if(!startUpdate) {
|
||||||
|
lastError = HTTP_UE_TOO_LESS_SPACE;
|
||||||
ret = HTTP_UPDATE_FAILED;
|
ret = HTTP_UPDATE_FAILED;
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
@ -181,6 +238,33 @@ t_httpUpdate_return ESP8266HTTPUpdate::handleUpdate(HTTPClient * http, const cha
|
|||||||
DEBUG_HTTP_UPDATE("[httpUpdate] runUpdate flash...\n");
|
DEBUG_HTTP_UPDATE("[httpUpdate] runUpdate flash...\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint8_t buf[4];
|
||||||
|
if(tcp->peekBytes(&buf[0], 4) != 4) {
|
||||||
|
DEBUG_HTTP_UPDATE("[httpUpdate] peekBytes magic header failed\n");
|
||||||
|
lastError = HTTP_UE_BIN_VERIFY_HEADER_FAILED;
|
||||||
|
http->end();
|
||||||
|
return HTTP_UPDATE_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
// check for valid first magic byte
|
||||||
|
if(buf[0] != 0xE9) {
|
||||||
|
DEBUG_HTTP_UPDATE("[httpUpdate] magic header not starts with 0xE9\n");
|
||||||
|
lastError = HTTP_UE_BIN_VERIFY_HEADER_FAILED;
|
||||||
|
http->end();
|
||||||
|
return HTTP_UPDATE_FAILED;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t bin_flash_size = ESP.magicFlashChipSize((buf[3] & 0xf0) >> 4);
|
||||||
|
|
||||||
|
// check if new bin fits to SPI flash
|
||||||
|
if(bin_flash_size > ESP.getFlashChipRealSize()) {
|
||||||
|
DEBUG_HTTP_UPDATE("[httpUpdate] magic header, new bin not fits SPI Flash\n");
|
||||||
|
lastError = HTTP_UE_BIN_FOR_WRONG_FLASH;
|
||||||
|
http->end();
|
||||||
|
return HTTP_UPDATE_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
if(runUpdate(*tcp, len, http->header("x-MD5"), command)) {
|
if(runUpdate(*tcp, len, http->header("x-MD5"), command)) {
|
||||||
ret = HTTP_UPDATE_OK;
|
ret = HTTP_UPDATE_OK;
|
||||||
DEBUG_HTTP_UPDATE("[httpUpdate] Update ok\n");
|
DEBUG_HTTP_UPDATE("[httpUpdate] Update ok\n");
|
||||||
@ -196,6 +280,7 @@ t_httpUpdate_return ESP8266HTTPUpdate::handleUpdate(HTTPClient * http, const cha
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
lastError = HTTP_UE_SERVER_NOT_REPORT_SIZE;
|
||||||
ret = HTTP_UPDATE_FAILED;
|
ret = HTTP_UPDATE_FAILED;
|
||||||
DEBUG_HTTP_UPDATE("[httpUpdate] Content-Length is 0 or not set by Server?!\n");
|
DEBUG_HTTP_UPDATE("[httpUpdate] Content-Length is 0 or not set by Server?!\n");
|
||||||
}
|
}
|
||||||
@ -204,16 +289,23 @@ t_httpUpdate_return ESP8266HTTPUpdate::handleUpdate(HTTPClient * http, const cha
|
|||||||
///< Not Modified (No updates)
|
///< Not Modified (No updates)
|
||||||
ret = HTTP_UPDATE_NO_UPDATES;
|
ret = HTTP_UPDATE_NO_UPDATES;
|
||||||
break;
|
break;
|
||||||
|
case HTTP_CODE_NOT_FOUND:
|
||||||
|
lastError = HTTP_UE_SERVER_FILE_NOT_FOUND;
|
||||||
|
ret = HTTP_UPDATE_FAILED;
|
||||||
|
break;
|
||||||
|
case HTTP_CODE_FORBIDDEN:
|
||||||
|
lastError = HTTP_UE_SERVER_FORBIDDEN;
|
||||||
|
ret = HTTP_UPDATE_FAILED;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
|
lastError = HTTP_UE_SERVER_WRONG_HTTP_CODE;
|
||||||
ret = HTTP_UPDATE_FAILED;
|
ret = HTTP_UPDATE_FAILED;
|
||||||
DEBUG_HTTP_UPDATE("[httpUpdate] HTTP Code is (%d)\n", code);
|
DEBUG_HTTP_UPDATE("[httpUpdate] HTTP Code is (%d)\n", code);
|
||||||
//http->writeToStream(&Serial1);
|
//http->writeToStream(&Serial1);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
http->end();
|
http->end();
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -229,6 +321,7 @@ bool ESP8266HTTPUpdate::runUpdate(Stream& in, uint32_t size, String md5, int com
|
|||||||
StreamString error;
|
StreamString error;
|
||||||
|
|
||||||
if(!Update.begin(size, command)) {
|
if(!Update.begin(size, command)) {
|
||||||
|
lastError = Update.getError();
|
||||||
Update.printError(error);
|
Update.printError(error);
|
||||||
error.trim(); // remove line ending
|
error.trim(); // remove line ending
|
||||||
DEBUG_HTTP_UPDATE("[httpUpdate] Update.begin failed! (%s)\n", error.c_str());
|
DEBUG_HTTP_UPDATE("[httpUpdate] Update.begin failed! (%s)\n", error.c_str());
|
||||||
@ -236,10 +329,15 @@ bool ESP8266HTTPUpdate::runUpdate(Stream& in, uint32_t size, String md5, int com
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(md5.length()) {
|
if(md5.length()) {
|
||||||
Update.setMD5(md5.c_str());
|
if(!Update.setMD5(md5.c_str())) {
|
||||||
|
lastError = HTTP_UE_SERVER_FAULTY_MD5;
|
||||||
|
DEBUG_HTTP_UPDATE("[httpUpdate] Update.setMD5 failed! (%s)\n", md5.c_str());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(Update.writeStream(in) != size) {
|
if(Update.writeStream(in) != size) {
|
||||||
|
lastError = Update.getError();
|
||||||
Update.printError(error);
|
Update.printError(error);
|
||||||
error.trim(); // remove line ending
|
error.trim(); // remove line ending
|
||||||
DEBUG_HTTP_UPDATE("[httpUpdate] Update.writeStream failed! (%s)\n", error.c_str());
|
DEBUG_HTTP_UPDATE("[httpUpdate] Update.writeStream failed! (%s)\n", error.c_str());
|
||||||
@ -247,6 +345,7 @@ bool ESP8266HTTPUpdate::runUpdate(Stream& in, uint32_t size, String md5, int com
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(!Update.end()) {
|
if(!Update.end()) {
|
||||||
|
lastError = Update.getError();
|
||||||
Update.printError(error);
|
Update.printError(error);
|
||||||
error.trim(); // remove line ending
|
error.trim(); // remove line ending
|
||||||
DEBUG_HTTP_UPDATE("[httpUpdate] Update.end failed! (%s)\n", error.c_str());
|
DEBUG_HTTP_UPDATE("[httpUpdate] Update.end failed! (%s)\n", error.c_str());
|
||||||
|
@ -38,6 +38,16 @@
|
|||||||
#define DEBUG_HTTP_UPDATE(...)
|
#define DEBUG_HTTP_UPDATE(...)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/// note we use HTTP client errors too so we start at 100
|
||||||
|
#define HTTP_UE_TOO_LESS_SPACE (-100)
|
||||||
|
#define HTTP_UE_SERVER_NOT_REPORT_SIZE (-101)
|
||||||
|
#define HTTP_UE_SERVER_FILE_NOT_FOUND (-102)
|
||||||
|
#define HTTP_UE_SERVER_FORBIDDEN (-103)
|
||||||
|
#define HTTP_UE_SERVER_WRONG_HTTP_CODE (-104)
|
||||||
|
#define HTTP_UE_SERVER_FAULTY_MD5 (-105)
|
||||||
|
#define HTTP_UE_BIN_VERIFY_HEADER_FAILED (-106)
|
||||||
|
#define HTTP_UE_BIN_FOR_WRONG_FLASH (-107)
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
HTTP_UPDATE_FAILED,
|
HTTP_UPDATE_FAILED,
|
||||||
HTTP_UPDATE_NO_UPDATES,
|
HTTP_UPDATE_NO_UPDATES,
|
||||||
@ -55,9 +65,14 @@ class ESP8266HTTPUpdate {
|
|||||||
|
|
||||||
t_httpUpdate_return updateSpiffs(const char * url, const char * current_version = "", const char * httpsFingerprint = "", bool reboot = false);
|
t_httpUpdate_return updateSpiffs(const char * url, const char * current_version = "", const char * httpsFingerprint = "", bool reboot = false);
|
||||||
|
|
||||||
|
int getLastError(void);
|
||||||
|
String getLastErrorString(void);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
t_httpUpdate_return handleUpdate(HTTPClient * http, const char * current_version, bool reboot = true, bool spiffs = false);
|
t_httpUpdate_return handleUpdate(HTTPClient * http, const char * current_version, bool reboot = true, bool spiffs = false);
|
||||||
bool runUpdate(Stream& in, uint32_t size, String md5, int command = U_FLASH);
|
bool runUpdate(Stream& in, uint32_t size, String md5, int command = U_FLASH);
|
||||||
|
|
||||||
|
int lastError;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern ESP8266HTTPUpdate ESPhttpUpdate;
|
extern ESP8266HTTPUpdate ESPhttpUpdate;
|
||||||
|
@ -85,21 +85,42 @@ static const IPAddress MDNS_MULTICAST_ADDR(224, 0, 0, 251);
|
|||||||
static const int MDNS_MULTICAST_TTL = 1;
|
static const int MDNS_MULTICAST_TTL = 1;
|
||||||
static const int MDNS_PORT = 5353;
|
static const int MDNS_PORT = 5353;
|
||||||
|
|
||||||
MDNSResponder::MDNSResponder() : _conn(0) { _services = 0; _arduinoAuth = false; }
|
struct MDNSService {
|
||||||
|
MDNSService* _next;
|
||||||
|
char _name[32];
|
||||||
|
char _proto[3];
|
||||||
|
uint16_t _port;
|
||||||
|
struct MDNSTxt * _txts;
|
||||||
|
uint16_t _txtLen; // length of all txts
|
||||||
|
};
|
||||||
|
|
||||||
|
struct MDNSTxt{
|
||||||
|
MDNSTxt * _next;
|
||||||
|
String _txt;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
MDNSResponder::MDNSResponder() : _conn(0) {
|
||||||
|
_services = 0;
|
||||||
|
_instanceName = "";
|
||||||
|
}
|
||||||
MDNSResponder::~MDNSResponder() {}
|
MDNSResponder::~MDNSResponder() {}
|
||||||
|
|
||||||
bool MDNSResponder::begin(const char* domain){
|
bool MDNSResponder::begin(const char* hostname){
|
||||||
// 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(hostname);
|
||||||
if (n > 255) { // Can only handle domains that are 255 chars in length.
|
if (n > 63) { // max size for a single label.
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copy in domain characters as lowercase
|
// Copy in hostname characters as lowercase
|
||||||
for (size_t i = 0; i < n; ++i)
|
_hostName = hostname;
|
||||||
_hostName[i] = tolower(domain[i]);
|
_hostName.toLowerCase();
|
||||||
_hostName[n] = '\0';
|
|
||||||
|
// If instance name is not already set copy hostname to instance name
|
||||||
|
if (_instanceName.equals("") ) _instanceName=hostname;
|
||||||
|
|
||||||
// Open the MDNS socket if it isn't already open.
|
// Open the MDNS socket if it isn't already open.
|
||||||
if (!_conn) {
|
if (!_conn) {
|
||||||
@ -138,6 +159,48 @@ void MDNSResponder::update() {
|
|||||||
_parsePacket();
|
_parsePacket();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void MDNSResponder::setInstanceName(String name){
|
||||||
|
if (name.length() > 63) return;
|
||||||
|
else _instanceName = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool MDNSResponder::addServiceTxt(char *name, char *proto, char *key, char *value){
|
||||||
|
MDNSService* servicePtr;
|
||||||
|
|
||||||
|
uint8_t txtLen = os_strlen(key) + os_strlen(value) + 1; // Add one for equals sign
|
||||||
|
txtLen+=1; //accounts for length byte added when building the txt responce
|
||||||
|
//Find the service
|
||||||
|
for (servicePtr = _services; servicePtr; servicePtr = servicePtr->_next) {
|
||||||
|
//Checking Service names
|
||||||
|
if(strcmp(servicePtr->_name, name) == 0 && strcmp(servicePtr->_proto, proto) == 0){
|
||||||
|
//found a service name match
|
||||||
|
if (servicePtr->_txtLen + txtLen > 1300) return false; //max txt record size
|
||||||
|
MDNSTxt *newtxt = new MDNSTxt;
|
||||||
|
newtxt->_txt = String(key) + "=" + String(value);
|
||||||
|
newtxt->_next = 0;
|
||||||
|
if(servicePtr->_txts == 0) { //no services have been added
|
||||||
|
//Adding First TXT to service
|
||||||
|
servicePtr->_txts = newtxt;
|
||||||
|
servicePtr->_txtLen += txtLen;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
MDNSTxt * txtPtr = servicePtr->_txts;
|
||||||
|
while(txtPtr->_next !=0) {
|
||||||
|
txtPtr = txtPtr->_next;
|
||||||
|
}
|
||||||
|
//adding another TXT to service
|
||||||
|
txtPtr->_next = newtxt;
|
||||||
|
servicePtr->_txtLen += txtLen;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
void MDNSResponder::addService(char *name, char *proto, uint16_t port){
|
void MDNSResponder::addService(char *name, char *proto, uint16_t port){
|
||||||
if(_getServicePort(name, proto) != 0) return;
|
if(_getServicePort(name, proto) != 0) return;
|
||||||
if(os_strlen(name) > 32 || os_strlen(proto) != 3) return; //bad arguments
|
if(os_strlen(name) > 32 || os_strlen(proto) != 3) return; //bad arguments
|
||||||
@ -146,8 +209,42 @@ void MDNSResponder::addService(char *name, char *proto, uint16_t port){
|
|||||||
os_strcpy(srv->_proto, proto);
|
os_strcpy(srv->_proto, proto);
|
||||||
srv->_port = port;
|
srv->_port = port;
|
||||||
srv->_next = 0;
|
srv->_next = 0;
|
||||||
if(_services) _services->_next = srv;
|
srv->_txts = 0;
|
||||||
else _services = srv;
|
srv->_txtLen = 0;
|
||||||
|
|
||||||
|
if(_services == 0) _services = srv;
|
||||||
|
else{
|
||||||
|
MDNSService* servicePtr = _services;
|
||||||
|
while(servicePtr->_next !=0) servicePtr = servicePtr->_next;
|
||||||
|
servicePtr->_next = srv;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
MDNSTxt * MDNSResponder::_getServiceTxt(char *name, char *proto){
|
||||||
|
MDNSService* servicePtr;
|
||||||
|
for (servicePtr = _services; servicePtr; servicePtr = servicePtr->_next) {
|
||||||
|
if(servicePtr->_port > 0 && strcmp(servicePtr->_name, name) == 0 && strcmp(servicePtr->_proto, proto) == 0){
|
||||||
|
if (servicePtr->_txts == 0) return false;
|
||||||
|
else{
|
||||||
|
return servicePtr->_txts;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t MDNSResponder::_getServiceTxtLen(char *name, char *proto){
|
||||||
|
MDNSService* servicePtr;
|
||||||
|
for (servicePtr = _services; servicePtr; servicePtr = servicePtr->_next) {
|
||||||
|
if(servicePtr->_port > 0 && strcmp(servicePtr->_name, name) == 0 && strcmp(servicePtr->_proto, proto) == 0){
|
||||||
|
if (servicePtr->_txts == 0) return false;
|
||||||
|
else{
|
||||||
|
return servicePtr->_txtLen;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t MDNSResponder::_getServicePort(char *name, char *proto){
|
uint16_t MDNSResponder::_getServicePort(char *name, char *proto){
|
||||||
@ -172,7 +269,7 @@ uint32_t MDNSResponder::_getOurIp(){
|
|||||||
return staIpInfo.ip.addr;
|
return staIpInfo.ip.addr;
|
||||||
} else {
|
} else {
|
||||||
#ifdef MDNS_DEBUG_ERR
|
#ifdef MDNS_DEBUG_ERR
|
||||||
os_printf("ERR_NO_LOCAL_IP\n");
|
Serial.printf("ERR_NO_LOCAL_IP\n");
|
||||||
#endif
|
#endif
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -217,9 +314,11 @@ void MDNSResponder::_parsePacket(){
|
|||||||
hostNameLen = 0;
|
hostNameLen = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(hostNameLen > 0 && strcmp(_hostName, hostName) != 0){
|
if(hostNameLen > 0 && !_hostName.equals(hostName) && !_instanceName.equals(hostName)){
|
||||||
#ifdef MDNS_DEBUG_ERR
|
#ifdef MDNS_DEBUG_ERR
|
||||||
os_printf("ERR_NO_HOST: %s\n", hostName);
|
Serial.printf("ERR_NO_HOST: %s\n", hostName);
|
||||||
|
Serial.printf("hostname: %s\n", _hostName.c_str() );
|
||||||
|
Serial.printf("instance: %s\n", _instanceName.c_str() );
|
||||||
#endif
|
#endif
|
||||||
_conn->flush();
|
_conn->flush();
|
||||||
return;
|
return;
|
||||||
@ -244,14 +343,14 @@ void MDNSResponder::_parsePacket(){
|
|||||||
localParsed = true;
|
localParsed = true;
|
||||||
} else {
|
} else {
|
||||||
#ifdef MDNS_DEBUG_ERR
|
#ifdef MDNS_DEBUG_ERR
|
||||||
os_printf("ERR_FQDN: %s\n", serviceName);
|
Serial.printf("ERR_FQDN: %s\n", serviceName);
|
||||||
#endif
|
#endif
|
||||||
_conn->flush();
|
_conn->flush();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
#ifdef MDNS_DEBUG_ERR
|
#ifdef MDNS_DEBUG_ERR
|
||||||
os_printf("ERR_SERVICE: %s\n", serviceName);
|
Serial.printf("ERR_SERVICE: %s\n", serviceName);
|
||||||
#endif
|
#endif
|
||||||
_conn->flush();
|
_conn->flush();
|
||||||
return;
|
return;
|
||||||
@ -268,7 +367,7 @@ void MDNSResponder::_parsePacket(){
|
|||||||
protoParsed = true;
|
protoParsed = true;
|
||||||
} else {
|
} else {
|
||||||
#ifdef MDNS_DEBUG_ERR
|
#ifdef MDNS_DEBUG_ERR
|
||||||
os_printf("ERR_PROTO: %s\n", protoName);
|
Serial.printf("ERR_PROTO: %s\n", protoName);
|
||||||
#endif
|
#endif
|
||||||
_conn->flush();
|
_conn->flush();
|
||||||
return;
|
return;
|
||||||
@ -285,7 +384,7 @@ void MDNSResponder::_parsePacket(){
|
|||||||
localParsed = true;
|
localParsed = true;
|
||||||
} else {
|
} else {
|
||||||
#ifdef MDNS_DEBUG_ERR
|
#ifdef MDNS_DEBUG_ERR
|
||||||
os_printf("ERR_FQDN: %s\n", localName);
|
Serial.printf("ERR_FQDN: %s\n", localName);
|
||||||
#endif
|
#endif
|
||||||
_conn->flush();
|
_conn->flush();
|
||||||
return;
|
return;
|
||||||
@ -296,14 +395,14 @@ void MDNSResponder::_parsePacket(){
|
|||||||
servicePort = _getServicePort(serviceName, protoName);
|
servicePort = _getServicePort(serviceName, protoName);
|
||||||
if(servicePort == 0){
|
if(servicePort == 0){
|
||||||
#ifdef MDNS_DEBUG_ERR
|
#ifdef MDNS_DEBUG_ERR
|
||||||
os_printf("ERR_NO_SERVICE: %s\n", serviceName);
|
Serial.printf("ERR_NO_SERVICE: %s\n", serviceName);
|
||||||
#endif
|
#endif
|
||||||
_conn->flush();
|
_conn->flush();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else if(serviceNameLen > 0 || protoNameLen > 0){
|
} else if(serviceNameLen > 0 || protoNameLen > 0){
|
||||||
#ifdef MDNS_DEBUG_ERR
|
#ifdef MDNS_DEBUG_ERR
|
||||||
os_printf("ERR_SERVICE_PROTO: %s\n", serviceName);
|
Serial.printf("ERR_SERVICE_PROTO: %s\n", serviceName);
|
||||||
#endif
|
#endif
|
||||||
_conn->flush();
|
_conn->flush();
|
||||||
return;
|
return;
|
||||||
@ -312,7 +411,7 @@ void MDNSResponder::_parsePacket(){
|
|||||||
// 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]);
|
Serial.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;
|
||||||
@ -339,24 +438,24 @@ void MDNSResponder::_parsePacket(){
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef MDNS_DEBUG_RX
|
#ifdef MDNS_DEBUG_RX
|
||||||
os_printf("REQ: ");
|
Serial.printf("REQ: ");
|
||||||
if(hostNameLen > 0) os_printf("%s.", hostName);
|
if(hostNameLen > 0) Serial.printf("%s.", hostName);
|
||||||
if(serviceNameLen > 0) os_printf("_%s.", serviceName);
|
if(serviceNameLen > 0) Serial.printf("_%s.", serviceName);
|
||||||
if(protoNameLen > 0) os_printf("_%s.", protoName);
|
if(protoNameLen > 0) Serial.printf("_%s.", protoName);
|
||||||
os_printf("local. ");
|
Serial.printf("local. ");
|
||||||
|
|
||||||
if(currentType == MDNS_TYPE_AAAA) os_printf(" AAAA ");
|
if(currentType == MDNS_TYPE_AAAA) Serial.printf(" AAAA ");
|
||||||
else if(currentType == MDNS_TYPE_A) os_printf(" A ");
|
else if(currentType == MDNS_TYPE_A) Serial.printf(" A ");
|
||||||
else if(currentType == MDNS_TYPE_PTR) os_printf(" PTR ");
|
else if(currentType == MDNS_TYPE_PTR) Serial.printf(" PTR ");
|
||||||
else if(currentType == MDNS_TYPE_SRV) os_printf(" SRV ");
|
else if(currentType == MDNS_TYPE_SRV) Serial.printf(" SRV ");
|
||||||
else if(currentType == MDNS_TYPE_TXT) os_printf(" TXT ");
|
else if(currentType == MDNS_TYPE_TXT) Serial.printf(" TXT ");
|
||||||
else os_printf(" 0x%04X ", currentType);
|
else Serial.printf(" 0x%04X ", currentType);
|
||||||
|
|
||||||
if(currentClass == MDNS_CLASS_IN) os_printf(" IN ");
|
if(currentClass == MDNS_CLASS_IN) Serial.printf(" IN ");
|
||||||
else if(currentClass == MDNS_CLASS_IN_FLUSH_CACHE) os_printf(" IN[F] ");
|
else if(currentClass == MDNS_CLASS_IN_FLUSH_CACHE) Serial.printf(" IN[F] ");
|
||||||
else os_printf(" 0x%04X ", currentClass);
|
else Serial.printf(" 0x%04X ", currentClass);
|
||||||
|
|
||||||
os_printf("\n");
|
Serial.printf("\n");
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
uint8_t responseMask = 0;
|
uint8_t responseMask = 0;
|
||||||
@ -371,8 +470,12 @@ void MDNSResponder::_parsePacket(){
|
|||||||
}
|
}
|
||||||
|
|
||||||
void MDNSResponder::enableArduino(uint16_t port, bool auth){
|
void MDNSResponder::enableArduino(uint16_t port, bool auth){
|
||||||
_arduinoAuth = auth;
|
|
||||||
addService("arduino", "tcp", port);
|
addService("arduino", "tcp", port);
|
||||||
|
addServiceTxt("arduino", "tcp", "tcp_check", "no");
|
||||||
|
addServiceTxt("arduino", "tcp", "ssh_upload", "no");
|
||||||
|
addServiceTxt("arduino", "tcp", "board", ARDUINO_BOARD);
|
||||||
|
addServiceTxt("arduino", "tcp", "auth_upload", (auth) ? "yes":"no");
|
||||||
}
|
}
|
||||||
|
|
||||||
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){
|
||||||
@ -380,17 +483,44 @@ void MDNSResponder::_reply(uint8_t replyMask, char * service, char *proto, uint1
|
|||||||
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);
|
Serial.printf("TX: mask:%01X, service:%s, proto:%s, port:%u\n", replyMask, service, proto, port);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
char nameLen = os_strlen(_hostName);
|
|
||||||
size_t serviceLen = os_strlen(service);
|
String instanceName = _instanceName;
|
||||||
|
size_t instanceNameLen = instanceName.length();
|
||||||
|
|
||||||
|
String hostName = _hostName;
|
||||||
|
size_t hostNameLen = hostName.length();
|
||||||
|
|
||||||
|
char underscore[] = "_";
|
||||||
|
|
||||||
|
// build service name with _
|
||||||
|
char serviceName[os_strlen(service)+2];
|
||||||
|
os_strcpy(serviceName,underscore);
|
||||||
|
os_strcat(serviceName, service);
|
||||||
|
size_t serviceNameLen = os_strlen(serviceName);
|
||||||
|
|
||||||
|
//build proto name with _
|
||||||
|
char protoName[5];
|
||||||
|
os_strcpy(protoName,underscore);
|
||||||
|
os_strcat(protoName, proto);
|
||||||
|
size_t protoNameLen = 4;
|
||||||
|
|
||||||
|
//local string
|
||||||
|
char localName[] = "local";
|
||||||
|
size_t localNameLen = 5;
|
||||||
|
|
||||||
|
//terminator
|
||||||
|
char terminator[] = "\0";
|
||||||
|
|
||||||
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++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//Write the header
|
||||||
_conn->flush();
|
_conn->flush();
|
||||||
uint8_t head[12] = {
|
uint8_t head[12] = {
|
||||||
0x00, 0x00, //ID = 0
|
0x00, 0x00, //ID = 0
|
||||||
@ -402,139 +532,142 @@ void MDNSResponder::_reply(uint8_t replyMask, char * service, char *proto, uint1
|
|||||||
};
|
};
|
||||||
_conn->append(reinterpret_cast<const char*>(head), 12);
|
_conn->append(reinterpret_cast<const char*>(head), 12);
|
||||||
|
|
||||||
if((replyMask & 0x8) == 0){
|
|
||||||
_conn->append(reinterpret_cast<const char*>(&nameLen), 1);
|
|
||||||
_conn->append(reinterpret_cast<const char*>(_hostName), nameLen);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(replyMask & 0xE){
|
|
||||||
uint8_t servHead[2] = {(uint8_t)(serviceLen+1), '_'};
|
|
||||||
uint8_t protoHead[2] = {0x4, '_'};
|
|
||||||
_conn->append(reinterpret_cast<const char*>(servHead), 2);
|
|
||||||
_conn->append(reinterpret_cast<const char*>(service), serviceLen);
|
|
||||||
_conn->append(reinterpret_cast<const char*>(protoHead), 2);
|
|
||||||
_conn->append(reinterpret_cast<const char*>(proto), 3);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t local[7] = {
|
|
||||||
0x05, //strlen(_local)
|
|
||||||
0x6C, 0x6F, 0x63, 0x61, 0x6C, //local
|
|
||||||
0x00, //End of domain
|
|
||||||
};
|
|
||||||
_conn->append(reinterpret_cast<const char*>(local), 7);
|
|
||||||
|
|
||||||
// PTR Response
|
// PTR Response
|
||||||
if(replyMask & 0x8){
|
if(replyMask & 0x8){
|
||||||
uint8_t ptr[10] = {
|
// Send the Name field (ie. "_http._tcp.local")
|
||||||
0x00, 0x0c, //PTR record query
|
_conn->append(reinterpret_cast<const char*>(&serviceNameLen), 1); // lenght of "_http"
|
||||||
0x00, 0x01, //Class IN
|
_conn->append(reinterpret_cast<const char*>(serviceName), serviceNameLen); // "_http"
|
||||||
0x00, 0x00, 0x11, 0x94, //TTL 4500
|
_conn->append(reinterpret_cast<const char*>(&protoNameLen), 1); // lenght of "_tcp"
|
||||||
0x00, (uint8_t)(3 + nameLen), //***DATA LEN (3 + strlen(host))
|
_conn->append(reinterpret_cast<const char*>(protoName), protoNameLen); // "_tcp"
|
||||||
};
|
_conn->append(reinterpret_cast<const char*>(&localNameLen), 1); // lenght "local"
|
||||||
_conn->append(reinterpret_cast<const char*>(ptr), 10);
|
_conn->append(reinterpret_cast<const char*>(localName), localNameLen); // "local"
|
||||||
_conn->append(reinterpret_cast<const char*>(&nameLen), 1);
|
_conn->append(reinterpret_cast<const char*>(&terminator), 1); // terminator
|
||||||
_conn->append(reinterpret_cast<const char*>(_hostName), nameLen);
|
|
||||||
uint8_t ptrTail[2] = {0xC0, 0x0C};
|
|
||||||
_conn->append(reinterpret_cast<const char*>(ptrTail), 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
// TXT Response
|
|
||||||
if(replyMask & 0x4){
|
|
||||||
if(replyMask & 0x8){
|
|
||||||
uint8_t txtHead[10] = {
|
|
||||||
0xC0, (uint8_t)(36 + serviceLen),//send the name
|
|
||||||
0x00, 0x10, //Type TXT
|
|
||||||
0x80, 0x01, //Class IN, with cache flush
|
|
||||||
0x00, 0x00, 0x11, 0x94, //TTL 4500
|
|
||||||
};
|
|
||||||
_conn->append(reinterpret_cast<const char*>(txtHead), 10);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(strcmp(reinterpret_cast<const char*>("arduino"), service) == 0){
|
|
||||||
//arduino
|
|
||||||
//arduino service dependance should be removed and properties abstracted
|
|
||||||
const char *tcpCheckExtra = "tcp_check=no";
|
|
||||||
uint8_t tcpCheckExtraLen = os_strlen(tcpCheckExtra);
|
|
||||||
|
|
||||||
const char *sshUploadExtra = "ssh_upload=no";
|
|
||||||
uint8_t sshUploadExtraLen = os_strlen(sshUploadExtra);
|
|
||||||
|
|
||||||
char boardName[64];
|
|
||||||
const char *boardExtra = "board=";
|
|
||||||
os_sprintf(boardName, "%s%s", boardExtra, ARDUINO_BOARD);
|
|
||||||
uint8_t boardNameLen = os_strlen(boardName);
|
|
||||||
|
|
||||||
char authUpload[16];
|
|
||||||
const char *authUploadExtra = "auth_upload=";
|
|
||||||
os_sprintf(authUpload, "%s%s", authUploadExtra, reinterpret_cast<const char*>((_arduinoAuth)?"yes":"no"));
|
|
||||||
uint8_t authUploadLen = os_strlen(authUpload);
|
|
||||||
|
|
||||||
uint16_t textDataLen = (1 + boardNameLen) + (1 + tcpCheckExtraLen) + (1 + sshUploadExtraLen) + (1 + authUploadLen);
|
//Send the type, class, ttl and rdata length
|
||||||
uint8_t txt[2] = {(uint8_t)(textDataLen >> 8), (uint8_t)(textDataLen)}; //DATA LEN
|
uint8_t ptrDataLen = instanceNameLen + serviceNameLen + protoNameLen + localNameLen + 5; // 5 is four label sizes and the terminator
|
||||||
_conn->append(reinterpret_cast<const char*>(txt), 2);
|
uint8_t ptrAttrs[10] = {
|
||||||
|
0x00, 0x0c, //PTR record query
|
||||||
_conn->append(reinterpret_cast<const char*>(&boardNameLen), 1);
|
0x00, 0x01, //Class IN
|
||||||
_conn->append(reinterpret_cast<const char*>(boardName), boardNameLen);
|
0x00, 0x00, 0x11, 0x94, //TTL 4500
|
||||||
_conn->append(reinterpret_cast<const char*>(&authUploadLen), 1);
|
0x00, ptrDataLen, //RData length
|
||||||
_conn->append(reinterpret_cast<const char*>(authUpload), authUploadLen);
|
};
|
||||||
_conn->append(reinterpret_cast<const char*>(&tcpCheckExtraLen), 1);
|
_conn->append(reinterpret_cast<const char*>(ptrAttrs), 10);
|
||||||
_conn->append(reinterpret_cast<const char*>(tcpCheckExtra), tcpCheckExtraLen);
|
|
||||||
_conn->append(reinterpret_cast<const char*>(&sshUploadExtraLen), 1);
|
//Send the RData (ie. "My IOT device._http._tcp.local")
|
||||||
_conn->append(reinterpret_cast<const char*>(sshUploadExtra), sshUploadExtraLen);
|
_conn->append(reinterpret_cast<const char*>(&instanceNameLen), 1); // lenght of "My IOT device"
|
||||||
} else {
|
_conn->append(reinterpret_cast<const char*>(instanceName.c_str()), instanceNameLen);// "My IOT device"
|
||||||
//not arduino
|
_conn->append(reinterpret_cast<const char*>(&serviceNameLen), 1); // lenght of "_http"
|
||||||
//we should figure out an API so TXT properties can be added for services
|
_conn->append(reinterpret_cast<const char*>(serviceName), serviceNameLen); // "_http"
|
||||||
uint8_t txt[2] = {0,0};
|
_conn->append(reinterpret_cast<const char*>(&protoNameLen), 1); // lenght of "_tcp"
|
||||||
_conn->append(reinterpret_cast<const char*>(txt), 2);
|
_conn->append(reinterpret_cast<const char*>(protoName), protoNameLen); // "_tcp"
|
||||||
|
_conn->append(reinterpret_cast<const char*>(&localNameLen), 1); // lenght "local"
|
||||||
|
_conn->append(reinterpret_cast<const char*>(localName), localNameLen); // "local"
|
||||||
|
_conn->append(reinterpret_cast<const char*>(&terminator), 1); // terminator
|
||||||
|
}
|
||||||
|
|
||||||
|
//TXT Responce
|
||||||
|
if(replyMask & 0x4){
|
||||||
|
//Send the name field (ie. "My IOT device._http._tcp.local")
|
||||||
|
_conn->append(reinterpret_cast<const char*>(&instanceNameLen), 1); // lenght of "My IOT device"
|
||||||
|
_conn->append(reinterpret_cast<const char*>(instanceName.c_str()), instanceNameLen);// "My IOT device"
|
||||||
|
_conn->append(reinterpret_cast<const char*>(&serviceNameLen), 1); // lenght of "_http"
|
||||||
|
_conn->append(reinterpret_cast<const char*>(serviceName), serviceNameLen); // "_http"
|
||||||
|
_conn->append(reinterpret_cast<const char*>(&protoNameLen), 1); // lenght of "_tcp"
|
||||||
|
_conn->append(reinterpret_cast<const char*>(protoName), protoNameLen); // "_tcp"
|
||||||
|
_conn->append(reinterpret_cast<const char*>(&localNameLen), 1); // lenght "local"
|
||||||
|
_conn->append(reinterpret_cast<const char*>(localName), localNameLen); // "local"
|
||||||
|
_conn->append(reinterpret_cast<const char*>(&terminator), 1); // terminator
|
||||||
|
|
||||||
|
//Send the type, class, ttl and rdata length
|
||||||
|
uint8_t txtDataLen = _getServiceTxtLen(service,proto);
|
||||||
|
uint8_t txtAttrs[10] = {
|
||||||
|
0x00, 0x10, //TXT record query
|
||||||
|
0x00, 0x01, //Class IN
|
||||||
|
0x00, 0x00, 0x11, 0x94, //TTL 4500
|
||||||
|
0x00, txtDataLen, //RData length
|
||||||
|
};
|
||||||
|
_conn->append(reinterpret_cast<const char*>(txtAttrs), 10);
|
||||||
|
|
||||||
|
//Send the RData
|
||||||
|
MDNSTxt * txtPtr = _getServiceTxt(service,proto);
|
||||||
|
while(txtPtr !=0){
|
||||||
|
uint8_t txtLen = txtPtr->_txt.length();
|
||||||
|
_conn->append(reinterpret_cast<const char*>(&txtLen), 1); // lenght of txt
|
||||||
|
_conn->append(reinterpret_cast<const char*>(txtPtr->_txt.c_str()), txtLen);// the txt
|
||||||
|
txtPtr = txtPtr->_next;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// SRV Response
|
|
||||||
if(replyMask & 0x2){
|
|
||||||
if(replyMask & 0xC){//send the name
|
|
||||||
uint8_t srvHead[2] = {0xC0, 0x0C};
|
|
||||||
if(replyMask & 0x8)
|
|
||||||
srvHead[1] = 36 + serviceLen;
|
|
||||||
_conn->append(reinterpret_cast<const char*>(srvHead), 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t srv[16] = {
|
//SRV Responce
|
||||||
0x00, 0x21, //Type SRV
|
if(replyMask & 0x2){
|
||||||
0x80, 0x01, //Class IN, with cache flush
|
//Send the name field (ie. "My IOT device._http._tcp.local")
|
||||||
|
_conn->append(reinterpret_cast<const char*>(&instanceNameLen), 1); // lenght of "My IOT device"
|
||||||
|
_conn->append(reinterpret_cast<const char*>(instanceName.c_str()), instanceNameLen);// "My IOT device"
|
||||||
|
_conn->append(reinterpret_cast<const char*>(&serviceNameLen), 1); // lenght of "_http"
|
||||||
|
_conn->append(reinterpret_cast<const char*>(serviceName), serviceNameLen); // "_http"
|
||||||
|
_conn->append(reinterpret_cast<const char*>(&protoNameLen), 1); // lenght of "_tcp"
|
||||||
|
_conn->append(reinterpret_cast<const char*>(protoName), protoNameLen); // "_tcp"
|
||||||
|
_conn->append(reinterpret_cast<const char*>(&localNameLen), 1); // lenght "local"
|
||||||
|
_conn->append(reinterpret_cast<const char*>(localName), localNameLen); // "local"
|
||||||
|
_conn->append(reinterpret_cast<const char*>(&terminator), 1); // terminator
|
||||||
|
|
||||||
|
//Send the type, class, ttl, rdata length, priority and weight
|
||||||
|
uint8_t srvDataSize = hostNameLen + localNameLen + 3; // 3 is 2 lable size bytes and the terminator
|
||||||
|
srvDataSize += 6; // Size of Priority, weight and port
|
||||||
|
uint8_t srvAttrs[10] = {
|
||||||
|
0x00, 0x21, //Type SRV
|
||||||
|
0x80, 0x01, //Class IN, with cache flush
|
||||||
0x00, 0x00, 0x00, 0x78, //TTL 120
|
0x00, 0x00, 0x00, 0x78, //TTL 120
|
||||||
0x00, (uint8_t)(9 + nameLen), //DATA LEN (9 + strlen(host))
|
0x00, srvDataSize, //RData length
|
||||||
0x00, 0x00, //Priority 0
|
|
||||||
0x00, 0x00, //Weight 0
|
|
||||||
(uint8_t)((port >> 8) & 0xFF), (uint8_t)(port & 0xFF)
|
|
||||||
};
|
};
|
||||||
_conn->append(reinterpret_cast<const char*>(srv), 16);
|
_conn->append(reinterpret_cast<const char*>(srvAttrs), 10);
|
||||||
_conn->append(reinterpret_cast<const char*>(&nameLen), 1);
|
|
||||||
_conn->append(reinterpret_cast<const char*>(_hostName), nameLen);
|
//Send the RData Priority weight and port
|
||||||
uint8_t srvTail[2] = {0xC0, (uint8_t)(20 + serviceLen + nameLen)};
|
uint8_t srvRData[6] = {
|
||||||
if(replyMask & 0x8)
|
0x00, 0x00, //Priority 0
|
||||||
srvTail[1] = 19 + serviceLen;
|
0x00, 0x00, //Weight 0
|
||||||
_conn->append(reinterpret_cast<const char*>(srvTail), 2);
|
(uint8_t)((port >> 8) & 0xFF), (uint8_t)(port & 0xFF)
|
||||||
|
};
|
||||||
|
_conn->append(reinterpret_cast<const char*>(srvRData), 6);
|
||||||
|
//Send the RData (ie. "esp8266.local")
|
||||||
|
_conn->append(reinterpret_cast<const char*>(&hostNameLen), 1); // lenght of "esp8266"
|
||||||
|
_conn->append(reinterpret_cast<const char*>(hostName.c_str()), hostNameLen);// "esp8266"
|
||||||
|
_conn->append(reinterpret_cast<const char*>(&localNameLen), 1); // lenght "local"
|
||||||
|
_conn->append(reinterpret_cast<const char*>(localName), localNameLen); // "local"
|
||||||
|
_conn->append(reinterpret_cast<const char*>(&terminator), 1); // terminator
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// A Response
|
// A Response
|
||||||
if(replyMask & 0x1){
|
if(replyMask & 0x1){
|
||||||
uint32_t ip = _getOurIp();
|
//Send the RData (ie. "esp8266.local")
|
||||||
if(replyMask & 0x2){//send the name (no compression for now)
|
_conn->append(reinterpret_cast<const char*>(&hostNameLen), 1); // lenght of "esp8266"
|
||||||
_conn->append(reinterpret_cast<const char*>(&nameLen), 1);
|
_conn->append(reinterpret_cast<const char*>(hostName.c_str()), hostNameLen);// "esp8266"
|
||||||
_conn->append(reinterpret_cast<const char*>(_hostName), nameLen);
|
_conn->append(reinterpret_cast<const char*>(&localNameLen), 1); // lenght "local"
|
||||||
_conn->append(reinterpret_cast<const char*>(local), 7);
|
_conn->append(reinterpret_cast<const char*>(localName), localNameLen); // "local"
|
||||||
}
|
_conn->append(reinterpret_cast<const char*>(&terminator), 1); // terminator
|
||||||
|
|
||||||
uint8_t aaa[14] = {
|
uint32_t ip = _getOurIp();
|
||||||
0x00, 0x01, //TYPE A
|
uint8_t aaaAttrs[10] = {
|
||||||
0x80, 0x01, //Class IN, with cache flush
|
0x00, 0x01, //TYPE A
|
||||||
|
0x80, 0x01, //Class IN, with cache flush
|
||||||
0x00, 0x00, 0x00, 0x78, //TTL 120
|
0x00, 0x00, 0x00, 0x78, //TTL 120
|
||||||
0x00, 0x04, //DATA LEN
|
0x00, 0x04, //DATA LEN
|
||||||
(uint8_t)(ip & 0xFF), (uint8_t)((ip >> 8) & 0xFF), (uint8_t)((ip >> 16) & 0xFF), (uint8_t)((ip >> 24) & 0xFF)
|
|
||||||
};
|
};
|
||||||
_conn->append(reinterpret_cast<const char*>(aaa), 14);
|
_conn->append(reinterpret_cast<const char*>(aaaAttrs), 10);
|
||||||
|
|
||||||
|
// Send RData
|
||||||
|
uint8_t aaaRData[4] = {
|
||||||
|
(uint8_t)(ip & 0xFF), //IP first octet
|
||||||
|
(uint8_t)((ip >> 8) & 0xFF), //IP second octet
|
||||||
|
(uint8_t)((ip >> 16) & 0xFF), //IP third octet
|
||||||
|
(uint8_t)((ip >> 24) & 0xFF) //IP fourth octet
|
||||||
|
};
|
||||||
|
_conn->append(reinterpret_cast<const char*>(aaaRData), 4);
|
||||||
}
|
}
|
||||||
_conn->send();
|
|
||||||
|
_conn->send();
|
||||||
}
|
}
|
||||||
|
|
||||||
MDNSResponder MDNS = MDNSResponder();
|
MDNSResponder MDNS = MDNSResponder();
|
||||||
|
@ -52,12 +52,8 @@ License (MIT license):
|
|||||||
|
|
||||||
class UdpContext;
|
class UdpContext;
|
||||||
|
|
||||||
struct MDNSService {
|
struct MDNSService;
|
||||||
MDNSService* _next;
|
struct MDNSTxt;
|
||||||
char _name[32];
|
|
||||||
char _proto[3];
|
|
||||||
uint16_t _port;
|
|
||||||
};
|
|
||||||
|
|
||||||
class MDNSResponder {
|
class MDNSResponder {
|
||||||
public:
|
public:
|
||||||
@ -78,16 +74,34 @@ public:
|
|||||||
addService(service.c_str(), proto.c_str(), port);
|
addService(service.c_str(), proto.c_str(), port);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool addServiceTxt(char *name, char *proto, char * key, char * value);
|
||||||
|
void addServiceTxt(const char *name, const char *proto, const char *key,const char * value){
|
||||||
|
addServiceTxt((char *)name, (char *)proto, (char *)key, (char *)value);
|
||||||
|
}
|
||||||
|
void addServiceTxt(String name, String proto, String key, String value){
|
||||||
|
addServiceTxt(name.c_str(), proto.c_str(), key.c_str(), value.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
void enableArduino(uint16_t port, bool auth=false);
|
void enableArduino(uint16_t port, bool auth=false);
|
||||||
|
|
||||||
|
void setInstanceName(String name);
|
||||||
|
void setInstanceName(const char * name){
|
||||||
|
setInstanceName(String(name));
|
||||||
|
}
|
||||||
|
void setInstanceName(char * name){
|
||||||
|
setInstanceName(String(name));
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct MDNSService * _services;
|
struct MDNSService * _services;
|
||||||
UdpContext* _conn;
|
UdpContext* _conn;
|
||||||
char _hostName[128];
|
String _hostName;
|
||||||
bool _arduinoAuth;
|
String _instanceName;
|
||||||
|
|
||||||
uint32_t _getOurIp();
|
uint32_t _getOurIp();
|
||||||
uint16_t _getServicePort(char *service, char *proto);
|
uint16_t _getServicePort(char *service, char *proto);
|
||||||
|
MDNSTxt * _getServiceTxt(char *name, char *proto);
|
||||||
|
uint16_t _getServiceTxtLen(char *name, char *proto);
|
||||||
void _parsePacket();
|
void _parsePacket();
|
||||||
void _reply(uint8_t replyMask, char * service, char *proto, uint16_t port);
|
void _reply(uint8_t replyMask, char * service, char *proto, uint16_t port);
|
||||||
};
|
};
|
||||||
|
24
libraries/GDBStub/License
Normal file
24
libraries/GDBStub/License
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
ESPRESSIF MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2015 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
|
||||||
|
|
||||||
|
Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case, it is free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
|
||||||
|
乐鑫 MIT 许可证
|
||||||
|
|
||||||
|
版权 (c) 2015 <乐鑫信息科技(上海)有限公司>
|
||||||
|
|
||||||
|
该许可证授权仅限于乐鑫信息科技 ESP8266 产品的应用开发。在此情况下,该许可证免费授权任何获得该软件及其相关文档(统称为“软件”)的人无限制地经营该软件,包括无限制的使用、复制、修改、合并、出版发行、散布、再授权、及贩售软件及软件副本的权利。被授权人在享受这些权利的同时,需服从下面的条件:
|
||||||
|
|
||||||
|
在软件和软件的所有副本中都必须包含以上的版权声明和授权声明。
|
||||||
|
|
||||||
|
该软件按本来的样子提供,没有任何明确或暗含的担保,包括但不仅限于关于试销性、适合某一特定用途和非侵权的保证。作者和版权持有人在任何情况下均不就由软件或软件使用引起的以合同形式、民事侵权或其它方式提出的任何索赔、损害或其它责任负责。
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
69
libraries/GDBStub/README-lib.md
Normal file
69
libraries/GDBStub/README-lib.md
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
|
||||||
|
GDBSTUB
|
||||||
|
=======
|
||||||
|
|
||||||
|
Intro
|
||||||
|
-----
|
||||||
|
|
||||||
|
While the ESP8266 supports the standard Gnu set of C programming utilities, for now the choice of debuggers
|
||||||
|
has been limited: there is an attempt at [OpenOCD support](https://github.com/projectgus/openocd), but at
|
||||||
|
the time of writing, it doesn't support hardware watchpoints and breakpoints yet, and it needs a separate
|
||||||
|
JTAG adapter connecting to the ESP8266s JTAG pins. As an alternative, [Cesanta](https://www.cesanta.com/)
|
||||||
|
has implemented a barebones[GDB stub](https://blog.cesanta.com/esp8266-gdb) in their Smart.js solution -
|
||||||
|
unfortunately, this only supports exception catching and needs some work before you can use it outside of
|
||||||
|
the Smart.js platform. Moreover, it also does not work with FreeRTOS.
|
||||||
|
|
||||||
|
For internal use, we at Espressif desired a GDB stub that works with FreeRTOS and is a bit more capable,
|
||||||
|
so we designed our own implementation of it. This stub works both under FreeRTOS as well as the OS-less
|
||||||
|
SDK and is able to catch exceptions and do backtraces on them, read and write memory, forward [os_]printf
|
||||||
|
statements to gdb, single-step instructions and set hardware break- and watchpoints. It connects to the
|
||||||
|
host machine (which runs gdb) using the standard serial connection that's also used for programming.
|
||||||
|
|
||||||
|
In order to be useful the gdbstub has to be used in conjunction with an xtensa-lx106-elf-gdb, for example
|
||||||
|
as generated by the [esp-open-sdk](https://github.com/pfalcon/esp-open-sdk) project.
|
||||||
|
|
||||||
|
Usage
|
||||||
|
-----
|
||||||
|
* Grab the gdbstub project and put the files in a directory called 'gdbstub' in your project. You can do this
|
||||||
|
either by checking out the Git repo, or adding the Git repo as a submodule to your project if it's already
|
||||||
|
in Git.
|
||||||
|
* Modify your Makefile. You'll need to include the gdbstub sources: if your Makefile is structured like the
|
||||||
|
ones in the Espressif examples, you can add `gdbstub` to the `SUBDIRS` define and `gdbstub/libgdbstub.a` to the
|
||||||
|
`COMPONENTS_eagle.app.v6` define. Also, you probably want to add `-ggdb` to your compiler flags (`TARGET_LDFLAGS`)
|
||||||
|
and, if you are debugging, change any optimation flags (-Os, -O2 etc) into `-Og`. Finally, make sure your Makefile
|
||||||
|
also compiles .S files.
|
||||||
|
* Configure gdbstub by editting `gdbstub-cfg.h`. There are a bunch of options you can tweak: FreeRTOS or bare SDK,
|
||||||
|
private exception/breakpoint stack, console redirection to GDB, wait till debugger attachment etc. You can also
|
||||||
|
configure the options by including the proper -Dwhatever gcc flags in your Makefiles.
|
||||||
|
* In your user_main.c, add an `#include <../gdbstub/gdbstub.h>` and call `gdbstub_init();` somewhere in user_main.
|
||||||
|
* Compile and flash your board.
|
||||||
|
* Run gdb, depending on your configuration immediately after resetting the board or after it has run into
|
||||||
|
an exception. The easiest way to do it is to use the provided script: xtensa-lx106-elf-gdb -x gdbcmds -b 38400
|
||||||
|
Change the '38400' into the baud rate your code uses. You may need to change the gdbcmds script to fit the
|
||||||
|
configuration of your hardware and build environment.
|
||||||
|
|
||||||
|
Notes
|
||||||
|
-----
|
||||||
|
* Using software breakpoints ('br') only works on code that's in RAM. Code in flash can only have a hardware
|
||||||
|
breakpoint ('hbr').
|
||||||
|
* Due to hardware limitations, only one hardware breakpount and one hardware watchpoint are available.
|
||||||
|
* Pressing control-C to interrupt the running program depends on gdbstub hooking the UART interrupt.
|
||||||
|
If some code re-hooks this afterwards, gdbstub won't be able to receive characters. If gdbstub handles
|
||||||
|
the interrupt, the user code will not receive any characters.
|
||||||
|
* Continuing from an exception is not (yet) supported in FreeRTOS mode.
|
||||||
|
* The WiFi hardware is designed to be serviced by software periodically. It has some buffers so it
|
||||||
|
will behave OK when some data comes in while the processor is busy, but these buffers are not infinite.
|
||||||
|
If the WiFi hardware receives lots of data while the debugger has stopped the CPU, it is bound
|
||||||
|
to crash. This will happen mostly when working with UDP and/or ICMP; TCP-connections in general will
|
||||||
|
not send much more data when the other side doesn't send any ACKs.
|
||||||
|
|
||||||
|
License
|
||||||
|
-------
|
||||||
|
This gdbstub is licensed under the Espressif MIT license, as described in the License file.
|
||||||
|
|
||||||
|
|
||||||
|
Thanks
|
||||||
|
------
|
||||||
|
* Cesanta, for their initial ESP8266 exception handling only gdbstub,
|
||||||
|
* jcmvbkbc, for providing an incompatible but interesting gdbstub for other Xtensa CPUs,
|
||||||
|
* Sysprogs (makers of VisualGDB), for their suggestions and bugreports.
|
@ -11,11 +11,14 @@ Change port and baud rate as necessary. This command requires python and pyseria
|
|||||||
```
|
```
|
||||||
nc localhost 9980
|
nc localhost 9980
|
||||||
```
|
```
|
||||||
- When crash happens, `Trap %d: pc=%p va=%p` line will appear in serial output.
|
- Once crash happens, close nc and start gdb:
|
||||||
- Close nc and start gdb:
|
|
||||||
```
|
```
|
||||||
xtensa-lx106-elf-gdb /path/to/Sketch.cpp.elf -ex "target remote :9980"
|
xtensa-lx106-elf-gdb /path/to/Sketch.cpp.elf -ex "target remote :9980"
|
||||||
```
|
```
|
||||||
|
Or, using the provided gdbcmds file:
|
||||||
|
```
|
||||||
|
xtensa-lx106-elf-gdb /path/to/Sketch.cpp.elf -x gdbcmds
|
||||||
|
```
|
||||||
- Use gdb to inspect program state at the point of an exception.
|
- Use gdb to inspect program state at the point of an exception.
|
||||||
|
|
||||||
## Tips and tricks
|
## Tips and tricks
|
||||||
@ -28,22 +31,4 @@ at the top of `__wrap_system_restart_local` in core_esp8266_postmortem.c.
|
|||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
GDB Server stub by Marko Mikulicic was taken from Cesanta's smart.js
|
Espressif MIT License. See License file.
|
||||||
|
|
||||||
https://github.com/cesanta/smart.js
|
|
||||||
|
|
||||||
Copyright (c) 2013-2014 Cesanta Software Limited
|
|
||||||
All rights reserved
|
|
||||||
|
|
||||||
This software is dual-licensed: you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU General Public License version 2 as
|
|
||||||
published by the Free Software Foundation. For the terms of this
|
|
||||||
license, see <http://www.gnu.org/licenses>.
|
|
||||||
|
|
||||||
You are free to use this software under the terms of the GNU General
|
|
||||||
Public License, but WITHOUT ANY WARRANTY; without even the implied
|
|
||||||
warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
||||||
See the GNU General Public License for more details.
|
|
||||||
|
|
||||||
Alternatively, you can license this software under a commercial
|
|
||||||
license, as set out in <https://www.cesanta.com/license>.
|
|
||||||
|
3
libraries/GDBStub/gdbcmds
Normal file
3
libraries/GDBStub/gdbcmds
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
set remote hardware-breakpoint-limit 1
|
||||||
|
set remote hardware-watchpoint-limit 1
|
||||||
|
target remote :9980
|
@ -1,9 +1,9 @@
|
|||||||
name=GDBStub
|
name=GDBStub
|
||||||
version=0.1
|
version=0.2
|
||||||
author=Marko Mikulicic (Cesanta)
|
author=Jeroen Domburg
|
||||||
maintainer=Ivan Grokhotkov <ivan@esp8266.com>
|
maintainer=Ivan Grokhotkov <ivan@esp8266.com>
|
||||||
sentence=GDB server stub from Cesanta's Smart.js
|
sentence=GDB server stub by Espressif
|
||||||
paragraph=GDB server stub helps debug crashes when JTAG isn't an option.
|
paragraph=GDB server stub helps debug crashes when JTAG isn't an option.
|
||||||
category=Uncategorized
|
category=Uncategorized
|
||||||
url=https://github.com/cesanta/smart.js
|
url=https://github.com/espressif/esp-gdbstub
|
||||||
architectures=esp8266
|
architectures=esp8266
|
||||||
|
@ -1,355 +0,0 @@
|
|||||||
/* GDB Server stub by Marko Mikulicic (Cesanta)
|
|
||||||
|
|
||||||
Copyright (c) 2013-2014 Cesanta Software Limited
|
|
||||||
All rights reserved
|
|
||||||
|
|
||||||
This software is dual-licensed: you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU General Public License version 2 as
|
|
||||||
published by the Free Software Foundation. For the terms of this
|
|
||||||
license, see <http://www.gnu.org/licenses>.
|
|
||||||
|
|
||||||
You are free to use this software under the terms of the GNU General
|
|
||||||
Public License, but WITHOUT ANY WARRANTY; without even the implied
|
|
||||||
warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
||||||
See the GNU General Public License for more details.
|
|
||||||
|
|
||||||
Alternatively, you can license this software under a commercial
|
|
||||||
license, as set out in <https://www.cesanta.com/license>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <stddef.h>
|
|
||||||
#include <stdbool.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include "ets_sys.h"
|
|
||||||
#include "user_interface.h"
|
|
||||||
#include "esp8266_peri.h"
|
|
||||||
|
|
||||||
#include "xtensa/corebits.h"
|
|
||||||
#include "xtensa/specreg.h"
|
|
||||||
|
|
||||||
#define __stringify_1(x...) #x
|
|
||||||
#define __stringify(x...) __stringify_1(x)
|
|
||||||
#define RSR(sr) \
|
|
||||||
({ \
|
|
||||||
uint32_t r; \
|
|
||||||
asm volatile("rsr %0,"__stringify(sr) : "=a"(r)); \
|
|
||||||
r; \
|
|
||||||
})
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* the saved registers begin at a fixed position in the xtos
|
|
||||||
* low-level exception handler. I don't know if 0x100 it's just an
|
|
||||||
* artifact of the actual xtos build ESP8266EX is using (although this nice
|
|
||||||
* round number looks deliberate). The exception handler is burned on rom
|
|
||||||
* so it should work on future SDK updates, but not necessarily on future
|
|
||||||
* revisions of the chip.
|
|
||||||
*/
|
|
||||||
#define V7_GDB_SP_OFFSET 0x100
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Addresses in this range are guaranteed to be readable without faulting.
|
|
||||||
* Contains ranges that are unmapped but innocuous.
|
|
||||||
*
|
|
||||||
* Putative ESP8266 memory map at:
|
|
||||||
* https://github.com/esp8266/esp8266-wiki/wiki/Memory-Map
|
|
||||||
*/
|
|
||||||
#define ESP_LOWER_VALID_ADDRESS 0x20000000
|
|
||||||
#define ESP_UPPER_VALID_ADDRESS 0x60000000
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Constructed by xtos.
|
|
||||||
*
|
|
||||||
* There is a UserFrame structure in
|
|
||||||
* ./esp_iot_rtos_sdk/extra_include/xtensa/xtruntime-frames.h
|
|
||||||
*/
|
|
||||||
struct xtos_saved_regs {
|
|
||||||
uint32_t pc; /* instruction causing the trap */
|
|
||||||
uint32_t ps;
|
|
||||||
uint32_t sar;
|
|
||||||
uint32_t vpri; /* current xtos virtual priority */
|
|
||||||
uint32_t a0; /* when __XTENSA_CALL0_ABI__ is true */
|
|
||||||
uint32_t a[16]; /* a2 - a15 */
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Register file in the format lx106 gdb port expects it.
|
|
||||||
*
|
|
||||||
* Inspired by gdb/regformats/reg-xtensa.dat from
|
|
||||||
* https://github.com/jcmvbkbc/crosstool-NG/blob/lx106-g%2B%2B/overlays/xtensa_lx106.tar
|
|
||||||
*/
|
|
||||||
struct regfile {
|
|
||||||
uint32_t a[16];
|
|
||||||
uint32_t pc;
|
|
||||||
uint32_t sar;
|
|
||||||
uint32_t litbase;
|
|
||||||
uint32_t sr176;
|
|
||||||
uint32_t sr208;
|
|
||||||
uint32_t ps;
|
|
||||||
};
|
|
||||||
|
|
||||||
#define printf ets_printf
|
|
||||||
extern void uart_write_char_d(char c);
|
|
||||||
|
|
||||||
/* TODO(mkm): not sure if gdb guarantees lowercase hex digits */
|
|
||||||
#define fromhex(c) \
|
|
||||||
(((c) &0x40) ? ((c) &0x20 ? (c) - 'a' + 10 : (c) - 'A' + 10) : (c) - '0')
|
|
||||||
#define hexdigit(n) (((n) < 10) ? '0' + (n) : 'a' + ((n) -10))
|
|
||||||
|
|
||||||
static struct regfile regs = {0};
|
|
||||||
static uint8_t gdb_send_checksum;
|
|
||||||
|
|
||||||
int gdb_read_uart() {
|
|
||||||
static char buf[512];
|
|
||||||
static char pos = 0;
|
|
||||||
|
|
||||||
if (pos == 0) {
|
|
||||||
size_t rx_count;
|
|
||||||
while ((rx_count = (USS(0) >> USRXC) & 0xff)>0 && pos < sizeof(buf)) {
|
|
||||||
buf[pos++] = U0F;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (pos == 0) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
return buf[--pos];
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
uint8_t read_unaligned_byte(uint8_t *addr) {
|
|
||||||
uint32_t *base = (uint32_t *) ((uintptr_t) addr & ~0x3);
|
|
||||||
uint32_t word;
|
|
||||||
|
|
||||||
word = *base;
|
|
||||||
return (uint8_t)(word >> 8 * ((uintptr_t) addr & 0x3));
|
|
||||||
}
|
|
||||||
|
|
||||||
void gdb_nack() {
|
|
||||||
printf("-");
|
|
||||||
}
|
|
||||||
|
|
||||||
void gdb_ack() {
|
|
||||||
printf("+");
|
|
||||||
}
|
|
||||||
|
|
||||||
void gdb_begin_packet() {
|
|
||||||
printf("$");
|
|
||||||
gdb_send_checksum = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void gdb_end_packet() {
|
|
||||||
printf("#%c%c", hexdigit(gdb_send_checksum >> 4),
|
|
||||||
hexdigit(gdb_send_checksum & 0xF));
|
|
||||||
}
|
|
||||||
|
|
||||||
void gdb_putchar(char ch) {
|
|
||||||
gdb_send_checksum += (uint8_t) ch;
|
|
||||||
printf("%c", ch);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* output a string while computing the checksum */
|
|
||||||
void gdb_putstr(char *str) {
|
|
||||||
while (*str) gdb_putchar(*str++);
|
|
||||||
}
|
|
||||||
|
|
||||||
void gdb_putbyte(uint8_t val) {
|
|
||||||
gdb_putchar(hexdigit(val >> 4));
|
|
||||||
gdb_putchar(hexdigit(val & 0xF));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 32-bit integer in native byte order */
|
|
||||||
void gdb_putint(uint32_t val) {
|
|
||||||
int i;
|
|
||||||
uint8_t *v = (uint8_t *) &val;
|
|
||||||
for (i = 0; i < 4; i++) {
|
|
||||||
gdb_putbyte(v[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* send a gdb packet with checksum */
|
|
||||||
void gdb_send_packet(char *str) {
|
|
||||||
gdb_begin_packet();
|
|
||||||
gdb_putstr(str);
|
|
||||||
gdb_end_packet();
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t gdb_read_unaligned(uint8_t *addr) {
|
|
||||||
if (addr < (uint8_t *) ESP_LOWER_VALID_ADDRESS ||
|
|
||||||
addr >= (uint8_t *) ESP_UPPER_VALID_ADDRESS) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return read_unaligned_byte(addr);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Handles the GDB server protocol.
|
|
||||||
* We currently support only the simple command set.
|
|
||||||
*
|
|
||||||
* Data is exchanged in packets like `$Cxxxxx#cc`
|
|
||||||
* where `C` is a single letter command name, `xxxx` is some data payload,
|
|
||||||
* and `cc` is a two digit hex checksum of the packet body.
|
|
||||||
* Replies follow the same structure except that they lack the command symbol.
|
|
||||||
*
|
|
||||||
* For a more complete description of the protocol, see
|
|
||||||
* https://sourceware.org/gdb/current/onlinedocs/gdb/Remote-Protocol.html
|
|
||||||
*/
|
|
||||||
void gdb_handle_char(int ch) {
|
|
||||||
static enum {
|
|
||||||
GDB_JUNK,
|
|
||||||
GDB_DATA,
|
|
||||||
GDB_CHECKSUM,
|
|
||||||
GDB_CHECKSUM2
|
|
||||||
} state = GDB_JUNK;
|
|
||||||
static char data[128];
|
|
||||||
static int pos = 0;
|
|
||||||
static uint8_t checksum;
|
|
||||||
|
|
||||||
switch (state) {
|
|
||||||
case GDB_JUNK:
|
|
||||||
if (ch == '$') {
|
|
||||||
checksum = 0;
|
|
||||||
state = GDB_DATA;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case GDB_DATA:
|
|
||||||
if (ch == '#') {
|
|
||||||
state = GDB_CHECKSUM;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
/* ignore too long commands, by acking and sending empty response */
|
|
||||||
if (pos > sizeof(data)) {
|
|
||||||
state = GDB_JUNK;
|
|
||||||
gdb_ack();
|
|
||||||
gdb_send_packet("");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
checksum += (uint8_t) ch;
|
|
||||||
data[pos++] = ch;
|
|
||||||
break;
|
|
||||||
case GDB_CHECKSUM:
|
|
||||||
if (fromhex(ch) != (checksum >> 4)) {
|
|
||||||
gdb_nack();
|
|
||||||
state = GDB_JUNK;
|
|
||||||
} else {
|
|
||||||
state = GDB_CHECKSUM2;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case GDB_CHECKSUM2:
|
|
||||||
state = GDB_JUNK;
|
|
||||||
if (fromhex(ch) != (checksum & 0xF)) {
|
|
||||||
gdb_nack();
|
|
||||||
pos = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
gdb_ack();
|
|
||||||
|
|
||||||
/* process commands */
|
|
||||||
switch (data[0]) {
|
|
||||||
case '?':
|
|
||||||
/* stop status */
|
|
||||||
gdb_send_packet("S09"); /* TRAP */
|
|
||||||
break;
|
|
||||||
case 'm': {
|
|
||||||
/* read memory */
|
|
||||||
int i;
|
|
||||||
uint32_t addr = 0;
|
|
||||||
uint32_t num = 0;
|
|
||||||
for (i = 1; i < pos && data[i] != ','; i++) {
|
|
||||||
addr <<= 4;
|
|
||||||
addr |= fromhex(data[i]);
|
|
||||||
}
|
|
||||||
for (i++; i < pos; i++) {
|
|
||||||
num <<= 4;
|
|
||||||
num |= fromhex(data[i]); /* should be decimal */
|
|
||||||
}
|
|
||||||
gdb_begin_packet();
|
|
||||||
for (i = 0; i < num; i++) {
|
|
||||||
gdb_putbyte(gdb_read_unaligned(((uint8_t *) addr) + i));
|
|
||||||
}
|
|
||||||
gdb_end_packet();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 'g': {
|
|
||||||
/* dump registers */
|
|
||||||
int i;
|
|
||||||
gdb_begin_packet();
|
|
||||||
for (i = 0; i < sizeof(regs); i++) {
|
|
||||||
gdb_putbyte(((uint8_t *) ®s)[i]);
|
|
||||||
}
|
|
||||||
gdb_end_packet();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
gdb_send_packet("");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
pos = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* The user should detach and let gdb do the talkin' */
|
|
||||||
void gdb_server() {
|
|
||||||
printf("waiting for gdb\n");
|
|
||||||
/*
|
|
||||||
* polling since we cannot wait for interrupts inside
|
|
||||||
* an interrupt handler of unknown level.
|
|
||||||
*
|
|
||||||
* Interrupts disabled so that the user (or v7 prompt)
|
|
||||||
* uart interrupt handler doesn't interfere.
|
|
||||||
*/
|
|
||||||
xthal_set_intenable(0);
|
|
||||||
for (;;) {
|
|
||||||
int ch = gdb_read_uart();
|
|
||||||
if (ch != -1) gdb_handle_char(ch);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* xtos low level exception handler (in rom)
|
|
||||||
* populates an xtos_regs structure with (most) registers
|
|
||||||
* present at the time of the exception and passes it to the
|
|
||||||
* high-level handler.
|
|
||||||
*
|
|
||||||
* Note that the a1 (sp) register is clobbered (bug? necessity?),
|
|
||||||
* however the original stack pointer can be inferred from the address
|
|
||||||
* of the saved registers area, since the exception handler uses the same
|
|
||||||
* user stack. This might be different in other execution modes on the
|
|
||||||
* quite variegated xtensa platform family, but that's how it works on ESP8266.
|
|
||||||
*/
|
|
||||||
void ICACHE_RAM_ATTR gdb_exception_handler(struct xtos_saved_regs *frame) {
|
|
||||||
ESP8266_REG(0x900) &= 0x7e; // Disable WDT
|
|
||||||
int i;
|
|
||||||
uint32_t cause = RSR(EXCCAUSE);
|
|
||||||
uint32_t vaddr = RSR(EXCVADDR);
|
|
||||||
memcpy(®s.a[2], frame->a, sizeof(frame->a));
|
|
||||||
|
|
||||||
regs.a[0] = frame->a0;
|
|
||||||
regs.a[1] = (uint32_t) frame + V7_GDB_SP_OFFSET;
|
|
||||||
regs.pc = frame->pc;
|
|
||||||
regs.sar = frame->sar;
|
|
||||||
regs.ps = frame->ps;
|
|
||||||
regs.litbase = RSR(LITBASE);
|
|
||||||
|
|
||||||
U0IE = 0;
|
|
||||||
ets_install_putc1(&uart_write_char_d);
|
|
||||||
|
|
||||||
printf("\nTrap %d: pc=%p va=%p\n", cause, frame->pc, vaddr);
|
|
||||||
gdb_server();
|
|
||||||
|
|
||||||
_ResetVector();
|
|
||||||
}
|
|
||||||
|
|
||||||
void gdb_init() {
|
|
||||||
char causes[] = {EXCCAUSE_ILLEGAL, EXCCAUSE_INSTR_ERROR,
|
|
||||||
EXCCAUSE_LOAD_STORE_ERROR, EXCCAUSE_DIVIDE_BY_ZERO,
|
|
||||||
EXCCAUSE_UNALIGNED, EXCCAUSE_INSTR_PROHIBITED,
|
|
||||||
EXCCAUSE_LOAD_PROHIBITED, EXCCAUSE_STORE_PROHIBITED};
|
|
||||||
int i;
|
|
||||||
for (i = 0; i < (int) sizeof(causes); i++) {
|
|
||||||
_xtos_set_exception_handler(causes[i], gdb_exception_handler);
|
|
||||||
}
|
|
||||||
}
|
|
61
libraries/GDBStub/src/internal/gdbstub-cfg.h
Normal file
61
libraries/GDBStub/src/internal/gdbstub-cfg.h
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
#ifndef GDBSTUB_CFG_H
|
||||||
|
#define GDBSTUB_CFG_H
|
||||||
|
|
||||||
|
/*
|
||||||
|
Enable this define if you're using the RTOS SDK. It will use a custom exception handler instead of the HAL
|
||||||
|
and do some other magic to make everything work and compile under FreeRTOS.
|
||||||
|
*/
|
||||||
|
#ifndef GDBSTUB_FREERTOS
|
||||||
|
#define GDBSTUB_FREERTOS 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
Enable this to make the exception and debugging handlers switch to a private stack. This will use
|
||||||
|
up 1K of RAM, but may be useful if you're debugging stack or stack pointer corruption problems. It's
|
||||||
|
normally disabled because not many situations need it. If for some reason the GDB communication
|
||||||
|
stops when you run into an error in your code, try enabling this.
|
||||||
|
*/
|
||||||
|
#ifndef GDBSTUB_USE_OWN_STACK
|
||||||
|
#define GDBSTUB_USE_OWN_STACK 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
If this is defined, gdbstub will break the program when you press Ctrl-C in gdb. it does this by
|
||||||
|
hooking the UART interrupt. Unfortunately, this means receiving stuff over the serial port won't
|
||||||
|
work for your program anymore. This will fail if your program sets an UART interrupt handler after
|
||||||
|
the gdbstub_init call.
|
||||||
|
*/
|
||||||
|
#ifndef GDBSTUB_CTRLC_BREAK
|
||||||
|
#define GDBSTUB_CTRLC_BREAK 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
Enabling this will redirect console output to GDB. This basically means that printf/os_printf output
|
||||||
|
will show up in your gdb session, which is useful if you use gdb to do stuff. It also means that if
|
||||||
|
you use a normal terminal, you can't read the printfs anymore.
|
||||||
|
*/
|
||||||
|
#ifndef GDBSTUB_REDIRECT_CONSOLE_OUTPUT
|
||||||
|
#define GDBSTUB_REDIRECT_CONSOLE_OUTPUT 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
Enable this if you want the GDB stub to wait for you to attach GDB before running. It does this by
|
||||||
|
breaking in the init routine; use the gdb 'c' command (continue) to start the program.
|
||||||
|
*/
|
||||||
|
#ifndef GDBSTUB_BREAK_ON_INIT
|
||||||
|
#define GDBSTUB_BREAK_ON_INIT 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
Function attributes for function types.
|
||||||
|
Gdbstub functions are placed in flash or IRAM using attributes, as defined here. The gdbinit function
|
||||||
|
(and related) can always be in flash, because it's called in the normal code flow. The rest of the
|
||||||
|
gdbstub functions can be in flash too, but only if there's no chance of them being called when the
|
||||||
|
flash somehow is disabled (eg during SPI operations or flash write/erase operations). If the routines
|
||||||
|
are called when the flash is disabled (eg due to a Ctrl-C at the wrong time), the ESP8266 will most
|
||||||
|
likely crash.
|
||||||
|
*/
|
||||||
|
#define ATTR_GDBINIT ICACHE_FLASH_ATTR
|
||||||
|
#define ATTR_GDBFN
|
||||||
|
|
||||||
|
#endif
|
404
libraries/GDBStub/src/internal/gdbstub-entry.S
Normal file
404
libraries/GDBStub/src/internal/gdbstub-entry.S
Normal file
@ -0,0 +1,404 @@
|
|||||||
|
/******************************************************************************
|
||||||
|
* Copyright 2015 Espressif Systems
|
||||||
|
*
|
||||||
|
* Description: Assembly routines for the gdbstub
|
||||||
|
*
|
||||||
|
* License: ESPRESSIF MIT License
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
#include "gdbstub-cfg.h"
|
||||||
|
|
||||||
|
#include <xtensa/config/specreg.h>
|
||||||
|
#include <xtensa/config/core-isa.h>
|
||||||
|
#include <xtensa/corebits.h>
|
||||||
|
|
||||||
|
#define DEBUG_PC (EPC + XCHAL_DEBUGLEVEL)
|
||||||
|
#define DEBUG_EXCSAVE (EXCSAVE + XCHAL_DEBUGLEVEL)
|
||||||
|
#define DEBUG_PS (EPS + XCHAL_DEBUGLEVEL)
|
||||||
|
|
||||||
|
|
||||||
|
.global gdbstub_savedRegs
|
||||||
|
|
||||||
|
#if GDBSTUB_USE_OWN_STACK
|
||||||
|
.global gdbstub_exceptionStack
|
||||||
|
#endif
|
||||||
|
|
||||||
|
.text
|
||||||
|
.literal_position
|
||||||
|
|
||||||
|
.text
|
||||||
|
.align 4
|
||||||
|
|
||||||
|
/*
|
||||||
|
The savedRegs struct:
|
||||||
|
uint32_t pc;
|
||||||
|
uint32_t ps;
|
||||||
|
uint32_t sar;
|
||||||
|
uint32_t vpri;
|
||||||
|
uint32_t a0;
|
||||||
|
uint32_t a[14]; //a2..a15
|
||||||
|
uint32_t litbase;
|
||||||
|
uint32_t sr176;
|
||||||
|
uint32_t sr208;
|
||||||
|
uint32_t a1;
|
||||||
|
uint32_t reason;
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
This is the debugging exception routine; it's called by the debugging vector
|
||||||
|
|
||||||
|
We arrive here with all regs intact except for a2. The old contents of A2 are saved
|
||||||
|
into the DEBUG_EXCSAVE special function register. EPC is the original PC.
|
||||||
|
*/
|
||||||
|
gdbstub_debug_exception_entry:
|
||||||
|
/*
|
||||||
|
//Minimum no-op debug exception handler, for debug
|
||||||
|
rsr a2,DEBUG_PC
|
||||||
|
addi a2,a2,3
|
||||||
|
wsr a2,DEBUG_PC
|
||||||
|
xsr a2, DEBUG_EXCSAVE
|
||||||
|
rfi XCHAL_DEBUGLEVEL
|
||||||
|
*/
|
||||||
|
|
||||||
|
//Save all regs to structure
|
||||||
|
movi a2, gdbstub_savedRegs
|
||||||
|
s32i a0, a2, 0x10
|
||||||
|
s32i a1, a2, 0x58
|
||||||
|
rsr a0, DEBUG_PS
|
||||||
|
s32i a0, a2, 0x04
|
||||||
|
rsr a0, DEBUG_EXCSAVE //was R2
|
||||||
|
s32i a0, a2, 0x14
|
||||||
|
s32i a3, a2, 0x18
|
||||||
|
s32i a4, a2, 0x1c
|
||||||
|
s32i a5, a2, 0x20
|
||||||
|
s32i a6, a2, 0x24
|
||||||
|
s32i a7, a2, 0x28
|
||||||
|
s32i a8, a2, 0x2c
|
||||||
|
s32i a9, a2, 0x30
|
||||||
|
s32i a10, a2, 0x34
|
||||||
|
s32i a11, a2, 0x38
|
||||||
|
s32i a12, a2, 0x3c
|
||||||
|
s32i a13, a2, 0x40
|
||||||
|
s32i a14, a2, 0x44
|
||||||
|
s32i a15, a2, 0x48
|
||||||
|
rsr a0, SAR
|
||||||
|
s32i a0, a2, 0x08
|
||||||
|
rsr a0, LITBASE
|
||||||
|
s32i a0, a2, 0x4C
|
||||||
|
rsr a0, 176
|
||||||
|
s32i a0, a2, 0x50
|
||||||
|
rsr a0, 208
|
||||||
|
s32i a0, a2, 0x54
|
||||||
|
rsr a0, DEBUGCAUSE
|
||||||
|
s32i a0, a2, 0x5C
|
||||||
|
rsr a4, DEBUG_PC
|
||||||
|
s32i a4, a2, 0x00
|
||||||
|
|
||||||
|
#if GDBSTUB_USE_OWN_STACK
|
||||||
|
//Move to our own stack
|
||||||
|
movi a1, exceptionStack+255*4
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//If ICOUNT is -1, disable it by setting it to 0, otherwise we will keep triggering on the same instruction.
|
||||||
|
rsr a2, ICOUNT
|
||||||
|
movi a3, -1
|
||||||
|
bne a2, a3, noIcountReset
|
||||||
|
movi a3, 0
|
||||||
|
wsr a3, ICOUNT
|
||||||
|
noIcountReset:
|
||||||
|
|
||||||
|
rsr a2, ps
|
||||||
|
addi a2, a2, -PS_EXCM_MASK
|
||||||
|
wsr a2, ps
|
||||||
|
rsync
|
||||||
|
|
||||||
|
//Call into the C code to do the actual handling.
|
||||||
|
call0 gdbstub_handle_debug_exception
|
||||||
|
|
||||||
|
DebugExceptionExit:
|
||||||
|
|
||||||
|
rsr a2, ps
|
||||||
|
addi a2, a2, PS_EXCM_MASK
|
||||||
|
wsr a2, ps
|
||||||
|
rsync
|
||||||
|
|
||||||
|
//Restore registers from the gdbstub_savedRegs struct
|
||||||
|
movi a2, gdbstub_savedRegs
|
||||||
|
l32i a0, a2, 0x00
|
||||||
|
wsr a0, DEBUG_PC
|
||||||
|
// l32i a0, a2, 0x54
|
||||||
|
// wsr a0, 208
|
||||||
|
l32i a0, a2, 0x50
|
||||||
|
//wsr a0, 176 //Some versions of gcc do not understand this...
|
||||||
|
.byte 0x00, 176, 0x13 //so we hand-assemble the instruction.
|
||||||
|
l32i a0, a2, 0x4C
|
||||||
|
wsr a0, LITBASE
|
||||||
|
l32i a0, a2, 0x08
|
||||||
|
wsr a0, SAR
|
||||||
|
l32i a15, a2, 0x48
|
||||||
|
l32i a14, a2, 0x44
|
||||||
|
l32i a13, a2, 0x40
|
||||||
|
l32i a12, a2, 0x3c
|
||||||
|
l32i a11, a2, 0x38
|
||||||
|
l32i a10, a2, 0x34
|
||||||
|
l32i a9, a2, 0x30
|
||||||
|
l32i a8, a2, 0x2c
|
||||||
|
l32i a7, a2, 0x28
|
||||||
|
l32i a6, a2, 0x24
|
||||||
|
l32i a5, a2, 0x20
|
||||||
|
l32i a4, a2, 0x1c
|
||||||
|
l32i a3, a2, 0x18
|
||||||
|
l32i a0, a2, 0x14
|
||||||
|
wsr a0, DEBUG_EXCSAVE //was R2
|
||||||
|
l32i a0, a2, 0x04
|
||||||
|
wsr a0, DEBUG_PS
|
||||||
|
l32i a1, a2, 0x58
|
||||||
|
l32i a0, a2, 0x10
|
||||||
|
|
||||||
|
//Read back vector-saved a2 value, put back address of this routine.
|
||||||
|
movi a2, gdbstub_debug_exception_entry
|
||||||
|
xsr a2, DEBUG_EXCSAVE
|
||||||
|
|
||||||
|
//All done. Return to where we came from.
|
||||||
|
rfi XCHAL_DEBUGLEVEL
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#if GDBSTUB_FREERTOS
|
||||||
|
/*
|
||||||
|
FreeRTOS exception handling code. For some reason or another, we can't just hook the main exception vector: it
|
||||||
|
seems FreeRTOS uses that for something else too (interrupts). FreeRTOS has its own fatal exception handler, and we
|
||||||
|
hook that. Unfortunately, that one is called from a few different places (eg directly in the DoubleExceptionVector)
|
||||||
|
so the precise location of the original register values are somewhat of a mystery when we arrive here...
|
||||||
|
|
||||||
|
As a 'solution', we'll just decode the most common case of the user_fatal_exception_handler being called from
|
||||||
|
the user exception handler vector:
|
||||||
|
- excsave1 - orig a0
|
||||||
|
- a1: stack frame:
|
||||||
|
sf+16: orig a1
|
||||||
|
sf+8: ps
|
||||||
|
sf+4: epc
|
||||||
|
sf+12: orig a0
|
||||||
|
sf: magic no?
|
||||||
|
*/
|
||||||
|
.global gdbstub_handle_user_exception
|
||||||
|
.global gdbstub_user_exception_entry
|
||||||
|
.align 4
|
||||||
|
gdbstub_user_exception_entry:
|
||||||
|
//Save all regs to structure
|
||||||
|
movi a0, gdbstub_savedRegs
|
||||||
|
s32i a1, a0, 0x14 //was a2
|
||||||
|
s32i a3, a0, 0x18
|
||||||
|
s32i a4, a0, 0x1c
|
||||||
|
s32i a5, a0, 0x20
|
||||||
|
s32i a6, a0, 0x24
|
||||||
|
s32i a7, a0, 0x28
|
||||||
|
s32i a8, a0, 0x2c
|
||||||
|
s32i a9, a0, 0x30
|
||||||
|
s32i a10, a0, 0x34
|
||||||
|
s32i a11, a0, 0x38
|
||||||
|
s32i a12, a0, 0x3c
|
||||||
|
s32i a13, a0, 0x40
|
||||||
|
s32i a14, a0, 0x44
|
||||||
|
s32i a15, a0, 0x48
|
||||||
|
rsr a2, SAR
|
||||||
|
s32i a2, a0, 0x08
|
||||||
|
rsr a2, LITBASE
|
||||||
|
s32i a2, a0, 0x4C
|
||||||
|
rsr a2, 176
|
||||||
|
s32i a2, a0, 0x50
|
||||||
|
rsr a2, 208
|
||||||
|
s32i a2, a0, 0x54
|
||||||
|
rsr a2, EXCCAUSE
|
||||||
|
s32i a2, a0, 0x5C
|
||||||
|
|
||||||
|
//Get the rest of the regs from the stack struct
|
||||||
|
l32i a3, a1, 12
|
||||||
|
s32i a3, a0, 0x10
|
||||||
|
l32i a3, a1, 16
|
||||||
|
s32i a3, a0, 0x58
|
||||||
|
l32i a3, a1, 8
|
||||||
|
s32i a3, a0, 0x04
|
||||||
|
l32i a3, a1, 4
|
||||||
|
s32i a3, a0, 0x00
|
||||||
|
|
||||||
|
#if GDBSTUB_USE_OWN_STACK
|
||||||
|
movi a1, exceptionStack+255*4
|
||||||
|
#endif
|
||||||
|
|
||||||
|
rsr a2, ps
|
||||||
|
addi a2, a2, -PS_EXCM_MASK
|
||||||
|
wsr a2, ps
|
||||||
|
rsync
|
||||||
|
|
||||||
|
call0 gdbstub_handle_user_exception
|
||||||
|
|
||||||
|
UserExceptionExit:
|
||||||
|
|
||||||
|
/*
|
||||||
|
Okay, from here on, it Does Not Work. There's not really any continuing from an exception in the
|
||||||
|
FreeRTOS case; there isn't any effort put in reversing the mess the exception code made yet. Maybe this
|
||||||
|
is still something we need to implement later, if there's any demand for it, or maybe we should modify
|
||||||
|
FreeRTOS to allow this in the future. (Which will then kill backwards compatibility... hmmm.)
|
||||||
|
*/
|
||||||
|
j UserExceptionExit
|
||||||
|
|
||||||
|
|
||||||
|
.global gdbstub_handle_uart_int
|
||||||
|
.global gdbstub_uart_entry
|
||||||
|
.align 4
|
||||||
|
gdbstub_uart_entry:
|
||||||
|
//On entry, the stack frame is at SP+16.
|
||||||
|
//This is a small stub to present that as the first arg to the gdbstub_handle_uart function.
|
||||||
|
movi a2, 16
|
||||||
|
add a2, a2, a1
|
||||||
|
movi a3, gdbstub_handle_uart_int
|
||||||
|
jx a3
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.global gdbstub_save_extra_sfrs_for_exception
|
||||||
|
.align 4
|
||||||
|
//The Xtensa OS HAL does not save all the special function register things. This bit of assembly
|
||||||
|
//fills the gdbstub_savedRegs struct with them.
|
||||||
|
gdbstub_save_extra_sfrs_for_exception:
|
||||||
|
movi a2, gdbstub_savedRegs
|
||||||
|
rsr a3, LITBASE
|
||||||
|
s32i a3, a2, 0x4C
|
||||||
|
rsr a3, 176
|
||||||
|
s32i a3, a2, 0x50
|
||||||
|
rsr a3, 208
|
||||||
|
s32i a3, a2, 0x54
|
||||||
|
rsr a3, EXCCAUSE
|
||||||
|
s32i a3, a2, 0x5C
|
||||||
|
ret
|
||||||
|
|
||||||
|
.global gdbstub_init_debug_entry
|
||||||
|
.global _DebugExceptionVector
|
||||||
|
.align 4
|
||||||
|
gdbstub_init_debug_entry:
|
||||||
|
//This puts the following 2 instructions into the debug exception vector:
|
||||||
|
// xsr a2, DEBUG_EXCSAVE
|
||||||
|
// jx a2
|
||||||
|
movi a2, _DebugExceptionVector
|
||||||
|
movi a3, 0xa061d220
|
||||||
|
s32i a3, a2, 0
|
||||||
|
movi a3, 0x00000002
|
||||||
|
s32i a3, a2, 4
|
||||||
|
|
||||||
|
//Tell the just-installed debug vector where to go.
|
||||||
|
movi a2, gdbstub_debug_exception_entry
|
||||||
|
wsr a2, DEBUG_EXCSAVE
|
||||||
|
|
||||||
|
ret
|
||||||
|
|
||||||
|
|
||||||
|
//Set up ICOUNT register to step one single instruction
|
||||||
|
.global gdbstub_icount_ena_single_step
|
||||||
|
.align 4
|
||||||
|
gdbstub_icount_ena_single_step:
|
||||||
|
movi a3, XCHAL_DEBUGLEVEL //Only count steps in non-debug mode
|
||||||
|
movi a2, -2
|
||||||
|
wsr a3, ICOUNTLEVEL
|
||||||
|
wsr a2, ICOUNT
|
||||||
|
isync
|
||||||
|
ret
|
||||||
|
|
||||||
|
|
||||||
|
//These routines all assume only one breakpoint and watchpoint is available, which
|
||||||
|
//is the case for the ESP8266 Xtensa core.
|
||||||
|
|
||||||
|
|
||||||
|
.global gdbstub_set_hw_breakpoint
|
||||||
|
gdbstub_set_hw_breakpoint:
|
||||||
|
//a2 - addr, a3 - len (unused here)
|
||||||
|
rsr a4, IBREAKENABLE
|
||||||
|
bbsi a4, 0, return_w_error
|
||||||
|
wsr a2, IBREAKA
|
||||||
|
movi a2, 1
|
||||||
|
wsr a2, IBREAKENABLE
|
||||||
|
isync
|
||||||
|
movi a2, 1
|
||||||
|
ret
|
||||||
|
|
||||||
|
.global gdbstub_del_hw_breakpoint
|
||||||
|
gdbstub_del_hw_breakpoint:
|
||||||
|
//a2 - addr
|
||||||
|
rsr a5, IBREAKENABLE
|
||||||
|
bbci a5, 0, return_w_error
|
||||||
|
rsr a3, IBREAKA
|
||||||
|
bne a3, a2, return_w_error
|
||||||
|
movi a2,0
|
||||||
|
wsr a2, IBREAKENABLE
|
||||||
|
isync
|
||||||
|
movi a2, 1
|
||||||
|
ret
|
||||||
|
|
||||||
|
.global gdbstub_set_hw_watchpoint
|
||||||
|
//a2 - addr, a3 - mask, a4 - type (1=read, 2=write, 3=access)
|
||||||
|
gdbstub_set_hw_watchpoint:
|
||||||
|
//Check if any of the masked address bits are set. If so, that is an error.
|
||||||
|
movi a5,0x0000003F
|
||||||
|
xor a5, a5, a3
|
||||||
|
bany a2, a5, return_w_error
|
||||||
|
//Check if watchpoint already is set
|
||||||
|
rsr a5, DBREAKC
|
||||||
|
movi a6, 0xC0000000
|
||||||
|
bany a6, a5, return_w_error
|
||||||
|
//Set watchpoint
|
||||||
|
wsr a2, DBREAKA
|
||||||
|
|
||||||
|
//Combine type and mask
|
||||||
|
movi a6, 0x3F
|
||||||
|
and a3, a3, a6
|
||||||
|
slli a4, a4, 30
|
||||||
|
or a3, a3, a4
|
||||||
|
wsr a3, DBREAKC
|
||||||
|
|
||||||
|
// movi a2, 1
|
||||||
|
mov a2, a3
|
||||||
|
isync
|
||||||
|
ret
|
||||||
|
|
||||||
|
|
||||||
|
.global gdbstub_del_hw_watchpoint
|
||||||
|
//a2 - addr
|
||||||
|
gdbstub_del_hw_watchpoint:
|
||||||
|
//See if the address matches
|
||||||
|
rsr a3, DBREAKA
|
||||||
|
bne a3, a2, return_w_error
|
||||||
|
//See if the bp actually is set
|
||||||
|
rsr a3, DBREAKC
|
||||||
|
movi a2, 0xC0000000
|
||||||
|
bnone a3, a2, return_w_error
|
||||||
|
//Disable bp
|
||||||
|
movi a2,0
|
||||||
|
wsr a2,DBREAKC
|
||||||
|
movi a2,1
|
||||||
|
isync
|
||||||
|
ret
|
||||||
|
|
||||||
|
return_w_error:
|
||||||
|
movi a2, 0
|
||||||
|
ret
|
||||||
|
|
||||||
|
|
||||||
|
//Breakpoint, with an attempt at a functional function prologue and epilogue...
|
||||||
|
.global gdbstub_do_break_breakpoint_addr
|
||||||
|
.global gdbstub_do_break
|
||||||
|
.align 4
|
||||||
|
gdbstub_do_break:
|
||||||
|
addi a1, a1, -16
|
||||||
|
s32i a15, a1, 12
|
||||||
|
mov a15, a1
|
||||||
|
|
||||||
|
gdbstub_do_break_breakpoint_addr:
|
||||||
|
break 0,0
|
||||||
|
|
||||||
|
mov a1, a15
|
||||||
|
l32i a15, a1, 12
|
||||||
|
addi a1, a1, 16
|
||||||
|
ret
|
25
libraries/GDBStub/src/internal/gdbstub-entry.h
Normal file
25
libraries/GDBStub/src/internal/gdbstub-entry.h
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
#ifndef GDBSTUB_ENTRY_H
|
||||||
|
#define GDBSTUB_ENTRY_H
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void gdbstub_init_debug_entry();
|
||||||
|
void gdbstub_do_break();
|
||||||
|
void gdbstub_icount_ena_single_step();
|
||||||
|
void gdbstub_save_extra_sfrs_for_exception();
|
||||||
|
void gdbstub_uart_entry();
|
||||||
|
|
||||||
|
int gdbstub_set_hw_breakpoint(int addr, int len);
|
||||||
|
int gdbstub_set_hw_watchpoint(int addr, int len, int type);
|
||||||
|
int gdbstub_del_hw_breakpoint(int addr);
|
||||||
|
int gdbstub_del_hw_watchpoint(int addr);
|
||||||
|
|
||||||
|
extern void* gdbstub_do_break_breakpoint_addr;
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
{
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
790
libraries/GDBStub/src/internal/gdbstub.c
Normal file
790
libraries/GDBStub/src/internal/gdbstub.c
Normal file
@ -0,0 +1,790 @@
|
|||||||
|
/******************************************************************************
|
||||||
|
* Copyright 2015 Espressif Systems
|
||||||
|
*
|
||||||
|
* Description: A stub to make the ESP8266 debuggable by GDB over the serial
|
||||||
|
* port.
|
||||||
|
*
|
||||||
|
* License: ESPRESSIF MIT License
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
|
#include "gdbstub.h"
|
||||||
|
#include <stddef.h>
|
||||||
|
#include "ets_sys.h"
|
||||||
|
#include "eagle_soc.h"
|
||||||
|
#include "c_types.h"
|
||||||
|
#include "gpio.h"
|
||||||
|
#include "xtensa/corebits.h"
|
||||||
|
|
||||||
|
#include "gdbstub.h"
|
||||||
|
#include "gdbstub-entry.h"
|
||||||
|
#include "gdbstub-cfg.h"
|
||||||
|
|
||||||
|
|
||||||
|
//From xtruntime-frames.h
|
||||||
|
struct XTensa_exception_frame_s {
|
||||||
|
uint32_t pc;
|
||||||
|
uint32_t ps;
|
||||||
|
uint32_t sar;
|
||||||
|
uint32_t vpri;
|
||||||
|
uint32_t a0;
|
||||||
|
uint32_t a[14]; //a2..a15
|
||||||
|
//These are added manually by the exception code; the HAL doesn't set these on an exception.
|
||||||
|
uint32_t litbase;
|
||||||
|
uint32_t sr176;
|
||||||
|
uint32_t sr208;
|
||||||
|
uint32_t a1;
|
||||||
|
//'reason' is abused for both the debug and the exception vector: if bit 7 is set,
|
||||||
|
//this contains an exception reason, otherwise it contains a debug vector bitmap.
|
||||||
|
uint32_t reason;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct XTensa_rtos_int_frame_s {
|
||||||
|
uint32_t exitPtr;
|
||||||
|
uint32_t pc;
|
||||||
|
uint32_t ps;
|
||||||
|
uint32_t a[16];
|
||||||
|
uint32_t sar;
|
||||||
|
};
|
||||||
|
|
||||||
|
#if GDBSTUB_FREERTOS
|
||||||
|
/*
|
||||||
|
Definitions for FreeRTOS. This redefines some os_* functions to use their non-os* counterparts. It
|
||||||
|
also sets up some function pointers for ROM functions that aren't in the FreeRTOS ld files.
|
||||||
|
*/
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
void _xt_isr_attach(int inum, void *fn);
|
||||||
|
void _xt_isr_unmask(int inum);
|
||||||
|
void os_install_putc1(void (*p)(char c));
|
||||||
|
#define os_printf(...) printf(__VA_ARGS__)
|
||||||
|
#define os_memcpy(a,b,c) memcpy(a,b,c)
|
||||||
|
typedef void wdtfntype();
|
||||||
|
static wdtfntype *ets_wdt_disable=(wdtfntype *)0x400030f0;
|
||||||
|
static wdtfntype *ets_wdt_enable=(wdtfntype *)0x40002fa0;
|
||||||
|
|
||||||
|
#else
|
||||||
|
/*
|
||||||
|
OS-less SDK defines. Defines some headers for things that aren't in the include files, plus
|
||||||
|
the xthal stack frame struct.
|
||||||
|
*/
|
||||||
|
#include "osapi.h"
|
||||||
|
#include "user_interface.h"
|
||||||
|
|
||||||
|
void _xtos_set_exception_handler(int cause, void (exhandler)(struct XTensa_exception_frame_s *frame));
|
||||||
|
int os_printf_plus(const char *format, ...) __attribute__ ((format (printf, 1, 2)));
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define EXCEPTION_GDB_SP_OFFSET 0x100
|
||||||
|
|
||||||
|
|
||||||
|
//We need some UART register defines.
|
||||||
|
#define ETS_UART_INUM 5
|
||||||
|
#define REG_UART_BASE( i ) (0x60000000+(i)*0xf00)
|
||||||
|
#define UART_STATUS( i ) (REG_UART_BASE( i ) + 0x1C)
|
||||||
|
#define UART_RXFIFO_CNT 0x000000FF
|
||||||
|
#define UART_RXFIFO_CNT_S 0
|
||||||
|
#define UART_TXFIFO_CNT 0x000000FF
|
||||||
|
#define UART_TXFIFO_CNT_S 16
|
||||||
|
#define UART_FIFO( i ) (REG_UART_BASE( i ) + 0x0)
|
||||||
|
#define UART_INT_ENA(i) (REG_UART_BASE(i) + 0xC)
|
||||||
|
#define UART_INT_CLR(i) (REG_UART_BASE(i) + 0x10)
|
||||||
|
#define UART_RXFIFO_TOUT_INT_ENA (BIT(8))
|
||||||
|
#define UART_RXFIFO_FULL_INT_ENA (BIT(0))
|
||||||
|
#define UART_RXFIFO_TOUT_INT_CLR (BIT(8))
|
||||||
|
#define UART_RXFIFO_FULL_INT_CLR (BIT(0))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//Length of buffer used to reserve GDB commands. Has to be at least able to fit the G command, which
|
||||||
|
//implies a minimum size of about 190 bytes.
|
||||||
|
#define PBUFLEN 256
|
||||||
|
//Length of gdb stdout buffer, for console redirection
|
||||||
|
#define OBUFLEN 32
|
||||||
|
|
||||||
|
//The asm stub saves the Xtensa registers here when a debugging exception happens.
|
||||||
|
struct XTensa_exception_frame_s gdbstub_savedRegs;
|
||||||
|
#if GDBSTUB_USE_OWN_STACK
|
||||||
|
//This is the debugging exception stack.
|
||||||
|
int exceptionStack[256];
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static unsigned char cmd[PBUFLEN]; //GDB command input buffer
|
||||||
|
static char chsum; //Running checksum of the output packet
|
||||||
|
#if GDBSTUB_REDIRECT_CONSOLE_OUTPUT
|
||||||
|
static unsigned char obuf[OBUFLEN]; //GDB stdout buffer
|
||||||
|
static int obufpos=0; //Current position in the buffer
|
||||||
|
#endif
|
||||||
|
static int32_t singleStepPs=-1; //Stores ps when single-stepping instruction. -1 when not in use.
|
||||||
|
|
||||||
|
//Small function to feed the hardware watchdog. Needed to stop the ESP from resetting
|
||||||
|
//due to a watchdog timeout while reading a command.
|
||||||
|
static void ATTR_GDBFN keepWDTalive() {
|
||||||
|
uint64_t *wdtval=(uint64_t*)0x3ff21048;
|
||||||
|
uint64_t *wdtovf=(uint64_t*)0x3ff210cc;
|
||||||
|
int *wdtctl=(int*)0x3ff210c8;
|
||||||
|
*wdtovf=*wdtval+1600000;
|
||||||
|
*wdtctl|=(1<<31);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Receive a char from the uart. Uses polling and feeds the watchdog.
|
||||||
|
static int ATTR_GDBFN gdbRecvChar() {
|
||||||
|
int i;
|
||||||
|
while (((READ_PERI_REG(UART_STATUS(0))>>UART_RXFIFO_CNT_S)&UART_RXFIFO_CNT)==0) {
|
||||||
|
keepWDTalive();
|
||||||
|
}
|
||||||
|
i=READ_PERI_REG(UART_FIFO(0));
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Send a char to the uart.
|
||||||
|
static void ATTR_GDBFN gdbSendChar(char c) {
|
||||||
|
while (((READ_PERI_REG(UART_STATUS(0))>>UART_TXFIFO_CNT_S)&UART_TXFIFO_CNT)>=126) ;
|
||||||
|
WRITE_PERI_REG(UART_FIFO(0), c);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Send the start of a packet; reset checksum calculation.
|
||||||
|
static void ATTR_GDBFN gdbPacketStart() {
|
||||||
|
chsum=0;
|
||||||
|
gdbSendChar('$');
|
||||||
|
}
|
||||||
|
|
||||||
|
//Send a char as part of a packet
|
||||||
|
static void ATTR_GDBFN gdbPacketChar(char c) {
|
||||||
|
if (c=='#' || c=='$' || c=='}' || c=='*') {
|
||||||
|
gdbSendChar('}');
|
||||||
|
gdbSendChar(c^0x20);
|
||||||
|
chsum+=(c^0x20)+'}';
|
||||||
|
} else {
|
||||||
|
gdbSendChar(c);
|
||||||
|
chsum+=c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Send a string as part of a packet
|
||||||
|
static void ATTR_GDBFN gdbPacketStr(char *c) {
|
||||||
|
while (*c!=0) {
|
||||||
|
gdbPacketChar(*c);
|
||||||
|
c++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Send a hex val as part of a packet. 'bits'/4 dictates the number of hex chars sent.
|
||||||
|
static void ATTR_GDBFN gdbPacketHex(int val, int bits) {
|
||||||
|
char hexChars[]="0123456789abcdef";
|
||||||
|
int i;
|
||||||
|
for (i=bits; i>0; i-=4) {
|
||||||
|
gdbPacketChar(hexChars[(val>>(i-4))&0xf]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Finish sending a packet.
|
||||||
|
static void ATTR_GDBFN gdbPacketEnd() {
|
||||||
|
gdbSendChar('#');
|
||||||
|
gdbPacketHex(chsum, 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Error states used by the routines that grab stuff from the incoming gdb packet
|
||||||
|
#define ST_ENDPACKET -1
|
||||||
|
#define ST_ERR -2
|
||||||
|
#define ST_OK -3
|
||||||
|
#define ST_CONT -4
|
||||||
|
|
||||||
|
//Grab a hex value from the gdb packet. Ptr will get positioned on the end
|
||||||
|
//of the hex string, as far as the routine has read into it. Bits/4 indicates
|
||||||
|
//the max amount of hex chars it gobbles up. Bits can be -1 to eat up as much
|
||||||
|
//hex chars as possible.
|
||||||
|
static long ATTR_GDBFN gdbGetHexVal(unsigned char **ptr, int bits) {
|
||||||
|
int i;
|
||||||
|
int no;
|
||||||
|
unsigned int v=0;
|
||||||
|
char c;
|
||||||
|
no=bits/4;
|
||||||
|
if (bits==-1) no=64;
|
||||||
|
for (i=0; i<no; i++) {
|
||||||
|
c=**ptr;
|
||||||
|
(*ptr)++;
|
||||||
|
if (c>='0' && c<='9') {
|
||||||
|
v<<=4;
|
||||||
|
v|=(c-'0');
|
||||||
|
} else if (c>='A' && c<='F') {
|
||||||
|
v<<=4;
|
||||||
|
v|=(c-'A')+10;
|
||||||
|
} else if (c>='a' && c<='f') {
|
||||||
|
v<<=4;
|
||||||
|
v|=(c-'a')+10;
|
||||||
|
} else if (c=='#') {
|
||||||
|
if (bits==-1) {
|
||||||
|
(*ptr)--;
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
return ST_ENDPACKET;
|
||||||
|
} else {
|
||||||
|
if (bits==-1) {
|
||||||
|
(*ptr)--;
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
return ST_ERR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Swap an int into the form gdb wants it
|
||||||
|
static int ATTR_GDBFN iswap(int i) {
|
||||||
|
int r;
|
||||||
|
r=((i>>24)&0xff);
|
||||||
|
r|=((i>>16)&0xff)<<8;
|
||||||
|
r|=((i>>8)&0xff)<<16;
|
||||||
|
r|=((i>>0)&0xff)<<24;
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Read a byte from the ESP8266 memory.
|
||||||
|
static unsigned char ATTR_GDBFN readbyte(unsigned int p) {
|
||||||
|
int *i=(int*)(p&(~3));
|
||||||
|
if (p<0x20000000 || p>=0x60000000) return -1;
|
||||||
|
return *i>>((p&3)*8);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Write a byte to the ESP8266 memory.
|
||||||
|
static void ATTR_GDBFN writeByte(unsigned int p, unsigned char d) {
|
||||||
|
int *i=(int*)(p&(~3));
|
||||||
|
if (p<0x20000000 || p>=0x60000000) return;
|
||||||
|
if ((p&3)==0) *i=(*i&0xffffff00)|(d<<0);
|
||||||
|
if ((p&3)==1) *i=(*i&0xffff00ff)|(d<<8);
|
||||||
|
if ((p&3)==2) *i=(*i&0xff00ffff)|(d<<16);
|
||||||
|
if ((p&3)==3) *i=(*i&0x00ffffff)|(d<<24);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Returns 1 if it makes sense to write to addr p
|
||||||
|
static int ATTR_GDBFN validWrAddr(int p) {
|
||||||
|
if (p>=0x3ff00000 && p<0x40000000) return 1;
|
||||||
|
if (p>=0x40100000 && p<0x40140000) return 1;
|
||||||
|
if (p>=0x60000000 && p<0x60002000) return 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Register file in the format lx106 gdb port expects it.
|
||||||
|
Inspired by gdb/regformats/reg-xtensa.dat from
|
||||||
|
https://github.com/jcmvbkbc/crosstool-NG/blob/lx106-g%2B%2B/overlays/xtensa_lx106.tar
|
||||||
|
As decoded by Cesanta.
|
||||||
|
*/
|
||||||
|
struct regfile {
|
||||||
|
uint32_t a[16];
|
||||||
|
uint32_t pc;
|
||||||
|
uint32_t sar;
|
||||||
|
uint32_t litbase;
|
||||||
|
uint32_t sr176;
|
||||||
|
uint32_t sr208;
|
||||||
|
uint32_t ps;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//Send the reason execution is stopped to GDB.
|
||||||
|
static void ATTR_GDBFN sendReason() {
|
||||||
|
#if 0
|
||||||
|
char *reason=""; //default
|
||||||
|
#endif
|
||||||
|
//exception-to-signal mapping
|
||||||
|
char exceptionSignal[]={4,31,11,11,2,6,8,0,6,7,0,0,7,7,7,7};
|
||||||
|
int i=0;
|
||||||
|
gdbPacketStart();
|
||||||
|
gdbPacketChar('T');
|
||||||
|
if (gdbstub_savedRegs.reason==0xff) {
|
||||||
|
gdbPacketHex(2, 8); //sigint
|
||||||
|
} else if (gdbstub_savedRegs.reason&0x80) {
|
||||||
|
//We stopped because of an exception. Convert exception code to a signal number and send it.
|
||||||
|
i=gdbstub_savedRegs.reason&0x7f;
|
||||||
|
if (i<sizeof(exceptionSignal)) return gdbPacketHex(exceptionSignal[i], 8); else gdbPacketHex(11, 8);
|
||||||
|
} else {
|
||||||
|
//We stopped because of a debugging exception.
|
||||||
|
gdbPacketHex(5, 8); //sigtrap
|
||||||
|
//Current Xtensa GDB versions don't seem to request this, so let's leave it off.
|
||||||
|
#if 0
|
||||||
|
if (gdbstub_savedRegs.reason&(1<<0)) reason="break";
|
||||||
|
if (gdbstub_savedRegs.reason&(1<<1)) reason="hwbreak";
|
||||||
|
if (gdbstub_savedRegs.reason&(1<<2)) reason="watch";
|
||||||
|
if (gdbstub_savedRegs.reason&(1<<3)) reason="swbreak";
|
||||||
|
if (gdbstub_savedRegs.reason&(1<<4)) reason="swbreak";
|
||||||
|
|
||||||
|
gdbPacketStr(reason);
|
||||||
|
gdbPacketChar(':');
|
||||||
|
//ToDo: watch: send address
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
gdbPacketEnd();
|
||||||
|
}
|
||||||
|
|
||||||
|
//Handle a command as received from GDB.
|
||||||
|
static int ATTR_GDBFN gdbHandleCommand(unsigned char *cmd, int len) {
|
||||||
|
//Handle a command
|
||||||
|
int i, j, k;
|
||||||
|
unsigned char *data=cmd+1;
|
||||||
|
if (cmd[0]=='g') { //send all registers to gdb
|
||||||
|
gdbPacketStart();
|
||||||
|
gdbPacketHex(iswap(gdbstub_savedRegs.a0), 32);
|
||||||
|
gdbPacketHex(iswap(gdbstub_savedRegs.a1), 32);
|
||||||
|
for (i=2; i<16; i++) gdbPacketHex(iswap(gdbstub_savedRegs.a[i-2]), 32);
|
||||||
|
gdbPacketHex(iswap(gdbstub_savedRegs.pc), 32);
|
||||||
|
gdbPacketHex(iswap(gdbstub_savedRegs.sar), 32);
|
||||||
|
gdbPacketHex(iswap(gdbstub_savedRegs.litbase), 32);
|
||||||
|
gdbPacketHex(iswap(gdbstub_savedRegs.sr176), 32);
|
||||||
|
gdbPacketHex(0, 32);
|
||||||
|
gdbPacketHex(iswap(gdbstub_savedRegs.ps), 32);
|
||||||
|
gdbPacketEnd();
|
||||||
|
} else if (cmd[0]=='G') { //receive content for all registers from gdb
|
||||||
|
gdbstub_savedRegs.a0=iswap(gdbGetHexVal(&data, 32));
|
||||||
|
gdbstub_savedRegs.a1=iswap(gdbGetHexVal(&data, 32));
|
||||||
|
for (i=2; i<16; i++) gdbstub_savedRegs.a[i-2]=iswap(gdbGetHexVal(&data, 32));
|
||||||
|
gdbstub_savedRegs.pc=iswap(gdbGetHexVal(&data, 32));
|
||||||
|
gdbstub_savedRegs.sar=iswap(gdbGetHexVal(&data, 32));
|
||||||
|
gdbstub_savedRegs.litbase=iswap(gdbGetHexVal(&data, 32));
|
||||||
|
gdbstub_savedRegs.sr176=iswap(gdbGetHexVal(&data, 32));
|
||||||
|
gdbGetHexVal(&data, 32);
|
||||||
|
gdbstub_savedRegs.ps=iswap(gdbGetHexVal(&data, 32));
|
||||||
|
gdbPacketStart();
|
||||||
|
gdbPacketStr("OK");
|
||||||
|
gdbPacketEnd();
|
||||||
|
} else if (cmd[0]=='m') { //read memory to gdb
|
||||||
|
i=gdbGetHexVal(&data, -1);
|
||||||
|
data++;
|
||||||
|
j=gdbGetHexVal(&data, -1);
|
||||||
|
gdbPacketStart();
|
||||||
|
for (k=0; k<j; k++) {
|
||||||
|
gdbPacketHex(readbyte(i++), 8);
|
||||||
|
}
|
||||||
|
gdbPacketEnd();
|
||||||
|
} else if (cmd[0]=='M') { //write memory from gdb
|
||||||
|
i=gdbGetHexVal(&data, -1); //addr
|
||||||
|
data++; //skip ,
|
||||||
|
j=gdbGetHexVal(&data, -1); //length
|
||||||
|
data++; //skip :
|
||||||
|
if (validWrAddr(i) && validWrAddr(i+j)) {
|
||||||
|
for (k=0; k<j; k++) {
|
||||||
|
writeByte(i, gdbGetHexVal(&data, 8));
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
//Make sure caches are up-to-date. Procedure according to Xtensa ISA document, ISYNC inst desc.
|
||||||
|
asm volatile("ISYNC\nISYNC\n");
|
||||||
|
gdbPacketStart();
|
||||||
|
gdbPacketStr("OK");
|
||||||
|
gdbPacketEnd();
|
||||||
|
} else {
|
||||||
|
//Trying to do a software breakpoint on a flash proc, perhaps?
|
||||||
|
gdbPacketStart();
|
||||||
|
gdbPacketStr("E01");
|
||||||
|
gdbPacketEnd();
|
||||||
|
}
|
||||||
|
} else if (cmd[0]=='?') { //Reply with stop reason
|
||||||
|
sendReason();
|
||||||
|
// } else if (strncmp(cmd, "vCont?", 6)==0) {
|
||||||
|
// gdbPacketStart();
|
||||||
|
// gdbPacketStr("vCont;c;s");
|
||||||
|
// gdbPacketEnd();
|
||||||
|
} else if (strncmp((char*)cmd, "vCont;c", 7)==0 || cmd[0]=='c') { //continue execution
|
||||||
|
return ST_CONT;
|
||||||
|
} else if (strncmp((char*)cmd, "vCont;s", 7)==0 || cmd[0]=='s') { //single-step instruction
|
||||||
|
//Single-stepping can go wrong if an interrupt is pending, especially when it is e.g. a task switch:
|
||||||
|
//the ICOUNT register will overflow in the task switch code. That is why we disable interupts when
|
||||||
|
//doing single-instruction stepping.
|
||||||
|
singleStepPs=gdbstub_savedRegs.ps;
|
||||||
|
gdbstub_savedRegs.ps=(gdbstub_savedRegs.ps & ~0xf)|(XCHAL_DEBUGLEVEL-1);
|
||||||
|
gdbstub_icount_ena_single_step();
|
||||||
|
return ST_CONT;
|
||||||
|
} else if (cmd[0]=='q') { //Extended query
|
||||||
|
if (strncmp((char*)&cmd[1], "Supported", 9)==0) { //Capabilities query
|
||||||
|
gdbPacketStart();
|
||||||
|
gdbPacketStr("swbreak+;hwbreak+;PacketSize=255");
|
||||||
|
gdbPacketEnd();
|
||||||
|
} else {
|
||||||
|
//We don't support other queries.
|
||||||
|
gdbPacketStart();
|
||||||
|
gdbPacketEnd();
|
||||||
|
return ST_ERR;
|
||||||
|
}
|
||||||
|
} else if (cmd[0]=='Z') { //Set hardware break/watchpoint.
|
||||||
|
data+=2; //skip 'x,'
|
||||||
|
i=gdbGetHexVal(&data, -1);
|
||||||
|
data++; //skip ','
|
||||||
|
j=gdbGetHexVal(&data, -1);
|
||||||
|
gdbPacketStart();
|
||||||
|
if (cmd[1]=='1') { //Set breakpoint
|
||||||
|
if (gdbstub_set_hw_breakpoint(i, j)) {
|
||||||
|
gdbPacketStr("OK");
|
||||||
|
} else {
|
||||||
|
gdbPacketStr("E01");
|
||||||
|
}
|
||||||
|
} else if (cmd[1]=='2' || cmd[1]=='3' || cmd[1]=='4') { //Set watchpoint
|
||||||
|
int access=0;
|
||||||
|
int mask=0;
|
||||||
|
if (cmd[1]=='2') access=2; //write
|
||||||
|
if (cmd[1]=='3') access=1; //read
|
||||||
|
if (cmd[1]=='4') access=3; //access
|
||||||
|
if (j==1) mask=0x3F;
|
||||||
|
if (j==2) mask=0x3E;
|
||||||
|
if (j==4) mask=0x3C;
|
||||||
|
if (j==8) mask=0x38;
|
||||||
|
if (j==16) mask=0x30;
|
||||||
|
if (j==32) mask=0x20;
|
||||||
|
if (j==64) mask=0x00;
|
||||||
|
if (mask!=0 && gdbstub_set_hw_watchpoint(i,mask, access)) {
|
||||||
|
gdbPacketStr("OK");
|
||||||
|
} else {
|
||||||
|
gdbPacketStr("E01");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
gdbPacketEnd();
|
||||||
|
} else if (cmd[0]=='z') { //Clear hardware break/watchpoint
|
||||||
|
data+=2; //skip 'x,'
|
||||||
|
i=gdbGetHexVal(&data, -1);
|
||||||
|
data++; //skip ','
|
||||||
|
j=gdbGetHexVal(&data, -1);
|
||||||
|
gdbPacketStart();
|
||||||
|
if (cmd[1]=='1') { //hardware breakpoint
|
||||||
|
if (gdbstub_del_hw_breakpoint(i)) {
|
||||||
|
gdbPacketStr("OK");
|
||||||
|
} else {
|
||||||
|
gdbPacketStr("E01");
|
||||||
|
}
|
||||||
|
} else if (cmd[1]=='2' || cmd[1]=='3' || cmd[1]=='4') { //hardware watchpoint
|
||||||
|
if (gdbstub_del_hw_watchpoint(i)) {
|
||||||
|
gdbPacketStr("OK");
|
||||||
|
} else {
|
||||||
|
gdbPacketStr("E01");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
gdbPacketEnd();
|
||||||
|
} else {
|
||||||
|
//We don't recognize or support whatever GDB just sent us.
|
||||||
|
gdbPacketStart();
|
||||||
|
gdbPacketEnd();
|
||||||
|
return ST_ERR;
|
||||||
|
}
|
||||||
|
return ST_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//Lower layer: grab a command packet and check the checksum
|
||||||
|
//Calls gdbHandleCommand on the packet if the checksum is OK
|
||||||
|
//Returns ST_OK on success, ST_ERR when checksum fails, a
|
||||||
|
//character if it is received instead of the GDB packet
|
||||||
|
//start char.
|
||||||
|
static int ATTR_GDBFN gdbReadCommand() {
|
||||||
|
unsigned char c;
|
||||||
|
unsigned char chsum=0, rchsum;
|
||||||
|
unsigned char sentchs[2];
|
||||||
|
int p=0;
|
||||||
|
unsigned char *ptr;
|
||||||
|
c=gdbRecvChar();
|
||||||
|
if (c!='$') return c;
|
||||||
|
while(1) {
|
||||||
|
c=gdbRecvChar();
|
||||||
|
if (c=='#') { //end of packet, checksum follows
|
||||||
|
cmd[p]=0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
chsum+=c;
|
||||||
|
if (c=='$') {
|
||||||
|
//Wut, restart packet?
|
||||||
|
chsum=0;
|
||||||
|
p=0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (c=='}') { //escape the next char
|
||||||
|
c=gdbRecvChar();
|
||||||
|
chsum+=c;
|
||||||
|
c^=0x20;
|
||||||
|
}
|
||||||
|
cmd[p++]=c;
|
||||||
|
if (p>=PBUFLEN) return ST_ERR;
|
||||||
|
}
|
||||||
|
//A # has been received. Get and check the received chsum.
|
||||||
|
sentchs[0]=gdbRecvChar();
|
||||||
|
sentchs[1]=gdbRecvChar();
|
||||||
|
ptr=&sentchs[0];
|
||||||
|
rchsum=gdbGetHexVal(&ptr, 8);
|
||||||
|
// os_printf("c %x r %x\n", chsum, rchsum);
|
||||||
|
if (rchsum!=chsum) {
|
||||||
|
gdbSendChar('-');
|
||||||
|
return ST_ERR;
|
||||||
|
} else {
|
||||||
|
gdbSendChar('+');
|
||||||
|
return gdbHandleCommand(cmd, p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Get the value of one of the A registers
|
||||||
|
static unsigned int ATTR_GDBFN getaregval(int reg) {
|
||||||
|
if (reg==0) return gdbstub_savedRegs.a0;
|
||||||
|
if (reg==1) return gdbstub_savedRegs.a1;
|
||||||
|
return gdbstub_savedRegs.a[reg-2];
|
||||||
|
}
|
||||||
|
|
||||||
|
//Set the value of one of the A registers
|
||||||
|
static void ATTR_GDBFN setaregval(int reg, unsigned int val) {
|
||||||
|
os_printf("%x -> %x\n", val, reg);
|
||||||
|
if (reg==0) gdbstub_savedRegs.a0=val;
|
||||||
|
if (reg==1) gdbstub_savedRegs.a1=val;
|
||||||
|
gdbstub_savedRegs.a[reg-2]=val;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Emulate the l32i/s32i instruction we're stopped at.
|
||||||
|
static void ATTR_GDBFN emulLdSt() {
|
||||||
|
unsigned char i0=readbyte(gdbstub_savedRegs.pc);
|
||||||
|
unsigned char i1=readbyte(gdbstub_savedRegs.pc+1);
|
||||||
|
unsigned char i2=readbyte(gdbstub_savedRegs.pc+2);
|
||||||
|
int *p;
|
||||||
|
if ((i0&0xf)==2 && (i1&0xf0)==0x20) {
|
||||||
|
//l32i
|
||||||
|
p=(int*)getaregval(i1&0xf)+(i2*4);
|
||||||
|
setaregval(i0>>4, *p);
|
||||||
|
gdbstub_savedRegs.pc+=3;
|
||||||
|
} else if ((i0&0xf)==0x8) {
|
||||||
|
//l32i.n
|
||||||
|
p=(int*)getaregval(i1&0xf)+((i1>>4)*4);
|
||||||
|
setaregval(i0>>4, *p);
|
||||||
|
gdbstub_savedRegs.pc+=2;
|
||||||
|
} else if ((i0&0xf)==2 && (i1&0xf0)==0x60) {
|
||||||
|
//s32i
|
||||||
|
p=(int*)getaregval(i1&0xf)+(i2*4);
|
||||||
|
*p=getaregval(i0>>4);
|
||||||
|
gdbstub_savedRegs.pc+=3;
|
||||||
|
} else if ((i0&0xf)==0x9) {
|
||||||
|
//s32i.n
|
||||||
|
p=(int*)getaregval(i1&0xf)+((i1>>4)*4);
|
||||||
|
*p=getaregval(i0>>4);
|
||||||
|
gdbstub_savedRegs.pc+=2;
|
||||||
|
} else {
|
||||||
|
os_printf("GDBSTUB: No l32i/s32i instruction: %x %x %x. Huh?", i2, i1, i0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//We just caught a debug exception and need to handle it. This is called from an assembly
|
||||||
|
//routine in gdbstub-entry.S
|
||||||
|
void ATTR_GDBFN gdbstub_handle_debug_exception() {
|
||||||
|
ets_wdt_disable();
|
||||||
|
|
||||||
|
if (singleStepPs!=-1) {
|
||||||
|
//We come here after single-stepping an instruction. Interrupts are disabled
|
||||||
|
//for the single step. Re-enable them here.
|
||||||
|
gdbstub_savedRegs.ps=(gdbstub_savedRegs.ps&~0xf)|(singleStepPs&0xf);
|
||||||
|
singleStepPs=-1;
|
||||||
|
}
|
||||||
|
|
||||||
|
sendReason();
|
||||||
|
while(gdbReadCommand()!=ST_CONT);
|
||||||
|
if ((gdbstub_savedRegs.reason&0x84)==0x4) {
|
||||||
|
//We stopped due to a watchpoint. We can't re-execute the current instruction
|
||||||
|
//because it will happily re-trigger the same watchpoint, so we emulate it
|
||||||
|
//while we're still in debugger space.
|
||||||
|
emulLdSt();
|
||||||
|
} else if ((gdbstub_savedRegs.reason&0x88)==0x8) {
|
||||||
|
//We stopped due to a BREAK instruction. Skip over it.
|
||||||
|
//Check the instruction first; gdb may have replaced it with the original instruction
|
||||||
|
//if it's one of the breakpoints it set.
|
||||||
|
if (readbyte(gdbstub_savedRegs.pc+2)==0 &&
|
||||||
|
(readbyte(gdbstub_savedRegs.pc+1)&0xf0)==0x40 &&
|
||||||
|
(readbyte(gdbstub_savedRegs.pc)&0x0f)==0x00) {
|
||||||
|
gdbstub_savedRegs.pc+=3;
|
||||||
|
}
|
||||||
|
} else if ((gdbstub_savedRegs.reason&0x90)==0x10) {
|
||||||
|
//We stopped due to a BREAK.N instruction. Skip over it, after making sure the instruction
|
||||||
|
//actually is a BREAK.N
|
||||||
|
if ((readbyte(gdbstub_savedRegs.pc+1)&0xf0)==0xf0 &&
|
||||||
|
readbyte(gdbstub_savedRegs.pc)==0x2d) {
|
||||||
|
gdbstub_savedRegs.pc+=3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ets_wdt_enable();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#if GDBSTUB_FREERTOS
|
||||||
|
//Freetos exception. This routine is called by an assembly routine in gdbstub-entry.S
|
||||||
|
void ATTR_GDBFN gdbstub_handle_user_exception() {
|
||||||
|
ets_wdt_disable();
|
||||||
|
gdbstub_savedRegs.reason|=0x80; //mark as an exception reason
|
||||||
|
sendReason();
|
||||||
|
while(gdbReadCommand()!=ST_CONT);
|
||||||
|
ets_wdt_enable();
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
|
||||||
|
//Non-OS exception handler. Gets called by the Xtensa HAL.
|
||||||
|
static void ATTR_GDBFN gdb_exception_handler(struct XTensa_exception_frame_s *frame) {
|
||||||
|
//Save the extra registers the Xtensa HAL doesn't save
|
||||||
|
gdbstub_save_extra_sfrs_for_exception();
|
||||||
|
//Copy registers the Xtensa HAL did save to gdbstub_savedRegs
|
||||||
|
os_memcpy(&gdbstub_savedRegs, frame, 19*4);
|
||||||
|
//Credits go to Cesanta for this trick. A1 seems to be destroyed, but because it
|
||||||
|
//has a fixed offset from the address of the passed frame, we can recover it.
|
||||||
|
gdbstub_savedRegs.a1=(uint32_t)frame+EXCEPTION_GDB_SP_OFFSET;
|
||||||
|
|
||||||
|
gdbstub_savedRegs.reason|=0x80; //mark as an exception reason
|
||||||
|
|
||||||
|
ets_wdt_disable();
|
||||||
|
*((uint32_t*)UART_INT_ENA(0)) = 0;
|
||||||
|
sendReason();
|
||||||
|
while(gdbReadCommand()!=ST_CONT);
|
||||||
|
ets_wdt_enable();
|
||||||
|
|
||||||
|
//Copy any changed registers back to the frame the Xtensa HAL uses.
|
||||||
|
os_memcpy(frame, &gdbstub_savedRegs, 19*4);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if GDBSTUB_REDIRECT_CONSOLE_OUTPUT
|
||||||
|
//Replacement putchar1 routine. Instead of spitting out the character directly, it will buffer up to
|
||||||
|
//OBUFLEN characters (or up to a \n, whichever comes earlier) and send it out as a gdb stdout packet.
|
||||||
|
static void ATTR_GDBFN gdb_semihost_putchar1(char c) {
|
||||||
|
int i;
|
||||||
|
obuf[obufpos++]=c;
|
||||||
|
if (c=='\n' || obufpos==OBUFLEN) {
|
||||||
|
gdbPacketStart();
|
||||||
|
gdbPacketChar('O');
|
||||||
|
for (i=0; i<obufpos; i++) gdbPacketHex(obuf[i], 8);
|
||||||
|
gdbPacketEnd();
|
||||||
|
obufpos=0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !GDBSTUB_FREERTOS
|
||||||
|
//The OS-less SDK uses the Xtensa HAL to handle exceptions. We can use those functions to catch any
|
||||||
|
//fatal exceptions and invoke the debugger when this happens.
|
||||||
|
static void ATTR_GDBINIT install_exceptions() {
|
||||||
|
int i;
|
||||||
|
int exno[]={EXCCAUSE_ILLEGAL, EXCCAUSE_SYSCALL, EXCCAUSE_INSTR_ERROR, EXCCAUSE_LOAD_STORE_ERROR,
|
||||||
|
EXCCAUSE_DIVIDE_BY_ZERO, EXCCAUSE_UNALIGNED, EXCCAUSE_INSTR_DATA_ERROR, EXCCAUSE_LOAD_STORE_DATA_ERROR,
|
||||||
|
EXCCAUSE_INSTR_ADDR_ERROR, EXCCAUSE_LOAD_STORE_ADDR_ERROR, EXCCAUSE_INSTR_PROHIBITED,
|
||||||
|
EXCCAUSE_LOAD_PROHIBITED, EXCCAUSE_STORE_PROHIBITED};
|
||||||
|
for (i=0; i<(sizeof(exno)/sizeof(exno[0])); i++) {
|
||||||
|
_xtos_set_exception_handler(exno[i], gdb_exception_handler);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
//FreeRTOS doesn't use the Xtensa HAL for exceptions, but uses its own fatal exception handler.
|
||||||
|
//We use a small hack to replace that with a jump to our own handler, which then has the task of
|
||||||
|
//decyphering and re-instating the registers the FreeRTOS code left.
|
||||||
|
extern void user_fatal_exception_handler();
|
||||||
|
extern void gdbstub_user_exception_entry();
|
||||||
|
|
||||||
|
static void ATTR_GDBINIT install_exceptions() {
|
||||||
|
//Replace the user_fatal_exception_handler by a jump to our own code
|
||||||
|
int *ufe=(int*)user_fatal_exception_handler;
|
||||||
|
//This mess encodes as a relative jump instruction to user_fatal_exception_handler
|
||||||
|
*ufe=((((int)gdbstub_user_exception_entry-(int)user_fatal_exception_handler)-4)<<6)|6;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#if GDBSTUB_CTRLC_BREAK
|
||||||
|
|
||||||
|
#if !GDBSTUB_FREERTOS
|
||||||
|
|
||||||
|
static void ATTR_GDBFN uart_hdlr(void *arg, void *frame) {
|
||||||
|
int doDebug=0, fifolen=0;
|
||||||
|
//Save the extra registers the Xtensa HAL doesn't save
|
||||||
|
gdbstub_save_extra_sfrs_for_exception();
|
||||||
|
|
||||||
|
fifolen=(READ_PERI_REG(UART_STATUS(0))>>UART_RXFIFO_CNT_S)&UART_RXFIFO_CNT;
|
||||||
|
while (fifolen!=0) {
|
||||||
|
if ((READ_PERI_REG(UART_FIFO(0)) & 0xFF)==0x3) doDebug=1; //Check if any of the chars is control-C. Throw away rest.
|
||||||
|
fifolen--;
|
||||||
|
}
|
||||||
|
WRITE_PERI_REG(UART_INT_CLR(0), UART_RXFIFO_FULL_INT_CLR|UART_RXFIFO_TOUT_INT_CLR);
|
||||||
|
|
||||||
|
if (doDebug) {
|
||||||
|
//Copy registers the Xtensa HAL did save to gdbstub_savedRegs
|
||||||
|
os_memcpy(&gdbstub_savedRegs, frame, 19*4);
|
||||||
|
gdbstub_savedRegs.a1=(uint32_t)frame+EXCEPTION_GDB_SP_OFFSET;
|
||||||
|
|
||||||
|
gdbstub_savedRegs.reason=0xff; //mark as user break reason
|
||||||
|
|
||||||
|
ets_wdt_disable();
|
||||||
|
sendReason();
|
||||||
|
while(gdbReadCommand()!=ST_CONT);
|
||||||
|
ets_wdt_enable();
|
||||||
|
//Copy any changed registers back to the frame the Xtensa HAL uses.
|
||||||
|
os_memcpy(frame, &gdbstub_savedRegs, 19*4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ATTR_GDBINIT install_uart_hdlr() {
|
||||||
|
ets_isr_attach(ETS_UART_INUM, uart_hdlr, NULL);
|
||||||
|
SET_PERI_REG_MASK(UART_INT_ENA(0), UART_RXFIFO_FULL_INT_ENA|UART_RXFIFO_TOUT_INT_ENA);
|
||||||
|
ets_isr_unmask((1<<ETS_UART_INUM)); //enable uart interrupt
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
void ATTR_GDBFN gdbstub_handle_uart_int(struct XTensa_rtos_int_frame_s *frame) {
|
||||||
|
int doDebug=0, fifolen=0, x;
|
||||||
|
|
||||||
|
fifolen=(READ_PERI_REG(UART_STATUS(0))>>UART_RXFIFO_CNT_S)&UART_RXFIFO_CNT;
|
||||||
|
while (fifolen!=0) {
|
||||||
|
if ((READ_PERI_REG(UART_FIFO(0)) & 0xFF)==0x3) doDebug=1; //Check if any of the chars is control-C. Throw away rest.
|
||||||
|
fifolen--;
|
||||||
|
}
|
||||||
|
WRITE_PERI_REG(UART_INT_CLR(0), UART_RXFIFO_FULL_INT_CLR|UART_RXFIFO_TOUT_INT_CLR);
|
||||||
|
|
||||||
|
if (doDebug) {
|
||||||
|
//Copy registers the Xtensa HAL did save to gdbstub_savedRegs
|
||||||
|
gdbstub_savedRegs.pc=frame->pc;
|
||||||
|
gdbstub_savedRegs.ps=frame->ps;
|
||||||
|
gdbstub_savedRegs.sar=frame->sar;
|
||||||
|
gdbstub_savedRegs.a0=frame->a[0];
|
||||||
|
gdbstub_savedRegs.a1=frame->a[1];
|
||||||
|
for (x=2; x<16; x++) gdbstub_savedRegs.a[x-2]=frame->a[x];
|
||||||
|
|
||||||
|
// gdbstub_savedRegs.a1=(uint32_t)frame+EXCEPTION_GDB_SP_OFFSET;
|
||||||
|
|
||||||
|
gdbstub_savedRegs.reason=0xff; //mark as user break reason
|
||||||
|
|
||||||
|
// ets_wdt_disable();
|
||||||
|
sendReason();
|
||||||
|
while(gdbReadCommand()!=ST_CONT);
|
||||||
|
// ets_wdt_enable();
|
||||||
|
//Copy any changed registers back to the frame the Xtensa HAL uses.
|
||||||
|
frame->pc=gdbstub_savedRegs.pc;
|
||||||
|
frame->ps=gdbstub_savedRegs.ps;
|
||||||
|
frame->sar=gdbstub_savedRegs.sar;
|
||||||
|
frame->a[0]=gdbstub_savedRegs.a0;
|
||||||
|
frame->a[1]=gdbstub_savedRegs.a1;
|
||||||
|
for (x=2; x<16; x++) frame->a[x]=gdbstub_savedRegs.a[x-2];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ATTR_GDBINIT install_uart_hdlr() {
|
||||||
|
_xt_isr_attach(ETS_UART_INUM, gdbstub_uart_entry);
|
||||||
|
SET_PERI_REG_MASK(UART_INT_ENA(0), UART_RXFIFO_FULL_INT_ENA|UART_RXFIFO_TOUT_INT_ENA);
|
||||||
|
_xt_isr_unmask((1<<ETS_UART_INUM)); //enable uart interrupt
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//gdbstub initialization routine.
|
||||||
|
void ATTR_GDBINIT gdbstub_init() {
|
||||||
|
#if GDBSTUB_REDIRECT_CONSOLE_OUTPUT
|
||||||
|
os_install_putc1(gdb_semihost_putchar1);
|
||||||
|
#endif
|
||||||
|
#if GDBSTUB_CTRLC_BREAK
|
||||||
|
install_uart_hdlr();
|
||||||
|
#endif
|
||||||
|
install_exceptions();
|
||||||
|
gdbstub_init_debug_entry();
|
||||||
|
#if GDBSTUB_BREAK_ON_INIT
|
||||||
|
gdbstub_do_break();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
extern void gdb_init() __attribute__((weak, alias("gdbstub_init")));
|
14
libraries/GDBStub/src/internal/gdbstub.h
Normal file
14
libraries/GDBStub/src/internal/gdbstub.h
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
#ifndef GDBSTUB_H
|
||||||
|
#define GDBSTUB_H
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void gdbstub_init();
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
459
libraries/GDBStub/src/xtensa/config/core-isa.h
Normal file
459
libraries/GDBStub/src/xtensa/config/core-isa.h
Normal file
@ -0,0 +1,459 @@
|
|||||||
|
/*
|
||||||
|
* xtensa/config/core-isa.h -- HAL definitions that are dependent on Xtensa
|
||||||
|
* processor CORE configuration
|
||||||
|
*
|
||||||
|
* See <xtensa/config/core.h>, which includes this file, for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Xtensa processor core configuration information.
|
||||||
|
|
||||||
|
Customer ID=7011; Build=0x2b6f6; Copyright (c) 1999-2010 Tensilica Inc.
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
a copy of this software and associated documentation files (the
|
||||||
|
"Software"), to deal in the Software without restriction, including
|
||||||
|
without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included
|
||||||
|
in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
|
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||||
|
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||||
|
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||||
|
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||||
|
|
||||||
|
#ifndef _XTENSA_CORE_CONFIGURATION_H
|
||||||
|
#define _XTENSA_CORE_CONFIGURATION_H
|
||||||
|
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
Parameters Useful for Any Code, USER or PRIVILEGED
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Note: Macros of the form XCHAL_HAVE_*** have a value of 1 if the option is
|
||||||
|
* configured, and a value of 0 otherwise. These macros are always defined.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/*----------------------------------------------------------------------
|
||||||
|
ISA
|
||||||
|
----------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#define XCHAL_HAVE_BE 0 /* big-endian byte ordering */
|
||||||
|
#define XCHAL_HAVE_WINDOWED 0 /* windowed registers option */
|
||||||
|
#define XCHAL_NUM_AREGS 16 /* num of physical addr regs */
|
||||||
|
#define XCHAL_NUM_AREGS_LOG2 4 /* log2(XCHAL_NUM_AREGS) */
|
||||||
|
#define XCHAL_MAX_INSTRUCTION_SIZE 3 /* max instr bytes (3..8) */
|
||||||
|
#define XCHAL_HAVE_DEBUG 1 /* debug option */
|
||||||
|
#define XCHAL_HAVE_DENSITY 1 /* 16-bit instructions */
|
||||||
|
#define XCHAL_HAVE_LOOPS 0 /* zero-overhead loops */
|
||||||
|
#define XCHAL_HAVE_NSA 1 /* NSA/NSAU instructions */
|
||||||
|
#define XCHAL_HAVE_MINMAX 0 /* MIN/MAX instructions */
|
||||||
|
#define XCHAL_HAVE_SEXT 0 /* SEXT instruction */
|
||||||
|
#define XCHAL_HAVE_CLAMPS 0 /* CLAMPS instruction */
|
||||||
|
#define XCHAL_HAVE_MUL16 1 /* MUL16S/MUL16U instructions */
|
||||||
|
#define XCHAL_HAVE_MUL32 1 /* MULL instruction */
|
||||||
|
#define XCHAL_HAVE_MUL32_HIGH 0 /* MULUH/MULSH instructions */
|
||||||
|
#define XCHAL_HAVE_DIV32 0 /* QUOS/QUOU/REMS/REMU instructions */
|
||||||
|
#define XCHAL_HAVE_L32R 1 /* L32R instruction */
|
||||||
|
#define XCHAL_HAVE_ABSOLUTE_LITERALS 1 /* non-PC-rel (extended) L32R */
|
||||||
|
#define XCHAL_HAVE_CONST16 0 /* CONST16 instruction */
|
||||||
|
#define XCHAL_HAVE_ADDX 1 /* ADDX#/SUBX# instructions */
|
||||||
|
#define XCHAL_HAVE_WIDE_BRANCHES 0 /* B*.W18 or B*.W15 instr's */
|
||||||
|
#define XCHAL_HAVE_PREDICTED_BRANCHES 0 /* B[EQ/EQZ/NE/NEZ]T instr's */
|
||||||
|
#define XCHAL_HAVE_CALL4AND12 0 /* (obsolete option) */
|
||||||
|
#define XCHAL_HAVE_ABS 1 /* ABS instruction */
|
||||||
|
/*#define XCHAL_HAVE_POPC 0*/ /* POPC instruction */
|
||||||
|
/*#define XCHAL_HAVE_CRC 0*/ /* CRC instruction */
|
||||||
|
#define XCHAL_HAVE_RELEASE_SYNC 0 /* L32AI/S32RI instructions */
|
||||||
|
#define XCHAL_HAVE_S32C1I 0 /* S32C1I instruction */
|
||||||
|
#define XCHAL_HAVE_SPECULATION 0 /* speculation */
|
||||||
|
#define XCHAL_HAVE_FULL_RESET 1 /* all regs/state reset */
|
||||||
|
#define XCHAL_NUM_CONTEXTS 1 /* */
|
||||||
|
#define XCHAL_NUM_MISC_REGS 0 /* num of scratch regs (0..4) */
|
||||||
|
#define XCHAL_HAVE_TAP_MASTER 0 /* JTAG TAP control instr's */
|
||||||
|
#define XCHAL_HAVE_PRID 1 /* processor ID register */
|
||||||
|
#define XCHAL_HAVE_EXTERN_REGS 1 /* WER/RER instructions */
|
||||||
|
#define XCHAL_HAVE_MP_INTERRUPTS 0 /* interrupt distributor port */
|
||||||
|
#define XCHAL_HAVE_MP_RUNSTALL 0 /* core RunStall control port */
|
||||||
|
#define XCHAL_HAVE_THREADPTR 0 /* THREADPTR register */
|
||||||
|
#define XCHAL_HAVE_BOOLEANS 0 /* boolean registers */
|
||||||
|
#define XCHAL_HAVE_CP 0 /* CPENABLE reg (coprocessor) */
|
||||||
|
#define XCHAL_CP_MAXCFG 0 /* max allowed cp id plus one */
|
||||||
|
#define XCHAL_HAVE_MAC16 0 /* MAC16 package */
|
||||||
|
#define XCHAL_HAVE_VECTORFPU2005 0 /* vector floating-point pkg */
|
||||||
|
#define XCHAL_HAVE_FP 0 /* floating point pkg */
|
||||||
|
#define XCHAL_HAVE_DFP 0 /* double precision FP pkg */
|
||||||
|
#define XCHAL_HAVE_DFP_accel 0 /* double precision FP acceleration pkg */
|
||||||
|
#define XCHAL_HAVE_VECTRA1 0 /* Vectra I pkg */
|
||||||
|
#define XCHAL_HAVE_VECTRALX 0 /* Vectra LX pkg */
|
||||||
|
#define XCHAL_HAVE_HIFIPRO 0 /* HiFiPro Audio Engine pkg */
|
||||||
|
#define XCHAL_HAVE_HIFI2 0 /* HiFi2 Audio Engine pkg */
|
||||||
|
#define XCHAL_HAVE_CONNXD2 0 /* ConnX D2 pkg */
|
||||||
|
|
||||||
|
|
||||||
|
/*----------------------------------------------------------------------
|
||||||
|
MISC
|
||||||
|
----------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#define XCHAL_NUM_WRITEBUFFER_ENTRIES 1 /* size of write buffer */
|
||||||
|
#define XCHAL_INST_FETCH_WIDTH 4 /* instr-fetch width in bytes */
|
||||||
|
#define XCHAL_DATA_WIDTH 4 /* data width in bytes */
|
||||||
|
/* In T1050, applies to selected core load and store instructions (see ISA): */
|
||||||
|
#define XCHAL_UNALIGNED_LOAD_EXCEPTION 1 /* unaligned loads cause exc. */
|
||||||
|
#define XCHAL_UNALIGNED_STORE_EXCEPTION 1 /* unaligned stores cause exc.*/
|
||||||
|
#define XCHAL_UNALIGNED_LOAD_HW 0 /* unaligned loads work in hw */
|
||||||
|
#define XCHAL_UNALIGNED_STORE_HW 0 /* unaligned stores work in hw*/
|
||||||
|
|
||||||
|
#define XCHAL_SW_VERSION 800001 /* sw version of this header */
|
||||||
|
|
||||||
|
#define XCHAL_CORE_ID "lx106" /* alphanum core name
|
||||||
|
(CoreID) set in the Xtensa
|
||||||
|
Processor Generator */
|
||||||
|
|
||||||
|
#define XCHAL_BUILD_UNIQUE_ID 0x0002B6F6 /* 22-bit sw build ID */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* These definitions describe the hardware targeted by this software.
|
||||||
|
*/
|
||||||
|
#define XCHAL_HW_CONFIGID0 0xC28CDAFA /* ConfigID hi 32 bits*/
|
||||||
|
#define XCHAL_HW_CONFIGID1 0x1082B6F6 /* ConfigID lo 32 bits*/
|
||||||
|
#define XCHAL_HW_VERSION_NAME "LX3.0.1" /* full version name */
|
||||||
|
#define XCHAL_HW_VERSION_MAJOR 2300 /* major ver# of targeted hw */
|
||||||
|
#define XCHAL_HW_VERSION_MINOR 1 /* minor ver# of targeted hw */
|
||||||
|
#define XCHAL_HW_VERSION 230001 /* major*100+minor */
|
||||||
|
#define XCHAL_HW_REL_LX3 1
|
||||||
|
#define XCHAL_HW_REL_LX3_0 1
|
||||||
|
#define XCHAL_HW_REL_LX3_0_1 1
|
||||||
|
#define XCHAL_HW_CONFIGID_RELIABLE 1
|
||||||
|
/* If software targets a *range* of hardware versions, these are the bounds: */
|
||||||
|
#define XCHAL_HW_MIN_VERSION_MAJOR 2300 /* major v of earliest tgt hw */
|
||||||
|
#define XCHAL_HW_MIN_VERSION_MINOR 1 /* minor v of earliest tgt hw */
|
||||||
|
#define XCHAL_HW_MIN_VERSION 230001 /* earliest targeted hw */
|
||||||
|
#define XCHAL_HW_MAX_VERSION_MAJOR 2300 /* major v of latest tgt hw */
|
||||||
|
#define XCHAL_HW_MAX_VERSION_MINOR 1 /* minor v of latest tgt hw */
|
||||||
|
#define XCHAL_HW_MAX_VERSION 230001 /* latest targeted hw */
|
||||||
|
|
||||||
|
|
||||||
|
/*----------------------------------------------------------------------
|
||||||
|
CACHE
|
||||||
|
----------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#define XCHAL_ICACHE_LINESIZE 4 /* I-cache line size in bytes */
|
||||||
|
#define XCHAL_DCACHE_LINESIZE 4 /* D-cache line size in bytes */
|
||||||
|
#define XCHAL_ICACHE_LINEWIDTH 2 /* log2(I line size in bytes) */
|
||||||
|
#define XCHAL_DCACHE_LINEWIDTH 2 /* log2(D line size in bytes) */
|
||||||
|
|
||||||
|
#define XCHAL_ICACHE_SIZE 0 /* I-cache size in bytes or 0 */
|
||||||
|
#define XCHAL_DCACHE_SIZE 0 /* D-cache size in bytes or 0 */
|
||||||
|
|
||||||
|
#define XCHAL_DCACHE_IS_WRITEBACK 0 /* writeback feature */
|
||||||
|
#define XCHAL_DCACHE_IS_COHERENT 0 /* MP coherence feature */
|
||||||
|
|
||||||
|
#define XCHAL_HAVE_PREFETCH 0 /* PREFCTL register */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
Parameters Useful for PRIVILEGED (Supervisory or Non-Virtualized) Code
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef XTENSA_HAL_NON_PRIVILEGED_ONLY
|
||||||
|
|
||||||
|
/*----------------------------------------------------------------------
|
||||||
|
CACHE
|
||||||
|
----------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#define XCHAL_HAVE_PIF 1 /* any outbound PIF present */
|
||||||
|
|
||||||
|
/* If present, cache size in bytes == (ways * 2^(linewidth + setwidth)). */
|
||||||
|
|
||||||
|
/* Number of cache sets in log2(lines per way): */
|
||||||
|
#define XCHAL_ICACHE_SETWIDTH 0
|
||||||
|
#define XCHAL_DCACHE_SETWIDTH 0
|
||||||
|
|
||||||
|
/* Cache set associativity (number of ways): */
|
||||||
|
#define XCHAL_ICACHE_WAYS 1
|
||||||
|
#define XCHAL_DCACHE_WAYS 1
|
||||||
|
|
||||||
|
/* Cache features: */
|
||||||
|
#define XCHAL_ICACHE_LINE_LOCKABLE 0
|
||||||
|
#define XCHAL_DCACHE_LINE_LOCKABLE 0
|
||||||
|
#define XCHAL_ICACHE_ECC_PARITY 0
|
||||||
|
#define XCHAL_DCACHE_ECC_PARITY 0
|
||||||
|
|
||||||
|
/* Cache access size in bytes (affects operation of SICW instruction): */
|
||||||
|
#define XCHAL_ICACHE_ACCESS_SIZE 1
|
||||||
|
#define XCHAL_DCACHE_ACCESS_SIZE 1
|
||||||
|
|
||||||
|
/* Number of encoded cache attr bits (see <xtensa/hal.h> for decoded bits): */
|
||||||
|
#define XCHAL_CA_BITS 4
|
||||||
|
|
||||||
|
|
||||||
|
/*----------------------------------------------------------------------
|
||||||
|
INTERNAL I/D RAM/ROMs and XLMI
|
||||||
|
----------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#define XCHAL_NUM_INSTROM 1 /* number of core instr. ROMs */
|
||||||
|
#define XCHAL_NUM_INSTRAM 2 /* number of core instr. RAMs */
|
||||||
|
#define XCHAL_NUM_DATAROM 1 /* number of core data ROMs */
|
||||||
|
#define XCHAL_NUM_DATARAM 2 /* number of core data RAMs */
|
||||||
|
#define XCHAL_NUM_URAM 0 /* number of core unified RAMs*/
|
||||||
|
#define XCHAL_NUM_XLMI 1 /* number of core XLMI ports */
|
||||||
|
|
||||||
|
/* Instruction ROM 0: */
|
||||||
|
#define XCHAL_INSTROM0_VADDR 0x40200000
|
||||||
|
#define XCHAL_INSTROM0_PADDR 0x40200000
|
||||||
|
#define XCHAL_INSTROM0_SIZE 1048576
|
||||||
|
#define XCHAL_INSTROM0_ECC_PARITY 0
|
||||||
|
|
||||||
|
/* Instruction RAM 0: */
|
||||||
|
#define XCHAL_INSTRAM0_VADDR 0x40000000
|
||||||
|
#define XCHAL_INSTRAM0_PADDR 0x40000000
|
||||||
|
#define XCHAL_INSTRAM0_SIZE 1048576
|
||||||
|
#define XCHAL_INSTRAM0_ECC_PARITY 0
|
||||||
|
|
||||||
|
/* Instruction RAM 1: */
|
||||||
|
#define XCHAL_INSTRAM1_VADDR 0x40100000
|
||||||
|
#define XCHAL_INSTRAM1_PADDR 0x40100000
|
||||||
|
#define XCHAL_INSTRAM1_SIZE 1048576
|
||||||
|
#define XCHAL_INSTRAM1_ECC_PARITY 0
|
||||||
|
|
||||||
|
/* Data ROM 0: */
|
||||||
|
#define XCHAL_DATAROM0_VADDR 0x3FF40000
|
||||||
|
#define XCHAL_DATAROM0_PADDR 0x3FF40000
|
||||||
|
#define XCHAL_DATAROM0_SIZE 262144
|
||||||
|
#define XCHAL_DATAROM0_ECC_PARITY 0
|
||||||
|
|
||||||
|
/* Data RAM 0: */
|
||||||
|
#define XCHAL_DATARAM0_VADDR 0x3FFC0000
|
||||||
|
#define XCHAL_DATARAM0_PADDR 0x3FFC0000
|
||||||
|
#define XCHAL_DATARAM0_SIZE 262144
|
||||||
|
#define XCHAL_DATARAM0_ECC_PARITY 0
|
||||||
|
|
||||||
|
/* Data RAM 1: */
|
||||||
|
#define XCHAL_DATARAM1_VADDR 0x3FF80000
|
||||||
|
#define XCHAL_DATARAM1_PADDR 0x3FF80000
|
||||||
|
#define XCHAL_DATARAM1_SIZE 262144
|
||||||
|
#define XCHAL_DATARAM1_ECC_PARITY 0
|
||||||
|
|
||||||
|
/* XLMI Port 0: */
|
||||||
|
#define XCHAL_XLMI0_VADDR 0x3FF00000
|
||||||
|
#define XCHAL_XLMI0_PADDR 0x3FF00000
|
||||||
|
#define XCHAL_XLMI0_SIZE 262144
|
||||||
|
#define XCHAL_XLMI0_ECC_PARITY 0
|
||||||
|
|
||||||
|
|
||||||
|
/*----------------------------------------------------------------------
|
||||||
|
INTERRUPTS and TIMERS
|
||||||
|
----------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#define XCHAL_HAVE_INTERRUPTS 1 /* interrupt option */
|
||||||
|
#define XCHAL_HAVE_HIGHPRI_INTERRUPTS 1 /* med/high-pri. interrupts */
|
||||||
|
#define XCHAL_HAVE_NMI 1 /* non-maskable interrupt */
|
||||||
|
#define XCHAL_HAVE_CCOUNT 1 /* CCOUNT reg. (timer option) */
|
||||||
|
#define XCHAL_NUM_TIMERS 1 /* number of CCOMPAREn regs */
|
||||||
|
#define XCHAL_NUM_INTERRUPTS 15 /* number of interrupts */
|
||||||
|
#define XCHAL_NUM_INTERRUPTS_LOG2 4 /* ceil(log2(NUM_INTERRUPTS)) */
|
||||||
|
#define XCHAL_NUM_EXTINTERRUPTS 13 /* num of external interrupts */
|
||||||
|
#define XCHAL_NUM_INTLEVELS 2 /* number of interrupt levels
|
||||||
|
(not including level zero) */
|
||||||
|
#define XCHAL_EXCM_LEVEL 1 /* level masked by PS.EXCM */
|
||||||
|
/* (always 1 in XEA1; levels 2 .. EXCM_LEVEL are "medium priority") */
|
||||||
|
|
||||||
|
/* Masks of interrupts at each interrupt level: */
|
||||||
|
#define XCHAL_INTLEVEL1_MASK 0x00003FFF
|
||||||
|
#define XCHAL_INTLEVEL2_MASK 0x00000000
|
||||||
|
#define XCHAL_INTLEVEL3_MASK 0x00004000
|
||||||
|
#define XCHAL_INTLEVEL4_MASK 0x00000000
|
||||||
|
#define XCHAL_INTLEVEL5_MASK 0x00000000
|
||||||
|
#define XCHAL_INTLEVEL6_MASK 0x00000000
|
||||||
|
#define XCHAL_INTLEVEL7_MASK 0x00000000
|
||||||
|
|
||||||
|
/* Masks of interrupts at each range 1..n of interrupt levels: */
|
||||||
|
#define XCHAL_INTLEVEL1_ANDBELOW_MASK 0x00003FFF
|
||||||
|
#define XCHAL_INTLEVEL2_ANDBELOW_MASK 0x00003FFF
|
||||||
|
#define XCHAL_INTLEVEL3_ANDBELOW_MASK 0x00007FFF
|
||||||
|
#define XCHAL_INTLEVEL4_ANDBELOW_MASK 0x00007FFF
|
||||||
|
#define XCHAL_INTLEVEL5_ANDBELOW_MASK 0x00007FFF
|
||||||
|
#define XCHAL_INTLEVEL6_ANDBELOW_MASK 0x00007FFF
|
||||||
|
#define XCHAL_INTLEVEL7_ANDBELOW_MASK 0x00007FFF
|
||||||
|
|
||||||
|
/* Level of each interrupt: */
|
||||||
|
#define XCHAL_INT0_LEVEL 1
|
||||||
|
#define XCHAL_INT1_LEVEL 1
|
||||||
|
#define XCHAL_INT2_LEVEL 1
|
||||||
|
#define XCHAL_INT3_LEVEL 1
|
||||||
|
#define XCHAL_INT4_LEVEL 1
|
||||||
|
#define XCHAL_INT5_LEVEL 1
|
||||||
|
#define XCHAL_INT6_LEVEL 1
|
||||||
|
#define XCHAL_INT7_LEVEL 1
|
||||||
|
#define XCHAL_INT8_LEVEL 1
|
||||||
|
#define XCHAL_INT9_LEVEL 1
|
||||||
|
#define XCHAL_INT10_LEVEL 1
|
||||||
|
#define XCHAL_INT11_LEVEL 1
|
||||||
|
#define XCHAL_INT12_LEVEL 1
|
||||||
|
#define XCHAL_INT13_LEVEL 1
|
||||||
|
#define XCHAL_INT14_LEVEL 3
|
||||||
|
#define XCHAL_DEBUGLEVEL 2 /* debug interrupt level */
|
||||||
|
#define XCHAL_HAVE_DEBUG_EXTERN_INT 1 /* OCD external db interrupt */
|
||||||
|
#define XCHAL_NMILEVEL 3 /* NMI "level" (for use with
|
||||||
|
EXCSAVE/EPS/EPC_n, RFI n) */
|
||||||
|
|
||||||
|
/* Type of each interrupt: */
|
||||||
|
#define XCHAL_INT0_TYPE XTHAL_INTTYPE_EXTERN_LEVEL
|
||||||
|
#define XCHAL_INT1_TYPE XTHAL_INTTYPE_EXTERN_LEVEL
|
||||||
|
#define XCHAL_INT2_TYPE XTHAL_INTTYPE_EXTERN_LEVEL
|
||||||
|
#define XCHAL_INT3_TYPE XTHAL_INTTYPE_EXTERN_LEVEL
|
||||||
|
#define XCHAL_INT4_TYPE XTHAL_INTTYPE_EXTERN_LEVEL
|
||||||
|
#define XCHAL_INT5_TYPE XTHAL_INTTYPE_EXTERN_LEVEL
|
||||||
|
#define XCHAL_INT6_TYPE XTHAL_INTTYPE_TIMER
|
||||||
|
#define XCHAL_INT7_TYPE XTHAL_INTTYPE_SOFTWARE
|
||||||
|
#define XCHAL_INT8_TYPE XTHAL_INTTYPE_EXTERN_EDGE
|
||||||
|
#define XCHAL_INT9_TYPE XTHAL_INTTYPE_EXTERN_EDGE
|
||||||
|
#define XCHAL_INT10_TYPE XTHAL_INTTYPE_EXTERN_EDGE
|
||||||
|
#define XCHAL_INT11_TYPE XTHAL_INTTYPE_EXTERN_EDGE
|
||||||
|
#define XCHAL_INT12_TYPE XTHAL_INTTYPE_EXTERN_EDGE
|
||||||
|
#define XCHAL_INT13_TYPE XTHAL_INTTYPE_EXTERN_EDGE
|
||||||
|
#define XCHAL_INT14_TYPE XTHAL_INTTYPE_NMI
|
||||||
|
|
||||||
|
/* Masks of interrupts for each type of interrupt: */
|
||||||
|
#define XCHAL_INTTYPE_MASK_UNCONFIGURED 0xFFFF8000
|
||||||
|
#define XCHAL_INTTYPE_MASK_SOFTWARE 0x00000080
|
||||||
|
#define XCHAL_INTTYPE_MASK_EXTERN_EDGE 0x00003F00
|
||||||
|
#define XCHAL_INTTYPE_MASK_EXTERN_LEVEL 0x0000003F
|
||||||
|
#define XCHAL_INTTYPE_MASK_TIMER 0x00000040
|
||||||
|
#define XCHAL_INTTYPE_MASK_NMI 0x00004000
|
||||||
|
#define XCHAL_INTTYPE_MASK_WRITE_ERROR 0x00000000
|
||||||
|
|
||||||
|
/* Interrupt numbers assigned to specific interrupt sources: */
|
||||||
|
#define XCHAL_TIMER0_INTERRUPT 6 /* CCOMPARE0 */
|
||||||
|
#define XCHAL_TIMER1_INTERRUPT XTHAL_TIMER_UNCONFIGURED
|
||||||
|
#define XCHAL_TIMER2_INTERRUPT XTHAL_TIMER_UNCONFIGURED
|
||||||
|
#define XCHAL_TIMER3_INTERRUPT XTHAL_TIMER_UNCONFIGURED
|
||||||
|
#define XCHAL_NMI_INTERRUPT 14 /* non-maskable interrupt */
|
||||||
|
|
||||||
|
/* Interrupt numbers for levels at which only one interrupt is configured: */
|
||||||
|
#define XCHAL_INTLEVEL3_NUM 14
|
||||||
|
/* (There are many interrupts each at level(s) 1.) */
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* External interrupt vectors/levels.
|
||||||
|
* These macros describe how Xtensa processor interrupt numbers
|
||||||
|
* (as numbered internally, eg. in INTERRUPT and INTENABLE registers)
|
||||||
|
* map to external BInterrupt<n> pins, for those interrupts
|
||||||
|
* configured as external (level-triggered, edge-triggered, or NMI).
|
||||||
|
* See the Xtensa processor databook for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Core interrupt numbers mapped to each EXTERNAL interrupt number: */
|
||||||
|
#define XCHAL_EXTINT0_NUM 0 /* (intlevel 1) */
|
||||||
|
#define XCHAL_EXTINT1_NUM 1 /* (intlevel 1) */
|
||||||
|
#define XCHAL_EXTINT2_NUM 2 /* (intlevel 1) */
|
||||||
|
#define XCHAL_EXTINT3_NUM 3 /* (intlevel 1) */
|
||||||
|
#define XCHAL_EXTINT4_NUM 4 /* (intlevel 1) */
|
||||||
|
#define XCHAL_EXTINT5_NUM 5 /* (intlevel 1) */
|
||||||
|
#define XCHAL_EXTINT6_NUM 8 /* (intlevel 1) */
|
||||||
|
#define XCHAL_EXTINT7_NUM 9 /* (intlevel 1) */
|
||||||
|
#define XCHAL_EXTINT8_NUM 10 /* (intlevel 1) */
|
||||||
|
#define XCHAL_EXTINT9_NUM 11 /* (intlevel 1) */
|
||||||
|
#define XCHAL_EXTINT10_NUM 12 /* (intlevel 1) */
|
||||||
|
#define XCHAL_EXTINT11_NUM 13 /* (intlevel 1) */
|
||||||
|
#define XCHAL_EXTINT12_NUM 14 /* (intlevel 3) */
|
||||||
|
|
||||||
|
|
||||||
|
/*----------------------------------------------------------------------
|
||||||
|
EXCEPTIONS and VECTORS
|
||||||
|
----------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#define XCHAL_XEA_VERSION 2 /* Xtensa Exception Architecture
|
||||||
|
number: 1 == XEA1 (old)
|
||||||
|
2 == XEA2 (new)
|
||||||
|
0 == XEAX (extern) */
|
||||||
|
#define XCHAL_HAVE_XEA1 0 /* Exception Architecture 1 */
|
||||||
|
#define XCHAL_HAVE_XEA2 1 /* Exception Architecture 2 */
|
||||||
|
#define XCHAL_HAVE_XEAX 0 /* External Exception Arch. */
|
||||||
|
#define XCHAL_HAVE_EXCEPTIONS 1 /* exception option */
|
||||||
|
#define XCHAL_HAVE_MEM_ECC_PARITY 0 /* local memory ECC/parity */
|
||||||
|
#define XCHAL_HAVE_VECTOR_SELECT 1 /* relocatable vectors */
|
||||||
|
#define XCHAL_HAVE_VECBASE 1 /* relocatable vectors */
|
||||||
|
#define XCHAL_VECBASE_RESET_VADDR 0x40000000 /* VECBASE reset value */
|
||||||
|
#define XCHAL_VECBASE_RESET_PADDR 0x40000000
|
||||||
|
#define XCHAL_RESET_VECBASE_OVERLAP 0
|
||||||
|
|
||||||
|
#define XCHAL_RESET_VECTOR0_VADDR 0x50000000
|
||||||
|
#define XCHAL_RESET_VECTOR0_PADDR 0x50000000
|
||||||
|
#define XCHAL_RESET_VECTOR1_VADDR 0x40000080
|
||||||
|
#define XCHAL_RESET_VECTOR1_PADDR 0x40000080
|
||||||
|
#define XCHAL_RESET_VECTOR_VADDR 0x50000000
|
||||||
|
#define XCHAL_RESET_VECTOR_PADDR 0x50000000
|
||||||
|
#define XCHAL_USER_VECOFS 0x00000050
|
||||||
|
#define XCHAL_USER_VECTOR_VADDR 0x40000050
|
||||||
|
#define XCHAL_USER_VECTOR_PADDR 0x40000050
|
||||||
|
#define XCHAL_KERNEL_VECOFS 0x00000030
|
||||||
|
#define XCHAL_KERNEL_VECTOR_VADDR 0x40000030
|
||||||
|
#define XCHAL_KERNEL_VECTOR_PADDR 0x40000030
|
||||||
|
#define XCHAL_DOUBLEEXC_VECOFS 0x00000070
|
||||||
|
#define XCHAL_DOUBLEEXC_VECTOR_VADDR 0x40000070
|
||||||
|
#define XCHAL_DOUBLEEXC_VECTOR_PADDR 0x40000070
|
||||||
|
#define XCHAL_INTLEVEL2_VECOFS 0x00000010
|
||||||
|
#define XCHAL_INTLEVEL2_VECTOR_VADDR 0x40000010
|
||||||
|
#define XCHAL_INTLEVEL2_VECTOR_PADDR 0x40000010
|
||||||
|
#define XCHAL_DEBUG_VECOFS XCHAL_INTLEVEL2_VECOFS
|
||||||
|
#define XCHAL_DEBUG_VECTOR_VADDR XCHAL_INTLEVEL2_VECTOR_VADDR
|
||||||
|
#define XCHAL_DEBUG_VECTOR_PADDR XCHAL_INTLEVEL2_VECTOR_PADDR
|
||||||
|
#define XCHAL_NMI_VECOFS 0x00000020
|
||||||
|
#define XCHAL_NMI_VECTOR_VADDR 0x40000020
|
||||||
|
#define XCHAL_NMI_VECTOR_PADDR 0x40000020
|
||||||
|
#define XCHAL_INTLEVEL3_VECOFS XCHAL_NMI_VECOFS
|
||||||
|
#define XCHAL_INTLEVEL3_VECTOR_VADDR XCHAL_NMI_VECTOR_VADDR
|
||||||
|
#define XCHAL_INTLEVEL3_VECTOR_PADDR XCHAL_NMI_VECTOR_PADDR
|
||||||
|
|
||||||
|
|
||||||
|
/*----------------------------------------------------------------------
|
||||||
|
DEBUG
|
||||||
|
----------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#define XCHAL_HAVE_OCD 1 /* OnChipDebug option */
|
||||||
|
#define XCHAL_NUM_IBREAK 1 /* number of IBREAKn regs */
|
||||||
|
#define XCHAL_NUM_DBREAK 1 /* number of DBREAKn regs */
|
||||||
|
#define XCHAL_HAVE_OCD_DIR_ARRAY 0 /* faster OCD option */
|
||||||
|
|
||||||
|
|
||||||
|
/*----------------------------------------------------------------------
|
||||||
|
MMU
|
||||||
|
----------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
/* See core-matmap.h header file for more details. */
|
||||||
|
|
||||||
|
#define XCHAL_HAVE_TLBS 1 /* inverse of HAVE_CACHEATTR */
|
||||||
|
#define XCHAL_HAVE_SPANNING_WAY 1 /* one way maps I+D 4GB vaddr */
|
||||||
|
#define XCHAL_SPANNING_WAY 0 /* TLB spanning way number */
|
||||||
|
#define XCHAL_HAVE_IDENTITY_MAP 1 /* vaddr == paddr always */
|
||||||
|
#define XCHAL_HAVE_CACHEATTR 0 /* CACHEATTR register present */
|
||||||
|
#define XCHAL_HAVE_MIMIC_CACHEATTR 1 /* region protection */
|
||||||
|
#define XCHAL_HAVE_XLT_CACHEATTR 0 /* region prot. w/translation */
|
||||||
|
#define XCHAL_HAVE_PTP_MMU 0 /* full MMU (with page table
|
||||||
|
[autorefill] and protection)
|
||||||
|
usable for an MMU-based OS */
|
||||||
|
/* If none of the above last 4 are set, it's a custom TLB configuration. */
|
||||||
|
|
||||||
|
#define XCHAL_MMU_ASID_BITS 0 /* number of bits in ASIDs */
|
||||||
|
#define XCHAL_MMU_RINGS 1 /* number of rings (1..4) */
|
||||||
|
#define XCHAL_MMU_RING_BITS 0 /* num of bits in RING field */
|
||||||
|
|
||||||
|
#endif /* !XTENSA_HAL_NON_PRIVILEGED_ONLY */
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* _XTENSA_CORE_CONFIGURATION_H */
|
||||||
|
|
80
libraries/GDBStub/src/xtensa/config/specreg.h
Normal file
80
libraries/GDBStub/src/xtensa/config/specreg.h
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
/*
|
||||||
|
* Xtensa Special Register symbolic names
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* $Id: //depot/rel/Boreal/Xtensa/SWConfig/hal/specreg.h.tpp#2 $ */
|
||||||
|
|
||||||
|
/* Customer ID=7011; Build=0x2b6f6; Copyright (c) 1998-2002 Tensilica Inc.
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
a copy of this software and associated documentation files (the
|
||||||
|
"Software"), to deal in the Software without restriction, including
|
||||||
|
without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included
|
||||||
|
in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
|
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||||
|
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||||
|
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||||
|
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||||
|
|
||||||
|
#ifndef XTENSA_SPECREG_H
|
||||||
|
#define XTENSA_SPECREG_H
|
||||||
|
|
||||||
|
/* Include these special register bitfield definitions, for historical reasons: */
|
||||||
|
#include <xtensa/corebits.h>
|
||||||
|
|
||||||
|
|
||||||
|
/* Special registers: */
|
||||||
|
#define SAR 3
|
||||||
|
#define LITBASE 5
|
||||||
|
#define IBREAKENABLE 96
|
||||||
|
#define DDR 104
|
||||||
|
#define IBREAKA_0 128
|
||||||
|
#define DBREAKA_0 144
|
||||||
|
#define DBREAKC_0 160
|
||||||
|
#define EPC_1 177
|
||||||
|
#define EPC_2 178
|
||||||
|
#define EPC_3 179
|
||||||
|
#define DEPC 192
|
||||||
|
#define EPS_2 194
|
||||||
|
#define EPS_3 195
|
||||||
|
#define EXCSAVE_1 209
|
||||||
|
#define EXCSAVE_2 210
|
||||||
|
#define EXCSAVE_3 211
|
||||||
|
#define INTERRUPT 226
|
||||||
|
#define INTENABLE 228
|
||||||
|
#define PS 230
|
||||||
|
#define VECBASE 231
|
||||||
|
#define EXCCAUSE 232
|
||||||
|
#define DEBUGCAUSE 233
|
||||||
|
#define CCOUNT 234
|
||||||
|
#define PRID 235
|
||||||
|
#define ICOUNT 236
|
||||||
|
#define ICOUNTLEVEL 237
|
||||||
|
#define EXCVADDR 238
|
||||||
|
#define CCOMPARE_0 240
|
||||||
|
|
||||||
|
/* Special cases (bases of special register series): */
|
||||||
|
#define IBREAKA 128
|
||||||
|
#define DBREAKA 144
|
||||||
|
#define DBREAKC 160
|
||||||
|
#define EPC 176
|
||||||
|
#define EPS 192
|
||||||
|
#define EXCSAVE 208
|
||||||
|
#define CCOMPARE 240
|
||||||
|
|
||||||
|
/* Special names for read-only and write-only interrupt registers: */
|
||||||
|
#define INTREAD 226
|
||||||
|
#define INTSET 226
|
||||||
|
#define INTCLEAR 227
|
||||||
|
|
||||||
|
#endif /* XTENSA_SPECREG_H */
|
||||||
|
|
164
libraries/GDBStub/src/xtensa/corebits.h
Normal file
164
libraries/GDBStub/src/xtensa/corebits.h
Normal file
@ -0,0 +1,164 @@
|
|||||||
|
/*
|
||||||
|
* xtensa/corebits.h - Xtensa Special Register field positions, masks, values.
|
||||||
|
*
|
||||||
|
* (In previous releases, these were defined in specreg.h, a generated file.
|
||||||
|
* This file is not generated, ie. it is processor configuration independent.)
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* $Id: //depot/rel/Boreal/Xtensa/OS/include/xtensa/corebits.h#2 $ */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2005-2007 Tensilica Inc.
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
* a copy of this software and associated documentation files (the
|
||||||
|
* "Software"), to deal in the Software without restriction, including
|
||||||
|
* without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
* permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
* the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included
|
||||||
|
* in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
|
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||||
|
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||||
|
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||||
|
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef XTENSA_COREBITS_H
|
||||||
|
#define XTENSA_COREBITS_H
|
||||||
|
|
||||||
|
/* EXCCAUSE register fields: */
|
||||||
|
#define EXCCAUSE_EXCCAUSE_SHIFT 0
|
||||||
|
#define EXCCAUSE_EXCCAUSE_MASK 0x3F
|
||||||
|
/* EXCCAUSE register values: */
|
||||||
|
/*
|
||||||
|
* General Exception Causes
|
||||||
|
* (values of EXCCAUSE special register set by general exceptions,
|
||||||
|
* which vector to the user, kernel, or double-exception vectors).
|
||||||
|
*/
|
||||||
|
#define EXCCAUSE_ILLEGAL 0 /* Illegal Instruction */
|
||||||
|
#define EXCCAUSE_SYSCALL 1 /* System Call (SYSCALL instruction) */
|
||||||
|
#define EXCCAUSE_INSTR_ERROR 2 /* Instruction Fetch Error */
|
||||||
|
# define EXCCAUSE_IFETCHERROR 2 /* (backward compatibility macro, deprecated, avoid) */
|
||||||
|
#define EXCCAUSE_LOAD_STORE_ERROR 3 /* Load Store Error */
|
||||||
|
# define EXCCAUSE_LOADSTOREERROR 3 /* (backward compatibility macro, deprecated, avoid) */
|
||||||
|
#define EXCCAUSE_LEVEL1_INTERRUPT 4 /* Level 1 Interrupt */
|
||||||
|
# define EXCCAUSE_LEVEL1INTERRUPT 4 /* (backward compatibility macro, deprecated, avoid) */
|
||||||
|
#define EXCCAUSE_ALLOCA 5 /* Stack Extension Assist (MOVSP instruction) for alloca */
|
||||||
|
#define EXCCAUSE_DIVIDE_BY_ZERO 6 /* Integer Divide by Zero */
|
||||||
|
#define EXCCAUSE_SPECULATION 7 /* Use of Failed Speculative Access (not implemented) */
|
||||||
|
#define EXCCAUSE_PRIVILEGED 8 /* Privileged Instruction */
|
||||||
|
#define EXCCAUSE_UNALIGNED 9 /* Unaligned Load or Store */
|
||||||
|
/* Reserved 10..11 */
|
||||||
|
#define EXCCAUSE_INSTR_DATA_ERROR 12 /* PIF Data Error on Instruction Fetch (RB-200x and later) */
|
||||||
|
#define EXCCAUSE_LOAD_STORE_DATA_ERROR 13 /* PIF Data Error on Load or Store (RB-200x and later) */
|
||||||
|
#define EXCCAUSE_INSTR_ADDR_ERROR 14 /* PIF Address Error on Instruction Fetch (RB-200x and later) */
|
||||||
|
#define EXCCAUSE_LOAD_STORE_ADDR_ERROR 15 /* PIF Address Error on Load or Store (RB-200x and later) */
|
||||||
|
#define EXCCAUSE_ITLB_MISS 16 /* ITLB Miss (no ITLB entry matches, hw refill also missed) */
|
||||||
|
#define EXCCAUSE_ITLB_MULTIHIT 17 /* ITLB Multihit (multiple ITLB entries match) */
|
||||||
|
#define EXCCAUSE_INSTR_RING 18 /* Ring Privilege Violation on Instruction Fetch */
|
||||||
|
/* Reserved 19 */ /* Size Restriction on IFetch (not implemented) */
|
||||||
|
#define EXCCAUSE_INSTR_PROHIBITED 20 /* Cache Attribute does not allow Instruction Fetch */
|
||||||
|
/* Reserved 21..23 */
|
||||||
|
#define EXCCAUSE_DTLB_MISS 24 /* DTLB Miss (no DTLB entry matches, hw refill also missed) */
|
||||||
|
#define EXCCAUSE_DTLB_MULTIHIT 25 /* DTLB Multihit (multiple DTLB entries match) */
|
||||||
|
#define EXCCAUSE_LOAD_STORE_RING 26 /* Ring Privilege Violation on Load or Store */
|
||||||
|
/* Reserved 27 */ /* Size Restriction on Load/Store (not implemented) */
|
||||||
|
#define EXCCAUSE_LOAD_PROHIBITED 28 /* Cache Attribute does not allow Load */
|
||||||
|
#define EXCCAUSE_STORE_PROHIBITED 29 /* Cache Attribute does not allow Store */
|
||||||
|
/* Reserved 30..31 */
|
||||||
|
#define EXCCAUSE_CP_DISABLED(n) (32+(n)) /* Access to Coprocessor 'n' when disabled */
|
||||||
|
#define EXCCAUSE_CP0_DISABLED 32 /* Access to Coprocessor 0 when disabled */
|
||||||
|
#define EXCCAUSE_CP1_DISABLED 33 /* Access to Coprocessor 1 when disabled */
|
||||||
|
#define EXCCAUSE_CP2_DISABLED 34 /* Access to Coprocessor 2 when disabled */
|
||||||
|
#define EXCCAUSE_CP3_DISABLED 35 /* Access to Coprocessor 3 when disabled */
|
||||||
|
#define EXCCAUSE_CP4_DISABLED 36 /* Access to Coprocessor 4 when disabled */
|
||||||
|
#define EXCCAUSE_CP5_DISABLED 37 /* Access to Coprocessor 5 when disabled */
|
||||||
|
#define EXCCAUSE_CP6_DISABLED 38 /* Access to Coprocessor 6 when disabled */
|
||||||
|
#define EXCCAUSE_CP7_DISABLED 39 /* Access to Coprocessor 7 when disabled */
|
||||||
|
/*#define EXCCAUSE_FLOATING_POINT 40*/ /* Floating Point Exception (not implemented) */
|
||||||
|
/* Reserved 40..63 */
|
||||||
|
|
||||||
|
/* PS register fields: */
|
||||||
|
#define PS_WOE_SHIFT 18
|
||||||
|
#define PS_WOE_MASK 0x00040000
|
||||||
|
#define PS_WOE PS_WOE_MASK
|
||||||
|
#define PS_CALLINC_SHIFT 16
|
||||||
|
#define PS_CALLINC_MASK 0x00030000
|
||||||
|
#define PS_CALLINC(n) (((n)&3)<<PS_CALLINC_SHIFT) /* n = 0..3 */
|
||||||
|
#define PS_OWB_SHIFT 8
|
||||||
|
#define PS_OWB_MASK 0x00000F00
|
||||||
|
#define PS_OWB(n) (((n)&15)<<PS_OWB_SHIFT) /* n = 0..15 (or 0..7) */
|
||||||
|
#define PS_RING_SHIFT 6
|
||||||
|
#define PS_RING_MASK 0x000000C0
|
||||||
|
#define PS_RING(n) (((n)&3)<<PS_RING_SHIFT) /* n = 0..3 */
|
||||||
|
#define PS_UM_SHIFT 5
|
||||||
|
#define PS_UM_MASK 0x00000020
|
||||||
|
#define PS_UM PS_UM_MASK
|
||||||
|
#define PS_EXCM_SHIFT 4
|
||||||
|
#define PS_EXCM_MASK 0x00000010
|
||||||
|
#define PS_EXCM PS_EXCM_MASK
|
||||||
|
#define PS_INTLEVEL_SHIFT 0
|
||||||
|
#define PS_INTLEVEL_MASK 0x0000000F
|
||||||
|
#define PS_INTLEVEL(n) ((n)&PS_INTLEVEL_MASK) /* n = 0..15 */
|
||||||
|
/* Backward compatibility (deprecated): */
|
||||||
|
#define PS_PROGSTACK_SHIFT PS_UM_SHIFT
|
||||||
|
#define PS_PROGSTACK_MASK PS_UM_MASK
|
||||||
|
#define PS_PROG_SHIFT PS_UM_SHIFT
|
||||||
|
#define PS_PROG_MASK PS_UM_MASK
|
||||||
|
#define PS_PROG PS_UM
|
||||||
|
|
||||||
|
/* DBREAKCn register fields: */
|
||||||
|
#define DBREAKC_MASK_SHIFT 0
|
||||||
|
#define DBREAKC_MASK_MASK 0x0000003F
|
||||||
|
#define DBREAKC_LOADBREAK_SHIFT 30
|
||||||
|
#define DBREAKC_LOADBREAK_MASK 0x40000000
|
||||||
|
#define DBREAKC_STOREBREAK_SHIFT 31
|
||||||
|
#define DBREAKC_STOREBREAK_MASK 0x80000000
|
||||||
|
|
||||||
|
/* DEBUGCAUSE register fields: */
|
||||||
|
#define DEBUGCAUSE_DEBUGINT_SHIFT 5
|
||||||
|
#define DEBUGCAUSE_DEBUGINT_MASK 0x20 /* debug interrupt */
|
||||||
|
#define DEBUGCAUSE_BREAKN_SHIFT 4
|
||||||
|
#define DEBUGCAUSE_BREAKN_MASK 0x10 /* BREAK.N instruction */
|
||||||
|
#define DEBUGCAUSE_BREAK_SHIFT 3
|
||||||
|
#define DEBUGCAUSE_BREAK_MASK 0x08 /* BREAK instruction */
|
||||||
|
#define DEBUGCAUSE_DBREAK_SHIFT 2
|
||||||
|
#define DEBUGCAUSE_DBREAK_MASK 0x04 /* DBREAK match */
|
||||||
|
#define DEBUGCAUSE_IBREAK_SHIFT 1
|
||||||
|
#define DEBUGCAUSE_IBREAK_MASK 0x02 /* IBREAK match */
|
||||||
|
#define DEBUGCAUSE_ICOUNT_SHIFT 0
|
||||||
|
#define DEBUGCAUSE_ICOUNT_MASK 0x01 /* ICOUNT would increment to zero */
|
||||||
|
|
||||||
|
/* MESR register fields: */
|
||||||
|
#define MESR_MEME 0x00000001 /* memory error */
|
||||||
|
#define MESR_MEME_SHIFT 0
|
||||||
|
#define MESR_DME 0x00000002 /* double memory error */
|
||||||
|
#define MESR_DME_SHIFT 1
|
||||||
|
#define MESR_RCE 0x00000010 /* recorded memory error */
|
||||||
|
#define MESR_RCE_SHIFT 4
|
||||||
|
#define MESR_LCE
|
||||||
|
#define MESR_LCE_SHIFT ?
|
||||||
|
#define MESR_LCE_L
|
||||||
|
#define MESR_ERRENAB 0x00000100
|
||||||
|
#define MESR_ERRENAB_SHIFT 8
|
||||||
|
#define MESR_ERRTEST 0x00000200
|
||||||
|
#define MESR_ERRTEST_SHIFT 9
|
||||||
|
#define MESR_DATEXC 0x00000400
|
||||||
|
#define MESR_DATEXC_SHIFT 10
|
||||||
|
#define MESR_INSEXC 0x00000800
|
||||||
|
#define MESR_INSEXC_SHIFT 11
|
||||||
|
#define MESR_WAYNUM_SHIFT 16
|
||||||
|
#define MESR_ACCTYPE_SHIFT 20
|
||||||
|
#define MESR_MEMTYPE_SHIFT 24
|
||||||
|
#define MESR_ERRTYPE_SHIFT 30
|
||||||
|
|
||||||
|
|
||||||
|
#endif /*XTENSA_COREBITS_H*/
|
||||||
|
|
@ -1,20 +1,20 @@
|
|||||||
/*
|
/*
|
||||||
Copyright (c) 2015 Michael C. Miller. All right reserved.
|
Copyright (c) 2015 Michael C. Miller. All right 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
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
This library is distributed in the hope that it will be useful,
|
This library is distributed in the hope that it will be useful,
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
Lesser General Public License for more details.
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
You should have received a copy of the GNU Lesser General Public
|
||||||
License along with this library; if not, write to the Free Software
|
License along with this library; if not, write to the Free Software
|
||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#if defined(ESP8266)
|
#if defined(ESP8266)
|
||||||
|
|
||||||
@ -26,9 +26,12 @@
|
|||||||
|
|
||||||
const uint32_t c_CycleCompensation = 4; // compensation us to trim adjust for digitalWrite delays
|
const uint32_t c_CycleCompensation = 4; // compensation us to trim adjust for digitalWrite delays
|
||||||
|
|
||||||
|
#define INVALID_PIN 63 // flag indicating never attached servo
|
||||||
|
|
||||||
struct ServoInfo {
|
struct ServoInfo {
|
||||||
uint8_t pin : 6; // a pin number from 0 to 63
|
uint8_t pin : 6; // a pin number from 0 to 62, 63 reserved
|
||||||
uint8_t isActive : 1; // true if this channel is enabled, pin not pulsed if false
|
uint8_t isActive : 1; // true if this channel is enabled, pin not pulsed if false
|
||||||
|
uint8_t isDetaching : 1; // true if this channel is being detached, maintains pulse integrity
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ServoState {
|
struct ServoState {
|
||||||
@ -76,29 +79,49 @@ static void Servo_Handler(T* timer)
|
|||||||
if (servoIndex < s_servoCount && s_servos[servoIndex].info.isActive) {
|
if (servoIndex < s_servoCount && s_servos[servoIndex].info.isActive) {
|
||||||
// pulse this channel low if activated
|
// pulse this channel low if activated
|
||||||
digitalWrite(s_servos[servoIndex].info.pin, LOW);
|
digitalWrite(s_servos[servoIndex].info.pin, LOW);
|
||||||
|
|
||||||
|
if (s_servos[servoIndex].info.isDetaching) {
|
||||||
|
s_servos[servoIndex].info.isActive = false;
|
||||||
|
s_servos[servoIndex].info.isDetaching = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
timer->nextChannel();
|
timer->nextChannel();
|
||||||
}
|
}
|
||||||
|
|
||||||
servoIndex = SERVO_INDEX(timer->timerId(), timer->getCurrentChannel());
|
servoIndex = SERVO_INDEX(timer->timerId(), timer->getCurrentChannel());
|
||||||
|
|
||||||
if (servoIndex < s_servoCount && timer->getCurrentChannel() < SERVOS_PER_TIMER) {
|
if (servoIndex < s_servoCount &&
|
||||||
|
timer->getCurrentChannel() < SERVOS_PER_TIMER) {
|
||||||
timer->SetPulseCompare(timer->usToTicks(s_servos[servoIndex].usPulse) - c_CycleCompensation);
|
timer->SetPulseCompare(timer->usToTicks(s_servos[servoIndex].usPulse) - c_CycleCompensation);
|
||||||
|
|
||||||
if (s_servos[servoIndex].info.isActive) { // check if activated
|
if (s_servos[servoIndex].info.isActive) {
|
||||||
digitalWrite(s_servos[servoIndex].info.pin, HIGH); // its an active channel so pulse it high
|
if (s_servos[servoIndex].info.isDetaching) {
|
||||||
|
// it was active, reset state and leave low
|
||||||
|
s_servos[servoIndex].info.isActive = false;
|
||||||
|
s_servos[servoIndex].info.isDetaching = false;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// its an active channel so pulse it high
|
||||||
|
digitalWrite(s_servos[servoIndex].info.pin, HIGH);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// finished all channels so wait for the refresh period to expire before starting over
|
if (!isTimerActive(timer->timerId())) {
|
||||||
// allow a few ticks to ensure the next match is not missed
|
// no active running channels on this timer, stop the ISR
|
||||||
uint32_t refreshCompare = timer->usToTicks(REFRESH_INTERVAL);
|
finISR(timer->timerId());
|
||||||
if ((timer->GetCycleCount() + c_CycleCompensation * 2) < refreshCompare) {
|
|
||||||
timer->SetCycleCompare(refreshCompare - c_CycleCompensation);
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// at least REFRESH_INTERVAL has elapsed
|
// finished all channels so wait for the refresh period to expire before starting over
|
||||||
timer->SetCycleCompare(timer->GetCycleCount() + c_CycleCompensation * 2);
|
// allow a few ticks to ensure the next match is not missed
|
||||||
|
uint32_t refreshCompare = timer->usToTicks(REFRESH_INTERVAL);
|
||||||
|
if ((timer->GetCycleCount() + c_CycleCompensation * 2) < refreshCompare) {
|
||||||
|
timer->SetCycleCompare(refreshCompare - c_CycleCompensation);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// at least REFRESH_INTERVAL has elapsed
|
||||||
|
timer->SetCycleCompare(timer->GetCycleCount() + c_CycleCompensation * 2);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
timer->setEndOfCycle();
|
timer->setEndOfCycle();
|
||||||
@ -166,6 +189,10 @@ Servo::Servo()
|
|||||||
// set default _minUs and _maxUs incase write() is called before attach()
|
// set default _minUs and _maxUs incase write() is called before attach()
|
||||||
_minUs = MIN_PULSE_WIDTH;
|
_minUs = MIN_PULSE_WIDTH;
|
||||||
_maxUs = MAX_PULSE_WIDTH;
|
_maxUs = MAX_PULSE_WIDTH;
|
||||||
|
|
||||||
|
s_servos[_servoIndex].info.isActive = false;
|
||||||
|
s_servos[_servoIndex].info.isDetaching = false;
|
||||||
|
s_servos[_servoIndex].info.pin = INVALID_PIN;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
_servoIndex = INVALID_SERVO; // too many servos
|
_servoIndex = INVALID_SERVO; // too many servos
|
||||||
@ -182,9 +209,11 @@ uint8_t Servo::attach(int pin, int minUs, int maxUs)
|
|||||||
ServoTimerSequence timerId;
|
ServoTimerSequence timerId;
|
||||||
|
|
||||||
if (_servoIndex < MAX_SERVOS) {
|
if (_servoIndex < MAX_SERVOS) {
|
||||||
pinMode(pin, OUTPUT); // set servo pin to output
|
if (s_servos[_servoIndex].info.pin == INVALID_PIN) {
|
||||||
digitalWrite(pin, LOW);
|
pinMode(pin, OUTPUT); // set servo pin to output
|
||||||
s_servos[_servoIndex].info.pin = pin;
|
digitalWrite(pin, LOW);
|
||||||
|
s_servos[_servoIndex].info.pin = pin;
|
||||||
|
}
|
||||||
|
|
||||||
// keep the min and max within 200-3000 us, these are extreme
|
// keep the min and max within 200-3000 us, these are extreme
|
||||||
// ranges and should support extreme servos while maintaining
|
// ranges and should support extreme servos while maintaining
|
||||||
@ -197,6 +226,7 @@ uint8_t Servo::attach(int pin, int minUs, int maxUs)
|
|||||||
if (!isTimerActive(timerId)) {
|
if (!isTimerActive(timerId)) {
|
||||||
initISR(timerId);
|
initISR(timerId);
|
||||||
}
|
}
|
||||||
|
s_servos[_servoIndex].info.isDetaching = false;
|
||||||
s_servos[_servoIndex].info.isActive = true; // this must be set after the check for isTimerActive
|
s_servos[_servoIndex].info.isActive = true; // this must be set after the check for isTimerActive
|
||||||
}
|
}
|
||||||
return _servoIndex;
|
return _servoIndex;
|
||||||
@ -206,10 +236,8 @@ void Servo::detach()
|
|||||||
{
|
{
|
||||||
ServoTimerSequence timerId;
|
ServoTimerSequence timerId;
|
||||||
|
|
||||||
s_servos[_servoIndex].info.isActive = false;
|
if (s_servos[_servoIndex].info.isActive) {
|
||||||
timerId = SERVO_INDEX_TO_TIMER(_servoIndex);
|
s_servos[_servoIndex].info.isDetaching = true;
|
||||||
if (!isTimerActive(timerId)) {
|
|
||||||
finISR(timerId);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
18
platform.txt
18
platform.txt
@ -6,28 +6,34 @@
|
|||||||
# https://github.com/arduino/Arduino/wiki/Arduino-IDE-1.5---3rd-party-Hardware-specification
|
# https://github.com/arduino/Arduino/wiki/Arduino-IDE-1.5---3rd-party-Hardware-specification
|
||||||
|
|
||||||
name=ESP8266 Modules
|
name=ESP8266 Modules
|
||||||
version=1.6.4
|
version=2.0.0
|
||||||
|
|
||||||
runtime.tools.xtensa-lx106-elf-gcc.path={runtime.platform.path}/tools/xtensa-lx106-elf
|
runtime.tools.xtensa-lx106-elf-gcc.path={runtime.platform.path}/tools/xtensa-lx106-elf
|
||||||
runtime.tools.esptool.path={runtime.platform.path}/tools/esptool
|
runtime.tools.esptool.path={runtime.platform.path}/tools/esptool
|
||||||
|
|
||||||
|
compiler.warning_flags=-w
|
||||||
|
compiler.warning_flags.none=-w
|
||||||
|
compiler.warning_flags.default=
|
||||||
|
compiler.warning_flags.more=-Wall
|
||||||
|
compiler.warning_flags.all=-Wall -Wextra
|
||||||
|
|
||||||
compiler.path={runtime.tools.xtensa-lx106-elf-gcc.path}/bin/
|
compiler.path={runtime.tools.xtensa-lx106-elf-gcc.path}/bin/
|
||||||
compiler.sdk.path={runtime.platform.path}/tools/sdk
|
compiler.sdk.path={runtime.platform.path}/tools/sdk
|
||||||
compiler.cpreprocessor.flags=-D__ets__ -DICACHE_FLASH -U__STRICT_ANSI__ "-I{compiler.sdk.path}/include"
|
compiler.cpreprocessor.flags=-D__ets__ -DICACHE_FLASH -U__STRICT_ANSI__ "-I{compiler.sdk.path}/include"
|
||||||
|
|
||||||
compiler.c.cmd=xtensa-lx106-elf-gcc
|
compiler.c.cmd=xtensa-lx106-elf-gcc
|
||||||
compiler.c.flags=-c -Os -g -Wpointer-arith -Wno-implicit-function-declaration -Wl,-EL -fno-inline-functions -nostdlib -mlongcalls -mtext-section-literals -falign-functions=4 -MMD -std=gnu99 -ffunction-sections -fdata-sections
|
compiler.c.flags=-c {compiler.warning_flags} -Os -g -Wpointer-arith -Wno-implicit-function-declaration -Wl,-EL -fno-inline-functions -nostdlib -mlongcalls -mtext-section-literals -falign-functions=4 -MMD -std=gnu99 -ffunction-sections -fdata-sections
|
||||||
|
|
||||||
compiler.S.cmd=xtensa-lx106-elf-gcc
|
compiler.S.cmd=xtensa-lx106-elf-gcc
|
||||||
compiler.S.flags=-c -g -x assembler-with-cpp -MMD
|
compiler.S.flags=-c -g -x assembler-with-cpp -MMD -mlongcalls
|
||||||
|
|
||||||
compiler.c.elf.flags=-g -Os -nostdlib -Wl,--no-check-sections -u call_user_start -Wl,-static "-L{compiler.sdk.path}/lib" "-L{compiler.sdk.path}/ld" "-T{build.flash_ld}" -Wl,--gc-sections -Wl,-wrap,system_restart_local -Wl,-wrap,register_chipv6_phy
|
compiler.c.elf.flags=-g {compiler.warning_flags} -Os -nostdlib -Wl,--no-check-sections -u call_user_start -Wl,-static "-L{compiler.sdk.path}/lib" "-L{compiler.sdk.path}/ld" "-T{build.flash_ld}" -Wl,--gc-sections -Wl,-wrap,system_restart_local -Wl,-wrap,register_chipv6_phy
|
||||||
|
|
||||||
compiler.c.elf.cmd=xtensa-lx106-elf-gcc
|
compiler.c.elf.cmd=xtensa-lx106-elf-gcc
|
||||||
compiler.c.elf.libs=-lm -lgcc -lhal -lphy -lnet80211 -llwip -lwpa -lmain -lpp -lsmartconfig -lwps -lcrypto -laxtls
|
compiler.c.elf.libs=-lm -lgcc -lhal -lphy -lpp -lnet80211 -llwip -lwpa -lcrypto -lmain -lwps -laxtls -lsmartconfig -lmesh
|
||||||
|
|
||||||
compiler.cpp.cmd=xtensa-lx106-elf-g++
|
compiler.cpp.cmd=xtensa-lx106-elf-g++
|
||||||
compiler.cpp.flags=-c -Os -g -mlongcalls -mtext-section-literals -fno-exceptions -fno-rtti -falign-functions=4 -std=c++11 -MMD -ffunction-sections -fdata-sections
|
compiler.cpp.flags=-c {compiler.warning_flags} -Os -g -mlongcalls -mtext-section-literals -fno-exceptions -fno-rtti -falign-functions=4 -std=c++11 -MMD -ffunction-sections -fdata-sections
|
||||||
|
|
||||||
compiler.as.cmd=xtensa-lx106-elf-as
|
compiler.as.cmd=xtensa-lx106-elf-as
|
||||||
|
|
||||||
|
@ -1,3 +1,116 @@
|
|||||||
|
esp_iot_sdk_v1.5.0_15_11_27 Release Note
|
||||||
|
----------------------------------------
|
||||||
|
Resolved Issues (Bugs listed below apply to Bug Bounty Program):
|
||||||
|
1. Returned value of system_get_rst_info is wrong.
|
||||||
|
|
||||||
|
Optimization:
|
||||||
|
1. Optimize espconn_regist_recvcb for UDP transmission.
|
||||||
|
2. Print information will prompt errors if the input parameters of os_time_arm excess the upper limit.
|
||||||
|
3. Optimize memory management.
|
||||||
|
4. Optimize RF frequency offset.
|
||||||
|
5. Print information will prompt errors if the size of bin file is too large in OTA.
|
||||||
|
6. Optimize mDNS.
|
||||||
|
7. Revise UART output print error when powered on again after call system_uart_swap.
|
||||||
|
8. Revise errors during multiple UDP transmissions.
|
||||||
|
9. Revise the error when wifi_station_set_config_default is called and the same AP is set as before, while information cannot be stored in the Flash.
|
||||||
|
10. Optimize the error of packet loss during UDP transmission process under single station mode.
|
||||||
|
11. Add new function, WPA2 Enterprise is supported.
|
||||||
|
12. SmartConfig version is upgraded to V2.5.3.
|
||||||
|
13. Mesh version is upgraded to V0.2.3.
|
||||||
|
14. User application needs to add "-lcrypto" in LINKFLAGS_eagle.app.v6 of Makefile.
|
||||||
|
|
||||||
|
Added APIs:
|
||||||
|
1.espconn_abort: bread TCP connection compulsively.
|
||||||
|
2.espconn_secure_delete: delete the SSL server when ESP8266 runs as SSL server.
|
||||||
|
3.wifi_station_set_cert_key: set certificate and private key for WPA2 Enterprise.
|
||||||
|
4.wifi_station_clear_cert_key: release the resource of connecting to WPA2 Enterprise AP, and clear the status.
|
||||||
|
|
||||||
|
|
||||||
|
AT_v0.51 release note:
|
||||||
|
1.Revise the error of the first byte in AT command when UART RX interrupt handler is implemented.
|
||||||
|
2.Revise the malfunction of display when AT+CWLAP is invoked to scan a specific AP.
|
||||||
|
|
||||||
|
|
||||||
|
esp_iot_sdk_v1.4.0_15_09_18 Release Note
|
||||||
|
----------------------------------------
|
||||||
|
Resolved Issues(Bugs below are eligible for Bug Bounty Program):
|
||||||
|
1.Espconn may fail to download big chunk of data(FOTA).
|
||||||
|
2.Invalid TCP data sent issue.
|
||||||
|
3.Fatal exceptions occur when change WiFi mode in WiFi scan callback.
|
||||||
|
4.WiFi compatibility problem of special network card.
|
||||||
|
5.Deep sleep may appear high current under certain circumstances.
|
||||||
|
|
||||||
|
Optimization:
|
||||||
|
1. Add a new method to check memory leaks (API : system_show_malloc).
|
||||||
|
2. Add print information when exception happens.
|
||||||
|
3. Resolve the problem of os_timer_disarm.
|
||||||
|
4. Optimize DHCP server, add API to set up the lease time of DHCP server. More details are in the “Added APIs”.
|
||||||
|
5. Add event “EVENT_STAMODE_DHCP_TIMEOUT” for the DHCP timeout handling mechanism.
|
||||||
|
6. Optimize handling of the reception of data and ZWP message.
|
||||||
|
7. Add new APIs to support SSL bidirectional authentication. More details are in the “Added APIs”.
|
||||||
|
8. Add new APIs to set up SSL certificates and encryption keys. API espconn_secure_set_default_certificate and espconn_secure_set_default_private_key should be called to set SSL certificate and secure key, if ESP8266 runs as SSL server. More details are in the “Added APIs”.
|
||||||
|
9. Optimize the process of FOTA (firmware upgrade through WiFi.
|
||||||
|
10. Optimize mDNS, and resolve the problem that in certain case the ESP8266 softAP can not work in the sta+AP mode.
|
||||||
|
11. Release mesh as a lib in the esp_iot_sdk, and do not provide SDK of the mesh version any more.
|
||||||
|
12. Optimize mesh’s handling of UDP packets.
|
||||||
|
13. Optimize checking of the validity of the mesh API’s parameters.
|
||||||
|
14. Add an API to set up the largest hop of mesh. For detailed information, go to mesh instructions.
|
||||||
|
15. Optimize the process of powering up and booting to shorten booting time by 20 ms.
|
||||||
|
16. Optimize the function of automatic frequency offset calibration.
|
||||||
|
17. Optimize the function of sniffer.
|
||||||
|
18. Strengthen reliability of the checking of beacon timeout.
|
||||||
|
19.Optimize Wi-Fi event mechanism, and add event “ EVENT_SOFTAPMODE_PROBEREQRECVED”, and reason for a failed connection.
|
||||||
|
20. Optimize Wi-Fi callback function and strengthen reliability of the software.
|
||||||
|
21. Add the function of data transferring between stations in the soft-AP mode.
|
||||||
|
22. Update SmartConfig to the version of 2.5.1.
|
||||||
|
|
||||||
|
23.Update esp_init_data_default.bin. Please use the newest esp_init_data_default.bin when burning.
|
||||||
|
|
||||||
|
24.Modify the espconn pointer in the receive callback of UDP. Parameters remote_ip and remote_port in it are the remote IP and port set by espconn_create. If users want to obtain IP and ports of the current sender, please call espconn_get_connection_info to get relevant information.
|
||||||
|
|
||||||
|
|
||||||
|
Added APIs:
|
||||||
|
1.System API
|
||||||
|
system_show_malloc : for checking memory leak, to print the memory usage.
|
||||||
|
2.DHCP server lease time related APIs
|
||||||
|
wifi_softap_set_dhcps_lease_time:set ESP8266 softAP DHCP server lease time.
|
||||||
|
wifi_softap_get_dhcps_lease_time:check ESP8266 softAP DHCP server lease time.
|
||||||
|
wifi_softap_reset_dhcps_lease_time:reset ESP8266 softAP DHCP server lease time which is 120 minutes by default.
|
||||||
|
3.wifi_station_dhcpc_set_maxtry:set the maximum number that ESP8266 station DHCP client will try to reconnect to the AP.
|
||||||
|
4.Force sleep APIs
|
||||||
|
wifi_fpm_open:enable force sleep function.
|
||||||
|
wifi_fpm_close:disable force sleep function.
|
||||||
|
wifi_fpm_do_sleep:force ESP8266 enter sleep mode.
|
||||||
|
wifi_fpm_do_wakeup:wake ESP8266 up from force sleep.
|
||||||
|
wifi_fpm_set_sleep_type:set sleep type of force sleep function.
|
||||||
|
wifi_fpm_get_sleep_type:get sleep type of force sleep function.
|
||||||
|
5.Send packet freedom APIs (to send user-define 802.11 packets)
|
||||||
|
wifi_register_send_pkt_freedom_cb:register a callback for sending user-define 802.11 packets.
|
||||||
|
wifi_unregister_send_pkt_freedom_cb:unregister the callback for sending user-define 802.11 packets.
|
||||||
|
wifi_send_pkt_freedom:send user-define 802.11 packet.
|
||||||
|
6.RFID LOCP APIs
|
||||||
|
wifi_rfid_locp_recv_open:enable RFID LOCP to receive WDS packets.
|
||||||
|
wifi_rfid_locp_recv_close:disable RFID LOCP.
|
||||||
|
wifi_register_rfid_locp_recv_cb:register a callback of receiving WDS packets.
|
||||||
|
wifi_unregister_rfid_locp_recv_cb:unregister the callback of receiving WDS packets.
|
||||||
|
7.Rate Control APIs
|
||||||
|
wifi_set_user_fixed_rate:set the fixed rate and mask of sending data from ESP8266
|
||||||
|
wifi_get_user_fixed_rate:check the fixed rate and mask of ESP8266
|
||||||
|
wifi_set_user_sup_rate:set the rate range supported by ESP8266 to limit the rate of sending packets from other devices.
|
||||||
|
wifi_set_user_rate_limit:limit the rate of sending data from ESP8266.
|
||||||
|
wifi_set_user_limit_rate_mask:set the interfaces of ESP8266 whose rate of sending packets is limited by wifi_set_user_rate_limit.
|
||||||
|
wifi_get_user_limit_rate_mask:get the interfaces of ESP8266 whose rate of sending packets is limited by wifi_set_user_rate_limit.
|
||||||
|
8.Espconn APIs
|
||||||
|
espconn_sendto:send UDP data.
|
||||||
|
espconn_secure_cert_req_enable:enable certificates verification function when ESP8266 runs as SSL client.
|
||||||
|
espconn_secure_cert_req_disable:disable certificates verification function when ESP8266 runs as SSL client.
|
||||||
|
espconn_secure_set_default_certificate:set the certificate when ESP8266 runs as SSL server.
|
||||||
|
espconn_secure_set_default_private_key:set the encryption key when ESP8266 runs as SSL server.
|
||||||
|
9.SmartConfig API
|
||||||
|
smartconfig_set_type: set the protocol type of SmartConfig.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
esp_iot_sdk_v1.3.0_15_08_10_p1 Release Note
|
esp_iot_sdk_v1.3.0_15_08_10_p1 Release Note
|
||||||
----------------------------------------
|
----------------------------------------
|
||||||
|
|
||||||
|
143
tools/sdk/include/at_custom.h
Normal file
143
tools/sdk/include/at_custom.h
Normal file
@ -0,0 +1,143 @@
|
|||||||
|
|
||||||
|
/*
|
||||||
|
* custom_at.h
|
||||||
|
*
|
||||||
|
* This file is part of Espressif's AT+ command set program.
|
||||||
|
* Copyright (C) 2013 - 2016, Espressif Systems
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of version 3 of the GNU General Public License as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along
|
||||||
|
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef CUSTOM_AT_H_
|
||||||
|
#define CUSTOM_AT_H_
|
||||||
|
|
||||||
|
#include "c_types.h"
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
char *at_cmdName;
|
||||||
|
int8_t at_cmdLen;
|
||||||
|
void (*at_testCmd)(uint8_t id);
|
||||||
|
void (*at_queryCmd)(uint8_t id);
|
||||||
|
void (*at_setupCmd)(uint8_t id, char *pPara);
|
||||||
|
void (*at_exeCmd)(uint8_t id);
|
||||||
|
}at_funcationType;
|
||||||
|
|
||||||
|
typedef void (*at_custom_uart_rx_intr)(uint8* data,int32 len);
|
||||||
|
|
||||||
|
typedef void (*at_custom_response_func_type)(const char *str);
|
||||||
|
|
||||||
|
extern uint8 at_customLinkMax;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Response "OK" to uart.
|
||||||
|
* @param None
|
||||||
|
* @retval None
|
||||||
|
*/
|
||||||
|
void at_response_ok(void);
|
||||||
|
/**
|
||||||
|
* @brief Response "ERROR" to uart.
|
||||||
|
* @param None
|
||||||
|
* @retval None
|
||||||
|
*/
|
||||||
|
void at_response_error(void);
|
||||||
|
/**
|
||||||
|
* @brief Response string.
|
||||||
|
* It is equivalent to at_port_print,if not call at_register_response_func or call at_register_response_func(NULL);
|
||||||
|
* It will run custom response function,if call at_register_response_func and parameter is not NULL.
|
||||||
|
* @param string
|
||||||
|
* @retval None
|
||||||
|
*/
|
||||||
|
void at_response(const char *str);
|
||||||
|
/**
|
||||||
|
* @brief register custom response function.
|
||||||
|
* @param response_func: the function that will run when call at_response
|
||||||
|
* @retval None
|
||||||
|
*/
|
||||||
|
void at_register_response_func(at_custom_response_func_type response_func);
|
||||||
|
/**
|
||||||
|
* @brief Task of process command or txdata.
|
||||||
|
* @param custom_at_cmd_array: the array of at cmd that custom defined
|
||||||
|
* cmd_num : the num of at cmd that custom defined
|
||||||
|
* @retval None
|
||||||
|
*/
|
||||||
|
void at_cmd_array_regist(at_funcationType *custom_at_cmd_array,uint32 cmd_num);
|
||||||
|
/**
|
||||||
|
* @brief get digit form at cmd line.the maybe alter pSrc
|
||||||
|
* @param p_src: at cmd line string
|
||||||
|
* result:the buffer to be placed result
|
||||||
|
* err : err num
|
||||||
|
* @retval TRUE:
|
||||||
|
* FALSE:
|
||||||
|
*/
|
||||||
|
bool at_get_next_int_dec(char **p_src,int*result,int* err);
|
||||||
|
/**
|
||||||
|
* @brief get string form at cmd line.the maybe alter pSrc
|
||||||
|
* @param p_dest: the buffer to be placed result
|
||||||
|
* p_src: at cmd line string
|
||||||
|
* max_len :max len of string excepted to get
|
||||||
|
* @retval None
|
||||||
|
*/
|
||||||
|
int32 at_data_str_copy(char *p_dest, char **p_src, int32 max_len);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief initialize at module
|
||||||
|
* @param None
|
||||||
|
* @retval None
|
||||||
|
*/
|
||||||
|
void at_init(void);
|
||||||
|
/**
|
||||||
|
* @brief print string to at port
|
||||||
|
* @param string
|
||||||
|
* @retval None
|
||||||
|
*/
|
||||||
|
void at_port_print(const char *str);
|
||||||
|
/**
|
||||||
|
* @brief print custom information when AT+GMR
|
||||||
|
* @param string
|
||||||
|
* @retval None
|
||||||
|
*/
|
||||||
|
void at_set_custom_info(char* info);
|
||||||
|
/**
|
||||||
|
* @brief if current at command is processing,you can call at_enter_special_state,
|
||||||
|
* then if other comamnd coming,it will return busy.
|
||||||
|
* @param None
|
||||||
|
* @retval None
|
||||||
|
*/
|
||||||
|
void at_enter_special_state(void);
|
||||||
|
/**
|
||||||
|
* @brief
|
||||||
|
* @param None
|
||||||
|
* @retval None
|
||||||
|
*/
|
||||||
|
void at_leave_special_state(void);
|
||||||
|
/**
|
||||||
|
* @brief get at version
|
||||||
|
* @param None
|
||||||
|
* @retval at version
|
||||||
|
* bit24~31: at main version
|
||||||
|
* bit23~16: at sub version
|
||||||
|
* bit15~8 : at test version
|
||||||
|
* bit7~0 : customized version
|
||||||
|
*/
|
||||||
|
uint32 at_get_version(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief register custom uart rx interrupt function
|
||||||
|
* @param rx_func: custom uart rx interrupt function.
|
||||||
|
* If rx_func is non-void,when rx interrupt comming,it will call rx_func(data,len),
|
||||||
|
* data is the buffer of data,len is the length of data.Otherwise,it will run AT rx function.
|
||||||
|
* @retval None
|
||||||
|
*/
|
||||||
|
void at_register_uart_rx_intr(at_custom_uart_rx_intr rx_func);
|
||||||
|
#endif
|
@ -14,6 +14,7 @@ typedef void (* espconn_reconnect_callback)(void *arg, sint8 err);
|
|||||||
#define ESPCONN_TIMEOUT -3 /* Timeout. */
|
#define ESPCONN_TIMEOUT -3 /* Timeout. */
|
||||||
#define ESPCONN_RTE -4 /* Routing problem. */
|
#define ESPCONN_RTE -4 /* Routing problem. */
|
||||||
#define ESPCONN_INPROGRESS -5 /* Operation in progress */
|
#define ESPCONN_INPROGRESS -5 /* Operation in progress */
|
||||||
|
#define ESPCONN_MAXNUM -7 /* Total number exceeds the set maximum*/
|
||||||
|
|
||||||
#define ESPCONN_ABRT -8 /* Connection aborted. */
|
#define ESPCONN_ABRT -8 /* Connection aborted. */
|
||||||
#define ESPCONN_RST -9 /* Connection reset. */
|
#define ESPCONN_RST -9 /* Connection reset. */
|
||||||
@ -21,6 +22,7 @@ typedef void (* espconn_reconnect_callback)(void *arg, sint8 err);
|
|||||||
#define ESPCONN_CONN -11 /* Not connected. */
|
#define ESPCONN_CONN -11 /* Not connected. */
|
||||||
|
|
||||||
#define ESPCONN_ARG -12 /* Illegal argument. */
|
#define ESPCONN_ARG -12 /* Illegal argument. */
|
||||||
|
#define ESPCONN_IF -14 /* UDP send error */
|
||||||
#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 */
|
||||||
@ -289,6 +291,17 @@ sint8 espconn_send(struct espconn *espconn, uint8 *psent, uint16 length);
|
|||||||
|
|
||||||
sint8 espconn_sent(struct espconn *espconn, uint8 *psent, uint16 length);
|
sint8 espconn_sent(struct espconn *espconn, uint8 *psent, uint16 length);
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
* FunctionName : espconn_sendto
|
||||||
|
* Description : send data for UDP
|
||||||
|
* Parameters : espconn -- espconn to set for UDP
|
||||||
|
* psent -- data to send
|
||||||
|
* length -- length of data to send
|
||||||
|
* Returns : error
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
|
sint16 espconn_sendto(struct espconn *espconn, uint8 *psent, uint16 length);
|
||||||
|
|
||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
* FunctionName : espconn_regist_connectcb
|
* FunctionName : espconn_regist_connectcb
|
||||||
* Description : used to specify the function that should be called when
|
* Description : used to specify the function that should be called when
|
||||||
@ -419,6 +432,15 @@ typedef void (*dns_found_callback)(const char *name, ip_addr_t *ipaddr, void *ca
|
|||||||
|
|
||||||
err_t espconn_gethostbyname(struct espconn *pespconn, const char *hostname, ip_addr_t *addr, dns_found_callback found);
|
err_t espconn_gethostbyname(struct espconn *pespconn, const char *hostname, ip_addr_t *addr, dns_found_callback found);
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
* FunctionName : espconn_abort
|
||||||
|
* Description : Forcely abort with host
|
||||||
|
* Parameters : espconn -- the espconn used to connect with the host
|
||||||
|
* Returns : result
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
|
sint8 espconn_abort(struct espconn *espconn);
|
||||||
|
|
||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
* FunctionName : espconn_encry_connect
|
* FunctionName : espconn_encry_connect
|
||||||
* Description : The function given as connection
|
* Description : The function given as connection
|
||||||
@ -502,15 +524,69 @@ bool espconn_secure_ca_enable(uint8 level, uint8 flash_sector );
|
|||||||
|
|
||||||
bool espconn_secure_ca_disable(uint8 level);
|
bool espconn_secure_ca_disable(uint8 level);
|
||||||
|
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
* FunctionName : espconn_secure_cert_req_enable
|
||||||
|
* Description : enable the client certificate authenticate and set the flash sector
|
||||||
|
* as client or server
|
||||||
|
* Parameters : level -- set for client or server
|
||||||
|
* 1: client,2:server,3:client and server
|
||||||
|
* flash_sector -- flash sector for save certificate
|
||||||
|
* Returns : result true or false
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
|
bool espconn_secure_cert_req_enable(uint8 level, uint8 flash_sector );
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
* FunctionName : espconn_secure_ca_disable
|
||||||
|
* Description : disable the client certificate authenticate as client or server
|
||||||
|
* Parameters : level -- set for client or server
|
||||||
|
* 1: client,2:server,3:client and server
|
||||||
|
* Returns : result true or false
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
|
bool espconn_secure_cert_req_disable(uint8 level);
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
* FunctionName : espconn_secure_set_default_certificate
|
||||||
|
* Description : Load the certificates in memory depending on compile-time
|
||||||
|
* and user options.
|
||||||
|
* Parameters : certificate -- Load the certificate
|
||||||
|
* length -- Load the certificate length
|
||||||
|
* Returns : result true or false
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
|
bool espconn_secure_set_default_certificate(const uint8* certificate, uint16 length);
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
* FunctionName : espconn_secure_set_default_private_key
|
||||||
|
* Description : Load the key in memory depending on compile-time
|
||||||
|
* and user options.
|
||||||
|
* Parameters : private_key -- Load the key
|
||||||
|
* length -- Load the key length
|
||||||
|
* Returns : result true or false
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
|
bool espconn_secure_set_default_private_key(const uint8* private_key, uint16 length);
|
||||||
|
|
||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
* FunctionName : espconn_secure_accept
|
* FunctionName : espconn_secure_accept
|
||||||
* Description : The function given as the listen
|
* Description : The function given as the listen
|
||||||
* Parameters : espconn -- the espconn used to listen the connection
|
* Parameters : espconn -- the espconn used to listen the connection
|
||||||
* Returns : none
|
* Returns : result
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
|
|
||||||
sint8 espconn_secure_accept(struct espconn *espconn);
|
sint8 espconn_secure_accept(struct espconn *espconn);
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
* FunctionName : espconn_secure_accepts
|
||||||
|
* Description : delete the secure server host
|
||||||
|
* Parameters : espconn -- the espconn used to listen the connection
|
||||||
|
* Returns : result
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
|
sint8 espconn_secure_delete(struct espconn *espconn);
|
||||||
|
|
||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
* FunctionName : espconn_igmp_join
|
* FunctionName : espconn_igmp_join
|
||||||
* Description : join a multicast group
|
* Description : join a multicast group
|
||||||
|
@ -145,11 +145,9 @@ inline uint32_t ETS_INTR_PENDING(void)
|
|||||||
ETS_INTR_DISABLE(ETS_SLC_INUM)
|
ETS_INTR_DISABLE(ETS_SLC_INUM)
|
||||||
|
|
||||||
|
|
||||||
void *pvPortMalloc(size_t xWantedSize) __attribute__((malloc, alloc_size(1)));
|
void *pvPortMalloc(size_t xWantedSize, const char* file, int line) __attribute__((malloc, alloc_size(1)));
|
||||||
void *pvPortRealloc(void* ptr, size_t xWantedSize) __attribute__((alloc_size(2)));
|
void *pvPortRealloc(void* ptr, size_t xWantedSize, const char* file, int line) __attribute__((alloc_size(2)));
|
||||||
void pvPortFree(void *ptr);
|
void vPortFree(void *ptr, const char* file, int line);
|
||||||
void *vPortMalloc(size_t xWantedSize) __attribute__((malloc, alloc_size(1)));
|
|
||||||
void vPortFree(void *ptr);
|
|
||||||
void *ets_memcpy(void *dest, const void *src, size_t n);
|
void *ets_memcpy(void *dest, const void *src, size_t n);
|
||||||
void *ets_memset(void *s, int c, size_t n);
|
void *ets_memset(void *s, int c, size_t n);
|
||||||
void ets_timer_arm_new(ETSTimer *a, int b, int c, int isMstimer);
|
void ets_timer_arm_new(ETSTimer *a, int b, int c, int isMstimer);
|
||||||
@ -174,5 +172,8 @@ void ets_intr_lock();
|
|||||||
void ets_intr_unlock();
|
void ets_intr_unlock();
|
||||||
int ets_vsnprintf(char * s, size_t n, const char * format, va_list arg) __attribute__ ((format (printf, 3, 0)));
|
int ets_vsnprintf(char * s, size_t n, const char * format, va_list arg) __attribute__ ((format (printf, 3, 0)));
|
||||||
int ets_vprintf(const char * format, va_list arg) __attribute__ ((format (printf, 1, 0)));
|
int ets_vprintf(const char * format, va_list arg) __attribute__ ((format (printf, 1, 0)));
|
||||||
|
bool ets_task(ETSTask task, uint8 prio, ETSEvent *queue, uint8 qlen);
|
||||||
|
bool ets_post(uint8 prio, ETSSignal sig, ETSParam par);
|
||||||
|
|
||||||
|
|
||||||
#endif /* _ETS_SYS_H */
|
#endif /* _ETS_SYS_H */
|
||||||
|
@ -1,13 +1,57 @@
|
|||||||
#ifndef __MEM_H__
|
#ifndef __MEM_H__
|
||||||
#define __MEM_H__
|
#define __MEM_H__
|
||||||
|
|
||||||
//void *pvPortMalloc( size_t xWantedSize );
|
/* Note: check_memleak_debug_enable is a weak function inside SDK.
|
||||||
//void vPortFree( void *pv );
|
* please copy following codes to user_main.c.
|
||||||
//void *pvPortZalloc(size_t size);
|
#include "mem.h"
|
||||||
|
|
||||||
#define os_malloc pvPortMalloc
|
bool ICACHE_FLASH_ATTR check_memleak_debug_enable(void)
|
||||||
#define os_free vPortFree
|
{
|
||||||
#define os_zalloc pvPortZalloc
|
return MEMLEAK_DEBUG_ENABLE;
|
||||||
#define os_realloc pvPortRealloc
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef MEMLEAK_DEBUG
|
||||||
|
#define MEMLEAK_DEBUG_ENABLE 0
|
||||||
|
#define os_free(s) vPortFree(s, "", 0)
|
||||||
|
#define os_malloc(s) pvPortMalloc(s, "", 0)
|
||||||
|
#define os_calloc(s) pvPortCalloc(s, "", 0);
|
||||||
|
#define os_realloc(p, s) pvPortRealloc(p, s, "", 0)
|
||||||
|
#define os_zalloc(s) pvPortZalloc(s, "", 0)
|
||||||
|
#else
|
||||||
|
#define MEMLEAK_DEBUG_ENABLE 1
|
||||||
|
|
||||||
|
#define os_free(s) \
|
||||||
|
do{\
|
||||||
|
static const char mem_debug_file[] ICACHE_RODATA_ATTR STORE_ATTR = __FILE__; \
|
||||||
|
vPortFree(s, mem_debug_file, __LINE__);\
|
||||||
|
}while(0)
|
||||||
|
|
||||||
|
#define os_malloc(s) \
|
||||||
|
({ \
|
||||||
|
static const char mem_debug_file[] ICACHE_RODATA_ATTR STORE_ATTR = __FILE__; \
|
||||||
|
pvPortMalloc(s, mem_debug_file, __LINE__); \
|
||||||
|
})
|
||||||
|
|
||||||
|
#define os_calloc(s) \
|
||||||
|
({ \
|
||||||
|
static const char mem_debug_file[] ICACHE_RODATA_ATTR STORE_ATTR = __FILE__; \
|
||||||
|
pvPortCalloc(s, mem_debug_file, __LINE__); \
|
||||||
|
})
|
||||||
|
|
||||||
|
#define os_realloc(p, s) \
|
||||||
|
({ \
|
||||||
|
static const char mem_debug_file[] ICACHE_RODATA_ATTR STORE_ATTR = __FILE__; \
|
||||||
|
pvPortRealloc(p, s, mem_debug_file, __LINE__); \
|
||||||
|
})
|
||||||
|
|
||||||
|
#define os_zalloc(s) \
|
||||||
|
({ \
|
||||||
|
static const char mem_debug_file[] ICACHE_RODATA_ATTR STORE_ATTR = __FILE__; \
|
||||||
|
pvPortZalloc(s, mem_debug_file, __LINE__); \
|
||||||
|
})
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
341
tools/sdk/include/mesh.h
Normal file
341
tools/sdk/include/mesh.h
Normal file
@ -0,0 +1,341 @@
|
|||||||
|
/*
|
||||||
|
* ESPRSSIF MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2015 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
|
||||||
|
*
|
||||||
|
* Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case,
|
||||||
|
* it is free of charge, to any person obtaining a copy of this software and associated
|
||||||
|
* documentation files (the "Software"), to deal in the Software without restriction, including
|
||||||
|
* without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
* and/or sell copies of the Software, and to permit persons to whom the Software is furnished
|
||||||
|
* to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all copies or
|
||||||
|
* substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||||
|
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||||
|
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||||
|
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#ifndef __LWIP_API_MESH_H__
|
||||||
|
#define __LWIP_API_MESH_H__
|
||||||
|
|
||||||
|
#include "ip_addr.h"
|
||||||
|
#include "user_interface.h"
|
||||||
|
#include "espconn.h"
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define ESP_MESH_GROUP_ID_LEN (6)
|
||||||
|
|
||||||
|
typedef void (* espconn_mesh_callback)();
|
||||||
|
typedef void (* espconn_mesh_scan_callback)(void *arg, int8_t status);
|
||||||
|
|
||||||
|
enum mesh_type {
|
||||||
|
MESH_CLOSE = 0,
|
||||||
|
MESH_LOCAL,
|
||||||
|
MESH_ONLINE,
|
||||||
|
MESH_NONE = 0xFF
|
||||||
|
};
|
||||||
|
/** \defgroup Mesh_APIs Mesh APIs
|
||||||
|
* @brief Mesh APIs
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** @addtogroup Mesh_APIs
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
enum mesh_status {
|
||||||
|
MESH_DISABLE = 0,
|
||||||
|
MESH_WIFI_CONN,
|
||||||
|
MESH_NET_CONN,
|
||||||
|
MESH_LOCAL_AVAIL,
|
||||||
|
MESH_ONLINE_AVAIL
|
||||||
|
};
|
||||||
|
|
||||||
|
enum mesh_node_type {
|
||||||
|
MESH_NODE_PARENT = 0,
|
||||||
|
MESH_NODE_CHILD,
|
||||||
|
MESH_NODE_ALL
|
||||||
|
};
|
||||||
|
|
||||||
|
struct mesh_scan_para_type {
|
||||||
|
espconn_mesh_scan_callback usr_scan_cb; // scan done callback
|
||||||
|
uint8_t grp_id[ESP_MESH_GROUP_ID_LEN]; // group id
|
||||||
|
bool grp_set; // group set
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Check whether the IP address is mesh local IP address or not.
|
||||||
|
*
|
||||||
|
* @attention 1. The range of mesh local IP address is 2.255.255.* ~ max_hop.255.255.*.
|
||||||
|
* @attention 2. IP pointer should not be NULL. If the IP pointer is NULL, it will return false.
|
||||||
|
*
|
||||||
|
* @param struct ip_addr *ip : IP address
|
||||||
|
*
|
||||||
|
* @return true : the IP address is mesh local IP address
|
||||||
|
* @return false : the IP address is not mesh local IP address
|
||||||
|
*/
|
||||||
|
bool espconn_mesh_local_addr(struct ip_addr *ip);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the information of router used by mesh network.
|
||||||
|
*
|
||||||
|
* @attention 1. The function should be called after mesh_enable_done
|
||||||
|
*
|
||||||
|
* @param struct station_config *router: router inforamtion
|
||||||
|
*
|
||||||
|
* @return true : succeed
|
||||||
|
* @return false : fail
|
||||||
|
*/
|
||||||
|
bool espconn_mesh_get_router(struct station_config *router);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set the information of router used by mesh network.
|
||||||
|
*
|
||||||
|
* @attention The function must be called before espconn_mesh_enable.
|
||||||
|
*
|
||||||
|
* @param struct station_config *router: router information.
|
||||||
|
* user should initialize the ssid and password.
|
||||||
|
*
|
||||||
|
* @return true : succeed
|
||||||
|
* @return false : fail
|
||||||
|
*/
|
||||||
|
bool espconn_mesh_set_router(struct station_config *router);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set server setup by user.
|
||||||
|
*
|
||||||
|
* @attention If users wants to use themself server, they use the function.
|
||||||
|
* but the function must be called before espconn_mesh_enable.
|
||||||
|
* at the same time, users need to implement the server.
|
||||||
|
*
|
||||||
|
* @param struct ip_addr *ip : ip address of server.
|
||||||
|
* @param uint16_t port : port used by server.
|
||||||
|
*
|
||||||
|
* @return true : succeed
|
||||||
|
* @return false : fail
|
||||||
|
*/
|
||||||
|
bool espconn_mesh_server_init(struct ip_addr *ip, uint16_t port);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the information of mesh node.
|
||||||
|
*
|
||||||
|
* @param enum mesh_node_type typ : mesh node type.
|
||||||
|
* @param uint8_t **info : the information will be saved in *info.
|
||||||
|
* @param uint8_t *count : the node count in *info.
|
||||||
|
*
|
||||||
|
* @return true : succeed
|
||||||
|
* @return false : fail
|
||||||
|
*/
|
||||||
|
bool espconn_mesh_get_node_info(enum mesh_node_type type,
|
||||||
|
uint8_t **info, uint8_t *count);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set WiFi cryption algrithm and password for mesh node.
|
||||||
|
*
|
||||||
|
* @attention The function must be called before espconn_mesh_enable.
|
||||||
|
*
|
||||||
|
* @param AUTH_MODE mode : cryption algrithm (WPA/WAP2/WPA_WPA2).
|
||||||
|
* @param uint8_t *passwd : password of WiFi.
|
||||||
|
* @param uint8_t passwd_len : length of password (8 <= passwd_len <= 64).
|
||||||
|
*
|
||||||
|
* @return true : succeed
|
||||||
|
* @return false : fail
|
||||||
|
*/
|
||||||
|
bool espconn_mesh_encrypt_init(AUTH_MODE mode, uint8_t *passwd, uint8_t passwd_len);
|
||||||
|
/**
|
||||||
|
* @brief Set prefix of SSID for mesh node.
|
||||||
|
*
|
||||||
|
* @attention The function must be called before espconn_mesh_enable.
|
||||||
|
*
|
||||||
|
* @param uint8_t *prefix : prefix of SSID.
|
||||||
|
* @param uint8_t prefix_len : length of prefix (0 < passwd_len <= 22).
|
||||||
|
*
|
||||||
|
* @return true : succeed
|
||||||
|
* @return false : fail
|
||||||
|
*/
|
||||||
|
bool espconn_mesh_set_ssid_prefix(uint8_t *prefix, uint8_t prefix_len);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set max hop for mesh network.
|
||||||
|
*
|
||||||
|
* @attention The function must be called before espconn_mesh_enable.
|
||||||
|
*
|
||||||
|
* @param uint8_t max_hops : max hop of mesh network (1 <= max_hops < 10, 4 is recommended).
|
||||||
|
*
|
||||||
|
* @return true : succeed
|
||||||
|
* @return false : fail
|
||||||
|
*/
|
||||||
|
bool espconn_mesh_set_max_hops(uint8_t max_hops);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set group ID of mesh node.
|
||||||
|
*
|
||||||
|
* @attention The function must be called before espconn_mesh_enable.
|
||||||
|
*
|
||||||
|
* @param uint8_t *grp_id : group ID.
|
||||||
|
* @param uint16_t gid_len: length of group ID, now gid_len = 6.
|
||||||
|
*
|
||||||
|
* @return true : succeed
|
||||||
|
* @return false : fail
|
||||||
|
*/
|
||||||
|
bool espconn_mesh_group_id_init(uint8_t *grp_id, uint16_t gid_len);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set the curent device type.
|
||||||
|
*
|
||||||
|
* @param uint8_t dev_type : device type of mesh node
|
||||||
|
*
|
||||||
|
* @return true : succeed
|
||||||
|
* @return false : fail
|
||||||
|
*/
|
||||||
|
bool espconn_mesh_set_dev_type(uint8_t dev_type);
|
||||||
|
/**
|
||||||
|
* @brief Get the curent device type.
|
||||||
|
*
|
||||||
|
* @param none
|
||||||
|
*
|
||||||
|
* @return device type
|
||||||
|
*/
|
||||||
|
uint8_t espconn_mesh_get_dev_type();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Try to establish mesh connection to server.
|
||||||
|
*
|
||||||
|
* @attention If espconn_mesh_connect fail, returns non-0 value, there is no connection, so it
|
||||||
|
* won't enter any espconn callback.
|
||||||
|
*
|
||||||
|
* @param struct espconn *usr_esp : the network connection structure, the usr_esp to
|
||||||
|
* listen to the connection
|
||||||
|
*
|
||||||
|
* @return 0 : succeed
|
||||||
|
* @return Non-0 : error code
|
||||||
|
* - ESPCONN_RTE - Routing Problem
|
||||||
|
* - ESPCONN_MEM - Out of memory
|
||||||
|
* - ESPCONN_ISCONN - Already connected
|
||||||
|
* - ESPCONN_ARG - Illegal argument, can't find the corresponding connection
|
||||||
|
* according to structure espconn
|
||||||
|
*/
|
||||||
|
int8_t espconn_mesh_connect(struct espconn *usr_esp);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Disconnect a mesh connection.
|
||||||
|
*
|
||||||
|
* @attention Do not call this API in any espconn callback. If needed, please use system
|
||||||
|
* task to trigger espconn_mesh_disconnect.
|
||||||
|
*
|
||||||
|
* @param struct espconn *usr_esp : the network connection structure
|
||||||
|
*
|
||||||
|
* @return 0 : succeed
|
||||||
|
* @return Non-0 : error code
|
||||||
|
* - ESPCONN_ARG - illegal argument, can't find the corresponding TCP connection
|
||||||
|
* according to structure espconn
|
||||||
|
*/
|
||||||
|
|
||||||
|
int8_t espconn_mesh_disconnect(struct espconn *usr_esp);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get current mesh status.
|
||||||
|
*
|
||||||
|
* @param null
|
||||||
|
*
|
||||||
|
* @return the current mesh status, please refer to enum mesh_status.
|
||||||
|
*/
|
||||||
|
int8_t espconn_mesh_get_status();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Send data through mesh network.
|
||||||
|
*
|
||||||
|
* @attention Please call espconn_mesh_sent after espconn_sent_callback of the pre-packet.
|
||||||
|
*
|
||||||
|
* @param struct espconn *usr_esp : the network connection structure
|
||||||
|
* @param uint8 *pdata : pointer of data
|
||||||
|
* @param uint16 len : data length
|
||||||
|
*
|
||||||
|
* @return 0 : succeed
|
||||||
|
* @return Non-0 : error code
|
||||||
|
* - ESPCONN_MEM - out of memory
|
||||||
|
* - ESPCONN_ARG - illegal argument, can't find the corresponding network transmission
|
||||||
|
* according to structure espconn
|
||||||
|
* - ESPCONN_MAXNUM - buffer of sending data is full
|
||||||
|
* - ESPCONN_IF - send UDP data fail
|
||||||
|
*/
|
||||||
|
int8_t espconn_mesh_sent(struct espconn *usr_esp, uint8 *pdata, uint16 len);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get max hop of mesh network.
|
||||||
|
*
|
||||||
|
* @param null.
|
||||||
|
*
|
||||||
|
* @return the current max hop of mesh
|
||||||
|
*/
|
||||||
|
uint8_t espconn_mesh_get_max_hops();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief To enable mesh network.
|
||||||
|
*
|
||||||
|
* @attention 1. the function should be called in user_init.
|
||||||
|
* @attention 2. if mesh node can not scan the mesh AP, it will be isolate node without trigger enable_cb.
|
||||||
|
* user can use espconn_mesh_get_status to get current status of node.
|
||||||
|
* @attention 3. if user try to enable online mesh, but node fails to establish mesh connection
|
||||||
|
* the node will work with local mesh.
|
||||||
|
*
|
||||||
|
* @param espconn_mesh_callback enable_cb : callback function of mesh-enable
|
||||||
|
* @param enum mesh_type type : type of mesh, local or online.
|
||||||
|
*
|
||||||
|
* @return null
|
||||||
|
*/
|
||||||
|
void espconn_mesh_enable(espconn_mesh_callback enable_cb, enum mesh_type type);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief To disable mesh network.
|
||||||
|
*
|
||||||
|
* @attention When mesh network is disabed, the system will trigger disable_cb.
|
||||||
|
*
|
||||||
|
* @param espconn_mesh_callback disable_cb : callback function of mesh-disable
|
||||||
|
* @param enum mesh_type type : type of mesh, local or online.
|
||||||
|
*
|
||||||
|
* @return null
|
||||||
|
*/
|
||||||
|
void espconn_mesh_disable(espconn_mesh_callback disable_cb);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief To print version of mesh.
|
||||||
|
*
|
||||||
|
* @param null
|
||||||
|
*
|
||||||
|
* @return null
|
||||||
|
*/
|
||||||
|
void espconn_mesh_print_ver();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief To get AP around node.
|
||||||
|
*
|
||||||
|
* @attention User can get normal AP or mesh AP using the function.
|
||||||
|
* If user plans to get normal AP, he/she needs to clear grp_set flag in para.
|
||||||
|
* If user plans to get mesh AP, he/she needs to set grp_set and grp_id;
|
||||||
|
*
|
||||||
|
* @param struct mesh_scan_para_type *para : callback function of mesh-disable
|
||||||
|
*
|
||||||
|
* @return null
|
||||||
|
*/
|
||||||
|
void espconn_mesh_scan(struct mesh_scan_para_type *para);
|
||||||
|
/**
|
||||||
|
* @}
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
@ -17,6 +17,7 @@ typedef enum {
|
|||||||
typedef enum {
|
typedef enum {
|
||||||
SC_TYPE_ESPTOUCH = 0,
|
SC_TYPE_ESPTOUCH = 0,
|
||||||
SC_TYPE_AIRKISS,
|
SC_TYPE_AIRKISS,
|
||||||
|
SC_TYPE_ESPTOUCH_AIRKISS,
|
||||||
} sc_type;
|
} sc_type;
|
||||||
|
|
||||||
typedef void (*sc_callback_t)(sc_status status, void *pdata);
|
typedef void (*sc_callback_t)(sc_status status, void *pdata);
|
||||||
@ -25,5 +26,6 @@ const char *smartconfig_get_version(void);
|
|||||||
bool smartconfig_start(sc_callback_t cb, ...);
|
bool smartconfig_start(sc_callback_t cb, ...);
|
||||||
bool smartconfig_stop(void);
|
bool smartconfig_stop(void);
|
||||||
bool esptouch_set_timeout(uint8 time_s); //15s~255s, offset:45s
|
bool esptouch_set_timeout(uint8 time_s); //15s~255s, offset:45s
|
||||||
|
bool smartconfig_set_type(sc_type type);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -132,6 +132,7 @@ enum flash_size_map system_get_flash_size_map(void);
|
|||||||
void system_phy_set_max_tpw(uint8 max_tpw);
|
void system_phy_set_max_tpw(uint8 max_tpw);
|
||||||
void system_phy_set_tpw_via_vdd33(uint16 vdd33);
|
void system_phy_set_tpw_via_vdd33(uint16 vdd33);
|
||||||
void system_phy_set_rfoption(uint8 option);
|
void system_phy_set_rfoption(uint8 option);
|
||||||
|
void system_phy_set_powerup_option(uint8 option);
|
||||||
|
|
||||||
bool system_param_save_with_protect(uint16 start_sec, void *param, uint16 len);
|
bool system_param_save_with_protect(uint16 start_sec, void *param, uint16 len);
|
||||||
bool system_param_load(uint16 start_sec, uint16 offset, void *param, uint16 len);
|
bool system_param_load(uint16 start_sec, uint16 offset, void *param, uint16 len);
|
||||||
@ -140,6 +141,8 @@ void system_soft_wdt_stop(void);
|
|||||||
void system_soft_wdt_restart(void);
|
void system_soft_wdt_restart(void);
|
||||||
void system_soft_wdt_feed(void);
|
void system_soft_wdt_feed(void);
|
||||||
|
|
||||||
|
void system_show_malloc(void);
|
||||||
|
|
||||||
#define NULL_MODE 0x00
|
#define NULL_MODE 0x00
|
||||||
#define STATION_MODE 0x01
|
#define STATION_MODE 0x01
|
||||||
#define SOFTAP_MODE 0x02
|
#define SOFTAP_MODE 0x02
|
||||||
@ -166,11 +169,14 @@ struct bss_info {
|
|||||||
|
|
||||||
uint8 bssid[6];
|
uint8 bssid[6];
|
||||||
uint8 ssid[32];
|
uint8 ssid[32];
|
||||||
|
uint8 ssid_len;
|
||||||
uint8 channel;
|
uint8 channel;
|
||||||
sint8 rssi;
|
sint8 rssi;
|
||||||
AUTH_MODE authmode;
|
AUTH_MODE authmode;
|
||||||
uint8 is_hidden;
|
uint8 is_hidden;
|
||||||
sint16 freq_offset;
|
sint16 freq_offset;
|
||||||
|
sint16 freqcal_val;
|
||||||
|
uint8 *esp_mesh_ie;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct _scaninfo {
|
typedef struct _scaninfo {
|
||||||
@ -240,10 +246,16 @@ uint8 wifi_station_get_ap_info(struct station_config config[]);
|
|||||||
bool wifi_station_dhcpc_start(void);
|
bool wifi_station_dhcpc_start(void);
|
||||||
bool wifi_station_dhcpc_stop(void);
|
bool wifi_station_dhcpc_stop(void);
|
||||||
enum dhcp_status wifi_station_dhcpc_status(void);
|
enum dhcp_status wifi_station_dhcpc_status(void);
|
||||||
|
bool wifi_station_dhcpc_set_maxtry(uint8 num);
|
||||||
|
|
||||||
char* wifi_station_get_hostname(void);
|
char* wifi_station_get_hostname(void);
|
||||||
bool wifi_station_set_hostname(char *name);
|
bool wifi_station_set_hostname(char *name);
|
||||||
|
|
||||||
|
int wifi_station_set_cert_key(uint8 *client_cert, int client_cert_len,
|
||||||
|
uint8 *private_key, int private_key_len,
|
||||||
|
uint8 *private_key_passwd, int private_key_passwd_len);
|
||||||
|
void wifi_station_clear_cert_key(void);
|
||||||
|
|
||||||
struct softap_config {
|
struct softap_config {
|
||||||
uint8 ssid[32];
|
uint8 ssid[32];
|
||||||
uint8 password[64];
|
uint8 password[64];
|
||||||
@ -268,6 +280,7 @@ struct station_info {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct dhcps_lease {
|
struct dhcps_lease {
|
||||||
|
bool enable;
|
||||||
struct ip_addr start_ip;
|
struct ip_addr start_ip;
|
||||||
struct ip_addr end_ip;
|
struct ip_addr end_ip;
|
||||||
};
|
};
|
||||||
@ -284,8 +297,13 @@ 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);
|
bool wifi_softap_get_dhcps_lease(struct dhcps_lease *please);
|
||||||
|
uint32 wifi_softap_get_dhcps_lease_time(void);
|
||||||
|
bool wifi_softap_set_dhcps_lease_time(uint32 minute);
|
||||||
|
bool wifi_softap_reset_dhcps_lease_time(void);
|
||||||
|
|
||||||
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);
|
||||||
|
|
||||||
@ -333,13 +351,22 @@ enum sleep_type {
|
|||||||
bool wifi_set_sleep_type(enum sleep_type type);
|
bool wifi_set_sleep_type(enum sleep_type type);
|
||||||
enum sleep_type wifi_get_sleep_type(void);
|
enum sleep_type wifi_get_sleep_type(void);
|
||||||
|
|
||||||
|
void wifi_fpm_open(void);
|
||||||
|
void wifi_fpm_close(void);
|
||||||
|
void wifi_fpm_do_wakeup(void);
|
||||||
|
sint8 wifi_fpm_do_sleep(uint32 sleep_time_in_us);
|
||||||
|
void wifi_fpm_set_sleep_type(enum sleep_type type);
|
||||||
|
enum sleep_type wifi_fpm_get_sleep_type(void);
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
EVENT_STAMODE_CONNECTED = 0,
|
EVENT_STAMODE_CONNECTED = 0,
|
||||||
EVENT_STAMODE_DISCONNECTED,
|
EVENT_STAMODE_DISCONNECTED,
|
||||||
EVENT_STAMODE_AUTHMODE_CHANGE,
|
EVENT_STAMODE_AUTHMODE_CHANGE,
|
||||||
EVENT_STAMODE_GOT_IP,
|
EVENT_STAMODE_GOT_IP,
|
||||||
|
EVENT_STAMODE_DHCP_TIMEOUT,
|
||||||
EVENT_SOFTAPMODE_STACONNECTED,
|
EVENT_SOFTAPMODE_STACONNECTED,
|
||||||
EVENT_SOFTAPMODE_STADISCONNECTED,
|
EVENT_SOFTAPMODE_STADISCONNECTED,
|
||||||
|
EVENT_SOFTAPMODE_PROBEREQRECVED,
|
||||||
EVENT_MAX
|
EVENT_MAX
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -370,6 +397,9 @@ enum {
|
|||||||
|
|
||||||
REASON_BEACON_TIMEOUT = 200,
|
REASON_BEACON_TIMEOUT = 200,
|
||||||
REASON_NO_AP_FOUND = 201,
|
REASON_NO_AP_FOUND = 201,
|
||||||
|
REASON_AUTH_FAIL = 202,
|
||||||
|
REASON_ASSOC_FAIL = 203,
|
||||||
|
REASON_HANDSHAKE_TIMEOUT = 204,
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@ -407,6 +437,11 @@ typedef struct {
|
|||||||
uint8 aid;
|
uint8 aid;
|
||||||
} Event_SoftAPMode_StaDisconnected_t;
|
} Event_SoftAPMode_StaDisconnected_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int rssi;
|
||||||
|
uint8 mac[6];
|
||||||
|
} Event_SoftAPMode_ProbeReqRecved_t;
|
||||||
|
|
||||||
typedef union {
|
typedef union {
|
||||||
Event_StaMode_Connected_t connected;
|
Event_StaMode_Connected_t connected;
|
||||||
Event_StaMode_Disconnected_t disconnected;
|
Event_StaMode_Disconnected_t disconnected;
|
||||||
@ -414,6 +449,7 @@ typedef union {
|
|||||||
Event_StaMode_Got_IP_t got_ip;
|
Event_StaMode_Got_IP_t got_ip;
|
||||||
Event_SoftAPMode_StaConnected_t sta_connected;
|
Event_SoftAPMode_StaConnected_t sta_connected;
|
||||||
Event_SoftAPMode_StaDisconnected_t sta_disconnected;
|
Event_SoftAPMode_StaDisconnected_t sta_disconnected;
|
||||||
|
Event_SoftAPMode_ProbeReqRecved_t ap_probereqrecved;
|
||||||
} Event_Info_u;
|
} Event_Info_u;
|
||||||
|
|
||||||
typedef struct _esp_event {
|
typedef struct _esp_event {
|
||||||
@ -430,7 +466,7 @@ typedef enum wps_type {
|
|||||||
WPS_TYPE_PBC,
|
WPS_TYPE_PBC,
|
||||||
WPS_TYPE_PIN,
|
WPS_TYPE_PIN,
|
||||||
WPS_TYPE_DISPLAY,
|
WPS_TYPE_DISPLAY,
|
||||||
WPS_TYPE_MAX
|
WPS_TYPE_MAX,
|
||||||
} WPS_TYPE_t;
|
} WPS_TYPE_t;
|
||||||
|
|
||||||
enum wps_cb_status {
|
enum wps_cb_status {
|
||||||
@ -447,4 +483,119 @@ bool wifi_wps_start(void);
|
|||||||
typedef void (*wps_st_cb_t)(int 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);
|
||||||
|
|
||||||
|
typedef void (*freedom_outside_cb_t)(uint8 status);
|
||||||
|
int wifi_register_send_pkt_freedom_cb(freedom_outside_cb_t cb);
|
||||||
|
void wifi_unregister_send_pkt_freedom_cb(void);
|
||||||
|
int wifi_send_pkt_freedom(uint8 *buf, int len, bool sys_seq);
|
||||||
|
|
||||||
|
int wifi_rfid_locp_recv_open(void);
|
||||||
|
void wifi_rfid_locp_recv_close(void);
|
||||||
|
|
||||||
|
typedef void (*rfid_locp_cb_t)(uint8 *frm, int len, int rssi);
|
||||||
|
int wifi_register_rfid_locp_recv_cb(rfid_locp_cb_t cb);
|
||||||
|
void wifi_unregister_rfid_locp_recv_cb(void);
|
||||||
|
|
||||||
|
enum FIXED_RATE {
|
||||||
|
PHY_RATE_48 = 0x8,
|
||||||
|
PHY_RATE_24 = 0x9,
|
||||||
|
PHY_RATE_12 = 0xA,
|
||||||
|
PHY_RATE_6 = 0xB,
|
||||||
|
PHY_RATE_54 = 0xC,
|
||||||
|
PHY_RATE_36 = 0xD,
|
||||||
|
PHY_RATE_18 = 0xE,
|
||||||
|
PHY_RATE_9 = 0xF,
|
||||||
|
};
|
||||||
|
|
||||||
|
#define FIXED_RATE_MASK_NONE 0x00
|
||||||
|
#define FIXED_RATE_MASK_STA 0x01
|
||||||
|
#define FIXED_RATE_MASK_AP 0x02
|
||||||
|
#define FIXED_RATE_MASK_ALL 0x03
|
||||||
|
|
||||||
|
int wifi_set_user_fixed_rate(uint8 enable_mask, uint8 rate);
|
||||||
|
int wifi_get_user_fixed_rate(uint8 *enable_mask, uint8 *rate);
|
||||||
|
|
||||||
|
enum support_rate {
|
||||||
|
RATE_11B5M = 0,
|
||||||
|
RATE_11B11M = 1,
|
||||||
|
RATE_11B1M = 2,
|
||||||
|
RATE_11B2M = 3,
|
||||||
|
RATE_11G6M = 4,
|
||||||
|
RATE_11G12M = 5,
|
||||||
|
RATE_11G24M = 6,
|
||||||
|
RATE_11G48M = 7,
|
||||||
|
RATE_11G54M = 8,
|
||||||
|
RATE_11G9M = 9,
|
||||||
|
RATE_11G18M = 10,
|
||||||
|
RATE_11G36M = 11,
|
||||||
|
};
|
||||||
|
|
||||||
|
int wifi_set_user_sup_rate(uint8 min, uint8 max);
|
||||||
|
|
||||||
|
enum RATE_11B_ID {
|
||||||
|
RATE_11B_B11M = 0,
|
||||||
|
RATE_11B_B5M = 1,
|
||||||
|
RATE_11B_B2M = 2,
|
||||||
|
RATE_11B_B1M = 3,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum RATE_11G_ID {
|
||||||
|
RATE_11G_G54M = 0,
|
||||||
|
RATE_11G_G48M = 1,
|
||||||
|
RATE_11G_G36M = 2,
|
||||||
|
RATE_11G_G24M = 3,
|
||||||
|
RATE_11G_G18M = 4,
|
||||||
|
RATE_11G_G12M = 5,
|
||||||
|
RATE_11G_G9M = 6,
|
||||||
|
RATE_11G_G6M = 7,
|
||||||
|
RATE_11G_B5M = 8,
|
||||||
|
RATE_11G_B2M = 9,
|
||||||
|
RATE_11G_B1M = 10
|
||||||
|
};
|
||||||
|
|
||||||
|
enum RATE_11N_ID {
|
||||||
|
RATE_11N_MCS7S = 0,
|
||||||
|
RATE_11N_MCS7 = 1,
|
||||||
|
RATE_11N_MCS6 = 2,
|
||||||
|
RATE_11N_MCS5 = 3,
|
||||||
|
RATE_11N_MCS4 = 4,
|
||||||
|
RATE_11N_MCS3 = 5,
|
||||||
|
RATE_11N_MCS2 = 6,
|
||||||
|
RATE_11N_MCS1 = 7,
|
||||||
|
RATE_11N_MCS0 = 8,
|
||||||
|
RATE_11N_B5M = 9,
|
||||||
|
RATE_11N_B2M = 10,
|
||||||
|
RATE_11N_B1M = 11
|
||||||
|
};
|
||||||
|
|
||||||
|
#define RC_LIMIT_11B 0
|
||||||
|
#define RC_LIMIT_11G 1
|
||||||
|
#define RC_LIMIT_11N 2
|
||||||
|
#define RC_LIMIT_P2P_11G 3
|
||||||
|
#define RC_LIMIT_P2P_11N 4
|
||||||
|
#define RC_LIMIT_NUM 5
|
||||||
|
|
||||||
|
#define LIMIT_RATE_MASK_NONE 0x00
|
||||||
|
#define LIMIT_RATE_MASK_STA 0x01
|
||||||
|
#define LIMIT_RATE_MASK_AP 0x02
|
||||||
|
#define LIMIT_RATE_MASK_ALL 0x03
|
||||||
|
|
||||||
|
bool wifi_set_user_rate_limit(uint8 mode, uint8 ifidx, uint8 max, uint8 min);
|
||||||
|
uint8 wifi_get_user_limit_rate_mask(void);
|
||||||
|
bool wifi_set_user_limit_rate_mask(uint8 enable_mask);
|
||||||
|
|
||||||
|
enum {
|
||||||
|
USER_IE_BEACON = 0,
|
||||||
|
USER_IE_PROBE_REQ,
|
||||||
|
USER_IE_PROBE_RESP,
|
||||||
|
USER_IE_ASSOC_REQ,
|
||||||
|
USER_IE_ASSOC_RESP,
|
||||||
|
USER_IE_MAX
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef void (*user_ie_manufacturer_recv_cb_t)(uint8 type, const uint8 sa[6], const uint8 m_oui[3], uint8 *ie, uint8 ie_len, int rssi);
|
||||||
|
|
||||||
|
bool wifi_set_user_ie(bool enable, uint8 *m_oui, uint8 type, uint8 *user_ie, uint8 len);
|
||||||
|
int wifi_register_user_ie_manufacturer_recv_cb(user_ie_manufacturer_recv_cb_t cb);
|
||||||
|
void wifi_unregister_user_ie_manufacturer_recv_cb(void);
|
||||||
|
|
||||||
#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.
BIN
tools/sdk/lib/libmesh.a
Normal file
BIN
tools/sdk/lib/libmesh.a
Normal file
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.
BIN
tools/sdk/lib/libwpa2.a
Normal file
BIN
tools/sdk/lib/libwpa2.a
Normal file
Binary file not shown.
Binary file not shown.
@ -1 +1 @@
|
|||||||
1.3.0_15_08_10_p1
|
1.5.0
|
||||||
|
Loading…
x
Reference in New Issue
Block a user