Browse Source

added gdb and updated code

development
Rohan Sircar 4 years ago
parent
commit
206751cfbb
  1. 5
      .gitignore
  2. 7
      .vscode/extensions.json
  3. 6
      .vscode/settings.json
  4. 24
      lib/GDBStub/License
  5. 69
      lib/GDBStub/README.md
  6. 20
      lib/GDBStub/gdbcmds
  7. 30
      lib/GDBStub/library.json
  8. 10
      lib/GDBStub/library.properties
  9. 41
      lib/GDBStub/src/GDBStub.h
  10. 87
      lib/GDBStub/src/internal/gdbstub-cfg.h
  11. 442
      lib/GDBStub/src/internal/gdbstub-entry.S
  12. 25
      lib/GDBStub/src/internal/gdbstub-entry.h
  13. 926
      lib/GDBStub/src/internal/gdbstub.c
  14. 459
      lib/GDBStub/src/xtensa/config/core-isa.h
  15. 80
      lib/GDBStub/src/xtensa/config/specreg.h
  16. 164
      lib/GDBStub/src/xtensa/corebits.h
  17. 30
      platformio.ini
  18. 449
      src/sketch_oct17esp.cpp
  19. 16
      src/sketch_oct17esp.hpp

5
.gitignore

@ -1,11 +1,8 @@
.pio
.pioenvs
.piolibdeps
.piolibdeps_old
.vscode/.browse.c_cpp.db*
.vscode/c_cpp_properties.json
.vscode/launch.json
website-source
website-source-copy
website-zipped
website-zipped_bak
.vscode

7
.vscode/extensions.json

@ -1,7 +0,0 @@
{
// See http://go.microsoft.com/fwlink/?LinkId=827846
// for the documentation about the extensions.json format
"recommendations": [
"platformio.platformio-ide"
]
}

6
.vscode/settings.json

@ -1,6 +0,0 @@
{
"terminal.integrated.env.linux": {
"PATH": "/home/rohan/.platformio/penv/bin:/home/rohan/.platformio/penv:/home/rohan/.cargo/bin:/home/rohan/bin:/home/rohan/.local/bin:/home/rohan/.nvm/versions/node/v12.10.0/bin:/home/rohan/miniconda3/condabin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/home/rohan/.cargo/bin",
"PLATFORMIO_CALLER": "vscode"
}
}

24
lib/GDBStub/License

@ -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
lib/GDBStub/README.md

@ -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.

20
lib/GDBStub/gdbcmds

@ -0,0 +1,20 @@
# ESP8266 HW limits the number of breakpoints/watchpoints
set remote hardware-breakpoint-limit 1
set remote hardware-watchpoint-limit 1
# Some GDBstub settings
set remote interrupt-on-connect on
set remote kill-packet off
set remote symbol-lookup-packet off
set remote verbose-resume-packet off
# The memory map, so GDB knows where it can install SW breakpoints
mem 0x20000000 0x3fefffff ro cache
mem 0x3ff00000 0x3fffffff rw
mem 0x40000000 0x400fffff ro cache
mem 0x40100000 0x4013ffff rw cache
mem 0x40140000 0x5fffffff ro cache
mem 0x60000000 0x60001fff rw
# Change the following to your sketch's ELF file
file /path/to/sketch.ino.elf
# Change the following to your serial port and baud
set serial baud 115200
target remote /dev/ttyUSB0

30
lib/GDBStub/library.json

@ -0,0 +1,30 @@
{
"name": "GDBStub",
"version": "0.3",
"keywords": "gdb, debug",
"description": "GDB server stub helps debug crashes when JTAG isn't an option.",
"repository":
{
"type": "git",
"url": "https://github.com/esp8266/Arduino.git"
},
"export": {
"include": "libraries/GDBStub"
},
"authors":
[
{
"name": "Jeroen Domburg"
},
{
"name": "Ivan Grokhotkov",
"email": "ivan@esp8266.com",
"maintainer": true
}
],
"frameworks": "arduino",
"platforms": "espressif8266",
"build": {
"libArchive": false
}
}

10
lib/GDBStub/library.properties

@ -0,0 +1,10 @@
name=GDBStub
version=0.3
author=Jeroen Domburg
maintainer=Ivan Grokhotkov <ivan@esp8266.com>
sentence=GDB server stub by Espressif
paragraph=GDB server stub helps debug crashes when JTAG isn't an option.
category=Uncategorized
url=https://github.com/espressif/esp-gdbstub
architectures=esp8266
dot_a_linkage=true

41
lib/GDBStub/src/GDBStub.h

@ -0,0 +1,41 @@
#ifndef GDBSTUB_H
#define GDBSTUB_H
#include <stdbool.h>
#include <stdint.h>
#include <stddef.h>
#include <gdb_hooks.h>
#include "internal/gdbstub-cfg.h"
#ifdef __cplusplus
extern "C" {
#endif
void gdbstub_init();
//Indicates whether gdbstub will attach to these or not
//Useful for other uart libs to avoid conflicts
bool gdbstub_has_putc1_control();
bool gdbstub_has_uart_isr_control();
#if GDBSTUB_REDIRECT_CONSOLE_OUTPUT
void gdbstub_set_putc1_callback(void (*callback)(char));
#endif
void gdbstub_write_char(char c);
void gdbstub_write(const char* buf, size_t size);
#if GDBSTUB_CTRLC_BREAK && !GDBSTUB_FREERTOS
void gdbstub_set_uart_isr_callback(void (*callback)(void*, uint8_t), void* arg);
//Override points for enabling tx and rx pins for uart0
void gdbstub_hook_enable_tx_pin_uart0(uint8_t pin);
void gdbstub_hook_enable_rx_pin_uart0(uint8_t pin);
#endif
#ifdef __cplusplus
}
#endif
#endif

87
lib/GDBStub/src/internal/gdbstub-cfg.h

@ -0,0 +1,87 @@
#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 1
#endif
/*
Enable this to cause the program to pause and wait for gdb to be connected when an exception is
encountered.
*/
#ifndef GDBSTUB_BREAK_ON_EXCEPTION
#define GDBSTUB_BREAK_ON_EXCEPTION 1
#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 1
#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 1
#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.
*/
#ifndef ATTR_GDBINIT
#define ATTR_GDBINIT ICACHE_FLASH_ATTR
#endif
#ifndef ATTR_GDBFN
#define ATTR_GDBFN ICACHE_RAM_ATTR
#endif
#ifndef ATTR_GDBEXTERNFN
#define ATTR_GDBEXTERNFN ICACHE_FLASH_ATTR
#endif
#ifndef ASATTR_GDBINIT
#define ASATTR_GDBINIT .section .irom0.text
#endif
#ifndef ASATTR_GDBFN
#define ASATTR_GDBFN .section .iram.text
#endif
#ifndef ASATTR_GDBEXTERNFN
#define ASATTR_GDBEXTERNFN .section .irom0.text
#endif
#endif

442
lib/GDBStub/src/internal/gdbstub-entry.S

@ -0,0 +1,442 @@
/******************************************************************************
* 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
ASATTR_GDBFN
.literal_position
ASATTR_GDBINIT
.literal_position
ASATTR_GDBFN
.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.
*/
.type gdbstub_debug_exception_entry, @function
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, 0x14
rsr a0, DEBUG_PS
s32i a0, a2, 0x04
rsr a0, DEBUG_EXCSAVE //was R2
s32i a0, a2, 0x18
s32i a3, a2, 0x1c
s32i a4, a2, 0x20
s32i a5, a2, 0x24
s32i a6, a2, 0x28
s32i a7, a2, 0x2c
s32i a8, a2, 0x30
s32i a9, a2, 0x34
s32i a10, a2, 0x38
s32i a11, a2, 0x3c
s32i a12, a2, 0x40
s32i a13, a2, 0x44
s32i a14, a2, 0x48
s32i a15, a2, 0x4c
rsr a0, SAR
s32i a0, a2, 0x08
rsr a0, LITBASE
s32i a0, a2, 0x50
rsr a0, 176
s32i a0, a2, 0x54
rsr a0, 208
s32i a0, a2, 0x58
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, 0x58
// wsr a0, 208
l32i a0, a2, 0x54
//wsr a0, 176 //Some versions of gcc do not understand this...
.byte 0x00, 176, 0x13 //so we hand-assemble the instruction.
l32i a0, a2, 0x50
wsr a0, LITBASE
l32i a0, a2, 0x08
wsr a0, SAR
l32i a15, a2, 0x4c
l32i a14, a2, 0x48
l32i a13, a2, 0x44
l32i a12, a2, 0x40
l32i a11, a2, 0x3c
l32i a10, a2, 0x38
l32i a9, a2, 0x34
l32i a8, a2, 0x30
l32i a7, a2, 0x2c
l32i a6, a2, 0x28
l32i a5, a2, 0x24
l32i a4, a2, 0x20
l32i a3, a2, 0x1c
l32i a0, a2, 0x18
wsr a0, DEBUG_EXCSAVE //was R2
l32i a0, a2, 0x04
wsr a0, DEBUG_PS
l32i a1, a2, 0x14
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
.size gdbstub_debug_exception_entry, .-gdbstub_debug_exception_entry
#if GDBSTUB_BREAK_ON_EXCEPTION
#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
.type gdbstub_user_exception_entry, @function
ASATTR_GDBFN
.align 4
gdbstub_user_exception_entry:
//Save all regs to structure
movi a0, gdbstub_savedRegs
s32i a1, a0, 0x18 //was a2
s32i a3, a0, 0x1c
s32i a4, a0, 0x20
s32i a5, a0, 0x24
s32i a6, a0, 0x28
s32i a7, a0, 0x2c
s32i a8, a0, 0x30
s32i a9, a0, 0x34
s32i a10, a0, 0x38
s32i a11, a0, 0x3c
s32i a12, a0, 0x40
s32i a13, a0, 0x44
s32i a14, a0, 0x48
s32i a15, a0, 0x4c
rsr a2, SAR
s32i a2, a0, 0x08
rsr a2, LITBASE
s32i a2, a0, 0x50
rsr a2, 176
s32i a2, a0, 0x54
rsr a2, 208
s32i a2, a0, 0x58
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
.size gdbstub_user_exception_entry, .-gdbstub_user_exception_entry
.global gdbstub_handle_uart_int
.global gdbstub_uart_entry
.type gdbstub_uart_entry, @function
ASATTR_GDBFN
.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
.size gdbstub_uart_entry, .-gdbstub_uart_entry
#endif
#endif
.global gdbstub_save_extra_sfrs_for_exception
.type gdbstub_save_extra_sfrs_for_exception, @function
ASATTR_GDBFN
.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, 0x50
rsr a3, 176
s32i a3, a2, 0x54
rsr a3, 208
s32i a3, a2, 0x58
rsr a3, EXCCAUSE
s32i a3, a2, 0x5C
ret
.size gdbstub_save_extra_sfrs_for_exception, .-gdbstub_save_extra_sfrs_for_exception
.global gdbstub_init_debug_entry
.global _DebugExceptionVector
.type gdbstub_init_debug_entry, @function
ASATTR_GDBINIT
.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
.size gdbstub_init_debug_entry, .-gdbstub_init_debug_entry
//Set up ICOUNT register to step one single instruction
.global gdbstub_icount_ena_single_step
.type gdbstub_icount_ena_single_step, @function
ASATTR_GDBFN
.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
.size gdbstub_icount_ena_single_step, .-gdbstub_icount_ena_single_step
//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
.type gdbstub_set_hw_breakpoint, @function
ASATTR_GDBFN
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
.size gdbstub_set_hw_breakpoint, .-gdbstub_set_hw_breakpoint
.global gdbstub_del_hw_breakpoint
.type gdbstub_del_hw_breakpoint, @function
ASATTR_GDBFN
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
.size gdbstub_del_hw_breakpoint, .-gdbstub_del_hw_breakpoint
.global gdbstub_set_hw_watchpoint
.type gdbstub_set_hw_watchpoint, @function
ASATTR_GDBFN
//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
.size gdbstub_set_hw_watchpoint, .-gdbstub_set_hw_watchpoint
.global gdbstub_del_hw_watchpoint
.type gdbstub_del_hw_watchpoint, @function
ASATTR_GDBFN
//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
.size gdbstub_del_hw_watchpoint, .-gdbstub_del_hw_watchpoint
//Breakpoint, with an attempt at a functional function prologue and epilogue...
.global gdbstub_do_break_breakpoint_addr
.global gdbstub_do_break
.type gdbstub_do_break, @function
ASATTR_GDBFN
.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
.size gdbstub_do_break, .-gdbstub_do_break

25
lib/GDBStub/src/internal/gdbstub-entry.h

@ -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

926
lib/GDBStub/src/internal/gdbstub.c

@ -0,0 +1,926 @@
/******************************************************************************
* 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 <Arduino.h>
#include "ets_sys.h"
#include "eagle_soc.h"
#include "c_types.h"
#include "gpio.h"
#include "xtensa/corebits.h"
#include "uart_register.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 a[16]; //a0..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;
//'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;
};
#if GDBSTUB_FREERTOS
struct XTensa_rtos_int_frame_s {
uint32_t exitPtr;
uint32_t pc;
uint32_t ps;
uint32_t a[16];
uint32_t sar;
};
/*
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 os_isr_attach(int inum, void *fn);
void os_install_putc1(void (*p)(char c));
#define os_printf(...) printf(__VA_ARGS__)
#define os_strncmp(...) strncmp(__VA_ARGS__)
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));
#endif
#define EXCEPTION_GDB_SP_OFFSET 0x100
//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
//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 bool gdb_attached = false;
static unsigned char cmd[PBUFLEN]; //GDB command input buffer
static char chsum; //Running checksum of the output packet
#if GDBSTUB_CTRLC_BREAK
static void (*uart_isr_callback)(void*, uint8_t) = NULL;
static void* uart_isr_arg = NULL;
#endif
#if GDBSTUB_REDIRECT_CONSOLE_OUTPUT
static void (*uart_putc1_callback)(char) = NULL;
#endif
//Stores ps when single-stepping instruction. -1 when not in use.
static int32_t singleStepPs = -1;
//Uart libs can reference these to see if gdb is attaching to them
bool gdbstub_has_putc1_control() {
#if GDBSTUB_REDIRECT_CONSOLE_OUTPUT
return true;
#else
return false;
#endif
}
bool gdbstub_has_uart_isr_control() {
#if GDBSTUB_CTRLC_BREAK
return true;
#else
return false;
#endif
}
//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;
}
//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
#define ST_DETACH -5
//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 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 iswap(int i) {
return ((i >> 24) & 0xff)
| (((i >> 16) & 0xff) << 8)
| (((i >> 8) & 0xff) << 16)
| (((i >> 0) & 0xff) << 24);
}
//Read a byte from the ESP8266 memory.
static unsigned char readbyte(unsigned int p) {
if (p < 0x20000000 || p >= 0x60000000) return -1;
int *i = (int*)(p & ~3);
return *i >> ((p & 3) * 8);
}
//Write a byte to the ESP8266 memory.
static void writeByte(unsigned int p, unsigned char d) {
if (p < 0x20000000 || p >= 0x60000000) return;
int *i = (int*)(p & ~3);
if ((p & 3) == 0) *i = (*i & 0xffffff00) | (d << 0);
else if ((p & 3) == 1) *i = (*i & 0xffff00ff) | (d << 8);
else if ((p & 3) == 2) *i = (*i & 0xff00ffff) | (d << 16);
else if ((p & 3) == 3) *i = (*i & 0x00ffffff) | (d << 24);
}
//Returns 1 if it makes sense to write to addr p
static int validWrAddr(int p) {
return (p >= 0x3ff00000 && p < 0x40000000)
|| (p >= 0x40100000 && p < 0x40140000)
|| (p >= 0x60000000 && p < 0x60002000);
}
static inline bool ATTR_GDBFN gdbRxFifoIsEmpty() {
return ((READ_PERI_REG(UART_STATUS(0)) >> UART_RXFIFO_CNT_S) & UART_RXFIFO_CNT) == 0;
}
static inline bool ATTR_GDBFN gdbTxFifoIsFull() {
return ((READ_PERI_REG(UART_STATUS(0)) >> UART_TXFIFO_CNT_S) & UART_TXFIFO_CNT) >= 126;
}
//Receive a char from the uart. Uses polling and feeds the watchdog.
static inline int gdbRecvChar() {
while (gdbRxFifoIsEmpty()) {
keepWDTalive();
}
return READ_PERI_REG(UART_FIFO(0));
}
//Send a char to the uart.
static void gdbSendChar(char c) {
while (gdbTxFifoIsFull())
;
WRITE_PERI_REG(UART_FIFO(0), c);
}
//Send the start of a packet; reset checksum calculation.
static void gdbPacketStart() {
chsum = 0;
gdbSendChar('$');
}
//Send a char as part of a packet
static void gdbPacketChar(char c) {
if (c == '#' || c == '$' || c == '}' || c == '*') {
gdbSendChar('}');
chsum += '}';
c ^= 0x20;
}
gdbSendChar(c);
chsum += c;
}
//Send a hex val as part of a packet. 'bits'/4 dictates the number of hex chars sent.
static void gdbPacketHex(int val, int bits) {
static const char hexChars[] = "0123456789abcdef";
int i;
for (i = bits; i > 0; i -= 4) {
gdbPacketChar(hexChars[(val >> (i - 4)) & 0xf]);
}
}
//Send a hex val as part of a packet. 'bits'/4 dictates the number of hex chars sent.
static void gdbPacketSwappedHexInt(int val) {
gdbPacketHex(iswap(val), 32);
}
static void gdbPacketXXXXInt() {
for (int i=0; i<8; i++) gdbPacketChar('x');
}
//Finish sending a packet.
static void gdbPacketEnd() {
gdbSendChar('#');
//Ok to use packet version here since hex char can never be an
//excape-requiring character
gdbPacketHex(chsum, 8);
}
// Send a complete packet containing str
static void gdbSendPacketStr(const char *c) {
gdbPacketStart();
while (*c != 0) {
gdbPacketChar(*c);
c++;
}
gdbPacketEnd();
}
// Send a complete packet containing str as an output message
static inline void ATTR_GDBEXTERNFN gdbSendOutputPacketStr(const unsigned char* buf, size_t size) {
size_t i;
gdbPacketStart();
gdbPacketChar('O');
for (i = 0; i < size; i++)
gdbPacketHex(buf[i], 8);
gdbPacketEnd();
}
// Send a complete packet containing c as an output message
static inline void ATTR_GDBEXTERNFN gdbSendOutputPacketChar(unsigned char c) {
gdbPacketStart();
gdbPacketChar('O');
gdbPacketHex(c, 8);
gdbPacketEnd();
}
static long gdbGetSwappedHexInt(unsigned char **ptr) {
return iswap(gdbGetHexVal(ptr, 32));
}
//Send the reason execution is stopped to GDB.
static void sendReason() {
static const char exceptionSignal[] = {4,31,11,11,2,6,8,0,6,7,0,0,7,7,7,7};
#if 0
char *reason=""; //default
#endif
//exception-to-signal mapping
size_t i;
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))
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();
}
static inline void ATTR_GDBFN gdbSendPacketOK() {
gdbSendPacketStr("OK");
}
static inline void ATTR_GDBFN gdbSendPacketE01() {
gdbSendPacketStr("E01");
}
static inline void ATTR_GDBFN gdbSendEmptyPacket() {
gdbPacketStart();
gdbPacketEnd();
}
void ATTR_GDBEXTERNFN gdbstub_write_char(char c) {
if (gdb_attached) {
ETS_UART_INTR_DISABLE();
gdbSendOutputPacketChar(c);
ETS_UART_INTR_ENABLE();
} else {
gdbSendChar(c);
}
}
void ATTR_GDBEXTERNFN gdbstub_write(const char* buf, size_t size) {
size_t i;
if (gdb_attached) {
ETS_UART_INTR_DISABLE();
gdbSendOutputPacketStr((const unsigned char *)buf, size);
ETS_UART_INTR_ENABLE();
} else {
for (i = 0; i < size; i++) {
gdbSendChar(buf[i]);
}
}
}
/*
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;
};
*/
//Handle a command as received from GDB.
static inline int gdbHandleCommand() {
//Handle a command
int i, j, k;
unsigned char *data = cmd + 1;
if (cmd[0]=='g') { //send all registers to gdb
gdbPacketStart();
gdbPacketSwappedHexInt(gdbstub_savedRegs.pc);
for (int i=1; i<=35; i++) gdbPacketXXXXInt();
gdbPacketSwappedHexInt(gdbstub_savedRegs.sar);
gdbPacketSwappedHexInt(gdbstub_savedRegs.litbase);
for (int i=38; i<=39; i++) gdbPacketXXXXInt();
gdbPacketSwappedHexInt(gdbstub_savedRegs.sr176);
for (int i=41; i<=41; i++) gdbPacketXXXXInt();
gdbPacketSwappedHexInt(gdbstub_savedRegs.ps);
for (int i=43; i<=96; i++) gdbPacketXXXXInt();
for (i=0; i<16; i++) gdbPacketSwappedHexInt(gdbstub_savedRegs.a[i]);
gdbPacketEnd();
} else if (cmd[0]=='G') { //receive content for all registers from gdb
gdbstub_savedRegs.pc=gdbGetSwappedHexInt(&data);
for (int i=1; i<=35; i++) gdbGetHexVal(&data, 32);
gdbstub_savedRegs.sar=gdbGetSwappedHexInt(&data);
gdbstub_savedRegs.litbase=gdbGetSwappedHexInt(&data);
for (int i=38; i<=39; i++) gdbGetHexVal(&data, 32);
gdbstub_savedRegs.sr176=gdbGetSwappedHexInt(&data);
for (int i=41; i<=41; i++) gdbGetHexVal(&data, 32);
gdbstub_savedRegs.ps=gdbGetSwappedHexInt(&data);
for (int i=43; i<=96; i++) gdbGetHexVal(&data, 32);
for (i=0; i<16; i++) gdbstub_savedRegs.a[i]=gdbGetSwappedHexInt(&data);
gdbSendPacketOK();
} else if ((cmd[0] | 0x20) == 'm') { //read/write memory to gdb
i = gdbGetHexVal(&data, -1); //addr
data++;
j = gdbGetHexVal(&data, -1); //length
if (cmd[0] == 'm') { //read memory to gdb
gdbPacketStart();
for (k = 0; k < j; k++) {
gdbPacketHex(readbyte(i++), 8);
}
gdbPacketEnd();
} else { //write memory from gdb
if (validWrAddr(i) && validWrAddr(i + j)) {
data++; //skip :
for (k = 0; k < j; k++, i++) {
writeByte(i, gdbGetHexVal(&data, 8));
}
//Make sure caches are up-to-date. Procedure according to Xtensa ISA document, ISYNC inst desc.
asm volatile("ISYNC\nISYNC\n");
gdbSendPacketOK();
} else {
//Trying to do a software breakpoint on a flash proc, perhaps?
gdbSendPacketE01();
}
}
} else if (cmd[0] == '?') { //Reply with stop reason
sendReason();
} else if (cmd[0] == 'c') { //continue execution
return ST_CONT;
} else if (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] == 'D') { //detach
gdbSendPacketOK();
return ST_DETACH;
} else if (cmd[0] == 'k') { //kill
system_restart_core();
} else if (cmd[0] == 'q') { //Extended query
if (os_strncmp((char*)&cmd[1], "Supported", 9) == 0) { //Capabilities query
gdbSendPacketStr("swbreak+;hwbreak+;PacketSize=FF"); //PacketSize is in hex
} else if (os_strncmp((char*)&cmd[1], "Attached", 8) == 0) {
//Let gdb know that it is attaching to a running program
//In general that just means it detaches instead of killing when it exits
gdbSendPacketStr("1");
} else {
//We don't support other queries.
gdbSendEmptyPacket();
}
// case insensitive compare matches 'Z' or 'z'
} else if ((cmd[0] | 0x20) == 'z' && cmd[1] >= '1' && cmd[2] <= '4') { //hardware break/watchpoint
int result;
data += 2; //skip 'x,'
i = gdbGetHexVal(&data, -1);
data++; //skip ','
j = gdbGetHexVal(&data, -1);
if (cmd[0] == 'Z') { //Set hardware break/watchpoint
if (cmd[1] == '1') { //Set breakpoint
result = gdbstub_set_hw_breakpoint(i, j);
} else { //Set watchpoint
int access;
unsigned 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;
result = mask != 0 && gdbstub_set_hw_watchpoint(i, mask, access);
}
} else { //Clear hardware break/watchpoint
if (cmd[1] == '1') { //hardware breakpoint
result = gdbstub_del_hw_breakpoint(i);
} else { //hardware watchpoint
result = gdbstub_del_hw_watchpoint(i);
}
}
if (result) {
gdbSendPacketOK();
} else {
gdbSendPacketE01();
}
} else {
//We don't recognize or support whatever GDB just sent us.
gdbSendEmptyPacket();
}
return ST_OK;
}
//Lower layer: grab a command packet and check the checksum
//Calls gdbHandleCommand on the packet if the checksum is OK
//Returns only if execution of the user program should continue
//Otherwise keeps reading uart data and executing commands
//Flags that gdb has been attached whenever a gdb formatted
// packet is received
//While gdb is attached, checks for ctl-c (\x03) if it's not
// already paused
//Keeps reading commands if it is paused, until either a
// continue, detach, or kill command is received
//It is not necessary for gdb to be attached for it to be paused
//For example, during an exception break, the program is
// paused but gdb might not be attached yet
static int gdbReadCommand() {
unsigned char chsum;
unsigned char sentchs[2];
size_t p;
unsigned char c;
unsigned char *ptr;
int result;
ETS_UART_INTR_DISABLE();
ets_wdt_disable();
sendReason();
while (true) {
gdbReadCommand_start:
while (gdbRecvChar() != '$')
;
gdbReadCommand_packetBegin:
chsum = 0;
p = 0;
while ((c = gdbRecvChar()) != '#') { //end of packet, checksum follows
if (c == '$') {
//Wut, restart packet?
goto gdbReadCommand_packetBegin;
}
if (c == '}') { //escape the next char
c = gdbRecvChar() ^ 0x20;
}
chsum += c;
cmd[p++] = c;
if (p >= PBUFLEN) {
//Received more than the size of the command buffer
goto gdbReadCommand_start;
}
}
cmd[p] = 0;
sentchs[0] = gdbRecvChar();
sentchs[1] = gdbRecvChar();
ptr = &sentchs[0];
if (gdbGetHexVal(&ptr, 8) == chsum) {
gdb_attached = true;
gdbSendChar('+');
result = gdbHandleCommand();
if (result != ST_OK) {
break;
}
} else {
gdbSendChar('-');
}
}
if (result == ST_DETACH) {
gdb_attached = false;
}
ets_wdt_enable();
ETS_UART_INTR_ENABLE();
return result;
}
//Get the value of one of the A registers
static unsigned int ATTR_GDBFN getaregval(int reg) {
return gdbstub_savedRegs.a[reg];
}
//Set the value of one of the A registers
static inline void ATTR_GDBFN setaregval(int reg, unsigned int val) {
// os_printf("%x -> %x\n", val, reg);
gdbstub_savedRegs.a[reg] = val;
}
//Emulate the l32i/s32i instruction we're stopped at.
static inline void emulLdSt() {
unsigned char i0 = readbyte(gdbstub_savedRegs.pc);
unsigned char i1 = readbyte(gdbstub_savedRegs.pc + 1);
unsigned char i2;
int *p;
if ((i0 & 0xf) == 2 && (i1 & 0xb0) == 0x20) {
//l32i or s32i
i2 = readbyte(gdbstub_savedRegs.pc + 2);
p = (int*)getaregval(i1 & 0xf) + (i2 * 4);
i0 >>= 4;
if ((i1 & 0xf0) == 0x20) { //l32i
setaregval(i0, *p);
} else { //s32i
*p = getaregval(i0);
}
gdbstub_savedRegs.pc += 3;
} else if ((i0 & 0xe) == 0x8) {
//l32i.n or s32i.n
p = (int*)getaregval(i1 & 0xf) + ((i1 >> 4) * 4);
if ((i0 & 0xf) == 0x8) { //l32i.n
setaregval(i0 >> 4, *p);
} else {
*p = getaregval(i0 >> 4);
}
gdbstub_savedRegs.pc += 2;
// } else {
// os_printf("GDBSTUB: No l32i/s32i instruction: %x %x. Huh?", i1, i0);
}
}
//We just caught a debug exception and need to handle it. This is called from an assembly
//routine in gdbstub-entry.S
static void gdbstub_handle_debug_exception_flash();
void ATTR_GDBFN gdbstub_handle_debug_exception() {
Cache_Read_Enable_New();
gdbstub_handle_debug_exception_flash();
}
static void __attribute__((noinline)) gdbstub_handle_debug_exception_flash() {
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;
}
gdbReadCommand();
if ((gdbstub_savedRegs.reason & 0x80) == 0) { //Watchpoint/BREAK/BREAK.N
if ((gdbstub_savedRegs.reason & 0x4) != 0) {
//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 & 0x8) != 0)
//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.
&& readbyte(gdbstub_savedRegs.pc + 2) == 0
&& (readbyte(gdbstub_savedRegs.pc + 1) & 0xf0) == 0x40
&& (readbyte(gdbstub_savedRegs.pc) & 0x0f) == 0x00)
|| (((gdbstub_savedRegs.reason & 0x10) != 0)
//We stopped due to a BREAK.N instruction. Skip over it, after making sure the instruction
//actually is a BREAK.N
&& (readbyte(gdbstub_savedRegs.pc + 1) & 0xf0) == 0xf0
&& readbyte(gdbstub_savedRegs.pc) == 0x2d)) {
gdbstub_savedRegs.pc += 3;
}
}
}
#if GDBSTUB_BREAK_ON_EXCEPTION || GDBSTUB_CTRLC_BREAK
#if !GDBSTUB_FREERTOS
static inline int gdbReadCommandWithFrame(void* frame) {
//Copy registers the Xtensa HAL did save to gdbstub_savedRegs
os_memcpy(&gdbstub_savedRegs, frame, 5 * 4);
os_memcpy(&gdbstub_savedRegs.a[2], ((uint32_t*)frame) + 5, 14 * 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.a[1] = (uint32_t)frame + EXCEPTION_GDB_SP_OFFSET;
int result = gdbReadCommand();
//Copy any changed registers back to the frame the Xtensa HAL uses.
os_memcpy(frame, &gdbstub_savedRegs, 5 * 4);
os_memcpy(((uint32_t*)frame) + 5, &gdbstub_savedRegs.a[2], 14 * 4);
return result;
}
#endif
#endif
#if GDBSTUB_BREAK_ON_EXCEPTION
#if GDBSTUB_FREERTOS
//Freertos exception. This routine is called by an assembly routine in gdbstub-entry.S
void ATTR_GDBFN gdbstub_handle_user_exception() {
gdbstub_savedRegs.reason |= 0x80; //mark as an exception reason
while (gdbReadCommand() != ST_CONT)
;
}
//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;
}
#else
//Non-OS exception handler. Gets called by the Xtensa HAL.
static void gdbstub_exception_handler_flash(struct XTensa_exception_frame_s *frame);
static void ATTR_GDBFN gdbstub_exception_handler(struct XTensa_exception_frame_s *frame) {
//Save the extra registers the Xtensa HAL doesn't save
gdbstub_save_extra_sfrs_for_exception();
Cache_Read_Enable_New();
gdbstub_exception_handler_flash(frame);
}
static void __attribute__((noinline)) gdbstub_exception_handler_flash(struct XTensa_exception_frame_s *frame) {
gdbstub_savedRegs.reason |= 0x80; //mark as an exception reason
while (gdbReadCommandWithFrame((void*)frame) != ST_CONT)
;
}
//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() {
static 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};
unsigned int i;
for (i = 0; i < (sizeof(exno) / sizeof(exno[0])); i++) {
_xtos_set_exception_handler(exno[i], gdbstub_exception_handler);
}
}
#endif
#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_GDBEXTERNFN gdbstub_semihost_putchar1(char c) {
if (!gdb_attached && uart_putc1_callback != NULL) {
uart_putc1_callback(c);
} else {
gdbstub_write_char(c);
}
}
void ATTR_GDBINIT gdbstub_set_putc1_callback(void (*func)(char)) {
uart_putc1_callback = func;
}
#endif
#if GDBSTUB_FREERTOS
static void ATTR_GDBINIT configure_uart() {}
#else
static void ATTR_GDBINIT configure_uart() {
#ifdef ARDUINO
// Set the UART input/output pins to TX=1, RX=3
pinMode(3, SPECIAL);
pinMode(1, FUNCTION_0);
#endif
WRITE_PERI_REG(UART_CONF0(0), 0b00011100); //8N1
SET_PERI_REG_MASK(UART_CONF0(0), UART_RXFIFO_RST | UART_TXFIFO_RST); //RESET FIFO
CLEAR_PERI_REG_MASK(UART_CONF0(0), UART_RXFIFO_RST | UART_TXFIFO_RST);
}
#endif
#if GDBSTUB_CTRLC_BREAK
#if GDBSTUB_FREERTOS
void ATTR_GDBFN gdbstub_handle_uart_int(struct XTensa_rtos_int_frame_s *frame) {
int doDebug = 0, fifolen, x;
fifolen = (READ_PERI_REG(UART_STATUS(0)) >> UART_RXFIFO_CNT_S)&UART_RXFIFO_CNT;
while (fifolen != 0) {
//Check if any of the chars is control-C. Throw away rest.
if ((READ_PERI_REG(UART_FIFO(0)) & 0xFF) == 0x3)
doDebug = 1;
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;
for (x = 0; x < 16; x++)
gdbstub_savedRegs.a[x] = frame->a[x];
// gdbstub_savedRegs.a1=(uint32_t)frame+EXCEPTION_GDB_SP_OFFSET;
gdbstub_savedRegs.reason = 0xff; //mark as user break reason
gdbReadCommand();
//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;
for (x = 0; x < 16; x++)
frame->a[x] = gdbstub_savedRegs.a[x];
}
}
static void ATTR_GDBINIT install_uart_hdlr() {
os_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);
ETS_UART_INTR_ENABLE();
}
#else
static void ATTR_GDBFN gdbstub_uart_hdlr(void* arg, void* frame) {
(void) arg;
unsigned char c;
//Save the extra registers the Xtensa HAL doesn't save
gdbstub_save_extra_sfrs_for_exception();
ETS_UART_INTR_DISABLE();
WRITE_PERI_REG(UART_INT_CLR(0), UART_RXFIFO_FULL_INT_CLR | UART_RXFIFO_TOUT_INT_CLR);
int fifolen = (READ_PERI_REG(UART_STATUS(0)) >> UART_RXFIFO_CNT_S)&UART_RXFIFO_CNT;
while (true) {
if (fifolen == 0) {
ETS_UART_INTR_ENABLE();
return;
}
c = READ_PERI_REG(UART_FIFO(0)) & 0xFF;
//Check if any of the chars is control-C
if (c == 0x3) {
break;
}
#if GDBSTUB_CTRLC_BREAK
if (!gdb_attached && uart_isr_callback != NULL) {
uart_isr_callback(uart_isr_arg, c);
}
#endif
fifolen--;
}
gdbstub_savedRegs.reason = 0xff; //mark as user break reason
gdbReadCommandWithFrame(frame);
}
static void ATTR_GDBINIT install_uart_hdlr() {
ETS_UART_INTR_DISABLE();
ETS_UART_INTR_ATTACH(gdbstub_uart_hdlr, NULL);
configure_uart();
WRITE_PERI_REG(UART_CONF1(0),
((16 & UART_RXFIFO_FULL_THRHD) << UART_RXFIFO_FULL_THRHD_S) |
((0x02 & UART_RX_TOUT_THRHD) << UART_RX_TOUT_THRHD_S) |
UART_RX_TOUT_EN);
WRITE_PERI_REG(UART_INT_CLR(0), 0xffff);
SET_PERI_REG_MASK(UART_INT_ENA(0), UART_RXFIFO_FULL_INT_ENA | UART_RXFIFO_TOUT_INT_ENA);
ETS_UART_INTR_ENABLE();
}
void ATTR_GDBINIT gdbstub_set_uart_isr_callback(void (*func)(void*, uint8_t), void* arg) {
ETS_UART_INTR_DISABLE();
uart_isr_callback = func;
uart_isr_arg = arg;
ETS_UART_INTR_ENABLE();
}
#endif
#endif
//gdbstub initialization routine.
void gdbstub_init() {
#if GDBSTUB_REDIRECT_CONSOLE_OUTPUT
os_install_putc1(gdbstub_semihost_putchar1);
#endif
#if GDBSTUB_CTRLC_BREAK
install_uart_hdlr();
#else
configure_uart();
#endif
#if GDBSTUB_BREAK_ON_EXCEPTION
install_exceptions();
#endif
gdbstub_init_debug_entry();
#if GDBSTUB_BREAK_ON_INIT
gdbstub_do_break();
#endif
}
bool ATTR_GDBEXTERNFN gdb_present() {
return true;
}
void ATTR_GDBFN gdb_do_break() { gdbstub_do_break(); }
void gdb_init() __attribute__((alias("gdbstub_init")));

459
lib/GDBStub/src/xtensa/config/core-isa.h

@ -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
lib/GDBStub/src/xtensa/config/specreg.h

@ -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
lib/GDBStub/src/xtensa/corebits.h

@ -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*/

30
platformio.ini

@ -11,26 +11,24 @@
[env:nodemcuv2]
; CXXFLAGS = -W -Wall -Wextra -Werror -std=c++11
lib_deps =
TFT_eSPI
ArduinoJson@5.13.4
DallasTemperature
Streaming
WebSockets
OneWire
DallasTemperature
Streaming
WebSockets
OneWire
ArduinoLog
platform = espressif8266
; lib_extra_dirs = ~/Documents/Arduino/libraries
board = nodemcuv2
framework = arduino
upload_speed = 460800
; build_flags = -D BEARSSL_SSL_BASIC
; baud_rate = 115200
monitor_speed = 115200
board_build.f_cpu = 160000000L
; lib_deps =
; MAX31850 DallasTemp
upload_port = 192.168.1.103
upload_protocol = espota
upload_flags =
--ip=192.168.1.103
; --port=8266
--auth=esp8266
; upload_port = 192.168.1.103
; upload_protocol = espota
; upload_flags =
; --ip=192.168.1.103
; --port=8266
; --auth=esp8266
build_flags =
-DLC_WIFI_SSID=${sysenv.WIFI_SSID}
-DLC_WIFI_PASS=${sysenv.WIFI_PASS}

449
src/sketch_oct17esp.cpp

@ -10,11 +10,17 @@
#include <Streaming.h>
#include <OneWire.h>
#include <DallasTemperature.h>
#include <GDBStub.h>
#include <ArduinoLog.h>
#define ONE_WIRE_BUS D1
// char wifiMultiSSID[30];
#include <sketch_oct17esp.hpp>
using namespace std;
SoftwareSerial s(D3, D2); //RX.TX
static char temperaturesJson[200];
@ -38,8 +44,7 @@ const char *password = "thereisnospoon"; // The password required to connect t
const char *OTAName = "ESP8266"; // A name and a password for the OTA service
const char *OTAPassword = "esp8266";
const size_t bufferSize = JSON_ARRAY_SIZE(3) + JSON_OBJECT_SIZE(2) + 3 * JSON_OBJECT_SIZE(5);
const size_t JSON_BUFFER_SIZE = JSON_ARRAY_SIZE(3) + JSON_OBJECT_SIZE(2) + 3 * JSON_OBJECT_SIZE(5) + 180;
// #define LED_RED 15 // specify the pins with an RGB LED connected
// #define LED_GREEN 12
// #define LED_BLUE 13
@ -58,11 +63,18 @@ void setup()
// pinMode(LED_RED, OUTPUT); // the pins with LEDs connected are outputs
// pinMode(LED_GREEN, OUTPUT);
// pinMode(LED_BLUE, OUTPUT);
Serial.begin(115200);
Log.begin(LOG_LEVEL_VERBOSE, &Serial);
Log.setPrefix(printTimestamp); // Uncomment to get timestamps as prefix
Log.setSuffix(printNewline); // Uncomment to get newline as suffix
// Serial << "Starting up ESP light controller with log level = " << Log.getLevel();
// gdbstub_init();
Serial << "Hello" << endl;
pinMode(ARDUINO_TO_ESP_PIN, INPUT);
// pinMode(ESP_TO_ARDUINO_PIN, OUTPUT);
// digitalWrite(ESP_TO_ARDUINO_PIN, 1);
Serial.begin(115200);
s.begin(9600); // Start the Serial communication to send messages to the computer
delay(10);
Serial.println("\r\n");
@ -80,7 +92,6 @@ void setup()
startServer(); // Start a HTTP server with a file read handler and an upload handler
Serial.println();
Serial.println("Dallas Temperature IC Control Library Demo");
sensors.begin();
sensors.setWaitForConversion(false);
sensors.requestTemperatures();
@ -100,58 +111,59 @@ void loop()
{
// // digitalWrite(ESP_TO_ARDUINO_PIN, 0);
webSocket.loop(); // constantly check for websocket events
// webSocket.loop(); // constantly check for websocket events
server.handleClient(); // run the server
ArduinoOTA.handle(); // listen for OTA events
previousArduinoState = currentArduinoState;
currentArduinoState = digitalRead(ARDUINO_TO_ESP_PIN);
if (previousArduinoState == LOW && currentArduinoState == HIGH)
{
Serial.println("Arduino turned on");
// Serial.println("Arduino turned on");
Log.notice("Arduino turned on");
//arduinoON = true;
//combineSettings();
displayCombinedSettings();
Serial.println("Settings sent to arduino");
}
Log.notice("Settings sent to arduino");
}
// if (rainbow)
// { // if the rainbow effect is turned on
// if (millis() > prevMillis + 32)
// {
// if (++hue == 360) // Cycle through the color wheel (increment by one degree every 32 ms)
// hue = 0;
// setHue(hue); // Set the RGB LED to the right color
// prevMillis = millis();
// }
// }
if (rainbow)
{ // if the rainbow effect is turned on
if (millis() > prevMillis + 32)
{
if (++hue == 360) // Cycle through the color wheel (increment by one degree every 32 ms)
hue = 0;
setHue(hue); // Set the RGB LED to the right color
prevMillis = millis();
}
if (s.available() > 0)
{
// Serial << F("Received JSON from arduino") << endl;
// Serial << F("Inside second if ") << endl;
// StaticJsonBuffer<100> jsonBuffer;
// Log.notice(F("Received JSON from arduino"));
DynamicJsonBuffer jsonBuffer(100);
// Serial << "S available = " << s.available();
JsonObject &root = jsonBuffer.parseObject(s);
JsonArray &lcd_data = root["lcdData"];
// lcd_data[0];
// char a[10];
sprintf(rtcDate, lcd_data[1] | "N/A");
// root.printTo(Serial);
// Serial << s.available() << endl;
// s.flush();
// Serial << (char)s.read() << endl;
// sensors.requestTemperatures();
// char str_temp[6];
// dtostrf(sensors.getTempCByIndex(0), 1, 1, str_temp);
// sprintf(a, "%s", str_temp);
// tft.drawString(str_temp, coordinates.x[3], coordinates.y[3], 2);
// Serial.println(sensors.getTempCByIndex(0));
delay(50);
}
// s.flush()
// if (s.available() > 0)
// {
// Serial << F("Received JSON from arduino") << endl;
// Serial << F("Inside second if ") << endl;
// StaticJsonBuffer<100> jsonBuffer;
// // DynamicJsonBuffer jsonBuffer(100);
// Serial << "S available = " << s.available();
// JsonObject &root = jsonBuffer.parseObject(s);
// JsonArray &lcd_data = root["lcdData"];
// // lcd_data[0];
// // char a[10];
// sprintf(rtcDate, lcd_data[1]);
// root.printTo(Serial);
// // Serial << s.available() << endl;
// // s.flush();
// // Serial << (char)s.read() << endl;
// // sensors.requestTemperatures();
// // char str_temp[6];
// // dtostrf(sensors.getTempCByIndex(0), 1, 1, str_temp);
// // sprintf(a, "%s", str_temp);
// // tft.drawString(str_temp, coordinates.x[3], coordinates.y[3], 2);
// // Serial.println(sensors.getTempCByIndex(0));
// delay(50);
// }
// sensors.requestTemperatures();
// Serial.println(sensors.getTempCByIndex(0));
// delay(1000);
@ -176,24 +188,30 @@ void loop()
// char b[10];
// char str_temp[6];
// saveTemperatureJson();
StaticJsonBuffer<200> jsonBuffer;
// StaticJsonBuffer<200> jsonBuffer;
DynamicJsonBuffer jsonBuffer(100);
JsonObject &root = jsonBuffer.createObject();
if (root == JsonObject::invalid())
if (!root.success())
{
Serial.println("Error creating temperature json");
Log.error("Error creating temperature json");
}
JsonArray &temperatures = root.createNestedArray("temperatures");
// temperatures.add(sensors.getTempCByIndex(0));
float temp = sensors.getTempCByIndex(0);
temperatures.add(temp);
temperatures.add(temp);
root.prettyPrintTo(Serial);
// Serial << "Sensor" << endl;
float temp1 = sensors.getTempCByIndex(0);
// Serial << "Sensor" << endl;
float temp2 = sensors.getTempCByIndex(1);
temperatures.add(temp1);
temperatures.add(temp2);
// root.prettyPrintTo(Serial);
root.prettyPrintTo(temperaturesJson);
// dtostrf(sensors.getTempCByIndex(0), 1, 1, str_temp);
// sprintf(b, "%s", str_temp);
// tft.drawString(str_temp, coordinates.x[3], coordinates.y[3], 2);
// Serial.println(sensors.getTempCByIndex(0));
// Serial << "Delay: " << delayInMillisSensors << endl;
// Serial << "Requesting temperatures" << endl;
sensors.requestTemperatures();
// delayInMillisSensors = 750 / (1 << (12 - SENSOR_RESOLUTION));
lastTempRequest = millis();
@ -209,10 +227,23 @@ void startWiFi()
Serial.print(ssid);
Serial.println("\" started\r\n");
wifiMulti.addAP("Rohan-2", "coldpark735"); // add Wi-Fi networks you want to connect to
// wifiMulti.addAP("Rohan-1", "Mir@1932");
wifiMulti.addAP("Rohan-3", "coldpark735");
// wifiMulti.addAP(wifiMultiSSID, wifiMultiPassword);
// #ifdef WIFI_SSID
// const char *wifiMultiSSID = WIFI_SSID;
// Serial << "Macro " << WIFI_SSID;
// // wifiMulti.addAP(LC_WIFI_SSID, "");
// #else
// const char *wifiMultiSSID = "ssid";
// #endif
// #ifdef WIFI_PASS
// const char *wifiMultiPassword = WIFI_PASS;
// #else
// const char *wifiMultiPassword = "password";
// #endif
// wifiMulti.addAP(wifiMultiSSID, wifiMultiPassword);
Serial.print(F("MAC: "));
Serial.println(WiFi.macAddress());
@ -303,11 +334,13 @@ void startMDNS()
}
void startServer()
{ // Start a HTTP server with a file read handler and an upload handler
server.on("/edit.html", HTTP_POST, []() { // If a POST request is sent to the /edit.html address,
server.send(200, "text/plain", "");
},
handleFileUpload); // go to 'handleFileUpload'
{ // Start a HTTP server with a file read handler and an upload handler
server.on(
"/edit.html", HTTP_POST, []() { // If a POST request is sent to the /edit.html address,
// server.send(200, "text/plain", "");
server.send(200);
},
handleFileUpload); // go to 'handleFileUpload'
server.onNotFound(handleNotFound); // if someone requests any other file or page, go to function 'handleNotFound'
// and check if the file exists
@ -316,10 +349,12 @@ void startServer()
server.on("/manualMode.html", HTTP_POST, handleManual);
server.on("/api/get/temperatures", HTTP_GET, []() {
sendCors();
server.send(200, "application/json", temperaturesJson);
});
server.on("/api/get/date", HTTP_GET, []() {
sendCors();
server.send(200, "text/plain", rtcDate);
});
@ -358,22 +393,31 @@ bool handleFileRead(String path)
return false;
}
void saveTemperatureJson()
void sendCors()
{
server.sendHeader("Access-Control-Allow-Origin", "*");
server.sendHeader("Access-Control-Max-Age", "10000");
server.sendHeader("Access-Control-Allow-Methods", "PUT,POST,GET,OPTIONS");
server.sendHeader("Access-Control-Allow-Headers", "*");
}
void saveTemperatureJson(DallasTemperature &sensors)
{
StaticJsonBuffer<200> jsonBuffer;
JsonObject &root = jsonBuffer.createObject();
if (root == JsonObject::invalid())
if (!root.success())
{
Serial.println("Error");
Log.error("Error creating temperature json object");
}
// JsonArray &data = root.createNestedArray("data");
// data.add(48);
// data.add(2);
JsonArray &temperatures = root.createNestedArray("temperatures");
float temp = sensors.getTempCByIndex(0);
temperatures.add(temp);
temperatures.add(temp);
float temp1 = sensors.getTempCByIndex(0);
float temp2 = sensors.getTempCByIndex(1);
temperatures.add(temp1);
temperatures.add(temp2);
temperatures.add(1);
root.prettyPrintTo(Serial);
root.prettyPrintTo(temperaturesJson);
@ -384,105 +428,50 @@ void saveTemperatureJson()
// }
// File settingsFile = SPIFFS.open("/temperatures.txt", "w");
// if (!settingsFile)
// Serial.println("Error wriing json to file");
// Log.error("Error wriing json to file");
// root.prettyPrintTo(settingsFile); //Export and save JSON object to SPIFFS area
// Serial.println("Json written to file");
// settingsFile.close();
}
void saveSettings1()
{
int shour = server.arg("shour").toInt();
int smin = server.arg("smin").toInt();
int fadePeriod = server.arg("fadePeriod").toInt();
int ehour = server.arg("ehour").toInt();
int emin = server.arg("emin").toInt();
StaticJsonBuffer<200> jsonBuffer1;
JsonObject &root = jsonBuffer1.createObject();
if (root == JsonObject::invalid())
{
Serial.println("Error");
}
root["shour1"] = shour;
root["fadePeriod1"] = fadePeriod;
root["smin1"] = smin;
root["ehour"] = ehour;
root["emin"] = emin;
root.prettyPrintTo(Serial);
if (SPIFFS.exists("/settingsFile1.txt"))
{
SPIFFS.remove("/settingsFile1.txt");
Serial.println("Old settings file removed");
}
File settingsFile = SPIFFS.open("/settingsFile1.txt", "w");
if (!settingsFile)
Serial.println("Error wriing json to file");
root.prettyPrintTo(settingsFile); //Export and save JSON object to SPIFFS area
Serial.println("Json written to file");
settingsFile.close();
}
void saveSettings2()
{
int shour = server.arg("shour").toInt();
int smin = server.arg("smin").toInt();
int fadePeriod = server.arg("fadePeriod").toInt();
int ehour = server.arg("ehour").toInt();
int emin = server.arg("emin").toInt();
StaticJsonBuffer<200> jsonBuffer7;
JsonObject &root = jsonBuffer7.createObject();
if (root == JsonObject::invalid())
{
Serial.println("Error");
}
root["shour2"] = shour;
root["fadePeriod2"] = fadePeriod;
root["smin2"] = smin;
root["ehour"] = ehour;
root["emin"] = emin;
root.prettyPrintTo(Serial);
if (SPIFFS.exists("/settingsFile2.txt"))
{
SPIFFS.remove("/settingsFile2.txt");
Serial.println("Old settings file removed");
}
File settingsFile = SPIFFS.open("/settingsFile2.txt", "w");
if (!settingsFile)
Serial.println("Error writing json to file");
root.prettyPrintTo(settingsFile); //Export and save JSON object to SPIFFS area
Serial.println("Json written to file");
settingsFile.close();
}
void saveSettings3()
void saveSettings(ESP8266WebServer &server, int num)
{
int shour = server.arg("shour").toInt();
int smin = server.arg("smin").toInt();
int fadePeriod = server.arg("fadePeriod").toInt();
int ehour = server.arg("ehour").toInt();
int emin = server.arg("emin").toInt();
StaticJsonBuffer<200> jsonBuffer8;
JsonObject &root = jsonBuffer8.createObject();
if (root == JsonObject::invalid())
Log.notice("Ballast num = %d", num);
const int shour = server.arg("shour").toInt();
const int smin = server.arg("smin").toInt();
const int fadePeriod = server.arg("fadePeriod").toInt();
const int ehour = server.arg("ehour").toInt();
const int emin = server.arg("emin").toInt();
StaticJsonBuffer<200> jsonBuffer;
JsonObject &root = jsonBuffer.createObject();
if (!root.success())
{
Serial.println("Error");
Log.error("Error creating json");
return;
}
root["shour3"] = shour;
root["fadePeriod3"] = fadePeriod;
root["smin3"] = smin;
root["shour"] = shour;
root["fadePeriod"] = fadePeriod;
root["smin"] = smin;
root["ehour"] = ehour;
root["emin"] = emin;
root.prettyPrintTo(Serial);
if (SPIFFS.exists("/settingsFile3.txt"))
char buf[40] = "";
sprintf(buf, "/settingsFile%d.txt", num);
Log.verbose("Settings file chosen = %s", buf);
if (SPIFFS.exists(buf))
{
SPIFFS.remove("/settingsFile3.txt");
Serial.println("Old settings file removed");
SPIFFS.remove(buf);
Log.notice("Old settings file removed");
}
File settingsFile = SPIFFS.open("/settingsFile3.txt", "w");
File settingsFile = SPIFFS.open(buf, "w");
if (!settingsFile)
Serial.println("Error writing json to file");
root.prettyPrintTo(Serial);
Log.error("Error opening settings file - %d", num);
root.prettyPrintTo(settingsFile); //Export and save JSON object to SPIFFS area
Serial.println("Json written to file");
Log.notice("Json written to file");
settingsFile.close();
// delete server;
}
void combineSettings()
{
File file1 = SPIFFS.open("/settingsFile1.txt", "r");
@ -540,30 +529,30 @@ void combineSettings()
root4["smin3"]=root3["smin3"];
root4["fadePeriod3"]=root3["fadePeriod3"];*/
DynamicJsonBuffer jsonBuffer(bufferSize);
DynamicJsonBuffer jsonBuffer(JSON_BUFFER_SIZE);
JsonObject &root = jsonBuffer.createObject();
JsonArray &settings = root.createNestedArray("settings");
JsonObject &settings_0 = settings.createNestedObject();
settings_0["shour"] = root1["shour1"];
settings_0["fadePeriod"] = root1["fadePeriod1"];
settings_0["smin"] = root1["smin1"];
settings_0["shour"] = root1["shour"];
settings_0["fadePeriod"] = root1["fadePeriod"];
settings_0["smin"] = root1["smin"];
settings_0["ehour"] = root1["ehour"];
settings_0["emin"] = root1["emin"];
JsonObject &settings_1 = settings.createNestedObject();
settings_1["shour"] = root2["shour2"];
settings_1["fadePeriod"] = root2["fadePeriod2"];
settings_1["smin"] = root2["smin2"];
settings_1["shour"] = root2["shour"];
settings_1["fadePeriod"] = root2["fadePeriod"];
settings_1["smin"] = root2["smin"];
settings_1["ehour"] = root2["ehour"];
settings_1["emin"] = root2["emin"];
JsonObject &settings_2 = settings.createNestedObject();
settings_2["shour"] = root3["shour3"];
settings_2["fadePeriod"] = root3["fadePeriod3"];
settings_2["smin"] = root3["smin3"];
settings_2["shour"] = root3["shour"];
settings_2["fadePeriod"] = root3["fadePeriod"];
settings_2["smin"] = root3["smin"];
settings_2["ehour"] = root3["ehour"];
settings_2["emin"] = root3["emin"];
@ -584,11 +573,76 @@ void combineSettings()
file4.close();
file5.close();
}
void combineSettings_new()
{
const File file1 = SPIFFS.open("/settingsFile1.txt", "r");
const File file2 = SPIFFS.open("/settingsFile2.txt", "r");
const File file3 = SPIFFS.open("/settingsFile3.txt", "r");
File file5 = SPIFFS.open("/manualMode.txt", "r");
if (SPIFFS.exists("/combinedSettingsFile.txt"))
{
SPIFFS.remove("/combinedSettingsFile.txt");
}
File file_arr[] = {file1, file2, file3};
File file4 = SPIFFS.open("/combinedSettingsFile.txt", "w");
StaticJsonBuffer<JSON_BUFFER_SIZE> jsonBuffer;
JsonObject &root = jsonBuffer.createObject();
JsonArray &settings = root.createNestedArray("settings");
StaticJsonBuffer<50> jsonBufferManual;
size_t size_manual = file5.size();
unique_ptr<char[]> buf_manual(new char[size_manual]);
file5.readBytes(buf_manual.get(), size_manual);
JsonObject &root_manual = jsonBufferManual.parseObject(buf_manual.get());
for (int i = 0; i < 3; i++)
{
const size_t file_size = file_arr[i].size();
const unique_ptr<char[]> buf(new char[file_size]);
file_arr[i].readBytes(buf.get(), file_size);
StaticJsonBuffer<(JSON_BUFFER_SIZE / 3) + 50> jsonBuffer;
JsonObject &root_i = jsonBuffer.parseObject(buf.get());
if (!root_i.success())
{
Log.error(F("Error creating json for file %d"), i + 1);
}
else
{
JsonObject &settings_i = settings.createNestedObject();
settings_i["shour"] = root_i["shour"];
settings_i["fadePeriod"] = root_i["fadePeriod"];
settings_i["smin"] = root_i["smin"];
settings_i["ehour"] = root_i["ehour"];
settings_i["emin"] = root_i["emin"];
// Log.notice("inside array temp");
// char buf[JSON_BUFFER_SIZE / 3];
// root_i.prettyPrintTo(buf);
// Log.trace("%s", buf);
Log.trace("Printing settings %d", i + 1);
// settings_i.prettyPrintTo(Serial);
// root.prettyPrintTo(Serial);
// settings.prettyPrintTo(Serial);
file_arr[i].close();
}
}
root["manual"] = root_manual["manual"];
Log.trace("Printing final root");
root.prettyPrintTo(Serial);
root.prettyPrintTo(file4);
file4.close();
file5.close();
}
/*void displaySettings()
{
File file = SPIFFS.open("/settingsFile.txt", "r");
if (!file){
Serial.println("Error reading settings file or file does not exist");
Log.error("Error reading settings file or file does not exist");
} else {
size_t size = file.size();
if ( size == 0 ) {
@ -599,7 +653,7 @@ void combineSettings()
StaticJsonBuffer<200> jsonBuffer2;
JsonObject& root = jsonBuffer2.parseObject(buf.get());
if (!root.success()) {
Serial.println("Error reading settings file");
Log.error("Error reading settings file");
} else {
Serial.println("Settings file loaded");
root.prettyPrintTo(Serial);
@ -615,30 +669,30 @@ void displayCombinedSettings()
File file = SPIFFS.open("/combinedSettingsFile.txt", "r");
if (!file)
{
Serial.println("Error reading settings file or file does not exist");
Log.error("Error reading combined settings file or file does not exist");
}
else
{
Serial.println("Settings file exists");
Log.notice("Settings file exists");
size_t size = file.size();
if (size == 0)
{
Serial.println("Settings file is empty");
Log.notice("Settings file is empty");
}
else
{
std::unique_ptr<char[]> buf5(new char[size]);
file.readBytes(buf5.get(), size);
// StaticJsonBuffer<300> jsonBuffer;
DynamicJsonBuffer jsonBuffer(bufferSize);
DynamicJsonBuffer jsonBuffer(JSON_BUFFER_SIZE);
JsonObject &root5 = jsonBuffer.parseObject(buf5.get());
if (!root5.success())
{
Serial.println("Error reading combined settings file");
Log.error("Error reading combined settings file");
}
else
{
Serial.println("Settings file loaded");
Log.notice("Settings file loaded");
root5.prettyPrintTo(Serial);
// digitalWrite(ESP_TO_ARDUINO_PIN,0);
// analogWrite(ESP_TO_ARDUINO_PIN,255);
@ -674,31 +728,22 @@ void handleManual()
}
void handleSettings()
{
if (server.arg("ballast").toInt() == 1)
handleSettings1();
else if (server.arg("ballast").toInt() == 2)
handleSettings2();
else if (server.arg("ballast").toInt() == 3)
handleSettings3();
displayCombinedSettings();
// if (server.arg("ballast").toInt() == 1)
// handleSettings1();
// else if (server.arg("ballast").toInt() == 2)
// handleSettings2();
// else if (server.arg("ballast").toInt() == 3)
// handleSettings3();
// displayCombinedSettings();
// server.sendHeader("Location", "/settings.html"); // Redirect the client to the success page
server.send(200);
}
void handleSettings1()
{
saveSettings1();
combineSettings();
}
void handleSettings2()
{
saveSettings2();
combineSettings();
}
void handleSettings3()
{
saveSettings3();
const int ballast_num = server.arg("ballast").toInt();
Log.notice("Chosen num = %d", ballast_num);
saveSettings(server, ballast_num);
combineSettings();
displayCombinedSettings();
server.send(200);
}
void handleFileUpload()
{ // upload a new file to the SPIFFS
HTTPUpload &upload = server.upload();
@ -741,6 +786,14 @@ void handleFileUpload()
}
}
// const char *text = R"(
// { " "
// ;''
// }
// qegqeg
// qegq
// )";
void webSocketEvent(uint8_t num, WStype_t type, uint8_t *payload, size_t lenght)
{ // When a WebSocket message is received
switch (type)
@ -777,6 +830,10 @@ void webSocketEvent(uint8_t num, WStype_t type, uint8_t *payload, size_t lenght)
rainbow = false;
}
break;
default:
{
Log.error("Unsupported operation - number %d", type);
}
}
}
@ -796,6 +853,8 @@ String formatBytes(size_t bytes)
{
return String(bytes / 1024.0 / 1024.0) + "MB";
}
else
return "";
}
String getContentType(String filename)
@ -847,3 +906,15 @@ void setHue(int hue)
// analogWrite(LED_GREEN, g);
// analogWrite(LED_BLUE, b);
}
void printTimestamp(Print *_logOutput)
{
char c[12];
int m = sprintf(c, "%10lu ", millis());
_logOutput->print(c);
}
void printNewline(Print *_logOutput)
{
_logOutput->print('\n');
}

16
src/sketch_oct17esp.hpp

@ -1,12 +1,8 @@
// /* This file was automatically generated. Do not edit! */
// #undef INTERFACE
void handleSettings3();
void handleSettings2();
void handleSettings1();
void combineSettings();
void saveSettings3();
void saveSettings2();
void saveSettings1();
void saveSettings(ESP8266WebServer& server, int num);
void saveTemperaturesJson(DallasTemperature& sensors);
String getContentType(String filename);
bool handleFileRead(String path);
void handleManual();
@ -36,4 +32,10 @@ extern const char *OTAName;
extern const char *password;
extern const char *ssid;
extern File fsUploadFile;
extern ESP8266WiFiMulti wifiMulti;
extern ESP8266WiFiMulti wifiMulti;
// ///////////////////
void sendCors();
void printTimestamp(Print *_logOutput);
void printNewline(Print *_logOutput);
Loading…
Cancel
Save