merge upstream from origin/master

This commit is contained in:
MaBecker 2017-02-28 07:24:55 +01:00
commit 07a5717611
108 changed files with 7420 additions and 493 deletions

3
.gitignore vendored
View File

@ -1,5 +1,6 @@
*~
*.tgz
*.d
*.o
*.elf
/*.hex
@ -30,3 +31,5 @@ xtensa-lx106-elf
*.c#
/function_keywords.js
/functions.html
targetlibs/nrf5x/examples
/.vscode

View File

@ -39,7 +39,7 @@ compiler:
env:
global:
#- RELEASE=1
- RELEASE=1
- TRAVIS=1
- V=0
- ESP8266_SDK_ROOT=$TRAVIS_BUILD_DIR/esp_iot_sdk_v2.0.0.p1
@ -63,6 +63,7 @@ env:
- LCTECH_STM32F103RBT6=1
- LINUX_BUILD=1
- EFM32GGSTK=1
- NUCLEOL476RG=1
script: make
notifications:

View File

@ -6,6 +6,14 @@
Puck.js: Allow Puck.IR to take pins for external IR LED (fix #927)
nRF52: Allow arbitrary NFC data to be specified (fix #1021)
nRF5x: Allow multiple advertising packets to be set at once with NRF.setAdvertising
nRF52: Add 'properties' object to BluetoothRemoteGATTCharacteristic
nRF52: Perform write without response if that is what is required
Pico/WiFi: Allow USB HID to work on Windows (from @nailxx)
Allow Puck.js/nRF52 devices to drive Neopixel/WS281x/APA10x LEDs with E.neopixelWrite (fix #1023)
Fix crash in JSON.stringify for zero-length typed arrays
Fix precedence of 'void' keyword (fix #1079)
nRF52: Add BluetoothRemoteGATTCharacteristic.startNotifications (fix #959)
nRF52: Added BluetoothDevice.gattserverdisconnected event
1v91 : Fix recent regression if no Boot Code defined at startup
Fix handling of return of rejected promise within a promise

View File

@ -1,9 +1,9 @@
FROM ubuntu:14.04
RUN apt-get update && apt-get install -y software-properties-common && apt-get update \
&& add-apt-repository ppa:terry.guo/gcc-arm-embedded \
&& add-apt-repository ppa:team-gcc-arm-embedded/ppa \
&& apt-get update \
&& apt-get install -y git gcc-arm-none-eabi build-essential python
&& apt-get install -y git gcc-arm-embedded build-essential python
RUN git clone https://github.com/espruino/Espruino espruino
WORKDIR /espruino

203
Makefile Executable file → Normal file
View File

@ -46,6 +46,7 @@
# MINISTM32_ANGLED_VE=1
# MINISTM32_ANGLED_VG=1
# ESP8266_BOARD=1 # ESP8266
# ESP32=1 # ESP32
# EFM32GGSTK=1 # Currently only works with DEBUG=1
# EMW3165=1 # MXCHIP EMW3165: STM32F411CE, BCM43362, 512KB flash 128KB RAM
# Or nothing for standard linux compile
@ -76,6 +77,7 @@
# VARIABLES=1700 # Sets number of variables for project defined firmware. This parameter can be dangerous, be careful before changing.
# # used in build_platform_config.py
# NO_COMPILE=1 # skips compiling and linking part, used to echo WRAPPERSOURCES only
# RTOS # adds RTOS functions, available only for ESP32 (yet)
ifndef GENDIR
GENDIR=$(shell pwd)/gen
@ -564,6 +566,17 @@ USE_FILESYSTEM=1
USE_GRAPHICS=1
USE_NET=1
else ifdef ESP32
BOARD=ESP32
EMBEDDED=1
USE_NET=1
#USE_HASHLIB=1
USE_GRAPHICS=1
USE_CRYPTO=1
USE_TLS=1
USE_TELNET=1
DEFINES+=-DESP_PLATFORM -DESP32=1
OPTIMIZEFLAGS+=-Og
else ifdef ESP8266_BOARD
RELEASE=1
@ -758,6 +771,8 @@ ifdef WIZNET
USE_WIZNET=1
else ifeq ($(FAMILY),ESP8266)
USE_ESP8266=1
else ifeq ($(FAMILY),ESP32)
USE_ESP32=1
else ifdef EMW3165
USE_WICED=1
else
@ -1012,6 +1027,26 @@ ifdef USE_NET
targetlibs/wiced/wwd/internal/bus_protocols/SDIO/wwd_bus_protocol.c
endif
ifdef USE_ESP32
DEFINES += -DUSE_ESP32
WRAPPERSOURCES += libs/network/esp32/jswrap_esp32_network.c \
targets/esp32/jswrap_esp32.c
INCLUDE += -I$(ROOT)/libs/network/esp32
SOURCES += libs/network/esp32/network_esp32.c \
targets/esp32/i2c.c \
targets/esp32/spi.c \
targets/esp32/jshardwareUart.c \
targets/esp32/jshardwareAnalog.c \
targets/esp32/jshardwarePWM.c \
targets/esp32/rtosutil.c \
targets/esp32/jshardwareTimer.c \
targets/esp32/jshardwarePulse.c
ifdef RTOS
DEFINES += -DRTOS
WRAPPERSOURCES += targets/esp32/jswrap_rtos.c
endif # RTOS
endif # USE_ESP32
ifdef USE_ESP8266
DEFINES += -DUSE_ESP8266
WRAPPERSOURCES += libs/network/esp8266/jswrap_esp8266_network.c \
@ -1419,7 +1454,7 @@ ifeq ($(FAMILY), NRF52)
PRECOMPILED_OBJS += $(NRF5X_SDK_PATH)/components/toolchain/gcc/gcc_startup_nrf52.o
DEFINES += -DSWI_DISABLE0 -DSOFTDEVICE_PRESENT -DNRF52 -DCONFIG_GPIO_AS_PINRESET -DS132 -DBLE_STACK_SUPPORT_REQD
DEFINES += -DNRF_SD_BLE_API_VERSION=3
DEFINES += -DNRF_SD_BLE_API_VERSION=3
SOFTDEVICE = $(NRF5X_SDK_PATH)/components/softdevice/s132/hex/s132_nrf52_3.0.0_softdevice.hex
@ -1441,6 +1476,9 @@ ifeq ($(FAMILY), NRF52)
# BLE HID Support (only NRF52)
INCLUDE += -I$(NRF5X_SDK_PATH)/components/ble/ble_services/ble_hids
TARGETSOURCES += $(NRF5X_SDK_PATH)/components/ble/ble_services/ble_hids/ble_hids.c
# Neopixel support (only NRF52)
INCLUDE += -I$(NRF5X_SDK_PATH)/components/drivers_nrf/i2s
TARGETSOURCES += $(NRF5X_SDK_PATH)/components/drivers_nrf/i2s/nrf_drv_i2s.c
endif #FAMILY == NRF52
@ -1492,15 +1530,20 @@ ifdef NRF5X
targets/nrf5x/bluetooth.c \
targets/nrf5x/bluetooth_utils.c \
targets/nrf5x/nrf5x_utils.c
ifeq ($(FAMILY), NRF52)
# Neopixel support (only NRF52)
SOURCES += targets/nrf5x/i2s_ws2812b_drive.c
endif
endif
# Careful here.. All these includes and sources assume a SoftDevice. Not efficeint/clean if softdevice (ble) is not enabled...
INCLUDE += -I$(NRF5X_SDK_PATH)/components
INCLUDE += -I$(NRF5X_SDK_PATH)/components/toolchain/cmsis/include
INCLUDE += -I$(NRF5X_SDK_PATH)/components/toolchain/gcc
INCLUDE += -I$(NRF5X_SDK_PATH)/components/toolchain
INCLUDE += -I$(NRF5X_SDK_PATH)/components/libraries/log
INCLUDE += -I$(NRF5X_SDK_PATH)/components/libraries/log/src
INCLUDE += -I$(NRF5X_SDK_PATH)/components/toolchain/cmsis/include
INCLUDE += -I$(NRF5X_SDK_PATH)/components/toolchain/gcc
INCLUDE += -I$(NRF5X_SDK_PATH)/components/toolchain
INCLUDE += -I$(NRF5X_SDK_PATH)/components/libraries/log
INCLUDE += -I$(NRF5X_SDK_PATH)/components/libraries/log/src
INCLUDE += -I$(NRF5X_SDK_PATH)/components/drivers_nrf/config
INCLUDE += -I$(NRF5X_SDK_PATH)/components/libraries/fstorage/config
INCLUDE += -I$(NRF5X_SDK_PATH)/components/libraries/util
@ -1684,6 +1727,12 @@ ifeq ($(FAMILY), EFM32GG)
endif #FAMILY == EFM32
ifeq ($(FAMILY),ESP32)
CFLAGS+=-Og -Wpointer-arith -Wno-error=unused-function -Wno-error=unused-but-set-variable \
-Wno-error=unused-variable -Wall -ffunction-sections -fdata-sections -mlongcalls -nostdlib \
-MMD -MP -std=gnu99 -fstrict-volatile-bitfields -fgnu89-inline
SOURCES += targets/esp32/jshardware.c
endif
ifeq ($(FAMILY),ESP8266)
# move os_printf strings into flash to save RAM space
@ -1844,6 +1893,101 @@ ifdef LINKER_FILE
LDFLAGS += -T$(LINKER_FILE)
endif
#
# Definitions for the build of the ESP32
#
ifdef ESP32
ifndef ESP_IDF_PATH
$(error "The ESP_IDF_PATH variable must be set")
endif
ifndef ESP_APP_TEMPLATE_PATH
$(error "The ESP_APP_TEMPLATE_PATH variable must be set")
endif
# The prefix for the ESP32 compiler
CCPREFIX=xtensa-esp32-elf-
SOURCES += targets/esp32/main.c
LDFLAGS += -L$(ESP_IDF_PATH)/ld \
-L$(ESP_IDF_PATH)/components/bt/lib \
-L$(ESP_IDF_PATH)/components/esp32/lib \
-L$(ESP_APP_TEMPLATE_PATH)/build/bootloader \
-L$(ESP_APP_TEMPLATE_PATH)/build/bt \
-L$(ESP_APP_TEMPLATE_PATH)/build/driver \
-L$(ESP_APP_TEMPLATE_PATH)/build/esp32 \
-L$(ESP_APP_TEMPLATE_PATH)/build/esptool_py \
-L$(ESP_APP_TEMPLATE_PATH)/build/expat \
-L$(ESP_APP_TEMPLATE_PATH)/build/freertos \
-L$(ESP_APP_TEMPLATE_PATH)/build/json \
-L$(ESP_APP_TEMPLATE_PATH)/build/log \
-L$(ESP_APP_TEMPLATE_PATH)/build/lwip \
-L$(ESP_APP_TEMPLATE_PATH)/build/mbedtls \
-L$(ESP_APP_TEMPLATE_PATH)/build/newlib \
-L$(ESP_APP_TEMPLATE_PATH)/build/nghttp \
-L$(ESP_APP_TEMPLATE_PATH)/build/nvs_flash \
-L$(ESP_APP_TEMPLATE_PATH)/build/partition_table \
-L$(ESP_APP_TEMPLATE_PATH)/build/spi_flash \
-L$(ESP_APP_TEMPLATE_PATH)/build/tcpip_adapter \
-L$(ESP_APP_TEMPLATE_PATH)/build/vfs \
-L$(ESP_APP_TEMPLATE_PATH)/build/newlib \
-L$(ESP_APP_TEMPLATE_PATH)/build/wpa_supplicant \
-L$(ESP_APP_TEMPLATE_PATH)/build/ethernet \
-lgcc
ESPTOOL?=
INCLUDE+=\
-I$(ESP_APP_TEMPLATE_PATH)/build/include \
-I$(ESP_IDF_PATH)/components \
-I$(ESP_IDF_PATH)/components/newlib/include \
-I$(ESP_IDF_PATH)/components/bt/include \
-I$(ESP_IDF_PATH)/components/driver/include \
-I$(ESP_IDF_PATH)/components/esp32/include \
-I$(ESP_IDF_PATH)/components/freertos/include \
-I$(ESP_IDF_PATH)/components/json/include \
-I$(ESP_IDF_PATH)/components/log/include \
-I$(ESP_IDF_PATH)/components/lwip/include/lwip \
-I$(ESP_IDF_PATH)/components/lwip/include/lwip/port \
-I$(ESP_IDF_PATH)/components/lwip/include/lwip/posix \
-I$(ESP_IDF_PATH)/components/newlib/include \
-I$(ESP_IDF_PATH)/components/spi_flash/include \
-I$(ESP_IDF_PATH)/components/nvs_flash/include \
-I$(ESP_IDF_PATH)/components/tcpip_adapter/include \
-I$(ESP_IDF_PATH)/components/vfs/include \
-Itargets/esp32/include
LDFLAGS+=-nostdlib -u call_user_start_cpu0 -Wl,--gc-sections -Wl,-static -Wl,-EL
LIBS+=-T esp32_out.ld \
-T$(ESP_IDF_PATH)/components/esp32/ld/esp32.common.ld \
-T$(ESP_IDF_PATH)/components/esp32/ld/esp32.rom.ld \
-T$(ESP_IDF_PATH)/components/esp32/ld/esp32.peripherals.ld \
$(ESP_IDF_PATH)/components/newlib/lib/libc.a \
$(ESP_IDF_PATH)/components/newlib/lib/libm.a \
-lbt \
-lbtdm_app \
-ldriver \
-lesp32 \
$(ESP_IDF_PATH)/components/esp32/libhal.a \
-lcore \
-lnet80211 \
-lphy \
-lwpa_supplicant \
-lrtc \
-lpp \
-lwpa \
-lexpat \
-lfreertos \
-ljson \
-llog \
-llwip \
-lmbedtls \
-lnghttp \
-lnvs_flash \
-lspi_flash \
-ltcpip_adapter \
-lvfs \
-lnewlib \
-lcoexist \
-lethernet \
-lstdc++ \
-lgcc
endif # ESP32
#
# Definitions for the build of the ESP8266
#
@ -1989,6 +2133,53 @@ proj: $(PLATFORM_CONFIG_FILE) $(PROJ_NAME)
$(PROJ_NAME): $(OBJS)
@echo $($(quiet_)link)
@$(call link)
# Linking for ESP32
else ifdef ESP32
ESP_ZIP = $(PROJ_NAME).tgz
espruino_esp32.bin: $(OBJS)
$(LD) $(LDFLAGS) -o espruino_esp32.elf -Wl,--start-group $(LIBS) $(OBJS) -Wl,--end-group
python $(ESP_IDF_PATH)/components/esptool_py/esptool/esptool.py \
--chip esp32 \
elf2image \
--flash_mode "dio" \
--flash_freq "40m" \
-o espruino_esp32.bin \
espruino_esp32.elf
$(ESP_ZIP): espruino_esp32.bin
$(Q)rm -rf build/$(basename $(ESP_ZIP))
$(Q)mkdir -p build/$(basename $(ESP_ZIP))
$(Q)cp $(ESP_APP_TEMPLATE_PATH)/build/bootloader/bootloader.bin \
espruino_esp32.bin \
$(ESP_APP_TEMPLATE_PATH)/build/partitions_singleapp.bin \
targets/esp32/README_flash.txt \
build/$(basename $(ESP_ZIP))
$(Q)tar -C build -zcf $(ESP_ZIP) ./$(basename $(ESP_ZIP))
proj: espruino_esp32.bin $(ESP_ZIP)
flash:
python $(ESP_IDF_PATH)/components/esptool_py/esptool/esptool.py \
--chip esp32 \
--port "/dev/ttyUSB0" \
--baud 921600 \
write_flash \
-z \
--flash_mode "dio" \
--flash_freq "40m" \
0x1000 $(ESP_APP_TEMPLATE_PATH)/build/bootloader/bootloader.bin \
0x10000 espruino_esp32.bin \
0x8000 $(ESP_APP_TEMPLATE_PATH)/build/partitions_singleapp.bin
erase_flash:
python $(ESP_IDF_PATH)/components/esptool_py/esptool/esptool.py \
--chip esp32 \
--port "/dev/ttyUSB0" \
--baud 921600 \
erase_flash
else ifdef ESP8266
# Linking the esp8266... The Espruino source files get compiled into the .text section. The

View File

@ -87,13 +87,17 @@ If you are a board manufacturer interested in getting your board officially supp
* [Original Espruino Board](http://www.espruino.com/EspruinoBoard) - great support.
* [Espruino Pico Board](http://www.espruino.com/Pico) - great support.
* [Puck.js](http://www.espruino.com/Puck.js) - great support.
* [Espruino WiFi Board](http://www.espruino.com/WiFi) - great support.
* Linux - WORKING
* [BBC micro:bit](http://www.espruino.com/MicroBit) - WORKING
* [STM32VLDISCOVERY](http://www.espruino.com/ReferenceSTM32VLDISCOVERY) - WORKING - limited memory so some features removed
* [STM32F3DISCOVERY](http://www.espruino.com/ReferenceSTM32F3DISCOVERY) - USB BROKEN
* [STM32F4DISCOVERY](http://www.espruino.com/ReferenceSTM32F4DISCOVERY) - WORKING
* STM32F401CDISCOVERY - appears WORKING, but very little testing done
* STM32F429IDISCOVERY - WORKING over serial (A9/A10). No USB and no LCD support
* NRF52832 Preview Development Kit - WORKING with limited functionality. Able to interface with Espruino over BLE (send commands from smartphone or computer) or serial as normal (send commands from chrome IDE or terminal).
* NRF51822 Development Kit - WORKING
* NRF52832 Development Kit - WORKING
* [HY STM32 2.4"](http://www.espruino.com/ReferenceHYSTM32_24) - WORKING
* [HY STM32 2.8"](http://www.espruino.com/ReferenceHYSTM32_28) - WORKING - limited memory so some features removed
* [HY STM32 3.2"](http://www.espruino.com/ReferenceHYSTM32_32) - WORKING
@ -104,8 +108,7 @@ If you are a board manufacturer interested in getting your board officially supp
* LC-TECH STM32F103RBT6 - WORKING, but with some issues (LED inverted logic, BTN needs pullup to work)
* [ST NUCLEO-F401RE](http://www.espruino.com/ReferenceNUCLEOF401RE) - WORKING
* ST NUCLEO-F411RE - WORKING
* ESP8266 - Beta - Reasonably stable, but expect to find issues
* NRF51/52 - Alpha - very early in development (GPIO, but not peripherals, no sleep or save)
* ESP8266 - WORKING - Reasonably stable, but expect to find issues
* Arduino (AVR) - NOT POSSIBLE due to the Hardward architecture of AVRs, even though it would fit into an ATMEGA2560. If `avr-gcc` ever gains an easy way to emulate Von Neumann architecture then it might be portable, but for now it isn't.
* Arduino (ARM) - very doable, but no work has been done on this.

View File

@ -1,24 +1,111 @@
Building
========
# Building
**Note:** If you're swapping between compiling for different targets, **you
need to call `make clean`** before you compile for the new target.
There are several options to building Espruino on various platforms for the OS and board versions that are avaiable.
Under Linux
-----------
To build, and run, Espruino on the OS that one is using is as simple as the following, if prerequisits are met:
Espruino is easy to build under Linux, and it is possible to build under MacOS with some effort. If you don't have Linux it's **much** easier to install it in a Virtual Machine. See the heading **Building under Windows/MacOS with a VM** below for more information.
```bash
make clean && make
```
### for STM32 Boards (incl. [Espruino Board](http://www.espruino.com/EspruinoBoard))
**Note:**
The (previously suggested) CodeSourcery GCC compiler is no longer available. We'd suggest you use [gcc-arm-none-eabi](https://launchpad.net/gcc-arm-embedded/+download).
* In general, have a look through the Makefile to see what other options are available
* If you're swapping between compiling for different targets, you need to call `make clean` before you compile for the new target.
* If you have a ld error, check the board name in the BOARDNAME=1 make in the Makefile.
* ```RELEASE=1``` for performance and code size, without it, assertions are kept for debugging.
* ```DEBUG=1``` is available.
Download the compiler, set up your path so you have access to it, and run:
## Under Linux
```YOUR_BOARD_NAME=1 RELEASE=1 make```
Espruino is easy to build under Linux, for either for Espruino running on Linux or a board.
The current reference OS for building is Ubuntu 16.04.1 LTS, and the following can ensure problem free development:
### for Espruino
```bash
sudo apt-get update
sudo apt-get install -y \
build-essential git python python-pip
sudo pip install --upgrade pip
# User choice for placement of source repos
mkdir -p ~/source/repos/github/espruino
cd ~/source/repos/github/espruino
git clone https://github.com/espruino/Espruino.git
cd Espruino
make clean && make
chmod +x espruino && sudo cp espruino /usr/local/bin
```
### for an example of cross compilation for the puck.js
Having successfully created an native OS Espruino, try a cross compilation.
```bash
sudo apt-get update
sudo pip install nrfutil
sudo apt-get install -y \
lib32z1 lib32ncurses5
wget https://launchpad.net/gcc-arm-embedded/5.0/5-2016-q3-update/+download/gcc-arm-none-eabi-5_4-2016q3-20160926-linux.tar.bz2
tar xjf gcc-arm-none-eabi-5_4-2016q3-20160926-linux.tar.bz2
sudo mv gcc-arm-none-eabi-5_4-2016q3-20160926 /usr/local
export PATH=/usr/local/gcc-arm-none-eabi-5_4-2016q3/bin:$PATH
cd ~/source/repos/github/espruino/Espruino
make clean && DFU_UPDATE_BUILD=1 PUCKJS=1 RELEASE=1 make
ls -l *puckjs*
```
## Under MacOS
* It is possible to build Espruino under MacOS with some effort.
* PR for an easy Espruino build under MacOS are welcome.
* If you don't have Linux it's much easier to install it in a Virtual Machine (see below).
## Under Windows
It is possible to build Espruino under Windows with the following addition to the Linux explanation:
* Install Bash on Ubuntu on Windows 10 <https://msdn.microsoft.com/da-dk/commandline/wsl/install_guide>
* After enabling, just use the instructions for Linux
Note:
* there is no access to USB in the present version
* copy any crosscompile output to one's user directory and either bluetooth or USB the result to the target
* Ubuntu 14.04 LTS is the present version.
Or use a Virtual machine as described below dependent on ones taste.
## Cross compilation
### for Raspberry Pi
Using [RASPBIAN JESSIE WITH PIXEL](https://www.raspberrypi.org/downloads/raspbian/), getting Espruino is easy.
To enable the full power of Espruino on the Pi, [WiringPi](http://wiringpi.com/):
* ```sudo apt-get install wiringpi```
Getting Espruino:
* clone this repository and cd into the directory
* ```make clean && make```
* ```chmod +x espruino && sudo cp espruino /usr/local/bin```
### for OpenWRT
Follow the instructions for [OpenWRT build system](https://wiki.openwrt.org/doc/howto/buildroot.exigence)
After a successful OpenWRT build, [OpenWRT Espruino packages](https://github.com/vshymanskyy/OpenWRT-Espruino-packages)
### for STM32 Boards (incl. [Espruino Board](http://www.espruino.com/EspruinoBoard)
```bash
make clean && YOUR_BOARD_NAME=1 RELEASE=1 make
```
* See the top of Makefile for board names
* Without `RELEASE=1`, assertions are kept in the code (which is good for debugging, bad for performance + code size)
* `BOARDNAME=1 RELEASE=1 make serialflash` will flash to /dev/ttyUSB0 using the STM32 serial bootloader (what's needed for the Espruino and HY boards)
* `BOARDNAME=1 RELEASE=1 make flash` will flash using st-flash if it's a discovery board, the maple bootloader if using that board, or will copy the binary to `/media/NUCLEO` if using a Nucleo board.
@ -27,39 +114,64 @@ It may complain that there isn't enough space on the chip. This isn't an issue u
* Disable the check by adding `TRAVIS=1`
* Change the compile flags from `-O3` to `-Os` in the `Makefile`
* Knock out some functionality (like `USE_GRAPHICS=1`) that you don't need in the `Makefile`
* Try different compilers. `codesourcery-2013.05-23-arm-none-eabi` provides low binary size for `-O3`
**Note:** Espruino boards contain a special bootloader at `0x08000000` (the default address), with the Espruino binary moved on 10240 bytes to `0x08002800`. To load the Espruino binary onto a board at the correct address, use `ESPRUINO_1V3=1 RELEASE=1 make serialflash`. If you want to make a binary that contains the bootloader as well as Espruino (like the ones that the Espruino Web IDE expects to use) use the script `scripts/create_espruino_image_1v3.sh` which will compile the bootloader *and* Espruino, and then join them together.
----
### for [Nordic Semiconductor's nRF51/nRF52 series devices](https://www.nordicsemi.com/eng/Products/Bluetooth-low-energy)
### for Nordic Semiconductor's nRF51/nRF52 series devices
Dependant on the board, either usb or bluetooth can be used to program the board or install the bootloader from different devices.
The (previously suggested) CodeSourcery GCC compiler is no longer available. We'd suggest you use [gcc-arm-none-eabi](https://launchpad.net/gcc-arm-embedded/+download).
* Bluetooth Low energy
* the board will appear as `Espruino XYZ` where `XYZ` is the board name
* USB
* the board appears as a drive to drop a hex on
Download the compiler, set up your path so you have access to it, and run:
#### for [puck.js](http://www.espruino.com/Puck.js)
```NRF52832DK=1 RELEASE=1 make```
The puck.js is based on the nRF52
**Note:** This is for the nRF52 devkit, use `NRF51822DK=1` instead for the nRF51 devkit, `MICROBIT=1` for the BBC micro:bit, or check the first 50-ish lines of the `Makefile` for more board options.
```bash
make clean && DFU_UPDATE_BUILD=1 PUCKJS=1 RELEASE=1 make
```
To program the nRF52 Development Kit with Espruino, type `NRF52832DK=1 RELEASE=1 make flash` on Linux. This will copy the generated `espruino_xx.xx_nrf52832.hex` file to the nRF devkit's USB flash drive - you can however do that manually if you want to.
The resulting file is a zip that has to be transferred to the puck.js via a Bluetooth low energy device.
See <https://www.espruino.com/Puck.js+Quick+Start> for information concerning transferring the zip to the puck.js.
Now Espruino is ready to use - you can either use [the Web IDE](http://www.espruino.com/Quick+Start) to connect, or you can use any serial terminal application as long as you connect at 9600 baud (no parity, 1 stop bit).
#### for [NRF52-DK](https://www.nordicsemi.com/eng/Products/Bluetooth-low-energy/nRF52-DK)
You can also connect via Bluetooth Low energy - the board will appear as `Espruino XYZ` where `XYZ` is the board name:
All boards based on the nRF52 have RAM and Flash to support Espruino without feature disablement.
* Use the Nordic UART Android app - install it, connect to the device, and then issue commands. Note that you will have to explicitly send a Carriage Return at the end of any command in order or it to execute (eg. `1+2 [newline]` then click send)
```bash
make clean && NRF52832DK=1 RELEASE=1 make
```
* Use Web Bluetooth - see [The BBC micro:bit page](http://www.espruino.com/MicroBit) for more information about this.
#### for [micro:bit](http://microbit.org/)
----
The micro:bit is based on the nRF51.
* ```make clean && MICROBIT=1 RELEASE=1 make```
* Drop the hex generated on the micro:bit drive and it is then an Espruino.
Note:
* At the time of writing, if one uses the [Espruino Web IDE](https://www.espruino.com/Web+IDE), access the Settings->Communications
* Request board details on connect: false
* Throttle Send: true
#### for [NRF51-DK](https://www.nordicsemi.com/eng/Products/nRF51-DK)
All boards based on the nRF51 are limited in RAM and Flash so many features are disabled.
```bash
make clean && NRF51822DK=1 RELEASE=1 make
```
### for esp8266
In order to compile for the esp8266 on Linux several pre-requisites have to be installed:
- the esp-open-sdk from https://github.com/pfalcon/esp-open-sdk, use make STANDALONE=n
- the Espressif SDK (version 1.5.0 with lwip patch as of this writing) from http://bbs.espressif.com/viewforum.php?f=46 and http://bbs.espressif.com/viewtopic.php?f=7&t=1528
* the esp-open-sdk from <https://github.com/pfalcon/esp-open-sdk>, use make STANDALONE=n
* the Espressif SDK (version 1.5.0 with lwip patch as of this writing) from <http://bbs.espressif.com/viewforum.php?f=46> and <http://bbs.espressif.com/viewtopic.php?f=7&t=1528>
To run make you need to pass a couple of environment variables to `make`. These include:
@ -69,16 +181,18 @@ To run make you need to pass a couple of environment variables to `make`. These
* `PATH=<Path to esp-open-sdk/xtensa-lx106-elf/bin/>`
* `COMPORT=</dev/ttyUSB0|COM1|...>`
The easiest is to place
the following lines into a script, adapt it to your needs and then run it.
```
The easiest is to place the following lines into a script, adapt it to your needs and then run it.
```bash
#! /bin/bash
export ESP8266_BOARD=1
export FLASH_4MB=1
export ESP8266_SDK_ROOT=/esp8266/esp_iot_sdk_v1.5.0
export PATH=$PATH:/esp8266/esp-open-sdk/xtensa-lx106-elf/bin/
export COMPORT=/dev/ttyUSB0
make $*
make clean && make $*
```
* If you do `make flash` it will try to flash your esp8266 module over serial
@ -87,13 +201,12 @@ make $*
* You will also get an `espruino_1v00_*_esp8266.tgz` archive, which contains everything you
need to flash a module (except for esptool.py), including a README_flash.txt
####Building on Eclipse
#### Building on Eclipse
When building on Eclipse, update the Makefile properties to include the definitions show above. The easiest way to achieve
that task is to right-click your Espruino project and select `properties`. From there, navigate to `C/C++ Build > Environment`.
----
### for EMW3165
#### for EMW3165
Note: the emw3165 port is very preliminary and does not include Wifi support at this time.
_The text below is what is planned in order to support Wifi, but it doesn't exist yet._
@ -109,120 +222,99 @@ The strategy employed is to compile portions of WICED into a library using the W
and then linking this into Espruino.
Setting up WICED:
- WICED does not officially support the EMW3165.
- Clone https://github.com/MXCHIP-EMW/WICED-for-EMW and follow the instructions there to configure
* WICED does not officially support the EMW3165.
* Clone <https://github.com/MXCHIP-EMW/WICED-for-EMW> and follow the instructions there to configure
WICED and build it. (You will need to sign up for a developer acct with Broadcom.)
- Build the apsta sample program (snippet) using a command-line like
* Build the apsta sample program (snippet) using a command-line like
`./make EMW3165-FreeRTOS-LwIP-snip.apsta download run JTAG=stlink-v2`
- Hook up your emw3165 to an ST-Link-v2 or your preferred STM32 programmer and flash using the
* Hook up your emw3165 to an ST-Link-v2 or your preferred STM32 programmer and flash using the
above command-line. You should see the EMW's access point.
- An alternative program to test with is the "scan" snip as it will also print something on the
* An alternative program to test with is the "scan" snip as it will also print something on the
console (works well with the WifiMCU board): `./make EMW3165-FreeRTOS-LwIP-snip.scan ...`
Compiling WICED into a library:
- ... if only this worked ...
* ... if only this worked ...
Compiling Espruino:
- To compile Espruino you will need to point to the WICED root and include files. This is
* To compile Espruino you will need to point to the WICED root and include files. This is
done by specifying a WICED_ROOT environment variable.
- Adapt the pathnames from the following script:
```
* Adapt the pathnames from the following script:
```bash
WICED_ROOT=/home/emw3165/WICED-for-EMW/WICED-SDK-3.3.1 make $*
```
----
### for Linux
Simple: Just run `make`
----
### for Raspberry Pi
On the Pi, just run `make`.
Or to cross-compile:
```
cd targetlibs
mkdir raspberrypi
cd raspberrypi
git clone git://github.com/raspberrypi/tools.git
sudo apt-get install ia32-libs
## Documentation
```bash
sudo pip install markdown
python scripts/build_docs.py
```
----
### for Carambola (OpenWRT)
To cross compile,
* Follow instructions at <https://github.com/8devices/carambola> to set toolchain up in ```~/workspace/carambola```
* Run ```CARAMBOLA=1 make```
----
### Documentation
```python scripts/build_docs.py ```
This will create a file called ```functions.html``` that is a version of [the reference pages](http://www.espruino.com/Reference),
but based on your source code.
----
## Virtual Machines under Windows and MacOS
Building under Windows/MacOS with a VM (Vagrant)
------------------------------------------------
The easiest solution for a Virtual Machine for Windows and MacOS is [VirtualBox](https://www.virtualbox.org/).
A really easy way to provision, ie setup the system for development, is [Vagrant](https://www.vagrantup.com).
* Clone this repository.
* Download and install the correct [VirtualBox](https://www.virtualbox.org/) for your platform. eg. If you have Windows, download 'VirtualBox for Windows Hosts'.
* Download and install the correct [Vagrant](https://www.vagrantup.com/downloads.html) for your platform.
> If running on MacOS, the two previous steps can be accomplished easily with [Homebrew Cask](http://caskroom.io): `brew cask install virtualbox vagrant` will do it.
* In your terminal application, navigate to your cloned working copy.
* Install the auto-network plugin with `vagrant plugin install vagrant-auto_network`
* Execute `vagrant up`. This will take a little while while the box is downloaded, and your virtual machine is provisioned.
* When it is complete, execute `vagrant ssh`, which will open an ssh session into your new VM.
* Execute `cd /vagrant && ESPRUINO_1V3=1 RELEASE=1 make` and wait.
* Espruino is now built. See the documentation under **Building under Linux** for more examples.
* To terminate the ssh session, simply execute `exit`.
* `vagrant suspend` will pause the VM, `vagrant halt` will stop it, and `vagrant up` will bring it back up again. See Vagrant's ["Getting Started"](http://docs.vagrantup.com/v2/getting-started/index.html) page for further information.
Note:
----
* Windows
* Installation of <https://git-scm.com/> gives a ssh that can be used with vagrant ssh
Building under Windows/MacOS with a VM
--------------------------------------
### Vagrant and VirtualBox
* Download and install the correct [VirtualBox](https://www.virtualbox.org/) for your platform. eg. If you have Windows, download 'VirtualBox for Windows Hosts'.
* Download the [Ubuntu 14.04 32 bit Desktop ISO Image](http://www.ubuntu.com/download/desktop)
* Run VirtualBox, and click the 'New' button
* Give the new OS a name, choose `Linux` as the type, and `Ubuntu (32 bit)` as the version
* Click `Next`, choose 2048MB of memory, and not to create a hard disk image (ignore the warning). **Note:** We're going to run Ubuntu right from the virtual CD without installing (because it's a bit faster and easier). If you have time you might want to create a hard disk image (you won't need as much memory then) and then choose to install Ubuntu when given the chance.
* Click start, and when prompted for a CD image choose the Ubuntu ISO you downloaded
* Wait until a picture of a keyboard appears at the bottom of the screen, then press enter
* Select a language, and then choose `Try Ubuntu` with the arrow keys
* When it's booted, press Alt-F2, type `gnome-terminal`, then enter. **Note:** You could also just press Ctrl-Alt-F2 to get a faster but less shiny-looking terminal window.
* In the terminal, type: `sudo add-apt-repository ppa:terry.guo/gcc-arm-embedded` and press enter when prompted
* Type `sudo apt-get update`
* Type `sudo apt-get install gcc-arm-none-eabi git` and press 'Y' if prompted
* Type `git clone https://github.com/espruino/Espruino.git`
* Type `cd Espruino`
* Type `ESPRUINO_1V3=1 RELEASE=1 make` and wait
* Espruino is now built. See the documentation under **Building under Linux** for more examples.
* When you exit the VM, make sure you choose `Save State`. If you `Power Off` you will lose everything you've done so far.
* For your host OS (Windows or MacOS)
* Download and install [VirtualBox](https://www.virtualbox.org/)
* Download and install [Vagrant](https://www.vagrantup.com/downloads.html)
* Note: for MacOS, the two previous steps can be accomplished easily with [Homebrew Cask](http://caskroom.io)
* `brew cask install virtualbox vagrant`
* Clone this repository and navigate with the command prompt to the contents
* Install the auto-network plugin
* `vagrant plugin install vagrant-auto_network`
* Execute
* `vagrant up`
* This will take a little while while the box is downloaded, and your virtual machine is provisioned.
* `vagrant ssh`
* a ssh session into your new VM will be created.
* `cd /vagrant && make clean && make`
* a native OS version of Espruino is now built. See this documentation for further examples
* To exit the ssh session
*`exit`.
* On the host OS, the following are useful vagrant commands
* `vagrant suspend`
* will pause the VM
* `vagrant halt`
* will stop the VM
* See Vagrant's ["Getting Started"](https://www.vagrantup.com/docs/getting-started/index.html) page for further information.
There's some more information on how to do this on the forum at http://forum.espruino.com/conversations/151 including links to a pre-made [Amazon EC2 instance](http://forum.espruino.com/conversations/151/?offset=25#comment20326).
### VirtualBox
----
If one does not wish to use vagrant, then install Virtual Box and use the Linux method.
## USB access
In order to access USB, bluetooth or connected USB devices, one has USB filters to dedicate access to the guest OS.
The easiest method is via the VirtualBox Manager, and select which devices should be dedicated to the VM with the device filter.
Note: VirtualBox Guest Additions from VirtualBox are required.
### To flash Espruino from the VM
* Plug the Espruino board in while holding BTN1, and wait for Windows to finish connecting to the USB device
* Go into the VirtualBox Manager (There's no need to stop your VM)
* Click on `USB`, then click on the icon with the `+` sign (With the tooltip 'Adds a new USB filter ... selected USB device')
* Click on the device labelled `STMicroelectronics STM32 ...`
* Click on the device labeled `STMicroelectronics STM32 ...`
* Now unplug the Espruino board, wait a few seconds, and plug it back in (holding BTN1 again)
* Go back into the VM, and type `sudo ESPRUINO_1V3=1 RELEASE=1 make serialflash`
* Your board will now be flashed
**Note:** if you want to you can change permissions so you don't need `sudo` by typing `sudo cp misc/45-espruino.rules /etc/udev/rules.d;sudo udevadm control --reload-rules` and then re-inserting the board.
**Note:** if you want to you can change permissions so you don't need `sudo` by typing `sudo cp misc/45-espruino.rules /etc/udev/rules.d;sudo udevadm control --reload-rules` and then re-inserting the board.

View File

@ -24,7 +24,7 @@ info = {
'build' : {
'defines' : [
'USE_NET',
'USE_TELNET',
'USE_TELNET',
'USE_GRAPHICS',
'USE_CRYPTO',
'USE_TLS'
@ -55,7 +55,11 @@ devices = {
# left-right, or top-bottom order
board_esp32 = {
<<<<<<< HEAD
'top' : [ 'D0','D4','D16','D17','D5','D18','D19','D20','D21','D3','D1','D22','D23','GND'],
=======
'top' : ['GND','D23','D22','D1','D3','D21','D20','D19','D18','D5','D17','D16','D4','D0'],
>>>>>>> 761dbafbae2ed426fc38a5b417031b815860ba83
'bottom' : ['D12','D14','D27','D26','D25','D33','D32','D35','D34','D39','D36','EN','3V3','GND'],
'right' : [ 'GND','D13','D9','D10','D11','D6','D7','D8','D15','D2']
};
@ -66,11 +70,19 @@ board_esp32["_css"] = """
width: 600px;
height: 435px;
left: 50px;
<<<<<<< HEAD
top: 150px;
background-image: url(img/ESP32.jpg);
}
#boardcontainer {
height: 675px;
=======
top: 170px;
background-image: url(img/ESP32.jpg);
}
#boardcontainer {
height: 700px;
>>>>>>> 761dbafbae2ed426fc38a5b417031b815860ba83
}
#board #right {
top: 80px;
@ -78,11 +90,19 @@ board_esp32["_css"] = """
}
#board #top {
bottom: 440px;
<<<<<<< HEAD
left: 157px;
}
#board #bottom {
top: 435px;
left: 157px;
=======
left: 155px;
}
#board #bottom {
top: 435px;
left: 155px;
>>>>>>> 761dbafbae2ed426fc38a5b417031b815860ba83
}
#board .rightpin {
height: 28px;
@ -96,6 +116,7 @@ boards = [ board_esp32 ];
def get_pins():
<<<<<<< HEAD
pins = pinutils.generate_pins(0,5);
#6-11 are used by Flash chip
pins.extend(pinutils.generate_pins(12,23));
@ -106,6 +127,24 @@ def get_pins():
pins = pinutils.fill_gaps_in_pin_list(pins);
=======
# { "name":"PD20", "sortingname":"D20", "port":"D", "num":"30", "functions":{ "I2C1_SDA":0 }, "csv":{} },
# pins = pinutils.generate_pins(0,5);
##6-11 are used by Flash chip
# pins.extend(pinutils.generate_pins(12,23));
# pins.extend(pinutils.generate_pins(25,27));
##32-33 are routed to rtc for xtal
# pins.extend(pinutils.generate_pins(34,39));
# pins = pinutils.fill_gaps_in_pin_list(pins);
pins = pinutils.generate_pins(0,39) # 40 General Purpose I/O Pins.
>>>>>>> 761dbafbae2ed426fc38a5b417031b815860ba83
pinutils.findpin(pins, "PD36", True)["functions"]["ADC1_IN0"]=0;
pinutils.findpin(pins, "PD37", True)["functions"]["ADC1_IN1"]=0;
pinutils.findpin(pins, "PD38", True)["functions"]["ADC1_IN2"]=0;
@ -132,8 +171,19 @@ def get_pins():
pinutils.findpin(pins, "PD0", True)["functions"]["LED_1"]=0;
pinutils.findpin(pins, "PD10", True)["functions"]["USART0_TX"]=0;
<<<<<<< HEAD
pinutils.findpin(pins, "PD16", True)["functions"]["UARTT2_RX"]=0;
pinutils.findpin(pins, "PD17", True)["functions"]["USART2_TX"]=0;
pinutils.findpin(pins, "PD32", True)["functions"]["USART0_RX"]=0;
return pins
return pins
=======
pinutils.findpin(pins, "PD16", True)["functions"]["USART2_RX"]=0;
pinutils.findpin(pins, "PD17", True)["functions"]["USART2_TX"]=0;
pinutils.findpin(pins, "PD32", True)["functions"]["USART0_RX"]=0;
# everything is non-5v tolerant
#for pin in pins:
# pin["functions"]["3.3"]=0;
return pins
>>>>>>> 761dbafbae2ed426fc38a5b417031b815860ba83

View File

@ -23,7 +23,7 @@ info = {
'default_console_tx' : "H0", # pin 24
'default_console_rx' : "H1", # pin 25
'default_console_baudrate' : "9600",
'variables' : 350,
'variables' : 300,
'binary_name' : 'espruino_%v_microbit.hex',
'build' : {
'defines' : [
@ -123,4 +123,7 @@ def get_pins():
{ "name":"PH0", "sortingname":"H0", "port":"D", "num":"24", "functions":{}, "csv":{} },
{ "name":"PH1", "sortingname":"H1", "port":"D", "num":"25", "functions":{}, "csv":{} }
];
# everything is non-5v tolerant
for pin in pins:
pin["functions"]["3.3"]=0;
return pins

View File

@ -101,6 +101,9 @@ def get_pins():
pinutils.findpin(pins, "PD4", True)["functions"]["ADC1_IN5"]=0;
pinutils.findpin(pins, "PD5", True)["functions"]["ADC1_IN6"]=0;
pinutils.findpin(pins, "PD6", True)["functions"]["ADC1_IN7"]=0;
# everything is non-5v tolerant
for pin in pins:
pin["functions"]["3.3"]=0;
#The boot/reset button will function as a reset button in normal operation. Pin reset on PD21 needs to be enabled on the nRF52832 device for this to work.
return pins

View File

@ -103,5 +103,8 @@ def get_pins():
pinutils.findpin(pins, "PD29", True)["functions"]["ADC1_IN5"]=0;
pinutils.findpin(pins, "PD30", True)["functions"]["ADC1_IN6"]=0;
pinutils.findpin(pins, "PD31", True)["functions"]["ADC1_IN7"]=0;
# everything is non-5v tolerant
for pin in pins:
pin["functions"]["3.3"]=0;
#The boot/reset button will function as a reset button in normal operation. Pin reset on PD21 needs to be enabled on the nRF52832 device for this to work.
return pins

View File

@ -42,7 +42,7 @@ chip = {
'spi' : 4,
'i2c' : 3,
'adc' : 1,
'dac' : 0,
'dac' : 2,
'saved_code' : {
# code size 300000 = 0x493E0 starts at 0x0800 0000 ends at 0x0804 93E0
# so we have some left room for Espruino firmware and no risk to clear it while saving

View File

@ -72,7 +72,8 @@ devices = {
board = {
'bottom' : [ 'D28', 'D29', 'D30', 'D31'],
'right' : [ 'GND', '3V', 'D2', 'D1' ],
'right2' : [ 'D6','D7','D8','D11','D13','D14','D15','D16','D23','D24','D27' ],
'left2' : [ 'D6','D7','D8','D11','D13','D14','D16','D23','D24','D27' ],
'right2' : [ 'D15' ],
'_notes' : {
'D11' : "Capacitive sense. D12 is connected to this pin via a 1 MOhm resistor",
'D29' : "If pulled up to 1 on startup, D28 and D29 become Serial1",
@ -105,9 +106,9 @@ board["_css"] = """
.pinD7 { position:absolute; left: 548px; top: 369px;}
.pinD8 { position:absolute; left: 512px; top: 398px;}
.pinD11 { position:absolute; left: 586px; top: 236px;}
.pinD13 { position:absolute; left: 509px; top: 293px;}
.pinD13 { position:absolute; left: 500px; top: 293px;}
.pinD14 { position:absolute; left: 523px; top: 270px;}
.pinD15 { position:absolute; left: 483px; top: 268px;}
.pinD15 { position:absolute; right: -483px; top: 268px;}
.pinD16 { position:absolute; left: 499px; top: 244px;}
.pinD23 { position:absolute; left: 157px; top: 438px;}
.pinD24 { position:absolute; left: 157px; top: 382px;}
@ -121,23 +122,18 @@ def get_pins():
pinutils.findpin(pins, "PD9", True)["functions"]["NFC1"]=0;
pinutils.findpin(pins, "PD10", True)["functions"]["NFC2"]=0;
pinutils.findpin(pins, "PD2", True)["functions"]["ADC1_IN0"]=0;
pinutils.findpin(pins, "PD2", True)["functions"]["3.3"]=0;
pinutils.findpin(pins, "PD3", True)["functions"]["ADC1_IN1"]=0;
pinutils.findpin(pins, "PD3", True)["functions"]["3.3"]=0;
pinutils.findpin(pins, "PD4", True)["functions"]["ADC1_IN2"]=0;
pinutils.findpin(pins, "PD4", True)["functions"]["3.3"]=0;
pinutils.findpin(pins, "PD5", True)["functions"]["ADC1_IN3"]=0;
pinutils.findpin(pins, "PD5", True)["functions"]["3.3"]=0;
pinutils.findpin(pins, "PD28", True)["functions"]["ADC1_IN4"]=0;
pinutils.findpin(pins, "PD28", True)["functions"]["3.3"]=0;
pinutils.findpin(pins, "PD28", True)["functions"]["USART1_TX"]=0;
pinutils.findpin(pins, "PD29", True)["functions"]["USART1_RX"]=0;
pinutils.findpin(pins, "PD29", True)["functions"]["ADC1_IN5"]=0;
pinutils.findpin(pins, "PD29", True)["functions"]["3.3"]=0;
pinutils.findpin(pins, "PD30", True)["functions"]["ADC1_IN6"]=0;
pinutils.findpin(pins, "PD30", True)["functions"]["3.3"]=0;
pinutils.findpin(pins, "PD31", True)["functions"]["ADC1_IN7"]=0;
pinutils.findpin(pins, "PD31", True)["functions"]["3.3"]=0;
pinutils.findpin(pins, "PD31", True)["functions"]["ADC1_IN7"]=0;
# everything is non-5v tolerant
for pin in pins:
pin["functions"]["3.3"]=0;
#The boot/reset button will function as a reset button in normal operation. Pin reset on PD21 needs to be enabled on the nRF52832 device for this to work.
return pins

View File

@ -101,7 +101,21 @@ void bleCompleteTaskFailAndUnLock(BleTask task, JsVar *data) {
bleCompleteTask(task, false, data);
jsvUnLock(data);
}
void bleSwitchTask(BleTask task) {
bleTask = task;
}
// ------------------------------------------------------------------------------
// ------------------------------------------------------------------------------
#ifdef NRF52
void bleSetActiveBluetoothGattServer(JsVar *var) {
jsvObjectSetChild(execInfo.hiddenRoot, BLE_NAME_GATT_SERVER, var);
}
JsVar *bleGetActiveBluetoothGattServer() {
return jsvObjectGetChild(execInfo.hiddenRoot, BLE_NAME_GATT_SERVER, 0);
}
#endif
// ------------------------------------------------------------------------------
// ------------------------------------------------------------------------------
@ -216,6 +230,40 @@ Called when an NFC field is detected
}
Called when an NFC field is no longer detected
*/
/*JSON{
"type" : "event",
"class" : "BluetoothDevice",
"name" : "gattserverdisconnected",
"ifdef" : "NRF52"
}
Called when the device gets disconnected.
To connect and then print `Disconnected` when the device is
disconnected, just do the following:
```
var gatt;
var t = getTime();
NRF.connect("aa:bb:cc:dd:ee:ff").then(function(gatt) {
gatt.device.on('gattserverdisconnected', function(event) {
console.log("Disconnected");
});
});
```
*/
/*JSON{
"type" : "event",
"class" : "BluetoothRemoteGATTCharacteristic",
"name" : "characteristicvaluechanged",
"ifdef" : "NRF52"
}
Called when a characteristic's value changes, *after* `BluetoothRemoteGATTCharacteristic.startNotifications` has been called.
See that for an example.
The first argument is of the form `{target : BluetoothRemoteGATTCharacteristic}`
`BluetoothRemoteGATTCharacteristic.value` will then contain the new value.
*/
/*JSON{
"type": "class",
@ -535,6 +583,43 @@ void jswrap_nrf_bluetooth_setAdvertising(JsVar *data, JsVar *options) {
jsble_advertising_start();
}
/*JSON{
"type" : "staticmethod",
"class" : "NRF",
"name" : "setScanResponse",
"generate" : "jswrap_nrf_bluetooth_setScanResponse",
"params" : [
["data","JsVar","The data to for the scan response"]
]
}
The raw scan response data should be supplied as an array. For example to return "Sample" for the device name:
```
NRF.setScanResponse([0x07, // Length of Data
0x09, // Param: Complete Local Name
'S', 'a', 'm', 'p', 'l', 'e']);
```
*/
void jswrap_nrf_bluetooth_setScanResponse(JsVar *data) {
uint32_t err_code;
jsvObjectSetOrRemoveChild(execInfo.hiddenRoot, BLE_NAME_SCAN_RESPONSE_DATA, data);
if (jsvIsArray(data) || jsvIsArrayBuffer(data)) {
JSV_GET_AS_CHAR_ARRAY(dPtr, dLen, data);
if (!dPtr) {
jsExceptionHere(JSET_TYPEERROR, "Unable to convert data argument to an array");
return;
}
err_code = sd_ble_gap_adv_data_set(NULL, 0, (uint8_t *)dPtr, dLen);
jsble_check_error(err_code);
} else if (!jsvIsUndefined(data)) {
jsExceptionHere(JSET_TYPEERROR, "Expecting array-like object or undefined, got %t", data);
}
}
/*JSON{
"type" : "staticmethod",
"class" : "NRF",
@ -548,6 +633,9 @@ void jswrap_nrf_bluetooth_setAdvertising(JsVar *data, JsVar *options) {
Change the services and characteristics Espruino advertises.
If you want to **change** the value of a characteristic, you need
to use `NRF.updateServices()` instead
To expose some information on Characteristic `ABCD` on service `BCDE` you could do:
```
@ -889,7 +977,7 @@ void jswrap_nrf_bluetooth_setScan_cb(JsVar *callback, JsVar *adv) {
}
} else if (field_type == BLE_GAP_AD_TYPE_16BIT_SERVICE_UUID_MORE_AVAILABLE ||
field_type == BLE_GAP_AD_TYPE_16BIT_SERVICE_UUID_COMPLETE) {
JsVar *s = jsvVarPrintf("%04x", *(uint16_t*)&dPtr[i+2]);
JsVar *s = jsvVarPrintf("%04x", UNALIGNED_UINT16(&dPtr[i+2]));
jsvArrayPushAndUnLock(services, s);
} else if (field_type == BLE_GAP_AD_TYPE_128BIT_SERVICE_UUID_MORE_AVAILABLE ||
field_type == BLE_GAP_AD_TYPE_128BIT_SERVICE_UUID_COMPLETE) {
@ -1037,20 +1125,18 @@ void jswrap_nrf_bluetooth_findDevices(JsVar *callback, JsVar *timeout) {
}
Start/stop listening for RSSI values on the currently active connection
RSSI is the 'Received Signal Strength Indication' in dBm
(where This device is a peripheral and is being connected to by a 'central' device)
```
// Start scanning
NRF.setRSSIHandler(function(rssi) {
console.log(rssi);
console.log(rssi); // prints -85 (or similar)
});
// prints -85 (or similar)
// Stop Scanning
NRF.setRSSIHandler();
```
RSSI is the 'Received Signal Strength Indication' in dBm
*/
void jswrap_nrf_bluetooth_setRSSIHandler(JsVar *callback) {
// set the callback event variable
@ -1886,12 +1972,31 @@ NRF.connect(device_address).then(function(d) {
});
```
For example, to listen to the output of another Puck.js's Nordic
Serial port service, you can use:
```
var gatt;
NRF.connect("pu:ck:js:ad:dr:es random").then(function(g) {
gatt = g;
return gatt.getPrimaryService("6e400001-b5a3-f393-e0a9-e50e24dcca9e");
}).then(function(service) {
return service.getCharacteristic("6e400003-b5a3-f393-e0a9-e50e24dcca9e");
}).then(function(characteristic) {
characteristic.on('characteristicvaluechanged', function(event) {
console.log("RX: "+JSON.stringify(event.target.value.buffer));
});
return characteristic.startNotifications();
}).then(function() {
console.log("Done!");
});
```
**Note:** This is only available on some devices
*/
JsVar *jswrap_nrf_BluetoothRemoteGATTCharacteristic_startNotifications(JsVar *characteristic) {
#if 0 // CENTRAL_LINK_COUNT>0
if (!bleNewTask(BLETASK_CHARACTERISTIC_NOTIFY, 0))
return 0;
#if CENTRAL_LINK_COUNT>0
// Set our characteristic's handle up in the list of handles to notify for
// TODO: What happens when we close the connection and re-open another?
uint16_t handle = (uint16_t)jsvGetIntegerAndUnLock(jsvObjectGetChild(characteristic, "handle_value", 0));
@ -1900,8 +2005,23 @@ JsVar *jswrap_nrf_BluetoothRemoteGATTCharacteristic_startNotifications(JsVar *ch
jsvSetArrayItem(handles, handle, characteristic);
jsvUnLock(handles);
}
JsVar *promise = jsvLockAgainSafe(blePromise);
jsble_central_characteristicNotify(characteristic, true);
JsVar *promise;
// Check for existing cccd_handle
uint16_t cccd = (uint16_t)jsvGetIntegerAndUnLock(jsvObjectGetChild(characteristic,"handle_cccd", 0));
if ( !cccd ) {
if (!bleNewTask(BLETASK_CHARACTERISTIC_DESC_AND_STARTNOTIFY, characteristic))
return 0;
promise = jsvLockAgainSafe(blePromise);
jsble_central_characteristicDescDiscover(characteristic);
}
else {
if (!bleNewTask(BLETASK_CHARACTERISTIC_NOTIFY, 0))
return 0;
promise = jsvLockAgainSafe(blePromise);
jsble_central_characteristicNotify(characteristic, true);
}
return promise;
#else
jsExceptionHere(JSET_ERROR, "Unimplemented");
@ -1914,12 +2034,12 @@ JsVar *jswrap_nrf_BluetoothRemoteGATTCharacteristic_startNotifications(JsVar *ch
"class" : "BluetoothRemoteGATTCharacteristic",
"name" : "stopNotifications",
"generate" : "jswrap_nrf_BluetoothRemoteGATTCharacteristic_stopNotifications",
"return" : ["JsVar", "A Promise that is resolved (or rejected) with data when notifications have been added" ]
"return" : ["JsVar", "A Promise that is resolved (or rejected) with data when notifications have been removed" ]
}
**Note:** This is only available on some devices
*/
JsVar *jswrap_nrf_BluetoothRemoteGATTCharacteristic_stopNotifications(JsVar *characteristic) {
#if 0 // CENTRAL_LINK_COUNT>0
#if CENTRAL_LINK_COUNT>0
// Remove our characteristic handle from the list of handles to notify for
uint16_t handle = (uint16_t)jsvGetIntegerAndUnLock(jsvObjectGetChild(characteristic, "handle_value", 0));
JsVar *handles = jsvObjectGetChild(execInfo.hiddenRoot, "bleHdl", JSV_ARRAY);

View File

@ -23,6 +23,7 @@ typedef enum {
BLETASK_CHARACTERISTIC, ///< Find characteristics
BLETASK_CHARACTERISTIC_WRITE, ///< Write to a characteristic
BLETASK_CHARACTERISTIC_READ, ///< Read from a characteristic
BLETASK_CHARACTERISTIC_DESC_AND_STARTNOTIFY, ///< Discover descriptors and start notifications
BLETASK_CHARACTERISTIC_NOTIFY, ///< Setting whether notifications are on or off
BLETASK_CENTRAL_END = BLETASK_CHARACTERISTIC_NOTIFY // ============= End of central tasks
} BleTask;
@ -38,6 +39,15 @@ void bleCompleteTaskSuccess(BleTask task, JsVar *data);
void bleCompleteTaskSuccessAndUnLock(BleTask task, JsVar *data);
void bleCompleteTaskFail(BleTask task, JsVar *data);
void bleCompleteTaskFailAndUnLock(BleTask task, JsVar *data);
void bleSwitchTask(BleTask task);
#ifdef NRF52
// Set the currently active GATT server
void bleSetActiveBluetoothGattServer(JsVar *var);
// Get the currently active GATT server (the return value needs unlocking)
JsVar *bleGetActiveBluetoothGattServer();
#endif
// ------------------------------------------------------------------------------
void jswrap_nrf_init();
bool jswrap_nrf_idle();
@ -53,6 +63,7 @@ JsVar *jswrap_nrf_bluetooth_getAddress();
JsVarFloat jswrap_nrf_bluetooth_getBattery();
void jswrap_nrf_bluetooth_setAdvertising(JsVar *data, JsVar *options);
void jswrap_nrf_bluetooth_setScanResponse(JsVar *data);
void jswrap_nrf_bluetooth_setServices(JsVar *data, JsVar *options);
void jswrap_nrf_bluetooth_updateServices(JsVar *data);
void jswrap_nrf_bluetooth_setScan(JsVar *callback);

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,36 @@
void jswrap_ESP32_wifi_soft_init();
void jswrap_ESP32_wifi_disconnect(JsVar *jsCallback);
void jswrap_ESP32_wifi_stopAP(JsVar *jsCallback);
void jswrap_ESP32_wifi_connect(
JsVar *jsSsid,
JsVar *jsOptions,
JsVar *jsCallback
);
void jswrap_ESP32_wifi_scan(JsVar *jsCallback);
void jswrap_ESP32_wifi_startAP(
JsVar *jsSsid, //!< The network SSID that we will use to listen as.
JsVar *jsOptions, //!< Configuration options.
JsVar *jsCallback //!< A callback to be invoked when completed.
);
JsVar *jswrap_ESP32_wifi_getStatus(JsVar *jsCallback);
void jswrap_ESP32_wifi_setConfig(JsVar *jsSettings);
JsVar *jswrap_ESP32_wifi_getDetails(JsVar *jsCallback);
JsVar *jswrap_ESP32_wifi_getAPDetails(JsVar *jsCallback);
void jswrap_ESP32_wifi_save(JsVar *what);
void jswrap_ESP32_wifi_restore(void);
JsVar *jswrap_ESP32_wifi_getIP(JsVar *jsCallback);
JsVar *jswrap_ESP32_wifi_getAPIP(JsVar *jsCallback);
void jswrap_ESP32_wifi_getHostByName(
JsVar *jsHostname,
JsVar *jsCallback
);
JsVar *jswrap_ESP32_wifi_getHostname(JsVar *jsCallback);
void jswrap_ESP32_wifi_setHostname(
JsVar *jsHostname //!< The hostname to set for device.
);
void jswrap_ESP32_ping(
JsVar *ipAddr, //!< A string or integer representation of an IP address.
JsVar *pingCallback //!< Optional callback function.
);
void esp32_wifi_init();

View File

@ -0,0 +1,232 @@
/*
* This file is part of Espruino, a JavaScript interpreter for Microcontrollers
*
* Copyright (C) 2013 Gordon Williams <gw@pur3.co.uk>
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* ----------------------------------------------------------------------------
* Implementation of JsNetwork for ESP32 - cloned from linux
* ----------------------------------------------------------------------------
*/
#include "network_esp32.h"
#include "network.h"
#include <string.h> // for memset
#define INVALID_SOCKET ((SOCKET)(-1))
#define SOCKET_ERROR (-1)
#include <sys/stat.h>
#include <errno.h>
#ifdef WIN32
#include <winsock.h>
#else
#ifndef ESP_PLATFORM
#include <sys/select.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <resolv.h>
#endif
#include <sys/socket.h>
#include <netdb.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
typedef struct sockaddr_in sockaddr_in;
typedef int SOCKET;
#endif
#define closesocket(SOCK) close(SOCK)
/// Get an IP address from a name. Sets out_ip_addr to 0 on failure
void net_esp32_gethostbyname(JsNetwork *net, char * hostName, uint32_t* out_ip_addr) {
NOT_USED(net);
struct hostent * host_addr_p = gethostbyname(hostName);
if (host_addr_p)
*out_ip_addr = *(uint32_t*)*host_addr_p->h_addr_list;
}
/// Called on idle. Do any checks required for this device
void net_esp32_idle(JsNetwork *net) {
NOT_USED(net);
}
/// Call just before returning to idle loop. This checks for errors and tries to recover. Returns true if no errors.
bool net_esp32_checkError(JsNetwork *net) {
NOT_USED(net);
bool hadErrors = false;
return hadErrors;
}
/// if host=0, creates a server otherwise creates a client (and automatically connects). Returns >=0 on success
int net_esp32_createsocket(JsNetwork *net, uint32_t host, unsigned short port) {
NOT_USED(net);
int sckt = -1;
if (host!=0) { // ------------------------------------------------- host (=client)
sockaddr_in sin;
sin.sin_family = AF_INET;
sin.sin_port = htons( port );
sckt = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (sckt<0) return sckt; // error
// turn on non-blocking mode
#ifdef WIN_OS
u_long n = 1;
ioctlsocket(sckt,FIONBIO,&n);
#endif
sin.sin_addr.s_addr = (in_addr_t)host;
int res = connect(sckt,(struct sockaddr *)&sin, sizeof(sockaddr_in) );
if (res == SOCKET_ERROR) {
#ifdef WIN_OS
int err = WSAGetLastError();
#else
int err = errno;
#endif
if (err != EINPROGRESS &&
err != EWOULDBLOCK) {
jsError("Connect failed (err %d)\n", err );
closesocket(sckt);
return -1;
}
}
} else { // ------------------------------------------------- no host (=server)
sckt = socket(AF_INET, // Go over TCP/IP
SOCK_STREAM, // This is a stream-oriented socket
IPPROTO_TCP); // Use TCP rather than UDP
if (sckt == INVALID_SOCKET) {
jsError("Socket creation failed");
return 0;
}
int optval = 1;
if (setsockopt(sckt,SOL_SOCKET,SO_REUSEADDR,(const char *)&optval,sizeof(optval)) < 0)
jsWarn("setsockopt(SO_REUSADDR) failed\n");
int nret;
sockaddr_in serverInfo;
memset(&serverInfo, 0, sizeof(serverInfo));
serverInfo.sin_family = AF_INET;
//serverInfo.sin_addr.s_addr = htonl(INADDR_LOOPBACK); // allow only LOCAL clients to connect
serverInfo.sin_addr.s_addr = INADDR_ANY; // allow anyone to connect
serverInfo.sin_port = (unsigned short)htons((unsigned short)port); // port
nret = bind(sckt, (struct sockaddr*)&serverInfo, sizeof(serverInfo));
if (nret == SOCKET_ERROR) {
jsError("Socket bind failed");
closesocket(sckt);
return -1;
}
// Make the socket listen
nret = listen(sckt, 10); // 10 connections (but this ignored on CC30000)
if (nret == SOCKET_ERROR) {
jsError("Socket listen failed, host:%d, port:%d\n",(int)host,(int)port);
closesocket(sckt);
return -1;
}
}
#ifdef SO_NOSIGPIPE
// disable SIGPIPE
int optval = 1;
if (setsockopt(sckt,SOL_SOCKET,SO_NOSIGPIPE,(const char *)&optval,sizeof(optval))<0)
jsWarn("setsockopt(SO_NOSIGPIPE) failed\n");
#endif
return sckt;
}
/// destroys the given socket
void net_esp32_closesocket(JsNetwork *net, int sckt) {
NOT_USED(net);
closesocket(sckt);
}
/// If the given server socket can accept a connection, return it (or return < 0)
int net_esp32_accept(JsNetwork *net, int sckt) {
NOT_USED(net);
// TODO: look for unreffed servers?
fd_set s;
FD_ZERO(&s);
FD_SET(sckt,&s);
// check for waiting clients
struct timeval timeout;
timeout.tv_sec = 0;
timeout.tv_usec = 0;
int n = select(sckt+1,&s,NULL,NULL,&timeout);
if (n>0) {
// we have a client waiting to connect... try to connect and see what happens
int theClient = accept(sckt,0,0);
return theClient;
}
return -1;
}
/// Receive data if possible. returns nBytes on success, 0 on no data, or -1 on failure
int net_esp32_recv(JsNetwork *net, int sckt, void *buf, size_t len) {
NOT_USED(net);
int num = 0;
fd_set s;
FD_ZERO(&s);
FD_SET(sckt,&s);
// check for waiting clients
struct timeval timeout;
timeout.tv_sec = 0;
timeout.tv_usec = 0;
int n = select(sckt+1,&s,NULL,NULL,&timeout);
if (n==SOCKET_ERROR) {
// we probably disconnected
return -1;
} else if (n>0) {
// receive data
num = (int)recv(sckt,buf,len,0);
if (num==0) num=-1; // select says data, but recv says 0 means connection is closed
}
return num;
}
/// Send data if possible. returns nBytes on success, 0 on no data, or -1 on failure
int net_esp32_send(JsNetwork *net, int sckt, const void *buf, size_t len) {
NOT_USED(net);
fd_set writefds;
FD_ZERO(&writefds);
FD_SET(sckt, &writefds);
struct timeval time;
time.tv_sec = 0;
time.tv_usec = 0;
int n = select(sckt+1, 0, &writefds, 0, &time);
if (n==SOCKET_ERROR ) {
// we probably disconnected so just get rid of this
return -1;
} else if (FD_ISSET(sckt, &writefds)) {
int flags = 0;
#if !defined(SO_NOSIGPIPE) && defined(MSG_NOSIGNAL)
flags |= MSG_NOSIGNAL;
#endif
n = (int)send(sckt, buf, len, flags);
return n;
} else
return 0; // just not ready
}
void netSetCallbacks_esp32(JsNetwork *net) {
net->idle = net_esp32_idle;
net->checkError = net_esp32_checkError;
net->createsocket = net_esp32_createsocket;
net->closesocket = net_esp32_closesocket;
net->accept = net_esp32_accept;
net->gethostbyname = net_esp32_gethostbyname;
net->recv = net_esp32_recv;
net->send = net_esp32_send;
net->chunkSize = 536;
}

View File

@ -0,0 +1,16 @@
/*
* This file is part of Espruino, a JavaScript interpreter for Microcontrollers
*
* Copyright (C) 2013 Gordon Williams <gw@pur3.co.uk>
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* ----------------------------------------------------------------------------
* Implementation of JsNetwork for Linux
* ----------------------------------------------------------------------------
*/
#include "network.h"
void netSetCallbacks_esp32(JsNetwork *net);

View File

@ -24,15 +24,18 @@
#ifdef WIN32
#include <winsock.h>
#else
#ifndef ESP_PLATFORM
#include <sys/select.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <resolv.h>
#endif
#include <sys/socket.h>
#include <sys/select.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <netinet/in.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <resolv.h>
typedef struct sockaddr_in sockaddr_in;
typedef int SOCKET;
#endif

View File

@ -28,6 +28,9 @@
#if defined(USE_ESP8266)
#include "network_esp8266.h"
#endif
#if defined(USE_ESP32)
#include "network_esp32.h"
#endif
#if defined(LINUX)
#include "network_linux.h"
#endif
@ -235,6 +238,9 @@ bool networkGetFromVar(JsNetwork *net) {
#if defined(USE_ESP8266)
case JSNETWORKTYPE_ESP8266_BOARD : netSetCallbacks_esp8266_board(net); break;
#endif
#if defined(USE_ESP32)
case JSNETWORKTYPE_ESP32 : netSetCallbacks_esp32(net); break;
#endif
#if defined(LINUX)
case JSNETWORKTYPE_SOCKET : netSetCallbacks_linux(net); break;
#endif

View File

@ -37,6 +37,7 @@ typedef enum {
JSNETWORKTYPE_W5500, ///< WIZnet W5500 support
JSNETWORKTYPE_JS, ///< JavaScript network type
JSNETWORKTYPE_ESP8266_BOARD, ///< Espressif ESP8266 board support
JSNETWORKTYPE_ESP32 /// < Espressif ESP32 board support
} JsNetworkType;
typedef struct {

View File

@ -24,6 +24,8 @@
#if defined(ESP8266)
extern int os_printf_plus(const char *format, ...) __attribute__((format(printf, 1, 2)));
#define printf os_printf_plus
#elif defined(ESP32) && !defined(RELEASE)
#define printf jsWarn
//#elif defined(LINUX)
//#define printf printf
#else

2
scripts/build_platform_config.py Executable file → Normal file
View File

@ -209,6 +209,8 @@ elif board.chip["family"]=="AVR":
board.chip["class"]="AVR"
elif board.chip["family"]=="ESP8266":
board.chip["class"]="ESP8266"
elif board.chip["family"]=="ESP32":
board.chip["class"]="ESP32"
else:
die('Unknown chip family '+board.chip["family"])

View File

@ -4,3 +4,16 @@
^\./libs/fat_sd
^\./libs/math
^\./tmp
^\./gen
^\./build
^\./xtensa-lx106-elf
^\./esp_iot_sdk_v2.0.0.p1/
^\./node_modules
^\./zipcontents
^\./libs/filesystem/fat_sd
^\./libs/hashlib
^\./libs/network/wiznet/.*/
^\./libs/network/cc3000
^\./libs/compression/heatshrink
^\./libs/crypto/mbedtls
^\./.*\.js

View File

@ -3,4 +3,12 @@
cd `dirname $0`
cd ..
find . | grep -f scripts/count_lines.include | grep -v -f scripts/count_lines.exclude
echo "Total lines"
find . | grep -f scripts/count_lines.include | grep -v -f scripts/count_lines.exclude | xargs cat | wc -l
#Can also count by lines written
#find . | grep -f scripts/count_lines.include | grep -v -f scripts/count_lines.exclude | xargs -I{} git blame {} | sed -ne "s/[^(]*(\([A-Za-z0-9]*\).*/\1/p" > blames
#sort blames | uniq -c | sort -n

View File

@ -421,4 +421,7 @@ unsigned int jshSetSystemClock(JsVar *options);
if (timeout<=0 || jspIsInterrupted()) { jsExceptionHere(JSET_INTERNALERROR, "Timeout on "REASON); } \
}
/** Send the given RGB pixel data out to neopixel/WS2811/APA104/etc */
bool jshNeopixelWrite(Pin pin, unsigned char *rgbData, size_t rgbSize);
#endif /* JSHARDWARE_H_ */

View File

@ -37,6 +37,10 @@ extern void jshPrintBanner(void); // prints a debugging banner while we're in be
extern void jshSoftInit(void); // re-inits wifi after a soft-reset
#endif
#ifdef ESP32
extern void jshSoftInit(void);
#endif
// ----------------------------------------------------------------------------
typedef enum {
IS_NONE,
@ -777,6 +781,9 @@ void jsiSemiInit(bool autoLoad) {
#ifdef ESP8266
jshSoftInit();
#endif
#ifdef ESP32
jshSoftInit();
#endif
if (jsiEcho()) { // intentionally not using jsiShowInputLine()
if (!loadFlash) {

View File

@ -1553,7 +1553,7 @@ NO_INLINE JsVar *jspeFactor() {
return jspeFactorTypeOf();
} else if (lex->tk==LEX_R_VOID) {
JSP_ASSERT_MATCH(LEX_R_VOID);
jsvUnLock(jspeFactor());
jsvUnLock(jspeUnaryExpression());
return 0;
}
JSP_MATCH(LEX_EOF);

View File

@ -238,6 +238,27 @@ JshPinFunction jshGetPinFunctionFromDevice(IOEventFlags device) {
}
}
// Convert a jshPinFunction to an event type flag
IOEventFlags jshGetFromDevicePinFunction(JshPinFunction func) {
switch (func & JSH_MASK_TYPE) {
case JSH_USART1 : return EV_SERIAL1;
case JSH_USART2 : return EV_SERIAL2;
case JSH_USART3 : return EV_SERIAL3;
case JSH_USART4 : return EV_SERIAL4;
case JSH_USART5 : return EV_SERIAL5;
case JSH_USART6 : return EV_SERIAL6;
case JSH_SPI1 : return EV_SPI1;
case JSH_SPI2 : return EV_SPI2;
case JSH_SPI3 : return EV_SPI3;
case JSH_I2C1 : return EV_I2C1;
case JSH_I2C2 : return EV_I2C2;
case JSH_I2C3 : return EV_I2C3;
default: return 0;
}
}
/** Try and find a specific type of function for the given pin. Can be given an invalid pin and will return 0. */
JshPinFunction NO_INLINE jshGetPinFunctionForPin(Pin pin, JshPinFunction functionType) {
if (!jshIsPinValid(pin)) return 0;

View File

@ -180,8 +180,7 @@ typedef enum {
(((F)&JSH_MASK_TYPE)>=JSH_TIMER1) && \
(((F)&JSH_MASK_TYPE)<=JSH_TIMER18))
#define JSH_PINFUNCTION_IS_DAC(F) ( \
(((F)&JSH_MASK_TYPE)==JSH_DAC) || \
0 )
(((F)&JSH_MASK_TYPE)==JSH_DAC))
#define JSH_PINFUNCTION_IS_USART(F) ( \
(((F)&JSH_MASK_TYPE)>=JSH_USART1) && \
(((F)&JSH_MASK_TYPE)<=JSH_USART6))
@ -217,6 +216,8 @@ void jshPinOutput(Pin pin, bool value);
// Convert an event type flag into a jshPinFunction for an actual hardware device
JshPinFunction jshGetPinFunctionFromDevice(IOEventFlags device);
// Convert a jshPinFunction to an event type flag
IOEventFlags jshGetFromDevicePinFunction(JshPinFunction func);
/** Try and find a specific type of function for the given pin. Can be given an invalid pin and will return 0. */
JshPinFunction NO_INLINE jshGetPinFunctionForPin(Pin pin, JshPinFunction functionType);

View File

@ -326,6 +326,12 @@ typedef int64_t JsSysTime;
#define NIBBLEFIELD_CLEAR(BITFIELD) memset(BITFIELD, 0, sizeof(BITFIELD)) ///< Clear all elements
*/
#if defined(NRF51)
// Cortex-M0 does not support unaligned reads
#define UNALIGNED_UINT16(addr) ((((uint16_t)*((uint8_t*)(addr)+1)) << 8) | (*(uint8_t*)(addr)))
#else
#define UNALIGNED_UINT16(addr) (*(uint16_t*)addr)
#endif
bool isWhitespace(char ch);
bool isNumeric(char ch);

View File

@ -3484,6 +3484,17 @@ JsVar *jsvNewTypedArray(JsVarDataArrayBufferViewType type, JsVarInt length) {
return array;
}
JsVar *jsvNewTypedArrayWithData(JsVarDataArrayBufferViewType type, JsVarInt length, unsigned char *data) {
JsVar *buf = jsvNewTypedArray(type, length);
if (!buf) return 0;
JsVarInt byteLength = JSV_ARRAYBUFFER_GET_SIZE(type) * length;
JsVar *arrayBufferData = jsvGetArrayBufferBackingString(buf);
if (arrayBufferData)
jsvSetString(arrayBufferData, (char *)data, byteLength);
jsvUnLock(arrayBufferData);
return buf;
}
JsVar *jsvNewArrayBufferWithPtr(unsigned int length, char **ptr) {
assert(ptr);
*ptr=0;

View File

@ -730,6 +730,9 @@ bool jsvReadConfigObject(JsVar *object, jsvConfigObject *configs, int nConfigs);
/// Create a new typed array of the given type and length
JsVar *jsvNewTypedArray(JsVarDataArrayBufferViewType type, JsVarInt length);
/// Create a new typed array of the given type and length (in elements), and fill it with the given data
JsVar *jsvNewTypedArrayWithData(JsVarDataArrayBufferViewType type, JsVarInt length, unsigned char *data);
/** Create a new arraybuffer of the given type and length, also return a pointer
* to the contiguous memory area containing it. Returns 0 if it was unable to
* allocate it. */

View File

@ -470,10 +470,10 @@ JsVar* jsvArrayBufferIteratorGetIndex(JsvArrayBufferIterator *it) {
return jsvNewFromInteger((JsVarInt)it->index);
}
bool jsvArrayBufferIteratorHasElement(JsvArrayBufferIterator *it) {
bool jsvArrayBufferIteratorHasElement(JsvArrayBufferIterator *it) {
if (it->type == ARRAYBUFFERVIEW_UNDEFINED) return false;
if (it->hasAccessedElement) return true;
return it->byteOffset <= (it->byteLength-JSV_ARRAYBUFFER_GET_SIZE(it->type));
return (it->byteOffset+JSV_ARRAYBUFFER_GET_SIZE(it->type)) <= it->byteLength;
}
void jsvArrayBufferIteratorNext(JsvArrayBufferIterator *it) {
@ -595,4 +595,3 @@ JsvIterator jsvIteratorClone(JsvIterator *it) {
}
return newit;
}

View File

@ -1177,6 +1177,48 @@ void jswrap_espruino_lockConsole() {
jsvUnLock(pwd);
}
/*JSON{
"type" : "staticmethod",
"class" : "E",
"name" : "neopixelWrite",
"generate" : "jswrap_E_neopixelWrite",
"params" : [
["pin", "pin", "Pin for output signal."],
["arrayOfData", "JsVar", "Array of RGB LED data bytes"]
]
}
Write to NeoPixel/WS281x/APA10x-style LEDs attached to the given pin
Different types of LED have the data in different orders - so don't
be surprised by RGB or BGR orderings!
**Note:** Espruino devices tend to have 3.3v IO, while WS2812/etc run
off of 5v. Many WS2812 will only register a logic '1' at 70%
of their input voltage - so if powering them off 5v you will not
be able to send them data reliably. You can work around this by
powering the LEDs off a lower voltage (for example 3.7v from a LiPo
battery), or can put the output into the `af_opendrain` state and use
a pullup resistor to 5v on STM32 based boards (nRF52 are not 5v tolerant
so you can't do this).
*/
void jswrap_E_neopixelWrite(Pin pin, JsVar *jsArrayOfData) {
JSV_GET_AS_CHAR_ARRAY(rgbData, rgbSize, jsArrayOfData);
if (!rgbData) {
jsExceptionHere(JSET_ERROR, "Couldn't convert %t to data to send to LEDs", jsArrayOfData);
return;
}
if (rgbSize == 0) {
jsExceptionHere(JSET_ERROR, "Data must be a non empty array.");
return;
}
if (rgbSize % 3 != 0) {
jsExceptionHere(JSET_ERROR, "Data length must be a multiple of 3 (RGB).");
return;
}
jshNeopixelWrite(pin, (unsigned char *)rgbData, rgbSize);
}
// ----------------------------------------- USB Specific Stuff
#ifdef USE_USB_HID

View File

@ -44,6 +44,7 @@ JsVar *jswrap_e_dumpStr();
JsVarInt jswrap_espruino_HSBtoRGB(JsVarFloat hue, JsVarFloat sat, JsVarFloat bri);
void jswrap_espruino_setPassword(JsVar *pwd);
void jswrap_espruino_lockConsole();
void jswrap_E_neopixelWrite(Pin pin, JsVar *jsArrayOfData);
void jswrap_espruino_setUSBHID(JsVar *arr);
bool jswrap_espruino_sendUSBHID(JsVar *arr);

View File

@ -423,7 +423,8 @@ void jsfSaveToFlash(JsvSaveFlashFlags flags, JsVar *bootCode) {
}
endOfData = cbData[1];
// make sure we write everything in buffer
for(int i=0;i<FLASH_UNITARY_WRITE_SIZE;i++)
int i;
for(i=0;i<FLASH_UNITARY_WRITE_SIZE;i++)
jsfSaveToFlash_writecb(0,cbData);
writtenBytes = endOfData - FLASH_SAVED_CODE_START;

View File

@ -420,7 +420,7 @@
// <e> I2S_ENABLED - nrf_drv_i2s - I2S peripheral driver
//==========================================================
#ifndef I2S_ENABLED
#define I2S_ENABLED 0
#define I2S_ENABLED 1
#endif
#if I2S_ENABLED
// <o> I2S_CONFIG_SCK_PIN - SCK pin <0-31>

View File

@ -16,7 +16,7 @@
#define CDC_CMD_EP 0x82 /* EP2 for CDC commands */
#define HID_IN_EP 0x81
#define HID_INTERFACE_NUMBER 0
#define HID_INTERFACE_NUMBER 2
#endif
extern USBD_HandleTypeDef hUsbDeviceFS;
@ -75,7 +75,7 @@ __ALIGN_BEGIN static const uint8_t USBD_CDC_HID_DeviceQualifierDesc[USB_LEN_DEV_
* No HID
* CDC on Interfaces 0 and 1
*/
#define USBD_CDC_CFGDESC_SIZE 67
#define USBD_CDC_CFGDESC_SIZE (67+8)
const __ALIGN_BEGIN uint8_t USBD_CDC_CfgDesc[USBD_CDC_CFGDESC_SIZE] __ALIGN_END =
{
/*Configuration Descriptor*/
@ -88,6 +88,16 @@ const __ALIGN_BEGIN uint8_t USBD_CDC_CfgDesc[USBD_CDC_CFGDESC_SIZE] __ALIGN_END
0xC0, /* bmAttributes: self powered */
0x32, /* MaxPower 0 mA */
/* Interface Association Descriptor */
0x08, /* bLength: IAD descriptor size */
0x0B, /* bDescriptorType: IAD */
0x00, /* bFirstInterface: Number if first interface for grouping */
0x02, /* bInterfaceCount: Interfaces count for grouping */
0x02, /* bFunctionClass: The same as bInterfaceClass below */
0x02, /* bFunctionSubClass: The same as bInterfaceSubClass below */
0x01, /* bFunctionProtocol: The same as bInterfaceProtocol below */
0x00, /* iFunction */
// -----------------------------------------------------------------------
/*CDC Interface Descriptor */
0x09, /* bLength: Interface Descriptor size */
@ -175,8 +185,8 @@ const __ALIGN_BEGIN uint8_t USBD_CDC_CfgDesc[USBD_CDC_CFGDESC_SIZE] __ALIGN_END
* HID on Interface 0
* CDC on Interfaces 1 and 2
*/
#define USBD_CDC_HID_CFGDESC_SIZE (67+25)
#define USBD_CDC_HID_CFGDESC_REPORT_SIZE_IDX 25
#define USBD_CDC_HID_CFGDESC_SIZE (67+25+8)
#define USBD_CDC_HID_CFGDESC_REPORT_SIZE_IDX 91
// NOT CONST - descriptor size needs updating as this is sent out
__ALIGN_BEGIN uint8_t USBD_CDC_HID_CfgDesc[USBD_CDC_HID_CFGDESC_SIZE] __ALIGN_END =
{
@ -190,6 +200,95 @@ __ALIGN_BEGIN uint8_t USBD_CDC_HID_CfgDesc[USBD_CDC_HID_CFGDESC_SIZE] __ALIGN_EN
0xC0, /* bmAttributes: self powered */
0x32, /* MaxPower 0 mA */
/* Interface Association Descriptor */
0x08, /* bLength: IAD descriptor size */
0x0B, /* bDescriptorType: IAD */
0x00, /* bFirstInterface: Number if first interface for grouping */
0x02, /* bInterfaceCount: Interfaces count for grouping */
0x02, /* bFunctionClass: The same as bInterfaceClass below */
0x02, /* bFunctionSubClass: The same as bInterfaceSubClass below */
0x01, /* bFunctionProtocol: The same as bInterfaceProtocol below */
0x00, /* iFunction */
// -----------------------------------------------------------------------
/*CDC Interface Descriptor */
0x09, /* bLength: Interface Descriptor size */
USB_DESC_TYPE_INTERFACE, /* bDescriptorType: Interface */
/* Interface descriptor type */
0, /* bInterfaceNumber: Number of Interface */
0x00, /* bAlternateSetting: Alternate setting */
0x01, /* bNumEndpoints: One endpoints used */
0x02, /* bInterfaceClass: Communication Interface Class */
0x02, /* bInterfaceSubClass: Abstract Control Model */
0x01, /* bInterfaceProtocol: Common AT commands */
0x00, /* iInterface: */
/*Header Functional Descriptor*/
0x05, /* bLength: Endpoint Descriptor size */
0x24, /* bDescriptorType: CS_INTERFACE */
0x00, /* bDescriptorSubtype: Header Func Desc */
0x10, /* bcdCDC: spec release number */
0x01,
/*Call Management Functional Descriptor*/
0x05, /* bFunctionLength */
0x24, /* bDescriptorType: CS_INTERFACE */
0x01, /* bDescriptorSubtype: Call Management Func Desc */
0x00, /* bmCapabilities: D0+D1 */
1, /* bDataInterface */
/*ACM Functional Descriptor*/
0x04, /* bFunctionLength */
0x24, /* bDescriptorType: CS_INTERFACE */
0x02, /* bDescriptorSubtype: Abstract Control Management desc */
0x02, /* bmCapabilities */
/*Union Functional Descriptor*/
0x05, /* bFunctionLength */
0x24, /* bDescriptorType: CS_INTERFACE */
0x06, /* bDescriptorSubtype: Union func desc */
0, /* bMasterInterface: Communication class interface */
1, /* bSlaveInterface0: Data Class Interface */
/*Endpoint 2 Descriptor*/
0x07, /* bLength: Endpoint Descriptor size */
USB_DESC_TYPE_ENDPOINT, /* bDescriptorType: Endpoint */
CDC_CMD_EP, /* bEndpointAddress */
0x03, /* bmAttributes: Interrupt */
LOBYTE(CDC_CMD_PACKET_SIZE), /* wMaxPacketSize: */
HIBYTE(CDC_CMD_PACKET_SIZE),
0x10, /* bInterval: */
/*---------------------------------------------------------------------------*/
/*Data class interface descriptor*/
0x09, /* bLength: Endpoint Descriptor size */
USB_DESC_TYPE_INTERFACE, /* bDescriptorType: */
1, /* bInterfaceNumber: Number of Interface */
0x00, /* bAlternateSetting: Alternate setting */
0x02, /* bNumEndpoints: Two endpoints used */
0x0A, /* bInterfaceClass: CDC */
0x00, /* bInterfaceSubClass: */
0x00, /* bInterfaceProtocol: */
0x00, /* iInterface: */
/*Endpoint OUT Descriptor*/
0x07, /* bLength: Endpoint Descriptor size */
USB_DESC_TYPE_ENDPOINT, /* bDescriptorType: Endpoint */
CDC_OUT_EP, /* bEndpointAddress */
0x02, /* bmAttributes: Bulk */
LOBYTE(CDC_DATA_FS_OUT_PACKET_SIZE), /* wMaxPacketSize: */
HIBYTE(CDC_DATA_FS_OUT_PACKET_SIZE),
0x00, /* bInterval: ignore for Bulk transfer */
/*Endpoint IN Descriptor*/
0x07, /* bLength: Endpoint Descriptor size */
USB_DESC_TYPE_ENDPOINT, /* bDescriptorType: Endpoint */
CDC_IN_EP, /* bEndpointAddress */
0x02, /* bmAttributes: Bulk */
LOBYTE(CDC_DATA_FS_IN_PACKET_SIZE), /* wMaxPacketSize: */
HIBYTE(CDC_DATA_FS_IN_PACKET_SIZE),
0x00, /* bInterval: ignore for Bulk transfer */
/************** Descriptor of Joystick Mouse interface ****************/
/* 9 */
0x09, /*bLength: Interface Descriptor size*/
@ -219,85 +318,6 @@ __ALIGN_BEGIN uint8_t USBD_CDC_HID_CfgDesc[USBD_CDC_HID_CFGDESC_SIZE] __ALIGN_EN
0x03, /*bmAttributes: Interrupt endpoint*/
HID_DATA_IN_PACKET_SIZE,0x00, /*wMaxPacketSize: 4 Byte max */
HID_FS_BINTERVAL, /*bInterval: Polling Interval (10 ms)*/
// -----------------------------------------------------------------------
/*CDC Interface Descriptor */
0x09, /* bLength: Interface Descriptor size */
USB_DESC_TYPE_INTERFACE, /* bDescriptorType: Interface */
/* Interface descriptor type */
1, /* bInterfaceNumber: Number of Interface */
0x00, /* bAlternateSetting: Alternate setting */
0x01, /* bNumEndpoints: One endpoints used */
0x02, /* bInterfaceClass: Communication Interface Class */
0x02, /* bInterfaceSubClass: Abstract Control Model */
0x01, /* bInterfaceProtocol: Common AT commands */
0x00, /* iInterface: */
/*Header Functional Descriptor*/
0x05, /* bLength: Endpoint Descriptor size */
0x24, /* bDescriptorType: CS_INTERFACE */
0x00, /* bDescriptorSubtype: Header Func Desc */
0x10, /* bcdCDC: spec release number */
0x01,
/*Call Management Functional Descriptor*/
0x05, /* bFunctionLength */
0x24, /* bDescriptorType: CS_INTERFACE */
0x01, /* bDescriptorSubtype: Call Management Func Desc */
0x00, /* bmCapabilities: D0+D1 */
2, /* bDataInterface */
/*ACM Functional Descriptor*/
0x04, /* bFunctionLength */
0x24, /* bDescriptorType: CS_INTERFACE */
0x02, /* bDescriptorSubtype: Abstract Control Management desc */
0x02, /* bmCapabilities */
/*Union Functional Descriptor*/
0x05, /* bFunctionLength */
0x24, /* bDescriptorType: CS_INTERFACE */
0x06, /* bDescriptorSubtype: Union func desc */
1, /* bMasterInterface: Communication class interface */
2, /* bSlaveInterface0: Data Class Interface */
/*Endpoint 2 Descriptor*/
0x07, /* bLength: Endpoint Descriptor size */
USB_DESC_TYPE_ENDPOINT, /* bDescriptorType: Endpoint */
CDC_CMD_EP, /* bEndpointAddress */
0x03, /* bmAttributes: Interrupt */
LOBYTE(CDC_CMD_PACKET_SIZE), /* wMaxPacketSize: */
HIBYTE(CDC_CMD_PACKET_SIZE),
0x10, /* bInterval: */
/*---------------------------------------------------------------------------*/
/*Data class interface descriptor*/
0x09, /* bLength: Endpoint Descriptor size */
USB_DESC_TYPE_INTERFACE, /* bDescriptorType: */
2, /* bInterfaceNumber: Number of Interface */
0x00, /* bAlternateSetting: Alternate setting */
0x02, /* bNumEndpoints: Two endpoints used */
0x0A, /* bInterfaceClass: CDC */
0x00, /* bInterfaceSubClass: */
0x00, /* bInterfaceProtocol: */
0x00, /* iInterface: */
/*Endpoint OUT Descriptor*/
0x07, /* bLength: Endpoint Descriptor size */
USB_DESC_TYPE_ENDPOINT, /* bDescriptorType: Endpoint */
CDC_OUT_EP, /* bEndpointAddress */
0x02, /* bmAttributes: Bulk */
LOBYTE(CDC_DATA_FS_OUT_PACKET_SIZE), /* wMaxPacketSize: */
HIBYTE(CDC_DATA_FS_OUT_PACKET_SIZE),
0x00, /* bInterval: ignore for Bulk transfer */
/*Endpoint IN Descriptor*/
0x07, /* bLength: Endpoint Descriptor size */
USB_DESC_TYPE_ENDPOINT, /* bDescriptorType: Endpoint */
CDC_IN_EP, /* bEndpointAddress */
0x02, /* bmAttributes: Bulk */
LOBYTE(CDC_DATA_FS_IN_PACKET_SIZE), /* wMaxPacketSize: */
HIBYTE(CDC_DATA_FS_IN_PACKET_SIZE),
0x00, /* bInterval: ignore for Bulk transfer */
} ;
#define USB_HID_DESC_SIZ 9
@ -839,5 +859,3 @@ uint8_t USBD_HID_SendReport (uint8_t *report, unsigned int len)
int USB_IsConnected() {
return hUsbDeviceFS.dev_state == USBD_STATE_CONFIGURED;
}

View File

@ -64,7 +64,7 @@
*/
/*---------- -----------*/
#define USBD_MAX_NUM_INTERFACES 1
#define USBD_MAX_NUM_INTERFACES 2
/*---------- -----------*/
#define USBD_MAX_NUM_CONFIGURATION 1
/*---------- -----------*/
@ -78,8 +78,8 @@
/****************************************/
/* #define for FS and HS identification */
#define DEVICE_FS 0
#define DEVICE_HS 1
#define DEVICE_FS 0
#define DEVICE_HS 1
/** @defgroup USBD_Exported_Macros
* @{

View File

@ -128,9 +128,9 @@ __ALIGN_BEGIN uint8_t USBD_FS_DeviceDesc[USB_LEN_DEV_DESC] __ALIGN_END =
0x00, /* bcdUSB */
#endif
0x02,
0x02, /*bDeviceClass - CDC */
0x00, /*bDeviceSubClass*/
0x00, /*bDeviceProtocol*/
0xEF, /*bDeviceClass - CDC */
0x02, /*bDeviceSubClass*/
0x01, /*bDeviceProtocol*/
USB_MAX_EP0_SIZE, /*bMaxPacketSize*/
LOBYTE(USBD_VID), /*idVendor*/
HIBYTE(USBD_VID), /*idVendor*/

View File

@ -1033,3 +1033,8 @@ unsigned int jshGetRandomNumber() {
unsigned int jshSetSystemClock(JsVar *options) {
return 0;
}
bool jshNeopixelWrite(Pin pin, unsigned char *rgbData, size_t rgbSize) {
jsExceptionHere(JSET_ERROR, "Neopixel writing not implemented");
return false;
}

View File

@ -0,0 +1,18 @@
How to flash Espruino ESP32
===========================
*** To flash an ESP32 using the serial port use:
python $(ESP_IDF_PATH)/components/esptool_py/esptool/esptool.py \
--chip esp32 \
--port "/dev/ttyUSB0" \
--baud 921600 \
write_flash \
-z \
--flash_mode "dio" \
--flash_freq "40m" \
0x1000 bootloader.bin \
0x10000 espruino_esp32.bin \
0x8000 partitions_singleapp.bin
On windows, its an option to use flash tools from espressif found here:
http://espressif.com/sites/default/files/tools/flash_download_tools_v3.4.4.zip

View File

@ -0,0 +1,15 @@
Digital Pulse
===
Espruino supports a command digitalPulse
##General##
ESP32 supports a so called RMT with a lot of timers. This is defined generally to support Remote Control. Anyway we will use it to create digital pulses.
##Usage for Espruino##
First version of digital pulse uses rmt driver.
There are 8 channel available. Each one with is connected to a pin. Timimg goes down to micro secs.
##Status##
Still waiting for my digital oscilloscope for testing.

View File

@ -0,0 +1,40 @@
# ESP32 Specific
A static class called "ESP32" is provided that supplies ESP32 specific APIs.
Note that there is no "requires" needed for these functions. They are static
and belong to the class. For example, to invoke the `reboot` method, one would
code:
```
ESP32.reboot();
```
These include:
## ESP32.neopixelWrite
Not yet implemented
## ESP32.getState
Returns a Java Script object that has the following properties filled in:
* `sdkVersion` - The version of the Espressif SDK that Espruino is using.
* `freeHeap` - The amount of heap storage unused.
##ESP32.setLogLevel
The ESP32 environment has built in diagnostics and logging. Calling this
method changes the logging levels for either specific component or the
environment as a whole. The signature of the function is:
`setLogLevel(tag, level)`
where:
* `tag` - The logging tag to specify. Use `*` for all tags.
* `level` - The logging level to log at or better. The levels are:
* verbose
* debug
* info
* warn
* error
* none
##ESP32.reboot
Reboot the ESP32 device.

View File

@ -0,0 +1,122 @@
# How to GIT for Espruino(ESP32)
Target of this is to be a help working with Git for ESP32 branch of Espruino.
Lets assume, that you already worked with Git for your own project.
If you are a total beginner, please go to Google and search for documents.
To be honest, I did this some years ago, and dont know for sure how this worked ;-)
Lets assume, we already have forked a repository from `https://github.com/espruino/Espruino` into our repository.
Lets give it the name OurRepository and open a cmd for our git folder in documents. Usually I take Windows Power Shell
for this.
BTW, dont forget to replace `OurRepository` by the name of your repository.
There is no way, that I know, to sync a fork directly. Only way is to sync our local copy first and then sync forket
repository from your local computer.
First step is to clone sources to your local computer.
```
git clone https://github.com/OurRepository/Espruino.git
```
Thats easy, depending on your connection, this will take more or less time. During this process you will see
something like this.
```
Cloning into Espruino
remote: Counting objects: 33631, done.
remote: Compressing objects: 100% (111/111), done.
remote: Total 33631 (delta 41), reused 0 (delta 0), pack-reused 33517
Receiving objects: 100% (33631/33631), 57.69 MiB | 5.21 MiB/s, done.
Resolving deltas: 100% (22537/22537), done.
Checking out files: 100% (2268/2268), done.
```
Next we switch to the new directory, named `Espruino`.
```
$ cd Espruino
```
Now its time to switch to the branch for ESP32.
```
git checkout ESP32
```
Well its time for a more complex action. The original repository is usually some steps ahead to your fork.
Means Gordon made some changes and these changes are not copied to your fork automatically.
Before you can synchronize your fork from the original repository, an upstream needs to be created.
This step has to be done only the first time.
```
git remote add upstream https://github.com/espruino/Espruino.git
```
Before using this, its a good idea to check actual status.
```
git remote -v
```
should see something like this
```
origin https://github.com/OurRepository/Espruino.git (fetch)
origin https://github.com/OurRepository/Espruino.git (push)
upstream https://github.com/espruino/Espruino.git (fetch)
upstream https://github.com/espruino/Espruino.git (push)
```
Upstream is available, so lets use it. Lets sync our local copy from the ESP32 branch in original repository
for Espruino.
```
git pull upstream ESP32
```
Of course, there is a log from Git where you can see what happened. There will be some lines like this.
```
remote: Counting objects: 71, done.
remote: Compressing objects: 100% (71/71), done.
remote: Total 71 (delta 31), reused 0 (delta 0), pack-reused 0
Unpacking objects: 100% (71/71), done.
From https://github.com/espruino/Espruino
branch ESP32 -> FETCH_HEAD
[new branch] ESP32 -> upstream/ESP32
Updating 1f7a760..9e2b4db
Fast-forward
Makefile |6 +-
boards/ESP32.py |2 +-
...
...
targets/esp32/tests/simple_web_server.js |14 +
targets/esp32/tests/timer1.js |3 +
16 files changed, 1271 insertions(+), 46 deletions(-)
create mode 100644 libs/network/esp32/network_esp32.c
create mode 100644 libs/network/esp32/network_esp32.h
...
```
If you already have some changes for the source, its a good idea to do them now. Obviously, you can also save all the
new things you got from Espruino(ESP32) directly to your fork.
```
git push origin ESP32
```
Once again you should get a log which looks like this
```
Counting objects: 71, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (71/71), done.
Writing objects: 100% (71/71), 18.27 KiB | 0 bytes/s, done.
Total 71 (delta 45), reused 0 (delta 0)
remote: Resolving deltas: 100% (45/45), completed with 14 local objects.
To https://github.com/OurRepository/Espruino.git
1f7a760..9e2b4db ESP32 -> ESP32
```
Well we are done with, our fork is in sync with original Espruino. At least for the ESP32 branch ;-) Git is a very complex
tool and sometimes it looks too complex. Like others I would prefer a nice UI where only a button needs to be pushed and
everything runs like magic. If there is a tool like this, please send me a link ;-)<br>If you want to get some more helpful
info around Git or other it fields, give the guys at SitePoint a try. They have been a big help in creating this tutorial.</p>

View File

@ -0,0 +1,74 @@
GPIO
====
ESP32 has a lot of GPIOs and supports different protocols etc. In this document we focus on simple GPIO binary handling. Documents for SPI, Analog, PWM etc. will follow.
###Available GPIOs / pins###
Even having GPIO named from 0 to 39, does not mean, we have all available. Some of them don't even exist, and only a few are available on DevkitC.
| CPU pin | GPIO | Devkit C|
| --- | --- | --- |
| 5 | 36 | X |
| 6 | 37 | |
| 7 | 38 | |
| 8 | 39 | X |
| 10 | 34 | X |
| 11 | 35 | X |
| 12 | 32 | X |
| 13 | 33 | X |
| 14 | 25 | X |
| 15 | 26 | X |
| 16 | 27 | X |
| 17 | 14 | X |
| 18 | 12 | X |
| 20 | 13 | X |
| 21 | 15 | X |
| 22 | 2 | X|
| 23 | 0 | X|
| 24 | 4 | X|
| 25 | 16 | X |
| 27 | 17 | X |
| 28 | 9 | |
| 29 | 10 | |
| 30 | 11 | |
| 31 | 6 | |
| 32 | 7 | |
| 33 | 8 | |
| 34 | 5 | X |
| 35 | 18 | X |
| 36 | 23 | X |
| 38 | 19 | X |
| 39 | 22 | X |
| 40 | 32 | |
| 41 | 10 | |
| 42 | 21 | X |
###Binary I/O###
Espruino/targets/esp32/jshardware.c is the main connection between Espruino Core and special sources to handle ESP32 specific commands.
For simple GPIO handling we have to fill following functions. For more information/detailed please go to source
| Function | Description |
| --- | --- |
| jshPinSetState | Set the state of the specific pin. |
| jshPinGetState | return current State of pin |
| jshPinSetValue | set the value of pin |
| jshPinGetValue | get the value of pin |
###Interrupts###
For commands like setWatch fast response of changes on pin is a must. Fastest way is catching interrupts. Following functions will do this particular job
| Function | Description |
| --- | --- |
| in jshInit | add a line to register GPIO interrupts (gpio_isr_register) |
| gpio_intr_test | function to handle interrupts, calls jshPushIOWatchEvent for each changed pin that is enabled for interrupt |
| jshGetWatchedPinState | Get the state of the pin associated with the event flag. Take care on parameter its IOEventFlags not pin |
| jshPinWatch | Enables or disables interrupt for pin |
| jshIsEventForPin | Determine if a given event is associated with a given pin |
###General functions###
Please have in mind, there are pins and IOEventFlags. Handling them is simple, we only have to add EV_EXTIO. There are some definitions in Espruino Core. In jshardware.c we handle it this way. May be in future we find a better way.
| Function | Description |
| --- | --- |
| pinToEV_EXTI | maps a pin to an event |
| | maping an event to a pin is done by subtracting EV_EXTI0 from IOEventFlag |
| pinToESP32Pin | converts a number to a gpio_num_t |

View File

@ -0,0 +1,26 @@
Hardware Timer
===
Espruino uses Highspeed hardware timer for functions like waveform.
##General##
ESP32 supports 2 groups of timer, both having 2 timer.
esp-idf supports driver for timer with components/driver/include/driver/timer.h
##Conection to Espruino##
An interrupt needs to be defined with IRAM_ATTR. To connect to Espruino, the isr (interrupt service routine) calls jstUtilTimerInterruptHandler.
##Problem##
This function is not defined as IRAM_ATTR or something similiar. Due to this, or whatever other reason we get a reset after some calls. There could be many reasons for that like:
- problems with floating point
- running out of memory, since isr use their own stack
- running out of time for isr
- something else ???
##Solution##
As long as we don't know better, the solution is to seperate isr from calling jstUtilTimerInterruptHandler.
For that we create a new task, which waits for a notification and after receiving one, calls the function in Espruino. Inside the isr we now have to send the notification. Sending a notification is done with vTaskNotifyGiveFromISR, a function of FREErtos.
Waiting for the notification uses ulTaskNotifyTake, another function in FREErtos.
##Status##
A first step with a simple waveform on an DAC port (GPIO25/GPIO26) runs without any crashes now. Thats good part of the answer, badly it does not change output :-(
We are working on that......

View File

@ -0,0 +1,30 @@
# Installation of Espruino
A build of Espruino consists of three binary files called:
* espruino_esp32.bin
* bootloader.bin
* paritions_singleapp.bin
These files are loaded into an ESP32 using the `esptool.py` command. An example
of usage would be:
```
esptool.py \
--chip esp32 \
--port "/dev/ttyUSB0" \
--baud 115200 \
write_flash \
-z \
--flash_mode "dio" \
--flash_freq "40m" \
0x10000 espruino_esp32.bin \
0x1000 /home/kolban/esp32/Espruino/template/build/bootloader/bootloader.bin \
0x8000 /home/kolban/esp32/Espruino/template/build/partitions_singleapp.bin
```
Remember to put your ESP32 into flash mode before running the command and then
reboot after loading the program.
The JavaScript development tooling (WebIDE) is best run through Chrome by installing
the [Espruino Web IDE](https://chrome.google.com/webstore/detail/espruino-web-ide/bleoifhkdalbjfbobjackfdifdneehpo).

View File

@ -0,0 +1,26 @@
# make menuconfig
Within the template project that builds the ESP-IDF environment, there is a
configuration file called `sdkconfig`. While this file can be edited by hand
there is an elegant full screen text based user interface for editing. We can
bring this up by running `make menuconfig`. This provides a menu driven editor
where properties can be changed.
Some options *must* be changed for correct operation of Espruino. These
are:
* Component config -> LWIP -> Enable SO_REUSEADDR option [Enable]
* Component config -> ESP32-specific config -> Task watchdog [Disable]
* Component config > FreeRTOS -> Halt when an SMP-untested function is called [Disable]
Other options can be changed at your discretion for changes in the environment that
are primarily to taste. Examples that I would consider are:
* Bootloader config -> Bootloader log verbosity - Consider changing this to `Verbose`.
* Serial flasher config -> Default baud rate - I have had success with 921600.
* Serial flasher config -> Use compressed upload - I have had success with this enabled.
* Component config -> Log output -> Default log verbosity - Consider changing this to `Verbose`.
* Component config -> Log output -> Use ANSI terminal colors in log output - I switch this off from the default of on.
When re-importing the latest versions of ESP-IDF, we will likely overwrite any changes
we made here. Either we copy the `sdkconfig` you have been using and put it back after
a refresh or else re-run `make menuconfig` after a refresh.

27
targets/esp32/docs/PWM.md Normal file
View File

@ -0,0 +1,27 @@
PWM
===
Espruino supports Analog output using PWM
##General##
ESP32 supports (at least) 2 optiins for PWM. Both have pros and cons.
- sigmadelta
driver for sigmadelta is very easy to use. Problem is a limitation in frequency.
Base of frequency is 80Mhz, which can be divided by a values from 1 to 255.
Therefore a frequency of 30khz is impossible this way
- ledc
driver for ledc is designed to control leds. Not a big surprise, if you see the name :-)
Driver allows a lot of options, like fadein and fadeout. There are 8 channel, which can be assigned to a GPIO. In the background are 4 timer, where each channel needs to be assigned to a specific timer. Therefore only 4 different frequencies are possible.
Last not least, Frequency is limited to about 75Khz
##Usage for Espruino##
First version of PWM uses ledc driver. Usually, this matches needs for frequency much more than sigmadelta. Mapping of PWM channel to timer is done in a special way.
There are 5 channel usable, as long as 5Khz are ok for frequency. Channels are internally controlled. If you try to use more than 5, you will get a message.
Left 3 channels are designed to support a frequency of your choice, as long as it is between 1hz and 78 Khz. If you try to use a 4th channel with a frequency, other than 5Khz you will a meesage.
##Problem##
Handling of PWM with those 5/3 method is not always easy to follow. As long as we don't have a better solution, its better to have this than nothing.
Limitation of frequency is boring, but as long as we use it for analog output, it should be acceptable.
Please have in mind, PWM via analog always need a lowpass filter, usually a simple RC.
##Status##
As mentioned above, this is a first step. Hopefully we get a better solution in the future. We could build our own solution, using RMT. If somebody wants to go into this direction, you are welcome. In that case please take care on implementation of digitalPulse, see jshardwarPulse for more information.

View File

@ -0,0 +1,276 @@
#Notes on the development of Espruino for ESP32
The github URL for core Espruino is:
https://github.com/espruino/Espruino.git
New board will trigger on
ESP32=1
To build, we need to set
```
export ESP32=1
export ESP_IDF_PATH=/path to ESP_IDF
export PATH=/opt/xtensa-esp32-elf/bin:$PATH
```
##The Espruino Github
Espruino is maintained as Open Source on Github. The master project repository is the organization called "espruino" that can be found here: `https://github.com/espruino`
The leader/founder/brains/owner behind the whole shooting match is Gordon Williams.
Within the espruino Github organization, we will find a Github repository called "Espruino".
`https://github.com/espruino/Espruino`
This is the master repository for the project.
Within this repository there is a branch called "ESP32". It is against this branch we will be performing our work.
Note: The thinking is that we will perform all changes necessary within that branch so that there will be no breakage of the master work should something go wrong. The ultimate goal is that at some date in the future, the majority of the work against an Espruino port to ESP32 will be considered "ready" and the work performed in the "ESP32" branch will be merged into the "master" branch and then on-going maintenance performed there.
Let us assume (as is actually the case at the time of writing) that the ESP32 branch does not yet exist. The first step will be someone with suitable authorization create that branch. Note that an Espruino on ESP32 developer will not be performing these steps. They are recorded here for interest and for potential future projects.
The recipe to perform the branch creation task is as follows:
* Clone a local copy of Espruino
```
$ git clone https://github.com/espruino/Espruino.git
```
* Change into the directory for the clone
```
$ cd Espruino
```
* Create a new branch
```
$ git branch ESP32
```
* Checkout the branch
```
$ git checkout ESP32
```
* Push the changes back to master in Github
```
$ git push -u origin --all
```
And now we will have created a branch.
## Coding standards
<Do we have these already written?>
No tabs, indent by two spaces
## Build instructions
In order to build Espruino for an ESP32, I am assuming you have a Linux environment at your disposal. While there is no technical reason you can't build Espruino on a different operating system, these notes assume Linux. If you don't have a Linux platform, consider using a Raspberry Pi or VirtualBox.
We will need three major environmental components in order to build Espruino. These are:
* An Xtensa ESP32 tool chain
* A copy of the Espressif IoT Development Framework (ESP-IDF)
* A copy of an ESP-IDF template application
### Let us now break these down.
The first is the Xtensa tool chain. The processor on an ESP32 is made by Xtensa and has its own architecture and instruction set. When we compile Espruino, we will be generating binary files that are the compiled C files. These binary files contain the executable instructions and data that will eventually be loaded on the ESP32. A compiler takes our source code and builds the resulting compiled code. Our source is C language in text files and our result must be Xtensa binaries. A tool chain is a suite of tools that take us from the source to the compiled binaries. These include C compilers, linkers, archivers and a few others. Espressif makes available a down loadable version of the Xtensa tool chain for Linux on x86 or x86-64. If you have previously been working with the ESP8266 toolchains, make sure that you realize that the toolchain for ESP32 is distinct from that of the ESP8266. The source code for the compilers is also available and can be downloaded and compiled yourself. I had to do this to get the tool chain running on the ARM architecture for my Raspberry Pi. I don't recommend building your own compiler unless you have a good reason. Instead find a binary version and download and trust that it won't do mischief on your machine.
In my recipes I choose to install the tool chain in /opt/xtensa-esp32-elf and add /opt/xtensa-esp32-elf/bin to your environmental PATH.
Next we need the ESP-IDF. This is the core of the framework that is the foundation upon which we build Espruino.
This package provides the libraries we link against in order to leverage the services of the ESP32 environment.
The package contains modules for WiFi, TCP/IP sockets, GPIO and much more. The package is distributed from Github and contains
pre-built libraries distributed in binary format as well as many modules that are distributed in source and need to be compiled.
Next we need an instance of an ESP-IDF template application. This is another project type that is extractable from Github.
The true purpose of this project type is to be the basis for one of your own ESP32 applications. The intent is that you download this
template application, rename it to reflect the name you want for your target app and then start editing the source for your own
purposes. It also contains a Makefile which knows how to build a full binary ready for flashing onto the ESP32.
At this point you may be thinking to yourself that this seems a strange component to include
in our Espruino story … but here is the thinking. The ESP-IDF is provided partially in binary format and partially
as source files that need compiled. Because of this, we would need to compile the ESP-IDF to be able to have all
the linkable libraries. Unfortunately, as of this time, there doesn't appear to be a recipe to simply "build all the
ESP-IDF libraries". Instead, it is the template application which builds them for us. When we download a
ready-to-compile template and ask it to build, the result is not only a compiled application … but a side
effect is that all the ESP-IDF libraries we need are also compiled and placed in directories for us to link
against. While it might be feasible to incorporate these rules to build all the ESP-IDF libraries that
Espruino requires into the Espruino Makefile, at this time we have decided that there is no immediate need to do that.
If we download the ESP-IDF and download the ESP-IDF template application and run a compile against that application,
the result (from Espruino build perspective) is that we have all the libraries we need to link against with minimal work
on our part. Thankfully, the recipe to achieve these tasks is very easy and very repeatable.
In early version of Espruino port, SDK for esp32 did not support I2C and SPI.
Only option at that time was to use Arduino related driver.
This changed with new SDK which supports I2C, I2S, SPI and a lot of other driver.
Therefore we don't need Arduino driver anymore. If somebody still wants to use them, we will keep a description at the end of this document.
Here are the instructions that need only be followed once.
* In your home directory (or wherever you want the root of your build to be) create a directory called "esp32".
```
$ mkdir esp32
```
* Change into that directory. This directory is what we will refer to as the ESP32 root directory in our story.
```
$ cd esp32
```
* Extract the ESP-IDF from Github
```
$ git clone --recursive https://github.com/espressif/esp-idf.git
```
* Change into the newly created esp-idf folder.
```
$ cd esp-idf
```
* Update the submodule.
```
$ git submodule update --init
```
* Change back up to the ESP32 root directory.
```
$ cd ..
```
* Extract the ESP-IDF template application to a folder called "template".
```
$ git clone https://github.com/espressif/esp-idf-template.git template
```
* Edit a file called setenv.sh and add the following lines:
```
#!/bin/bash
export ESP_IDF_PATH=$(pwd)/esp-idf
export IDF_PATH=$(pwd)/esp-idf
export ESP_APP_TEMPLATE_PATH=$(pwd)/template
export ESP32=1
[[ ":$PATH:" != *":/opt/xtensa-esp32-elf/bin:"* ]] && PATH="/opt/xtensa-esp32-elf/bin:${PATH}"
```
* Make the script executable:
```
$ chmod u+x setenv.sh
```
* Execute the environment script to set the variables. You will need to re-run this each time you open a new shell for building Espruino.
```
$ . ./setenv.sh
```
* Change into the new template directory.
```
$ cd template
```
* If you need Arduino, you have to do it here with commands at the end of this document
* Run the `make menuconfig`.
```
$ make menuconfig
```
* Change some of the settings necessary for Espruino:
```
Component config -> LWIP -> Enable SO_REUSEADDR option [Enable]
Component config -> ESP32-specific config -> Task watchdog [Disable]
sooner or later we need to find a way to refresh Task watchdog
Component config -> FreeRTOS -> Halt when an SMP-untested function is called [Disable]
some functions are marked as "SMP-untested" and a call results in a reset
on our test they work fine, and for testing we need some of them
```
* Perform a build to create the libraries and the template application.
```
$ make
```
* Change back up to the ESP32 root directory.
```
$ cd ..
```
* Extract Espruino source from YOUR fork of Espruino:
```
$ git clone https://github.com/YOURGITHUBID/Espruino.git
```
* Change into the Espruino folder.
```
$ cd Espruino
```
$ Build Espruino:
```
$ make
```
If all has built correctly, you will now find that you have a flash-able binary representing Espruino for the ESP32.
In summary, here are the steps again without commentary:
```
$ mkdir esp32
$ cd esp32
$ git clone --recursive https://github.com/espressif/esp-idf.git
$ cd esp-idf
$ git submodule update --init
$ cd ..
$ git clone https://github.com/espressif/esp-idf-template.git template
$ nano setenv.sh
>>>
#!/bin/bash
export ESP_IDF_PATH=$(pwd)/esp-idf
export IDF_PATH=$(pwd)/esp-idf
export ESP_APP_TEMPLATE_PATH=$(pwd)/template
export ESP32=1
[[ ":$PATH:" != *":/opt/xtensa-esp32-elf/bin:"* ]] && PATH="/opt/xtensa-esp32-elf/bin:${PATH}"
<<<
$ chmod u+x setenv.sh
$ . ./setenv.sh
$ cd template
$ make menuconfig
$ make
$ cd ..
$ git clone https://github.com/YOURGITHUBID/Espruino.git
$ cd Espruino
$ make
```
### Include Arduino driver###
* Make the components folder.
```
$ mkdir components
```
* Change into the components folder.
```
$ cd components
```
* Retrieve the Arduino-esp32 project
```
$ git clone https://github.com/espressif/arduino-esp32.git
```
* Edit the `main.cpp` source file
```
$ nano arduino-esp32/cores/esp32/main.cpp
>>> Comment out app_main
/*
extern "C" void app_main()
{
init();
initVariant();
initWiFi();
xTaskCreatePinnedToCore(loopTask, "loopTask", 4096, NULL, 1, NULL, 1);
}
*/
<<<
```
* Change back up to the template folder
```
$ cd ..
```

View File

@ -0,0 +1,28 @@
RTOS for Espruino
===
With RTOS we get a new world for Espruino. Before I forget to mention, actual sources are on very early state. Usually Espruino is very well tested, for this new functions, hmm, let me say, hmm, its more like a proof of concept.
To get RTOS running for Espruino on ESP32 you have to define RTOS=1 before starting make.
###General
RTOS is a shortcut for RealTime Operating System. Realtime OS are welknown in the world, usually they support running more than one task. In big systems, number of tasks can be very high. Obviously, this needs a lot of memory and some control of tasks. Words like priorities, queues, semaphores and more belong to this world.
Lets take a first look into this world to see, what Espruino can do with that.
###Tasks
From outside tasks are seperate applications running on a computer at the same time. They could work together, or totally independent from all others.
Ususally in the world of micro computers, we have one CPU only. Ok, ESP32 has two of them, but even with 2 CPUs, there must be a way to have several application running at the same time.
Its a good point to switch wording now from application to task. A task can be a full sized application like Espruino. But it can also be a simple function like reading input from serial and prepare it for other tasks. Even something like a blinker can be a task.
One of the magic words for tasks is priority. Based on priority, the OS decides how often a task gets time to work. This will not really work with an endless loop.
Next magic words are interrupts. Interrupts like a timer will suspend running task, make a decision based on priority which task should get some time and resumes that task.
###Queues
Lets take a closer look to the concept of the uart reading task mentioned earlier. This task reads data and prepares the data for later use. Tasks like this are often used, but working for themselve sounds senseless. Reading keystrokes from a console for example without doing anything is like talking to a wall.
Good for us, we have a solution and this is called Espruino. Espruino uses uart info to run complex javascript functions. But how could the console task tell Espruino about incomin keystrokes.
The way RTOS supports this is called a queue. One task, in our case the console task writes data into this queue and another task reads data from this queue.
###Task interaction###
RTOSfree supports a lot of functions to interact between tasks. Queues have already been mentioned in previous chapter. Other options are semaphores and notification.
Notification are an option to awake a task really quick. Each task has an area of memory which is available for function calls from other tasks. Simple action is, that one task is waiting for "something", and another task is telling that "something" happened.
###API calls
RTOS supports a lot of functions to work with queues and tasks on a low level. Good part of low level is, you can do a lot of special things. Bad part is, you have to do everything on this low level.
Usually you combine low level calls to easy to use utilities. As a first step we have some functions in targets/esp32/rtosutil.c. Take a short look to the header file to get more information around the functions supported.
###Espruino commands
Rtosutil supports functions on level of C. To use them in Espruino, they need a wrapper. And this wrapper is named jswrap_rtos.c. For each command you can see the wrapper data in the source. BTW, Espruino uses these lines to create its own documentation.
###Examples in Javascript
have to be done

18
targets/esp32/docs/SPI.md Normal file
View File

@ -0,0 +1,18 @@
# SPI
The ESP32 has three SPI buses called HSPI, VSPI and FSPI. Of these three, HSPI
and VSPI are available for our use. The default pin mappings for these
buses are:
| SPI | MOSI | MISO | CLK | SS |
+------+------+------+-----+----+
| HSPI | 13 | 12 | 14 | 15 |
| VSPI | 23 | 19 | 18 | 5 |
In the world of Espruino, there are logical SPIs called SPI1 and SPI2.
We have mapped SPI1 -> HSPI and SPI2 -> VSPI.
As of 2016-10-26 the ESP-IDF SPI drivers have NOT yet been released however
we have a technique that is available to us through the use of the Arduino-ESP32
project. We have linked the Arduino-ESP32 code with our current Espruino to achieve
SPI. This will keep us going until the proper libraries are released. The Espruino
externals will not be affected by our internal SPI implementation.

View File

@ -0,0 +1,55 @@
# Save and Load programs
When we have entered a program, we need to be able to save that program so that when the
device is restarted, the program loads and runs.
The primary mechanism for this is the routine called `jsfSaveToFlash` found in `jswrap_flash.c`.
The signature for this is:
```
void jsfSaveToFlash(JsvSaveFlashFlags flags, JsVar *bootCode)
```
It assumes that the program will be saved starting at `FLASH_SAVED_CODE_START`. The first
word (4bytes) is the amount of boot code saved. The second word is the end address of
decompressed JS code. The boot code is saved at FLASH_SAVED_CODE_START+8. The saved
state starts at FLASH_SAVED_CODE_START + 8 + boot_code_length.
In the following table, the offsets are relative to FLASH_SAVED_CODE_START
| Name | Address offset
+------------------------+-----------------------
| boot_code_length | 0
| <end> | 4
| Boot code | 8
| Saved state | 8 + boot_code_length
`FLASH_MAGIC` is `0xDEADBEEF`.
`FLASH_MAGIC_LOCATION` is `FLASH_SAVED_CODE_START + FLASH_CODE_LENGTH - 4`.
`FLASH_CODE_LENGTH` is `65536`.
The `ESP32.py` file describes the flasg details in a section called `saved_code`:
```
'saved_code' : {
'address' : 0x100000,
'page_size' : 4096,
'pages' : 16,
'flash_available' : 960, # firmware can be up to this size
}
```
```
jsfSaveToFlash_writecb(unsigned char ch, uint32_t *cbdata)
```
Write 1 byte specified by `ch` to flash.
```
jsfSaveToFlash_checkcb(unsigned char ch, uint32_t *cbdata)
```
Validate that the character supplied can be read back.
```
bool jsfFlashContainsCode()
```
Validate that the data contains code.

View File

@ -0,0 +1,38 @@
Internals
===
RTOS and the SDK for ESP32 bring up some new screws and bolts.
In this document, we will list at least some of them.
##Tasks##
Rtos supports a simple form of tasks. These tasks get a priority on start and some other information.
| Task | Stack | Priority | CPU |
| --- | --- | --- | --- |
| EspruinoTask | 10000 | 5 | 0 |
| ConsoleTask | 2048 | 20 | 0 |
| TimerTask | 2048 | 19 | 0 |
##Interrupt Level##
Each realtime OS uses interrupts, and so does RTOS. There are some predefined or reserved for future use. For more info see esp-idf/components/esp32/include/soc/soc.h line 259ff..
Based on actual version of esp-idf, interrupt levels are assigned automatically.
##Timer##
ESP32 generally support 2 groups of timers each having 2 timer. Timer is used for interrupt driven handling inside Espruino like Waveforms.
| Group | Timer | used for |
| --- | --- | --- |
| 0 | 0 | Espruino Util Timer |
| 0 | 1 | testing only |
| 1 | 0 | free |
| 1 | 1 | free |
##Uarts##
ESP32 supports 3 uarts, which can be assigned to GPIO ports. Espruino right now only uses uart_num_0 for console.
| Uart | used for |
| --- | --- |
| uart_num_0 | espruino console |
| uart_num_1 | free |
| uart_num_2 | free |

View File

@ -0,0 +1,40 @@
# ESP32 and WiFi
Using the ESP8266 board as a model, we must implement the ESP32 WiFi functions. This will entail
the creation of a new source file called `jswrap_esp32_network.c` which will live in
`libs/network/esp32`. There will also be a corresponding `jswrap_esp32_network.h`.
The majority of the WiFi API is documented in the Espruino docs here:
http://www.espruino.com/Reference#Wifi
This will expose a module called `Wifi` which will have the following static methods defined
upon it:
* `connect` - Connect to an access point
* `disconnect`
* `getAPDetails`
* `getAPIP`
* `getDetails`
* `getHostByName`
* `getHostname`
* `getIP`
* `getStatus`
* `ping`
* `restore`
* `save`
* `scan`
* `setConfig`
* `setHostname`
* `startAP`
* `stopAP`
# Implementation status
## connect
Working.
## disconnect
Working.
## All others
Not yet implemented

154
targets/esp32/i2c.c Normal file
View File

@ -0,0 +1,154 @@
/*
* This file is designed to support i2c functions in Espruino,
* a JavaScript interpreter for Microcontrollers designed by Gordon Williams
*
* Copyright (C) 2016 by Rhys Williams (wilberforce)
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* ----------------------------------------------------------------------------
* This file is designed to be parsed during the build process
*
* Contains ESP32 board specific functions.
* ----------------------------------------------------------------------------
*/
#include "i2c.h"
#include "driver/i2c.h"
#define ACK_CHECK_EN 0x1 /*!< I2C master will check ack from slave*/
#define ACK_CHECK_DIS 0x0 /*!< I2C master will not check ack from slave */
#define ACK_VAL 0x0 /*!< I2C ack value */
#define NACK_VAL 0x1 /*!< I2C nack value */
/* To do:
support both i2c ports - done
Test!
Stop bits param - bool sendStop
https://esp-idf.readthedocs.io/en/latest/api/i2c.html
*/
static esp_err_t checkError( char * caller, esp_err_t ret ) {
switch(ret) {
case ESP_OK: break;
case ESP_ERR_INVALID_ARG: {
jsError( "%s:, Parameter error\n", caller );
break;
}
case ESP_FAIL: {
jsError( "%s:, slave doesn't ACK the transfer.\n", caller );
break;
}
case ESP_ERR_TIMEOUT: {
jsError( "%s:, Operation timeout because the bus is busy.\n", caller );
break;
}
default: {
jsError( "%s:, unknown error code %d, \n", caller, ret );
break;
}
}
return ret;
}
int getI2cFromDevice( IOEventFlags device ) {
switch(device) {
case EV_I2C1: return I2C_NUM_0;
case EV_I2C2: return I2C_NUM_1;
default: return -1;
}
}
/** Set-up I2C master for ESP32, default pins are SCL:21, SDA:22. Only device I2C1 is supported
* and only master mode. */
void jshI2CSetup(IOEventFlags device, JshI2CInfo *info) {
int i2c_master_port = getI2cFromDevice(device);
if (i2c_master_port == -1) {
jsError("Only I2C1 and I2C2 supported");
return;
}
Pin scl;
Pin sda;
if ( i2c_master_port == I2C_NUM_0 ) {
scl = info->pinSCL != PIN_UNDEFINED ? info->pinSCL : 21;
sda = info->pinSDA != PIN_UNDEFINED ? info->pinSDA : 22;
}
// Unsure on what to default these pins to?
if ( i2c_master_port == I2C_NUM_1 ) {
scl = info->pinSCL != PIN_UNDEFINED ? info->pinSCL : 16;
sda = info->pinSDA != PIN_UNDEFINED ? info->pinSDA : 17;
}
i2c_config_t conf;
conf.mode = I2C_MODE_MASTER;
conf.sda_io_num = pinToESP32Pin(sda);
conf.sda_pullup_en = GPIO_PULLUP_ENABLE;
conf.scl_io_num = pinToESP32Pin(scl);
conf.scl_pullup_en = GPIO_PULLUP_ENABLE;
conf.master.clk_speed = info->bitrate;
esp_err_t err=i2c_param_config(i2c_master_port, &conf);
if ( err == ESP_ERR_INVALID_ARG ) {
jsError("jshI2CSetup: Invalid arguments");
return;
}
err=i2c_driver_install(i2c_master_port, conf.mode, 0, 0, 0);
if ( err == ESP_OK ) {
jsWarn("jshI2CSetup: driver installed, sda: %d sdl: %d freq: %d, \n", sda, scl, info->bitrate);
} else {
checkError("jshI2CSetup",err);
}
}
void jshI2CWrite(IOEventFlags device,
unsigned char address,
int nBytes,
const unsigned char *data,
bool sendStop) {
int i2c_master_port = getI2cFromDevice(device);
if (i2c_master_port == -1) {
jsError("Only I2C1 and I2C2 supported");
return;
}
esp_err_t ret;
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
ret=i2c_master_start(cmd);
ret=i2c_master_write_byte(cmd, address << 1 | I2C_MASTER_WRITE, ACK_CHECK_EN);
ret=i2c_master_write(cmd, data, nBytes, ACK_CHECK_EN);
if ( sendStop ) ret=i2c_master_stop(cmd);
ret = i2c_master_cmd_begin(i2c_master_port, cmd, 1000 / portTICK_RATE_MS); // 1000 seems very large for ticks_to_wait???
i2c_cmd_link_delete(cmd);
checkError( "jshI2CWrite", ret);
}
void jshI2CRead(IOEventFlags device,
unsigned char address,
int nBytes,
unsigned char *data,
bool sendStop) {
if (nBytes <= 0) {
return;
}
int i2c_master_port = getI2cFromDevice(device);
if (i2c_master_port == -1) {
jsError("Only I2C1 and I2C2 supported");
return;
}
esp_err_t ret;
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
ret=i2c_master_start(cmd);
ret=i2c_master_write_byte(cmd, ( i2c_master_port << 1 ) | I2C_MASTER_READ, ACK_CHECK_EN);
if (nBytes > 1) {
ret=i2c_master_read(cmd, data, nBytes - 1, ACK_VAL);
}
ret=i2c_master_read_byte(cmd, data + nBytes - 1, NACK_VAL);
if ( sendStop ) ret=i2c_master_stop(cmd);
ret = i2c_master_cmd_begin(i2c_master_port, cmd, 1000 / portTICK_RATE_MS);
i2c_cmd_link_delete(cmd);
checkError( "jshI2CRead", ret);
}

27
targets/esp32/i2c.h Normal file
View File

@ -0,0 +1,27 @@
/*
* This file is designed to support i2c functions in Espruino for ESP32,
* a JavaScript interpreter for Microcontrollers designed by Gordon Williams
*
* Copyright (C) 2016 by Rhys Williams (wilberforce)
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* ----------------------------------------------------------------------------
* This file is designed to be parsed during the build process
*
* Contains ESP32 board specific functions.
* ----------------------------------------------------------------------------
*/
#include "jspininfo.h"
#include "jshardware.h"
#include "driver/gpio.h"
// Convert an Espruino pin to an ESP32 pin number.
gpio_num_t pinToESP32Pin(Pin pin);
void jshI2CSetup(IOEventFlags device, JshI2CInfo *info);
void jshI2CWrite(IOEventFlags device, unsigned char address, int nBytes, const unsigned char *data, bool sendStop);
void jshI2CRead(IOEventFlags device, unsigned char address, int nBytes, unsigned char *data, bool sendStop);

687
targets/esp32/jshardware.c Normal file
View File

@ -0,0 +1,687 @@
/*
* This file is part of Espruino, a JavaScript interpreter for Microcontrollers
*
* Copyright (C) 2015 Gordon Williams <gw@pur3.co.uk>
*
* This Source Code Form is subject to the terms of the Mozilla Publici
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* ----------------------------------------------------------------------------
* This file is designed to be parsed during the build process
*
* Contains ESP32 board specific functions.
* ----------------------------------------------------------------------------
*/
/**
* The ESP32 must implement its part of the Espruino contract. This file
* provides implementations for interfaces that are expected to be provided
* by an Espruino board. The signatures of the exposed functions are part
* of the Espruino environment and can not be changed without express
* approval from all the stakeholders. In addition, the semantics of the
* functions should follow the expected conventions.
*/
#include <stdio.h>
#include "jshardware.h"
#include "jshardwareUart.h"
#include "jshardwareAnalog.h"
#include "jshardwareTimer.h"
#include "jshardwarePWM.h"
#include "jshardwarePulse.h"
#include "jsutils.h"
#include "jstimer.h"
#include "jsparse.h"
#include "jsinteractive.h"
#include "jspininfo.h"
#include "jswrap_esp32_network.h"
#include "esp_attr.h"
#include "esp_log.h"
#include "esp_wifi.h"
#include "esp_system.h"
#include "esp_spi_flash.h"
#include "rom/ets_sys.h"
#include "rom/uart.h"
#include "driver/gpio.h"
#include "i2c.h"
#include "spi.h"
#define FLASH_MAX (4*1024*1024) //4MB
#define FLASH_PAGE_SHIFT 12 // Shift is much faster than division by 4096 (size of page)
#define FLASH_PAGE ((uint32_t)1<<FLASH_PAGE_SHIFT) //4KB
#define UNUSED(x) (void)(x)
/**
* Convert a pin id to the corresponding Pin Event id.
*/
static IOEventFlags pinToEV_EXTI(
Pin pin // !< The pin to map to the event id.
) {
// Map pin 0 to EV_EXTI0
// Map pin 1 to EV_EXTI1
// ...
// Map pin x to ECEXTIx
return (IOEventFlags)(EV_EXTI0 + pin);
}
static uint8_t g_pinState[JSH_PIN_COUNT];
/**
* interrupt handler for gpio interrupts
*/
void IRAM_ATTR gpio_intr_handler(void* arg){
//GPIO intr process. Mainly copied from esp-idf
UNUSED(arg);
IOEventFlags exti;
Pin gpio_num = 0;
uint32_t gpio_intr_status = READ_PERI_REG(GPIO_STATUS_REG); //read status to get interrupt status for GPIO0-31
uint32_t gpio_intr_status_h = READ_PERI_REG(GPIO_STATUS1_REG);//read status1 to get interrupt status for GPIO32-39
SET_PERI_REG_MASK(GPIO_STATUS_W1TC_REG, gpio_intr_status); //Clear intr for gpio0-gpio31
SET_PERI_REG_MASK(GPIO_STATUS1_W1TC_REG, gpio_intr_status_h); //Clear intr for gpio32-39
do {
g_pinState[gpio_num] = 0;
if(gpio_num < 32) {
if(gpio_intr_status & BIT(gpio_num)) { //gpio0-gpio31
exti = pinToEV_EXTI(gpio_num);
jshPushIOWatchEvent(exti);
}
} else {
if(gpio_intr_status_h & BIT(gpio_num - 32)) {
exti = pinToEV_EXTI(gpio_num);
jshPushIOWatchEvent(exti);
}
}
} while(++gpio_num < GPIO_PIN_COUNT);
}
void jshPinSetStateRange( Pin start, Pin end, JshPinState state ) {
for ( Pin p=start; p<=end; p++ ) {
jshPinSetState(p, state);
}
}
void jshPinDefaultPullup() {
// 6-11 are used by Flash chip
// 32-33 are routed to rtc for xtal
jshPinSetStateRange(0,0,JSHPINSTATE_GPIO_IN_PULLUP);
jshPinSetStateRange(12,19,JSHPINSTATE_GPIO_IN_PULLUP);
jshPinSetStateRange(21,22,JSHPINSTATE_GPIO_IN_PULLUP);
jshPinSetStateRange(25,27,JSHPINSTATE_GPIO_IN_PULLUP);
jshPinSetStateRange(34,39,JSHPINSTATE_GPIO_IN_PULLUP);
}
/**
* Initialize the JavaScript hardware interface.
*/
void jshInit() {
uint32_t freeHeapSize = esp_get_free_heap_size();
jsWarn( "Free heap size: %d", freeHeapSize);
esp32_wifi_init();
//jswrap_ESP32_wifi_soft_init();
jshInitDevices();
if (JSHPINSTATE_I2C != 13 || JSHPINSTATE_GPIO_IN_PULLDOWN != 6 || JSHPINSTATE_MASK != 15) {
jsError("JshPinState #defines have changed, please update pinStateToString()");
}
/*
jsWarn( "JSHPINSTATE_I2C %d\n",JSHPINSTATE_I2C );
jsWarn( "JSHPINSTATE_GPIO_IN_PULLDOWN %d\n",JSHPINSTATE_GPIO_IN_PULLDOWN );
jsWarn( "JSHPINSTATE_MASK %d\n",JSHPINSTATE_MASK );
*/
gpio_isr_register(gpio_intr_handler,NULL,0,NULL); //changed to automatic assign of interrupt
// Initialize something for each of the possible pins.
jshPinDefaultPullup();
} // End of jshInit
/**
* Reset the Espruino environment.
*/
void jshReset() {
jshResetDevices();
jshPinDefaultPullup() ;
jsWarn("jshReset(): To implement - reset of i2c and SPI\n");
jsWarn(">> jshReset()\n");
}
/**
* Re-init the ESP32 after a soft-reset
*/
void jshSoftInit() {
jsWarn(">> jshSoftInit()\n");
jswrap_ESP32_wifi_soft_init();
}
/**
* Handle whatever needs to be done in the idle loop when there's nothing to do.
*
* Nothing is needed on the ESP32.
*/
void jshIdle() {
}
// ESP32 chips don't have a serial number but they do have a MAC address
int jshGetSerialNumber(unsigned char *data, int maxChars) {
assert(maxChars >= 6); // it's 32
esp_wifi_get_mac(WIFI_IF_STA, data);
return 6;
}
//===== Interrupts and sleeping
//Mux to protect the JshInterrupt status
//static portMUX_TYPE xJshInterrupt = portMUX_INITIALIZER_UNLOCKED;
void jshInterruptOff() {
//xTaskResumeAll();
//taskEXIT_CRITICAL(&xJshInterrupt);
taskDISABLE_INTERRUPTS();
}
void jshInterruptOn() {
//taskENTER_CRITICAL(&xJshInterrupt);
taskENABLE_INTERRUPTS();
}
/// Enter simple sleep mode (can be woken up by interrupts). Returns true on success
bool jshSleep(JsSysTime timeUntilWake) {
UNUSED(timeUntilWake);
return true;
} // End of jshSleep
/**
* Delay (blocking) for the supplied number of microseconds.
*/
void jshDelayMicroseconds(int microsec) {
ets_delay_us(microsec);
} // End of jshDelayMicroseconds
/**
* Set the state of the specific pin.
*
* The possible states are:
*
* JSHPINSTATE_UNDEFINED
* JSHPINSTATE_GPIO_OUT
* JSHPINSTATE_GPIO_OUT_OPENDRAIN
* JSHPINSTATE_GPIO_OUT_OPENDRAIN_PULLUP
* JSHPINSTATE_GPIO_IN
* JSHPINSTATE_GPIO_IN_PULLUP
* JSHPINSTATE_GPIO_IN_PULLDOWN
* JSHPINSTATE_ADC_IN
* JSHPINSTATE_AF_OUT
* JSHPINSTATE_AF_OUT_OPENDRAIN
* JSHPINSTATE_USART_IN
* JSHPINSTATE_USART_OUT
* JSHPINSTATE_DAC_OUT
* JSHPINSTATE_I2C
*
* This function is exposed indirectly through the exposed global function called
* `pinMode()`. For example, `pinMode(pin, "input")` will set the given pin to input.
*/
void jshPinSetState(
Pin pin, //!< The pin to have its state changed.
JshPinState state //!< The new desired state of the pin.
) {
gpio_mode_t mode;
gpio_pull_mode_t pull_mode=GPIO_FLOATING;
switch(state) {
case JSHPINSTATE_GPIO_OUT:
mode = GPIO_MODE_INPUT_OUTPUT;
break;
case JSHPINSTATE_GPIO_IN:
mode = GPIO_MODE_INPUT;
break;
case JSHPINSTATE_GPIO_IN_PULLUP:
mode = GPIO_MODE_INPUT;
pull_mode=GPIO_PULLUP_ONLY;
break;
case JSHPINSTATE_GPIO_IN_PULLDOWN:
mode = GPIO_MODE_INPUT;
pull_mode=GPIO_PULLDOWN_ONLY;
break;
case JSHPINSTATE_GPIO_OUT_OPENDRAIN:
mode = GPIO_MODE_INPUT_OUTPUT_OD;
break;
case JSHPINSTATE_GPIO_OUT_OPENDRAIN_PULLUP:
mode = GPIO_MODE_INPUT_OUTPUT_OD;
pull_mode=GPIO_PULLUP_ONLY;
break;
default:
jsError( "jshPinSetState: Unexpected state: %d", state);
return;
}
gpio_num_t gpioNum = pinToESP32Pin(pin);
gpio_set_direction(gpioNum, mode);
gpio_set_pull_mode(gpioNum, pull_mode);
gpio_pad_select_gpio(gpioNum);
g_pinState[pin] = state; // remember what we set this to...
}
/**
* Return the current state of the selected pin.
* \return The current state of the selected pin.
*/
JshPinState jshPinGetState(Pin pin) {
if ( jshPinGetValue(pin) & 1 )
return g_pinState[pin] | JSHPINSTATE_PIN_IS_ON;
return g_pinState[pin];
}
//===== GPIO and PIN stuff =====
/**
* Set the value of the corresponding pin.
*/
void jshPinSetValue(
Pin pin, //!< The pin to have its value changed.
bool value //!< The new value of the pin.
) {
gpio_num_t gpioNum = pinToESP32Pin(pin);
gpio_set_level(gpioNum, (uint32_t)value);
}
/**
* Get the value of the corresponding pin.
* \return The current value of the pin.
*/
bool CALLED_FROM_INTERRUPT jshPinGetValue( // can be called at interrupt time
Pin pin //!< The pin to have its value read.
) {
gpio_num_t gpioNum = pinToESP32Pin(pin);
bool level = gpio_get_level(gpioNum);
return level;
}
JsVarFloat jshPinAnalog(Pin pin) {
return (JsVarFloat) readADC(pin) / 4096;
}
int jshPinAnalogFast(Pin pin) {
return readADC(pin) << 4;
}
/**
* Set the output PWM value.
*/
JshPinFunction jshPinAnalogOutput(Pin pin,
JsVarFloat value,
JsVarFloat freq,
JshAnalogOutputFlags flags) { // if freq<=0, the default is used
UNUSED(flags);
if(pin == 25 || pin == 26){
value = (value * 256);
uint8_t val8 = value;
writeDAC(pin,val8);
}
else{
value = (value * PWMTimerRange);
uint16_t val16 = value;
writePWM(pin,val16,(int) freq);
}
return 0;
}
/**
*
*/
void jshSetOutputValue(JshPinFunction func, int value) {
int pin;
if (JSH_PINFUNCTION_IS_DAC(func)) {
uint8_t val = (uint8_t)(value >> 8);
switch (func & JSH_MASK_INFO) {
case JSH_DAC_CH1: writeDAC(25,val); break;
case JSH_DAC_CH2: writeDAC(26,val); break;
}
}
else{
pin = ((func >> JSH_SHIFT_INFO) << 4) + ((func >> JSH_SHIFT_TYPE) & 15);
value >> (16 - PWMTimerBit);
setPWM(pin,value);
}
}
/**
*
*/
void jshEnableWatchDog(JsVarFloat timeout) {
UNUSED(timeout);
jsError(">> jshEnableWatchDog Not implemented,using taskwatchdog from RTOS");
}
// Kick the watchdog
void jshKickWatchDog() {
jsError(">> jshKickWatchDog Not implemented,using taskwatchdog from RTOS");
}
/**
* Get the state of the pin associated with the event flag.
*/
bool CALLED_FROM_INTERRUPT jshGetWatchedPinState(IOEventFlags eventFlag) { // can be called at interrupt time
gpio_num_t gpioNum = pinToESP32Pin((Pin)(eventFlag-EV_EXTI0));
bool level = gpio_get_level(gpioNum);
return level;
}
/**
* Set the value of the pin to be the value supplied and then wait for
* a given period and set the pin value again to be the opposite.
*/
void jshPinPulse(
Pin pin, //!< The pin to be pulsed.
bool pulsePolarity, //!< The value to be pulsed into the pin.
JsVarFloat pulseTime //!< The duration in milliseconds to hold the pin.
) {
int duration = (int)pulseTime * 1000; //from millisecs to microsecs
sendPulse(pin, pulsePolarity, duration);
}
/**
* Determine whether the pin can be watchable.
* \return Returns true if the pin is wathchable.
*/
bool jshCanWatch(
Pin pin //!< The pin that we are asking whether or not we can watch it.
) {
UNUSED(pin);
return true; //lets assume all pins will do
}
/**
* Do what ever is necessary to watch a pin.
* \return The event flag for this pin.
*/
IOEventFlags jshPinWatch(
Pin pin, //!< The pin to be watched.
bool shouldWatch //!< True for watching and false for unwatching.
) {
gpio_num_t gpioNum = pinToESP32Pin(pin);
if(shouldWatch){
gpio_set_intr_type(gpioNum,GPIO_INTR_ANYEDGE); //set posedge interrupt
gpio_set_direction(gpioNum,GPIO_MODE_INPUT); //set as input
gpio_set_pull_mode(gpioNum,GPIO_PULLUP_ONLY); //enable pull-up mode
gpio_intr_enable(gpioNum); //enable interrupt
}
else{
if(gpio_intr_disable(gpioNum) == ESP_ERR_INVALID_ARG){ //disable interrupt
jsError("*** jshPinWatch error");
}
}
return pin;
}
/**
*
*/
JshPinFunction jshGetCurrentPinFunction(Pin pin) {
if (jshIsPinValid(pin)) {
int i;
for (i=0;i<JSH_PININFO_FUNCTIONS;i++) {
JshPinFunction func = pinInfo[pin].functions[i];
if (JSH_PINFUNCTION_IS_TIMER(func) ||
JSH_PINFUNCTION_IS_DAC(func))
return func;
}
}
return JSH_NOTHING;
}
/**
* Determine if a given event is associated with a given pin.
* \return True if the event is associated with the pin and false otherwise.
*/
bool jshIsEventForPin(
IOEvent *event, //!< The event that has been detected.
Pin pin //!< The identity of a pin.
) {
return IOEVENTFLAGS_GETTYPE(event->flags) == pinToEV_EXTI(pin);
}
//===== USART and Serial =====
void jshUSARTSetup(IOEventFlags device, JshUSARTInfo *inf) {
initSerial(device,inf);
}
bool jshIsUSBSERIALConnected() {
return false; // "On non-USB boards this just returns false"
}
/**
* Kick a device into action (if required).
*
*/
void jshUSARTKick(
IOEventFlags device //!< The device to be kicked.
) {
int c = jshGetCharToTransmit(device);
while(c >= 0) {
if(device == EV_SERIAL1) uart_tx_one_char((uint8_t)c);
else writeSerial(device,(uint8_t)c);
c = jshGetCharToTransmit(device);
}
}
//===== System time stuff =====
/**
* Given a time in milliseconds as float, get us the value in microsecond
*/
JsSysTime jshGetTimeFromMilliseconds(JsVarFloat ms) {
return (JsSysTime) (ms * 1000.0);
}
/**
* Given a time in microseconds, get us the value in milliseconds (float)
*/
JsVarFloat jshGetMillisecondsFromTime(JsSysTime time) {
return (JsVarFloat) time / 1000.0;
}
/**
* Return the current time in microseconds.
*/
JsSysTime CALLED_FROM_INTERRUPT jshGetSystemTime() { // in us -- can be called at interrupt time
struct timeval tm;
gettimeofday(&tm, 0);
return (JsSysTime)(tm.tv_sec)*1000000L + tm.tv_usec;
}
/**
* Set the current time in microseconds.
*/
void jshSetSystemTime(JsSysTime newTime) {
struct timeval tm;
struct timezone tz;
tm.tv_sec=(time_t)(newTime/1000000L);
tm.tv_usec=0;
tz.tz_minuteswest=0;
tz.tz_dsttime=0;
settimeofday(&tm, &tz);
}
void jshUtilTimerDisable() {
disableTimer(0);
}
void jshUtilTimerStart(JsSysTime period) {
startTimer(0,(uint64_t) period);
}
void jshUtilTimerReschedule(JsSysTime period) {
rescheduleTimer(0,(uint64_t) period);
}
//===== Miscellaneous =====
static uint64_t DEVICE_INITIALISED_FLAGS = 0L;
bool jshIsDeviceInitialised(IOEventFlags device) {
uint64_t mask = 1ULL << (int)device;
return (DEVICE_INITIALISED_FLAGS & mask) != 0L;
// UNUSED(device);
// jsError(">> jshIsDeviceInitialised not implemented");
// return 0;
} // End of jshIsDeviceInitialised
void jshSetDeviceInitialised(IOEventFlags device, bool isInit) {
uint64_t mask = 1ULL << (int)device;
if (isInit) {
DEVICE_INITIALISED_FLAGS |= mask;
} else {
DEVICE_INITIALISED_FLAGS &= ~mask;
}
}
// the esp32 temperature sensor - undocumented library function call. Unsure of values returned.
JsVarFloat jshReadTemperature() {
extern uint8_t temprature_sens_read();
return temprature_sens_read();
}
// the esp8266 can read the VRef but then there's no analog input, so we don't support this
JsVarFloat jshReadVRef() {
jsError(">> jshReadVRef Not implemented");
return NAN;
}
unsigned int jshGetRandomNumber() {
return (unsigned int)rand();
}
//===== Read-write flash =====
/**
* Determine available flash depending on EEprom size
*
*/
uint32_t jshFlashMax() {
return (FLASH_MAX-1);
}
/**
* Read data from flash memory into the buffer.
*
* This reads from flash using memory-mapped reads. Only works for the first 1MB and
* requires 4-byte aligned reads.
*
*/
void jshFlashRead(
void *buf, //!< buffer to read into
uint32_t addr, //!< Flash address to read from
uint32_t len //!< Length of data to read
) {
if(len == 1){ // Can't read a single byte using the API, so read 4 and select the byte requested
uint word;
spi_flash_read(addr & 0xfffffffc,&word,4);
*(uint8_t *)buf = (word >> ((addr & 3) << 3 )) & 255;
}
else spi_flash_read(addr, buf, len);
}
/**
* Write data to flash memory from the buffer.
*
* This is called from jswrap_flash_write and ... which guarantee that addr is 4-byte aligned
* and len is a multiple of 4.
*/
void jshFlashWrite(
void *buf, //!< Buffer to write from
uint32_t addr, //!< Flash address to write into
uint32_t len //!< Length of data to write
) {
spi_flash_write(addr, buf, len);
}
/**
* Return start address and size of the flash page the given address resides in.
* Returns false if no page.
*/
bool jshFlashGetPage(
uint32_t addr, //!<
uint32_t *startAddr, //!<
uint32_t *pageSize //!<
) {
if (addr >= FLASH_MAX) return false;
*startAddr = addr & ~(FLASH_PAGE-1);
*pageSize = FLASH_PAGE;
return true;
}
void addFlashArea(JsVar *jsFreeFlash, uint32_t addr, uint32_t length) {
JsVar *jsArea = jsvNewObject();
if (!jsArea) return;
jsvObjectSetChildAndUnLock(jsArea, "addr", jsvNewFromInteger((JsVarInt)addr));
jsvObjectSetChildAndUnLock(jsArea, "length", jsvNewFromInteger((JsVarInt)length));
jsvArrayPushAndUnLock(jsFreeFlash, jsArea);
}
JsVar *jshFlashGetFree() {
JsVar *jsFreeFlash = jsvNewEmptyArray();
if (!jsFreeFlash) return 0;
// Space should be reserved here in the parition table - assume 4Mb EEPROM
// Set just after programme save area
addFlashArea(jsFreeFlash, 0x100000 + FLASH_PAGE * 16, 0x300000-FLASH_PAGE * 16-1);
return jsFreeFlash;
}
/**
* Erase the flash page containing the address.
*/
void jshFlashErasePage(
uint32_t addr //!<
) {
spi_flash_erase_sector(addr >> FLASH_PAGE_SHIFT);
}
unsigned int jshSetSystemClock(JsVar *options) {
UNUSED(options);
jsError(">> jshSetSystemClock Not implemented");
return 0;
}
/**
* Convert an Espruino pin id to a native ESP32 pin id.
*/
gpio_num_t pinToESP32Pin(Pin pin) {
if ( pin < 40 )
return pin + GPIO_NUM_0;
jsError( "pinToESP32Pin: Unknown pin: %d", pin);
return -1;
}
bool jshNeopixelWrite(Pin pin, unsigned char *rgbData, size_t rgbSize) {
jsExceptionHere(JSET_ERROR, "Neopixel writing not implemented");
return false;
}

View File

@ -0,0 +1,131 @@
/*
* This file is designed to support Analog functions in Espruino,
* a JavaScript interpreter for Microcontrollers designed by Gordon Williams
*
* Copyright (C) 2016 by Juergen Marsch
*
* This Source Code Form is subject to the terms of the Mozilla Publici
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* ----------------------------------------------------------------------------
* This file is designed to be parsed during the build process
*
* Contains ESP32 board specific functions.
* ----------------------------------------------------------------------------
*/
#include "esp_log.h"
#include "jshardwareAnalog.h"
#include "driver/adc.h"
#include "driver/dac.h"
#include <stdio.h>
#define adc_channel_max 8
adc_atten_t adc_channel[8];
adc1_channel_t pinToAdcChannel(Pin pin){
adc1_channel_t channel;
switch(pin){
case 36: channel = ADC1_CHANNEL_0; break;
case 37: channel = ADC1_CHANNEL_1; break;
case 38: channel = ADC1_CHANNEL_2; break;
case 39: channel = ADC1_CHANNEL_3; break;
case 32: channel = ADC1_CHANNEL_4; break;
case 33: channel = ADC1_CHANNEL_5; break;
case 34: channel = ADC1_CHANNEL_6; break;
case 35: channel = ADC1_CHANNEL_7; break;
default: channel = -1; break;
}
return channel;
}
adc_atten_t rangeToAdcAtten(int range){
adc_atten_t atten;
switch (range){
case 1000: atten = ADC_ATTEN_0db; break;
case 1340: atten = ADC_ATTEN_2_5db; break;
case 2000: atten = ADC_ATTEN_6db; break;
case 3600: atten = ADC_ATTEN_11db; break;
default: atten = ADC_ATTEN_11db; break;
}
return atten;
}
int pinToAdcChannelIdx(Pin pin){
int idx;
switch(pin){
case 36: idx = 0;break;
case 37: idx = 1;break;
case 38: idx = 2;break;
case 39: idx = 3;break;
case 32: idx = 4;break;
case 33: idx = 5;break;
case 34: idx = 6;break;
case 35: idx = 7;break;
default: idx = -1; break;
}
return idx;
}
dac_channel_t pinToDacChannel(Pin pin){
dac_channel_t channel;
switch(pin){
case 25: channel = DAC_CHANNEL_1; break;
case 26: channel = DAC_CHANNEL_2; break;
default: channel = -1; break;
}
return channel;
}
void initADC(int ADCgroup){
switch(ADCgroup){
case 1:
adc1_config_width(ADC_WIDTH_12Bit);
for(int i = 0; i < adc_channel_max; i++){ adc_channel[i] = ADC_ATTEN_11db; }
break;
case 2:
jsExceptionHere(JSET_ERROR, "not implemented\n");
break;
case 3:
jsExceptionHere(JSET_ERROR, "not implemented\n");
break;
default:
jsExceptionHere(JSET_ERROR, "out of range\n");
break;
}
}
void rangeADC(Pin pin,int range){
int idx,atten;
idx = pinToAdcChannelIdx(pin);
printf("idx:%d\n",idx);
if(idx >= 0){
adc_channel[idx] = rangeToAdcAtten(range);
printf("Atten:%d \n",adc_channel[idx]);
}
}
int readADC(Pin pin){
adc1_channel_t channel; int value;
channel = pinToAdcChannel(pin);
adc1_config_channel_atten(channel,adc_channel[pinToAdcChannelIdx(pin)]);
if(channel >= 0) {
value = adc1_get_voltage(channel);
return value;
}
else return -1;
}
void writeDAC(Pin pin,uint8_t value){
dac_channel_t channel;
if(value > 255){
jsExceptionHere(JSET_ERROR, "not implemented, only 8 bit supported\n");
return;
}
channel = pinToDacChannel(pin);
if(channel >= 0) dac_out_voltage(channel, value);
}

View File

@ -0,0 +1,24 @@
/*
* This file is designed to support Analog functions in Espruino for ESP32,
* a JavaScript interpreter for Microcontrollers designed by Gordon Williams
*
* Copyright (C) 2016 by Juergen Marsch
*
* This Source Code Form is subject to the terms of the Mozilla Publici
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* ----------------------------------------------------------------------------
* This file is designed to be parsed during the build process
*
* Contains ESP32 board specific functions.
* ----------------------------------------------------------------------------
*/
#include "jspininfo.h"
void initADC(int ADCgroup);
int readADC(Pin pin);
void rangeADC(Pin pin,int range);
void writeDAC(Pin pin,uint8_t value);

View File

@ -0,0 +1,122 @@
/*
* This file is designed to support PWM functions in Espruino,
* a JavaScript interpreter for Microcontrollers designed by Gordon Williams
*
* Copyright (C) 2016 by Juergen Marsch
*
* This Source Code Form is subject to the terms of the Mozilla Publici
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* ----------------------------------------------------------------------------
* This file is designed to be parsed during the build process
*
* Contains ESP32 board specific functions.
* ----------------------------------------------------------------------------
*/
#include "esp_log.h"
#include "jsutils.h"
#include "jshardwarePWM.h"
#include "driver/ledc.h"
#include <stdio.h>
#define PWMFreqDefault 5000
#define PWMPinEmpty 111
#define PWMTimerDefault 3
int getTimerIndex(Pin pin,int freq){
int i;
for(i = 0; i < PWMFreqMax; i++){
if(PWMFreqChannels[i].pin == pin) return i;
}
return -1;
}
int getFreeTimer(Pin pin,int freq){
int i;
i = getTimerIndex(pin,freq);
if(i >= 0) return i;
for(i = 0; i < PWMFreqMax; i++){
if(PWMFreqChannels[i].pin == PWMPinEmpty) return i;
}
return -1;
}
int getChannelIndex(Pin pin){
int i;
for(i = 0; i < PWMMax; i++){
if(PWMChannels[i].pin == pin) return i;
}
return -1;
}
int getFreeChannel(pin){
int i;
i = getChannelIndex(pin);
if(i >= 0) return i;
for(i = 0; i < PWMMax; i++){
if(PWMChannels[i].pin == PWMPinEmpty) return i;
}
return -1;
}
void timerConfig(int freq,int timer){
ledc_timer_config_t PWM_timer = {
.bit_num = LEDC_TIMER_10_BIT,//set timer counter bit number
.freq_hz = freq,//set frequency of pwm
.speed_mode = LEDC_HIGH_SPEED_MODE,//timer mode,
.timer_num = timer//timer index
};
ledc_timer_config(&PWM_timer);
}
void channelConfig(int timer, int channel, int value, Pin pin){
ledc_channel_config_t PWM_channel = {
.channel = channel,//set LEDC channel 0
.duty = value,//set the duty for initialization.(duty range is 0 ~ ((2**bit_num)-1)
.gpio_num = pin,//GPIO number
.intr_type = LEDC_INTR_DISABLE,//GPIO INTR TYPE, as an example, we enable fade_end interrupt here.
.speed_mode = LEDC_HIGH_SPEED_MODE,//set LEDC mode, from ledc_mode_t
.timer_sel = timer
};
ledc_channel_config(&PWM_channel);
}
void PWMInit(){
int i;
timerConfig(PWMFreqDefault,PWMTimerDefault);
for(i = 0; i < PWMMax; i++) PWMChannels[i].pin = PWMPinEmpty;
for(i = 0; i < PWMFreqMax; i++) PWMFreqChannels[i].pin = PWMPinEmpty;
}
void writePWM(Pin pin,uint16_t value,int freq){
int channel; int timer;
if(freq == PWMFreqDefault || freq == 0){
channel = getFreeChannel(pin);
if(channel < 0){jsError("no PWM channel available anymore");}
else{
PWMChannels[channel].pin = pin;
channelConfig(PWMTimerDefault,channel,value,pin);
}
}
else{
timer = getFreeTimer(pin,freq);
if(timer < 0){jsError("no PWM channel available anymore");}
else{
PWMFreqChannels[timer].pin = pin;
PWMFreqChannels[timer].freq = freq;
timerConfig(freq,timer);
channelConfig(timer,PWMMax + timer,value,pin);
}
}
}
void setPWM(Pin pin,uint16_t value){
int channel = getChannelIndex(pin);
if(channel < 0){jsError("pin not assigned to pwm");}
else{
ledc_set_duty(LEDC_HIGH_SPEED_MODE, channel, value);
}
}

View File

@ -0,0 +1,33 @@
/*
* This file is designed to support PWM functions in Espruino for ESP32,
* a JavaScript interpreter for Microcontrollers designed by Gordon Williams
*
* Copyright (C) 2016 by Juergen Marsch
*
* This Source Code Form is subject to the terms of the Mozilla Publici
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* ----------------------------------------------------------------------------
* This file is designed to be parsed during the build process
*
* Contains ESP32 board specific functions.
* ----------------------------------------------------------------------------
*/
#include "jspininfo.h"
#define PWMMax 5 //maximum PWM channel for Analog output (freq = 50000)
#define PWMFreqMax 3 //maximum PWM channel with free frequency
#define PWMTimerBit 10 //10 bit for value
#define PWMTimerRange 1024
struct PWMChannel{Pin pin;}; //will be extended once we know more about PWM for Espruino on ESP32
struct PWMChannel PWMChannels[PWMMax];
struct PWMFreqChannel{Pin pin; int freq};
struct PWMFreqChannel PWMFreqChannels[PWMFreqMax];
void PWMInit();
void writePWM(Pin pin, uint16_t value,int freq);
void setPWM(Pin pin,uint16_t value);

View File

@ -0,0 +1,99 @@
/*
* This file is designed to support Pulse functions in Espruino,
* a JavaScript interpreter for Microcontrollers designed by Gordon Williams
*
* Copyright (C) 2016 by Juergen Marsch
*
* This Source Code Form is subject to the terms of the Mozilla Publici
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* ----------------------------------------------------------------------------
* This file is designed to be parsed during the build process
*
* Contains ESP32 board specific functions.
* ----------------------------------------------------------------------------
*/
#include "esp_log.h"
#include "jsutils.h"
#include "jshardwarePulse.h"
#include "driver/rmt.h"
#include <stdio.h>
#define RMTPinEmpty 111
rmt_item32_t items[1];
int getRMTIndex(Pin pin){
int i;
for(i = 0; i < RMTChannelMax; i++){
if(RMTChannels[i].pin == pin) return i;
}
return -1;
}
int getFreeRMT(Pin pin){
for(int i = 0; i < RMTChannelMax; i++){
if(RMTChannels[i].pin == RMTPinEmpty) {
RMTChannels[i].pin = pin;
return i;
}
}
return -1;
}
void RMTInit(){
int i;
for(i = 0; i < RMTChannelMax; i++) RMTChannels[i].pin = RMTPinEmpty;
}
int RMTInitChannel(Pin pin, bool pulsePolarity){
rmt_config_t config;
int i = getFreeRMT(pin);
if(i >= 0){
config.rmt_mode = RMT_MODE_TX;
config.channel = i;
config.gpio_num = pin;
config.mem_block_num = 1;
config.tx_config.loop_en = 0;
config.tx_config.carrier_en = 0;
config.tx_config.idle_output_en = 1;
if(pulsePolarity) config.tx_config.idle_level = RMT_IDLE_LEVEL_HIGH;
else config.tx_config.idle_level = RMT_IDLE_LEVEL_LOW;
config.tx_config.carrier_duty_percent = 50;
config.tx_config.carrier_freq_hz = 10000;
config.tx_config.carrier_level = 1;
config.clk_div = 80;
rmt_config(&config);
rmt_driver_install(config.channel, 0, 0);
return i;
}
else return -1;
}
void setPulseLow(int duration){
items[0].duration0 = duration;
items[0].level0 = 0;
items[0].duration1 = 10;
items[0].level1 = 1;
}
rmt_item32_t *setPulseHigh(int duration){
items[0].duration0 = duration;
items[0].level0 = 1;
items[0].duration1 = 10;
items[0].level1 = 0;
}
//pin to be pulsed. value to be pulsed into the pin. duration in milliseconds to hold the pin.
void sendPulse(Pin pin, bool pulsePolarity, int duration){
int i;
i = getRMTIndex(pin);
if(i < 0) i = RMTInitChannel(pin,pulsePolarity);
if(i >= 0){
if(pulsePolarity) setPulseLow(duration);else setPulseHigh(duration);
rmt_write_items(i, items,1,1);
}
else printf("all RMT channels in use\n");
return;
}

View File

@ -0,0 +1,29 @@
/*
* This file is designed to support Pulse functions in Espruino for ESP32,
* a JavaScript interpreter for Microcontrollers designed by Gordon Williams
*
* Copyright (C) 2016 by Juergen Marsch
*
* This Source Code Form is subject to the terms of the Mozilla Publici
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* ----------------------------------------------------------------------------
* This file is designed to be parsed during the build process
*
* Contains ESP32 board specific functions.
* ----------------------------------------------------------------------------
*/
#include "jspininfo.h"
#define RMTChannelMax 8 //maximum RMT channel
struct RMTChannel{Pin pin;}; //will be extended once we know more about RMT functions for Espruino on ESP32
struct RMTChannel RMTChannels[RMTChannelMax];
void RMTInit();
void sendPulse(Pin pin, //!< The pin to be pulsed.
bool pulsePolarity, //!< The value to be pulsed into the pin.
int duration //!< The duration in microseconds to hold the pin.
);

View File

@ -0,0 +1,44 @@
/*
* This file is designed to support Timer functions in Espruino,
* a JavaScript interpreter for Microcontrollers designed by Gordon Williams
*
* Copyright (C) 2016 by Juergen Marsch
*
* This Source Code Form is subject to the terms of the Mozilla Publici
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* ----------------------------------------------------------------------------
* This file is designed to be parsed during the build process
*
* Contains ESP32 board specific functions.
* ----------------------------------------------------------------------------
*/
#include <stdio.h>
#include "esp_log.h"
#include "esp_attr.h"
#include "esp_system.h"
#include "freertos/FreeRTOS.h"
#include "freertos/queue.h"
#include "freertos/task.h"
#include "jshardwareTimer.h"
#include "rtosutil.h"
#include "soc/timer_group_struct.h"
#include "driver/timer.h"
#include "jstimer.h"
void startTimer(int timer_idx,uint64_t duration){
timer_Start(timer_idx,duration);
}
void disableTimer(int timer_idx){
timer_disable_intr(TIMER_GROUP_0, timer_idx);
}
void rescheduleTimer(int timer_idx,uint64_t duration){
timer_Reschedule(timer_idx,duration);
}

View File

@ -0,0 +1,25 @@
/*
* This file is designed to support Timer functions in Espruino for ESP32,
* a JavaScript interpreter for Microcontrollers designed by Gordon Williams
*
* Copyright (C) 2016 by Juergen Marsch
*
* This Source Code Form is subject to the terms of the Mozilla Publici
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* ----------------------------------------------------------------------------
* This file is designed to be parsed during the build process
*
* Contains ESP32 board specific functions.
* ----------------------------------------------------------------------------
*/
void initTimer();
void startTimer(int timer_idx,uint64_t duration);
void disableTimer(int timer_idx);
void rescheduleTimer(int timer_idx,uint64_t duration);

View File

@ -0,0 +1,105 @@
/*
* This file is designed to support FREERTOS functions in Espruino,
* a JavaScript interpreter for Microcontrollers designed by Gordon Williams
*
* Copyright (C) 2016 by Juergen Marsch
*
* This Source Code Form is subject to the terms of the Mozilla Publici
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* ----------------------------------------------------------------------------
* This file is designed to be parsed during the build process
*
* Contains ESP32 board specific functions.
* ----------------------------------------------------------------------------
*/
#include "jshardwareUart.h"
#include "driver/uart.h"
#include <stdio.h>
#include <string.h>
#include <jsdevices.h>
bool serial2_initialized = false;
bool serial3_initialized = false;
void initUart(int uart_num,uart_config_t uart_config,int txpin,int rxpin){
int r;
r = uart_param_config(uart_num, &uart_config); //Configure UART1 parameters
r = uart_set_pin(uart_num, txpin, rxpin, -1, -1); //Set UART0 pins(TX: IO16, RX: IO17, RTS: IO18, CTS: IO19)
r = uart_driver_install(uart_num, 1024, 1024, 10, NULL, 0); //Install UART driver( We don't need an event queue here)
}
void initSerial(IOEventFlags device,JshUSARTInfo *inf){
uart_config_t uart_config = {
.baud_rate = inf->baudRate,
.data_bits = (inf->bytesize == 7)? UART_DATA_7_BITS : UART_DATA_8_BITS,
.stop_bits = (inf->stopbits == 1)? UART_STOP_BITS_1 : UART_STOP_BITS_2,
//.flow_ctrl = (inf->xOnXOff)? UART_HW_FLOWCTRL_DISABLE : UART_HW_FLOWCTRL_CTS_RTS,
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
.rx_flow_ctrl_thresh = 122,
.parity = UART_PARITY_DISABLE
};
switch(inf->parity){
case 0: uart_config.parity = UART_PARITY_DISABLE; break;
case 1: uart_config.parity = UART_PARITY_ODD; break;
case 2: uart_config.parity = UART_PARITY_EVEN; break;
}
if(device == EV_SERIAL1) initUart(uart_console,uart_config,-1,-1);
else{
if(device == EV_SERIAL2){
if(inf->pinTX == 0xff) inf->pinTX = 4;
if(inf->pinRX == 0xff) inf->pinRX = 5;
if(serial2_initialized) uart_driver_delete(uart_Serial2);
initUart(uart_Serial2,uart_config,inf->pinTX,inf->pinRX);
serial2_initialized = true;
}
else{
if(inf->pinTX == 0xff) inf->pinTX = 17;
if(inf->pinRX == 0xff) inf->pinRX = 16;
if(serial3_initialized) uart_driver_delete(uart_Serial3);
initUart(uart_Serial3,uart_config,inf->pinTX,inf->pinRX);
serial3_initialized = true;
}
}
}
void initConsole(){
uart_config_t uart_config = {
.baud_rate = 115200,
.data_bits = UART_DATA_8_BITS,
.parity = UART_PARITY_DISABLE,
.stop_bits = UART_STOP_BITS_1,
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
.rx_flow_ctrl_thresh = 122,
};
initUart(uart_console,uart_config,-1,-1);
}
uint8_t rxbuf[256];
void consoleToEspruino(){
int len = uart_read_bytes(uart_console, rxbuf, sizeof(rxbuf), 100); //Read data from UART
if(len > 0) jshPushIOCharEvents(EV_SERIAL1, rxbuf, len);
}
void serialToEspruino(){
int len;
if(serial2_initialized){
len = uart_read_bytes(uart_Serial2,rxbuf, sizeof(rxbuf),0);
if(len > 0)jshPushIOCharEvents(EV_SERIAL2, rxbuf, len);
}
if(serial3_initialized){
len = uart_read_bytes(uart_Serial3,rxbuf, sizeof(rxbuf),0);
if(len > 0) jshPushIOCharEvents(EV_SERIAL3, rxbuf,len);
}
}
void writeSerial(IOEventFlags device,uint8_t c){
char str[2]; int r;
str[1] = '\0';
str[0] = (char)c;
if(device == EV_SERIAL2){ r = uart_write_bytes(uart_Serial2, (const char*)str,1);}
else{r = uart_write_bytes(uart_Serial3, (const char*)str,1);}
}

View File

@ -0,0 +1,27 @@
/*
* This file is designed to support UART functions in Espruino,
* a JavaScript interpreter for Microcontrollers designed by Gordon Williams
*
* Copyright (C) 2016 by Juergen Marsch
*
* This Source Code Form is subject to the terms of the Mozilla Publici
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* ----------------------------------------------------------------------------
* This file is designed to be parsed during the build process
*
* Contains ESP32 board specific functions.
* ----------------------------------------------------------------------------
*/
#include "jshardware.h"
#define uart_console 0
#define uart_Serial2 1
#define uart_Serial3 2
void initConsole();
void initSerial(IOEventFlags device,JshUSARTInfo *inf);
void writeSerial(IOEventFlags device,uint8_t c);
void consoleToEspruino();
void serialToEspruino();

View File

@ -0,0 +1,139 @@
/*
* This file is part of Espruino, a JavaScript interpreter for Microcontrollers
*
* Copyright (C) 2013 Gordon Williams <gw@pur3.co.uk>
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* ----------------------------------------------------------------------------
* ESP32 specific exposed components.
* ----------------------------------------------------------------------------
*/
#include <stdio.h>
#include "jswrap_esp32.h"
#include "jshardwareAnalog.h"
#include "esp_system.h"
#include "esp_log.h"
static char *tag = "jswrap_esp32";
/*JSON{
"type" : "staticmethod",
"class" : "ESP32",
"name" : "setAtten",
"generate" : "jswrap_ESP32_setAtten",
"params" : [
["pin", "pin", "Pin for Analog read"],
["atten", "int", "Attenuate factor"]
]
}*/
void jswrap_ESP32_setAtten(Pin pin,int atten){
printf("Atten:%d\n",atten);
rangeADC(pin, atten);
}
/*JSON{
"type" : "staticmethod",
"class" : "ESP32",
"name" : "reboot",
"generate" : "jswrap_ESP32_reboot"
}
Perform a hardware reset/reboot of the ESP32.
*/
void jswrap_ESP32_reboot() {
ESP_LOGD(tag, ">> jswrap_ESP32_reboot");
esp_restart(); // Call the ESP-IDF to restart the ESP32.
ESP_LOGD(tag, "<< jswrap_ESP32_reboot");
} // End of jswrap_ESP32_reboot
/*JSON{
"type" : "staticmethod",
"class" : "ESP32",
"name" : "getState",
"generate" : "jswrap_ESP32_getState",
"return" : ["JsVar", "The state of the ESP32"]
}
Returns an object that contains details about the state of the ESP32 with the following fields:
* `sdkVersion` - Version of the SDK.
* `cpuFrequency` - CPU operating frequency in Mhz.
* `freeHeap` - Amount of free heap in bytes.
* `maxCon` - Maximum number of concurrent connections.
* `flashMap` - Configured flash size&map: '512KB:256/256' .. '4MB:512/512'
* `flashKB` - Configured flash size in KB as integer
* `flashChip` - Type of flash chip as string with manufacturer & chip, ex: '0xEF 0x4016`
*/
JsVar *jswrap_ESP32_getState() {
// Create a new variable and populate it with the properties of the ESP32 that we
// wish to return.
JsVar *esp32State = jsvNewObject();
// system_get_sdk_version() - is deprecated , need to find alternative
jsvObjectSetChildAndUnLock(esp32State, "sdkVersion", jsvNewFromString("1.0 2016-12-03"));
//jsvObjectSetChildAndUnLock(esp32State, "cpuFrequency", jsvNewFromInteger(system_get_cpu_freq()));
jsvObjectSetChildAndUnLock(esp32State, "freeHeap", jsvNewFromInteger(esp_get_free_heap_size()));
return esp32State;
} // End of jswrap_ESP32_getState
/*JSON{
"type" : "staticmethod",
"class" : "ESP32",
"name" : "setLogLevel",
"generate" : "jswrap_ESP32_setLogLevel",
"params" : [
["tag", "JsVar", "The tag to set logging."],
["logLevel", "JsVar", "The log level to set."]
]
}
Set the logLevel for the corresponding debug tag. If tag is `*` then we reset all
tags to this logLevel. The logLevel may be one of:
* verbose
* debug
* info
* warn
* error
* none
*/
/**
* The ESP-IDF provides a logging/debug mechanism where logging statements can be inserted
* into the code. At run time, the logging levels can be adjusted dynamically through
* a call to esp_log_level_set. This allows us to selectively switch on or off
* distinct log levels. Imagine a situation where you have no logging (normal status)
* and something isn't working as desired. Now what you can do is switch on all logging
* or a subset of logging through this JavaScript API.
*/
void jswrap_ESP32_setLogLevel(JsVar *jsTagToSet, JsVar *jsLogLevel) {
char tagToSetStr[20];
esp_log_level_t level;
ESP_LOGD(tag, ">> jswrap_ESP32_setLogLevel");
// TODO: Add guards for invalid parameters.
jsvGetString(jsTagToSet, tagToSetStr, sizeof(tagToSetStr));
// Examine the level string and see what kind of level it is.
if (jsvIsStringEqual(jsLogLevel, "verbose")) {
level = ESP_LOG_VERBOSE;
} else if (jsvIsStringEqual(jsLogLevel, "debug")) {
level = ESP_LOG_DEBUG;
} else if (jsvIsStringEqual(jsLogLevel, "info")) {
level = ESP_LOG_INFO;
} else if (jsvIsStringEqual(jsLogLevel, "warn")) {
level = ESP_LOG_WARN;
} else if (jsvIsStringEqual(jsLogLevel, "error")) {
level = ESP_LOG_ERROR;
} else if (jsvIsStringEqual(jsLogLevel, "none")) {
level = ESP_LOG_NONE;
} else {
ESP_LOGW(tag, "<< jswrap_ESP32_setLogLevel - Unknown log level");
return;
}
esp_log_level_set(tagToSetStr, level); // Call the ESP-IDF to set the log level for the given tag.
ESP_LOGD(tag, "<< jswrap_ESP32_setLogLevel");
return;
} // End of jswrap_ESP32_setLogLevel

View File

@ -0,0 +1,26 @@
/*
* This file is part of Espruino, a JavaScript interpreter for Microcontrollers
*
* Copyright (C) 2015 Gordon Williams <gw@pur3.co.uk>
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* ----------------------------------------------------------------------------
* This file is designed to be parsed during the build process
*
* Contains ESP32 board specific function definitions.
* ----------------------------------------------------------------------------
*/
#ifndef TARGETS_ES32_JSWRAP_ESP32_H_
#define TARGETS_ESP32_JSWRAP_ESP32_H_
#include "jsvar.h"
#include "jspin.h"
//===== ESP32 Library
JsVar *jswrap_ESP32_getState();
void jswrap_ESP32_setLogLevel(JsVar *jsTagToSet, JsVar *jsLogLevel);
void jswrap_ESP32_reboot();
void jswrap_ESP32_setAtten(Pin pin,int atten);
#endif /* TARGETS_ESP32_JSWRAP_ESP32_H_ */

240
targets/esp32/jswrap_rtos.c Normal file
View File

@ -0,0 +1,240 @@
/*
* This file is part of Espruino, a JavaScript interpreter for Microcontrollers
*
* Copyright (C) 2013 Gordon Williams <gw@pur3.co.uk>
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* ----------------------------------------------------------------------------
* Task, queue and timer specific exposed components.
* ----------------------------------------------------------------------------
*/
#include <stdio.h>
#include "jswrap_rtos.h"
#include "jsparse.h"
#include "rtosutil.h"
/*JSON{
"type" : "class",
"class" : "Queue"
}
A class to support some simple Queue handling for RTOS queues
*/
/*JSON{
"type" : "constructor",
"class" : "Queue",
"name" : "Queue",
"generate" : "jswrap_Queue_constructor",
"params" : [ ["queueName", "JsVar", "Name of the queue"] ],
"return" : ["JsVar","A Queue object"]
}
Creates a Queue Object
*/
JsVar *jswrap_Queue_constructor(JsVar *queueName){
int idx; char name[20];
JsVar *queue = jspNewObject(0, "Queue");
if (!queue) return 0;
name[jsvGetString(queueName, name, sizeof(name))] = '\0';
idx = queue_indexByName(name);
jsvObjectSetChildAndUnLock(queue, "index", jsvNewFromInteger(idx));
return queue;
}
/*JSON{
"type" : "method",
"class" : "Queue",
"name" : "read",
"generate" : "jswrap_Queue_read"
}
reads one character from queue, if available
*/
void jswrap_Queue_read(JsVar *parent) {
char data;
JsVar *idx = jsvObjectGetChild(parent,"index",1);
queue_read(jsvGetInteger(idx));
jsvUnLock(idx);
return;
}
/*JSON{
"type" : "method",
"class" : "Queue",
"name" : "writeChar",
"params" : [ ["char", "JsVar", "char to be send"] ],
"generate" : "jswrap_Queue_writeChar"
}
Writes one character to queue
*/
void jswrap_Queue_writeChar(JsVar *parent,char c){
JsVar *idx = jsvObjectGetChild(parent,"index",1);
queue_writeChar(idx,c);
}
/*JSON{
"type" : "method",
"class" : "Queue",
"name" : "log",
"generate" : "jswrap_Queue_log"
}
logs list of queues
*/
void jswrap_Queue_log(JsVar *parent) {
queue_list();
return;
}
/*JSON{
"type" : "class",
"class" : "Task"
}
A class to support some simple Task handling for RTOS tasks
*/
/*JSON{
"type" : "constructor",
"class" : "Task",
"name" : "Task",
"generate" : "jswrap_Task_constructor",
"params" : [ ["taskName", "JsVar", "Name of the task"] ],
"return" : ["JsVar","A Task object"]
}
Creates a Task Object
*/
JsVar *jswrap_Task_constructor(JsVar *taskName){
int idx; char name[20];
JsVar *task = jspNewObject(0, "Task");
if (!task) return 0;
name[jsvGetString(taskName, name, sizeof(name))] = '\0';
idx = task_indexByName(name);
jsvObjectSetChildAndUnLock(task, "index", jsvNewFromInteger(idx));
return task;
}
/*JSON{
"type" : "method",
"class" : "Task",
"name" : "suspend",
"generate" : "jswrap_Task_suspend"
}
Suspend task, be careful not to suspend Espruino task itself
*/
void jswrap_Task_suspend(JsVar *parent){
JsVar *idx = jsvObjectGetChild(parent,"index",1);
task_Suspend(jsvGetInteger(idx));
return;
}
/*JSON{
"type" : "method",
"class" : "Task",
"name" : "resume",
"generate" : "jswrap_Task_resume"
}
Resumes a suspended task
*/
void jswrap_Task_resume(JsVar *parent){
JsVar *idx = jsvObjectGetChild(parent,"index",1);
task_Resume(jsvGetInteger(idx));
return;
}
/*JSON{
"type" : "method",
"class" : "Task",
"name" : "getCurrent",
"generate" : "jswrap_Task_getCurrent",
"return" : ["JsVar","Name of current task"]
}
returns name of actual task
*/
JsVar *jswrap_Task_getCurrent(JsVar *parent){
return jsvNewFromString(task_getCurrentName());
}
/*JSON{
"type" : "method",
"class" : "Task",
"name" : "notify",
"generate" : "jswrap_Task_notify"
}
Sends a binary notify to task
*/
void jswrap_Task_notify(JsVar *parent){
JsVar *idx = jsvObjectGetChild(parent,"index",1);
task_notify(jsvGetInteger(idx));
}
/*JSON{
"type" : "method",
"class" : "Task",
"name" : "log",
"generate" : "jswrap_Task_log"
}
logs list of tasks
*/
void jswrap_Task_log(JsVar *parent) {
task_list();
return;
}
/*JSON{
"type" : "class",
"class" : "Timer"
}
A class to handle Timer on base of ESP32 Timer
*/
/*JSON{
"type" : "constructor",
"class" : "Timer",
"name" : "Timer",
"generate" : "jswrap_Timer_constructor",
"params" : [ ["timerName", "JsVar", "Timer Name"],
["group", "int", "Timer group"],
["index", "int", "Timer index"],
["isrIndex", "int", "isr (0 = Espruino, 1 = test)"] ],
"return" : ["JsVar","A Timer Object"]
}
Creates a Timer Object
*/
JsVar *jswrap_Timer_constructor(JsVar *timerName,int group, int index, int isrIndex){
int idx; char name[20];
JsVar *timer = jspNewObject(0, "Timer");
if(!timer) return 0;
name[jsvGetString(timerName, name, sizeof(name))] = '\0';
idx = timer_Init(name,group,index,isrIndex);
jsvObjectSetChildAndUnLock(timer, "index", jsvNewFromInteger(idx));
return timer;
}
/*JSON{
"type" : "method",
"class" : "Timer",
"name" : "start",
"params" : [["duration","int","duration of timmer in micro secs"]],
"generate" : "jswrap_Timer_start"
}
Starts a timer
*/
void jswrap_Timer_start(JsVar *parent, int duration){
JsVar *idx = jsvObjectGetChild(parent,"index",1);
timer_Start(jsvGetInteger(idx),duration);
}
/*JSON{
"type" : "method",
"class" : "Timer",
"name" : "reschedule",
"params" : [["duration","int","duration of timmer in micro secs"]],
"generate" : "jswrap_Timer_reschedule"
}
Reschedules a timer, needs to be started at least once
*/
void jswrap_Timer_reschedule(JsVar *parent, int duration){
JsVar *idx = jsvObjectGetChild(parent,"index",1);
timer_Reschedule(jsvGetInteger(idx),duration);
}
/*JSON{
"type" : "method",
"class" : "Timer",
"name" : "log",
"generate" : "jswrap_Timer_log"
}
logs list of timers
*/
void jswrap_Timer_log(JsVar *parent) {
timer_List();
return;
}

View File

@ -0,0 +1,42 @@
/*
* This file is part of Espruino, a JavaScript interpreter for Microcontrollers
*
* Copyright (C) 2015 Gordon Williams <gw@pur3.co.uk>
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* ----------------------------------------------------------------------------
* This file is designed to be parsed during the build process
*
* Task, queue and timer specific exposed components.
* ----------------------------------------------------------------------------
*/
#ifndef TARGETS_JSWRAP_RTOS_H_
#define TARGETS_JSWRAP_RTOS_H_
#include "jsvar.h"
//===== Queue Library
JsVar *jswrap_Queue_constructor(JsVar *queueName);
void jswrap_Queue_read(JsVar *parent);
void jswrap_Queue_writeChar(JsVar *parent,char c);
void jswrap_Queue_log(JsVar *parent);
// ==== Task handling
JsVar *jswrap_Task_constructor(JsVar *taskName);
void jswrap_Task_suspend(JsVar *parent);
void jswrap_Task_resume(JsVar *parent);
JsVar *jswrap_Task_getCurrent(JsVar *parent);
void jswrap_Task_notify(JsVar *taskName);
void jswrap_Task_log(JsVar *parent);
// ==== Timer handling
JsVar *jswrap_Timer_constructor(JsVar *timerName,int group, int index, int isrIndex);
void jswrap_Timer_start(JsVar *parent, int duration);
void jswrap_Timer_reschedule(JsVar *parent, int duration);
void jswrap_Timer_log(JsVar *parent);
#endif /* TARGETS_JSWRAP_RTOS_H_ */

81
targets/esp32/main.c Normal file
View File

@ -0,0 +1,81 @@
#include "freertos/FreeRTOS.h"
#include "esp_wifi.h"
#include "esp_system.h"
#include "esp_event.h"
#include "esp_event_loop.h"
#include "nvs_flash.h"
#include <stdio.h>
#include <jsdevices.h>
#include <jsinteractive.h>
#include "rtosutil.h"
#include "jstimer.h"
#include "jshardwareUart.h"
#include "jshardwareAnalog.h"
#include "jshardwareTimer.h"
#include "jshardwarePWM.h"
#include "jshardwarePulse.h"
#include "spi.h" //rename to jahardwareSPI.h ?
#include "esp_spi_flash.h"
extern void jswrap_ESP32_wifi_restore(void) ;
extern void initialise_wifi(void);
static void uartTask(void *data) {
initConsole();
while(1) {
consoleToEspruino();
serialToEspruino();
}
}
static void timerTask(void *data) {
vTaskDelay(500 / portTICK_PERIOD_MS);
timers_Init();
timer_Init("EspruinoTimer",0,0,0);
timer_List();
while(1) {
taskWaitNotify();
jstUtilTimerInterruptHandler();
}
}
static void espruinoTask(void *data) {
PWMInit();
RMTInit();
SPIChannelsInit();
initADC(1);
jshInit(); // Initialize the hardware
jswrap_ESP32_wifi_restore();
jsvInit(); // Initialize the variables
vTaskDelay(1000 / portTICK_PERIOD_MS);
jsiInit(true); // Initialize the interactive subsystem
while(1) {
jsiLoop(); // Perform the primary loop processing
}
}
/**
* The main entry point into Espruino on an ESP32.
*/
int app_main(void)
{
nvs_flash_init();
spi_flash_init();
tcpip_adapter_init();
#ifdef RTOS
queues_init();
tasks_init();
task_init(espruinoTask,"EspruinoTask",10000,5,0);
task_init(uartTask,"ConsoleTask",2000,20,0);
task_init(timerTask,"TimerTask",2048,19,0);
#else
xTaskCreatePinnedToCore(&espruinoTask, "espruinoTask", 10000, NULL, 5, NULL, 0);
xTaskCreatePinnedToCore(&uartTask,"uartTask",2000,NULL,20,NULL,0);
xTaskCreatePinnedToCore(&timerTask,"timerTask",2048,NULL,19,NULL,0);
#endif
return 0;
}

249
targets/esp32/rtosutil.c Normal file
View File

@ -0,0 +1,249 @@
/*
* This file is designed to support FREERTOS functions in Espruino,
* a JavaScript interpreter for Microcontrollers designed by Gordon Williams
*
* Copyright (C) 2016 by Juergen Marsch
*
* This Source Code Form is subject to the terms of the Mozilla Publici
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* ----------------------------------------------------------------------------
* This file is designed to be parsed during the build process
*
* Task, queue and timer specific exposed components.
* ----------------------------------------------------------------------------
*/
#include "rom/uart.h"
#include "rtosutil.h"
#include "soc/timer_group_struct.h"
#include "driver/timer.h"
#include <stdio.h>
#include <string.h>
// implementation of simple queue oriented commands. see header file for more info.
void queues_init(){
int i;
for(i = 0; i < queueMax; i++){ RTOSqueues[i].name = NULL; RTOSqueues[i].handle = NULL;}
}
int queue_indexByName(char *queueName){
int i;
for(i = 0; i < queueMax; i++){
if(RTOSqueues[i].handle != 0){
if(strcmp(queueName,RTOSqueues[i].name) == 0){
return i;
}
}
}
return -1;
}
QueueHandle_t queue_handleByName(char *queueName){
int idx;
idx = queue_indexByName(queueName);
return RTOSqueues[idx].handle;
}
int queue_init(char *queueName,int length,int sizeOfEntry){
int i;
for(i = 0; i < queueMax; i++){
if(NULL == RTOSqueues[i].handle){
RTOSqueues[i].name = queueName;
RTOSqueues[i].handle = xQueueCreate(length,sizeOfEntry);
return i;
}
}
return -1;
}
void queue_list(){
int i;
for(i = 0; i < queueMax; i++){
if(RTOSqueues[i].name == NULL) return;
printf("queue %s : %d\n",RTOSqueues[i].name,RTOSqueues[i].handle);
}
}
char *queue_read(int idx){
char data;
if(xQueueReceive(RTOSqueues[idx].handle,&data,0)){
return data;
}
return NULL;
}
void queue_writeChar(int idx,char c){
if(!xQueueSend(RTOSqueues[idx].handle,&c,1)){
printf("SerialTaskOverflow\n");
}
}
// implementation of simple task oriented commands. see header file for more info.
void tasks_init(){
int i;
for(i = 0; i < taskMax; i++){ RTOStasks[i].name = NULL; RTOStasks[i].handle = NULL;}
}
int task_indexByName(char *taskName){
int i;
for(i = 0; i < taskMax; i++){
if(RTOStasks[i].handle != 0){
if(strcmp(taskName,RTOStasks[i].name) == 0){
return i;
}
}
}
return -1;
}
TaskHandle_t task_handleByName(char *taskName){
int idx;
idx = task_indexByName(taskName);
return RTOStasks[idx].handle;
}
int *task_getCurrentIndex(){
int i;TaskHandle_t handle;
handle = xTaskGetCurrentTaskHandle();
for(i = 0; i < taskMax; i++){
if(RTOStasks[i].handle == handle){
return i;
}
}
return NULL;
}
char *task_getCurrentName(){
int i;TaskHandle_t handle;
handle = xTaskGetCurrentTaskHandle();
for(i = 0; i < taskMax; i++){
if(RTOStasks[i].handle == handle){
return RTOStasks[i].name;
}
}
return NULL;
}
int task_init(TaskFunction_t taskCode, char *taskName,unsigned short stackDepth,UBaseType_t priority,BaseType_t coreId){
int i;
for(i = 0; i < taskMax; i++){
if(NULL == RTOStasks[i].handle){
RTOStasks[i].name = taskName;
xTaskCreatePinnedToCore(taskCode,taskName,stackDepth,NULL,priority,&RTOStasks[i].handle,coreId);
return i;
}
}
return -1;
}
void task_list(){
int i;
for(i = 0; i < taskMax;i++){
if(RTOStasks[i].name == NULL) return;
printf("task %s : %d\n",RTOStasks[i].name,RTOStasks[i].handle);
}
}
void task_Suspend(int idx){
vTaskSuspend(RTOStasks[idx].handle);
}
void task_Resume(int idx){
vTaskResume(RTOStasks[idx].handle);
}
void task_notify(int idx){
xTaskNotifyGive(RTOStasks[idx].handle);
}
void taskWaitNotify(){
ulTaskNotifyTake(pdTRUE,portMAX_DELAY);
}
#define TIMER_INTR_SEL TIMER_INTR_LEVEL /*!< Timer level interrupt */
#define TIMER_GROUP TIMER_GROUP_0 /*!< Test on timer group 0 */
#define TIMER_DIVIDER 80 /*!< Hardware timer clock divider */
#define TIMER_SCALE (TIMER_BASE_CLK / TIMER_DIVIDER) /*!< used to calculate counter value */
#define TIMER_FINE_ADJ (1.4*(TIMER_BASE_CLK / TIMER_DIVIDER)/1000000) /*!< used to compensate alarm value */
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
void IRAM_ATTR espruino_isr(void *para){
int idx = (int) para;
//printf("y%d",idx);
if(idx == 0){
TIMERG0.hw_timer[TIMER_0].update = 1;
TIMERG0.int_clr_timers.t0 = 1;
}
else{
TIMERG0.hw_timer[TIMER_1].update = 1;
TIMERG0.int_clr_timers.t1 = 1;
}
vTaskNotifyGiveFromISR(RTOStasks[ESP32Timers[idx].taskToNotifyIdx].handle,&xHigherPriorityTaskWoken);
}
void IRAM_ATTR test_isr(void *para){
int idx = (int) para;
printf("x\n");
if(idx == 0){
TIMERG0.hw_timer[TIMER_0].update = 1;
TIMERG0.int_clr_timers.t0 = 1;
}
else{
TIMERG0.hw_timer[TIMER_1].update = 1;
TIMERG0.int_clr_timers.t1 = 1;
}
}
void timers_Init(){
int i;
for(i = 0; i < timerMax; i++){
ESP32Timers[i].name = NULL;
}
}
int timer_indexByName(char *timerName){
int i;
for(i = 0; i < timerMax; i++){
if(ESP32Timers[i].name == NULL) return -1;
if(strcmp(timerName,ESP32Timers[i].name) == 0){
return i;
}
}
return -1;
}
int timer_Init(char *timerName,int group,int index,int isr_idx){
int i;
for(i = 0; i < timerMax; i++){
if(ESP32Timers[i].name == NULL){
ESP32Timers[i].name = timerName;
ESP32Timers[i].group = group;
ESP32Timers[i].index = index;
timer_config_t config;
config.alarm_en = 1;
config.auto_reload = 1;
config.counter_dir = TIMER_COUNT_UP;
config.divider = TIMER_DIVIDER;
config.intr_type = TIMER_INTR_SEL;
config.counter_en = TIMER_PAUSE;
timer_init(group, index, &config);/*Configure timer*/
timer_pause(group, index);/*Stop timer counter*/
timer_set_counter_value(group, index, 0x00000000ULL);/*Load counter value */
timer_enable_intr(group, index);
if(isr_idx == 0){
ESP32Timers[i].taskToNotifyIdx = task_indexByName("TimerTask");
timer_isr_register(group, index, espruino_isr, (void*) i, ESP_INTR_FLAG_IRAM, NULL);
}
else{
timer_isr_register(group, index, test_isr, (void*) i, ESP_INTR_FLAG_IRAM, NULL);
}
return i;
}
}
return -1;
}
void timer_Start(int idx,uint64_t duration){
//printf("StartTimer:%d = %d\n",idx,duration);
timer_enable_intr(ESP32Timers[idx].group, ESP32Timers[idx].index);
timer_set_alarm_value(ESP32Timers[idx].group, ESP32Timers[idx].index, duration - TIMER_FINE_ADJ);
TIMERG0.hw_timer[idx].config.alarm_en = 1;
timer_start(ESP32Timers[idx].group, ESP32Timers[idx].index);
}
void timer_Reschedule(int idx,uint64_t duration){
//printf("reschedule:%d\n",cnt++);
timer_set_alarm_value(ESP32Timers[idx].group, ESP32Timers[idx].index, duration - TIMER_FINE_ADJ);
TIMERG0.hw_timer[idx].config.alarm_en = 1;
}
void timer_List(){
int i;
for(i = 0; i < timerMax; i++){
if(ESP32Timers[i].name == NULL){printf("timer %d free\n",i);}
else {printf("timer %s : %d.%d\n",ESP32Timers[i].name,ESP32Timers[i].group,ESP32Timers[i].index);}
}
return;
}

63
targets/esp32/rtosutil.h Normal file
View File

@ -0,0 +1,63 @@
/*
* This file is designed to support FREERTOS functions in Espruino,
* a JavaScript interpreter for Microcontrollers designed by Gordon Williams
*
* Copyright (C) 2016 by Juergen Marsch
*
* This Source Code Form is subject to the terms of the Mozilla Publici
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* ----------------------------------------------------------------------------
* This file is designed to be parsed during the build process
*
* Task, queue and timer specific exposed components.
* ----------------------------------------------------------------------------
*/
#include "freertos/FreeRTOS.h"
#include "freertos/queue.h"
#include "freertos/task.h"
#define queueMax 10 //for queus we use an array of name/handle info. Core RTOS is not very helpful for this
struct RTOSqueue{ char *name;QueueHandle_t handle;};
struct RTOSqueue RTOSqueues[queueMax];
#define taskMax 10 //for tasks we use an array of name/handle info similiar to queue array
struct RTOStask{ char *name;TaskHandle_t handle;int rx;};
struct RTOStask RTOStasks[taskMax];
#define timerMax 2 //for Timer we use an array of timer relevant info
struct ESP32Timer{ char *name; int group; int index; uint64_t duration; int taskToNotifyIdx; };
struct ESP32Timer ESP32Timers[timerMax];
void queues_init(); //initializes array of queues
int queue_indexByName(char *queueName); //returns index of queue in queue array by name
QueueHandle_t queue_handleByName(char *queueName); //returns handle of queue by name
int queue_init(char *queueName,int length,int sizeOfEntry); //initializes a queue with name,length and size of each entry
char *queue_read(int idx); //reads one character from queue
void queue_writeChar(int idx,char c); //writes one char to queue
void queue_list(); //logs queue list
void tasks_init(); //initializes array of tasks
int task_indexByName(char *taskName); //returns index of task in task array by name
TaskHandle_t task_handleByName(char *taskName); //returns handle of task by name
int *task_getCurrentIndex(); //returns index of actual task
char *task_getCurrentName(); //returns name of actual task
int task_init(TaskFunction_t taskCode, char *taskName,unsigned short stackDepth,UBaseType_t priority,BaseType_t coreId);
//initializes a task, using nonstandard rtos api call xTaskCreatePinnedToCore
void task_list(); //lists all entrys of task array usinf printf
void task_Suspend(int idx); //suspends task given by index in task array
void task_Resume(int idx); //resumes task given by index in task array
void task_notify(int idx); //notify task given by index with binary
void taskWaitNotify(); //waits for notify
void timers_Init();
int timer_indexByName(char *timerName);
int timer_Init(char *timerName,int group,int index,int isr_idx);
void timer_Start(int idx,uint64_t duration);
void timer_Reschedule(int idx,uint64_t duration);
void timer_List();
void console_readToQueue(); //reads char from uart and writes to RTOS queue, not using interrupts (yet)

203
targets/esp32/spi.c Normal file
View File

@ -0,0 +1,203 @@
/*
* This file is designed to support spi functions in Espruino for ESP32,
* a JavaScript interpreter for Microcontrollers designed by Gordon Williams
*
* Copyright (C) 2016 by Rhys Williams (wilberforce)
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* ----------------------------------------------------------------------------
* This file is designed to be parsed during the build process
*
* Contains ESP32 board specific functions.
* ----------------------------------------------------------------------------
*/
#include "jspininfo.h"
#include "jshardware.h"
#include "driver/gpio.h"
#include "spi.h"
#define UNUSED(x) (void)(x)
int getSPIChannelPnt(IOEventFlags device){
return device - EV_SPI1;
}
void SPIChannelsInit(){
int i;
for(i = 0; i < SPIMax; i++){
SPIChannels[i].spi = NULL;
SPIChannels[i].spi_read = false;
SPIChannels[i].g_lastSPIRead = (uint32_t)-1;
}
SPIChannels[0].HOST = HSPI_HOST;
SPIChannels[1].HOST = VSPI_HOST;
}
void jshSetDeviceInitialised(IOEventFlags device, bool isInit);
/*
https://hackadaycom.files.wordpress.com/2016/10/esp32_pinmap.png
HSPI 2 //SPI bus normally mapped to pins 12 - 15, but can be matrixed to any pins
15 HSPI SS
14 HSPI SCK
12 HSPI MISO
13 HSPI MOSI
VSPI 3 //SPI bus normally attached to pin:
5 VSPI SS
18 VSPI SCK
19 VSPI MISO
23 VSPI MOSI
Does not correspond to:
https://github.com/espressif/esp-idf/blob/master/examples/26_spi_master/main/spi_master.c#L34
#define PIN_NUM_MISO 25
#define PIN_NUM_MOSI 23
#define PIN_NUM_CLK 19
#define PIN_NUM_CS 22
#define PIN_NUM_DC 21
#define PIN_NUM_RST 18
#define PIN_NUM_BCKL 5
To do:
implement inf->spiMSB
Test with ILI9341 works, but could be faster.
Espruino supports sendig byte by byte, no mass sending is supported.
*/
/**
* Initialize the hardware SPI device.
* On the ESP32, hardware SPI is implemented via a set of default pins defined
* as follows:
*
*
*/
void jshSPISetup(
IOEventFlags device, //!< The identity of the SPI device being initialized.
JshSPIInfo *inf //!< Flags for the SPI device.
) {
int channelPnt = getSPIChannelPnt(device);
Pin sck, miso, mosi;
if(SPIChannels[channelPnt].HOST == HSPI_HOST){
sck = inf->pinSCK != PIN_UNDEFINED ? inf->pinSCK : 14;
miso = inf->pinMISO != PIN_UNDEFINED ? inf->pinMISO : 12;
mosi = inf->pinMOSI != PIN_UNDEFINED ? inf->pinMOSI : 13;
}
else {
sck = inf->pinSCK != PIN_UNDEFINED ? inf->pinSCK : 5;
miso = inf->pinMISO != PIN_UNDEFINED ? inf->pinMISO : 19;
mosi = inf->pinMOSI != PIN_UNDEFINED ? inf->pinMOSI : 23;
}
spi_bus_config_t buscfg={
.miso_io_num=miso,
.mosi_io_num=mosi,
.sclk_io_num=sck,
.quadwp_io_num=-1,
.quadhd_io_num=-1
};
// SPI_DEVICE_BIT_LSBFIRST - test inf->spiMSB need to look at what values...
uint32_t flags = 0;
spi_device_interface_config_t devcfg={
.clock_speed_hz=inf->baudRate,
.mode=inf->spiMode,
.spics_io_num= -1, //set CS not used by driver
.queue_size=7, //We want to be able to queue 7 transactions at a time
.flags=flags
};
if(SPIChannels[channelPnt].spi){
spi_bus_remove_device(SPIChannels[channelPnt].spi);
spi_bus_free(SPIChannels[channelPnt].HOST);
jsWarn("spi was already in use, removed old assignment");
}
esp_err_t ret=spi_bus_initialize(SPIChannels[channelPnt].HOST, &buscfg, 1);
assert(ret==ESP_OK);
ret = spi_bus_add_device(SPIChannels[channelPnt].HOST, &devcfg, &SPIChannels[channelPnt].spi);
assert(ret==ESP_OK);
jshSetDeviceInitialised(device, true);
}
/** Send data through the given SPI device (if data>=0), and return the result
* of the previous send (or -1). If data<0, no data is sent and the function
* waits for data to be returned */
int jshSPISend(
IOEventFlags device, //!< The identity of the SPI device through which data is being sent.
int data //!< The data to be sent or an indication that no data is to be sent.
) {
int channelPnt = getSPIChannelPnt(device);
uint8_t byte = (uint8_t)data;
//os_printf("> jshSPISend - device=%d, data=%x\n", device, data);
int retData = (int)SPIChannels[channelPnt].g_lastSPIRead;
if (data >=0) {
// Send 8 bits of data taken from "data" over the selected spi and store the returned
// data for subsequent retrieval.
//spiTransferBits(_spi[which_spi], (uint32_t)data, &g_lastSPIRead, 8);
esp_err_t ret;
spi_transaction_t t;
memset(&t, 0, sizeof(t)); //Zero out the transaction
t.length=8; //Command is 8 bits
t.tx_buffer=&data; //The data is the cmd itself
// https://esp-idf.readthedocs.io/en/latest/api/spi_master.html#type-definitions
// should this be a switch or always read?
t.flags=SPI_TRANS_USE_RXDATA;
ret=spi_device_transmit(SPIChannels[channelPnt].spi, &t); //Transmit - blocks until result - need to change this?
assert(ret == ESP_OK);
SPIChannels[channelPnt].g_lastSPIRead=t.rx_data[0];
} else {
SPIChannels[channelPnt].g_lastSPIRead = (uint32_t)-1;
}
return (int)retData;
}
/**
* Send 16 bit data through the given SPI device.
*/
void jshSPISend16(
IOEventFlags device, //!< Unknown
int data //!< Unknown
) {
int channelPnt = getSPIChannelPnt(device);
//spiWriteWord(_spi[which_spi], data);
jsError(">> jshSPISend16: Not implemented");
}
/**
* Set whether to send 16 bits or 8 over SPI.
*/
void jshSPISet16(
IOEventFlags device, //!< Unknown
bool is16 //!< Unknown
) {
UNUSED(device);
UNUSED(is16);
jsError(">> jshSPISend16: Not implemented");
}
/**
* Wait until SPI send is finished.
*/
void jshSPIWait(
IOEventFlags device //!< Unknown
) {
int channelPnt = getSPIChannelPnt(device);
//spiWaitReady(_spi[which_spi]);
//jsError(">> jshSPIWait: Not implemented");
}
/** Set whether to use the receive interrupt or not */
void jshSPISetReceive(IOEventFlags device, bool isReceive) {
int channelPnt = getSPIChannelPnt(device);
SPIChannels[channelPnt].spi_read = isReceive;
}

42
targets/esp32/spi.h Normal file
View File

@ -0,0 +1,42 @@
/*
* This file is designed to support spi functions in Espruino for ESP32,
* a JavaScript interpreter for Microcontrollers designed by Gordon Williams
*
* Copyright (C) 2016 by Rhys Williams (wilberforce)
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* ----------------------------------------------------------------------------
* This file is designed to be parsed during the build process
*
* Contains ESP32 board specific functions.
* ----------------------------------------------------------------------------
*/
#include "jspininfo.h"
#include "jshardware.h"
#include "driver/gpio.h"
#include "driver/spi_master.h"
// Convert an Espruino pin to an ESP32 pin number.
gpio_num_t pinToESP32Pin(Pin pin);
#define SPIMax 2
struct SPIChannel{
spi_device_handle_t spi;
bool spi_read;
uint32_t g_lastSPIRead;
spi_host_device_t HOST;
};
struct SPIChannel SPIChannels[SPIMax];
void SPIChannelsInit();
void jshSPISetup( IOEventFlags device, JshSPIInfo *inf );
int jshSPISend( IOEventFlags device, int data );
void jshSPISend16( IOEventFlags device, int data );
void jshSPISet16( IOEventFlags device, bool is16 );
void jshSPIWait( IOEventFlags device );
void jshSPISetReceive(IOEventFlags device, bool isReceive);

View File

@ -0,0 +1,46 @@
console.log('Button and GPIO tests');
// Led on D22 should flash once per second
// [boot] button on board should toggle led state
// Any one wire devices on D23 should be listed.
var led = Pin(D23);
var led = Pin(D22);
//var led = Pin(D15); //
//
var toggle=1;
//pinMode(F5, "input");
digitalWrite(D23, 0);
pinMode(D23, "input");
var ow = new OneWire(D23);
console.log('look for one wire');
var sensors = ow.search().map(function (device) {
console.log(device);
return require("DS18B20").connect(ow, device);
});
console.log(sensors);
function updateLed(){
digitalWrite(led, toggle);
toggle=!toggle;
}
// Boot button 1 up 0 down
digitalRead(D0);
function button_down() {
updateLed();
print('button');
}
setWatch(button_down,D0, {repeat:true, edge:"rising"});
setInterval( function() {
//console.log('tick');
updateLed();
}, 1000 );

View File

@ -0,0 +1,15 @@
// Connect to an access point and get a web page.
//
var ssid="guest";
var password="kolbanguest";
var wifi=require("Wifi");
wifi.connect(ssid, {password: password}, function() {
console.log("Connected to access point, getting web page");
var http = require("http");
http.get("http://www.espruino.com", function(res) {
res.on('data', function(data) {
console.log(data);
});
});
});

View File

@ -0,0 +1,15 @@
// Connect to an access point and get a web page.
//
var ssid="guest";
var password="kolbanguest";
var wifi=require("Wifi");
wifi.connect(ssid, {password: password}, function() {
console.log("Connected to access point, getting web page");
var http = require("http");
http.get("https://httpbin.org/ip", function(res) {
res.on('data', function(data) {
console.log(data);
});
});
});

View File

@ -0,0 +1,43 @@
var okey = atob("MIIEogIBAAKCAQEAwcBeteXIax0S+gNFv4f0K+q4LOv/E7kmiT8IvZl85NvUDF/slro/x/EreRMGmjcxoeT7+U62nrVu07lZhc+WAiluBX6Ykb2h7lJ/1M3MKV4uK5Yq92p1MxVXzYhVbCKBmcKrPu7Od+hLIMLIMTu0zwc23cE4tSUP4WV38BAzol3k9Rhd1MIjdZ3QUBTYYrvPveUv1TCdsQNsAGv5ZhJx57Anm52W7jTzwBw1O4cn31TD0KD3US/yDKL2IH7BSBFiadN5AzBJbh/ch16/aOfUBIlKNZf9LofMOVLxNm9hxpP2vgckl9u9nTtWiCR5EmKZaTqTqN7bsoLkNKR1GJ6yBwIBIwKCAQAQm3XVE7IXz0rE+PdZj09xeoTQpoOT+e1cOJpZZO1ys8G36vcFmu+GKp1ThUm1cnH37w5Ikbfht8erv24SyKZ1NsBJnSMFLYLoirp/9GH06tDB6EzTYOV5aDq52HxZudCYJqD2xAMRl5FpNURb/c2rWGPJ3Vyhz/oMAWINQzegM8in120G0ZmEnbdvdDWivWKJ4Ap1/fqiWr6yBLbG7gKnLkU3PksQG0YtTahSGXdfEPAi7+CIcRi8svM2Agecm7DH3MW/pgHY8JX87psAmgqCONyVqcAiBlBwQrIk59pczKuzCOSp66STM5S7pXwIuWz/YDJPaGPIL8U/GAyQvJxjAoGBAPfc71FJNg+pKvQMUybGutDtACkexYBNVInpkAKBtGszPjN8xVmmh9huHj+zooFSxQPB2FmsNW7i69pf09FFFgf2tDL22BcG9VldpJR8l77EVw2arovoKC1TyCWxNvD+LYA6VIdd0OXUfUIXG9RGnnnNmHplO5IQ4ka2KI3XEuBtAoGBAMgcrRSRVBTBQtWEyz/cCivdrzdV2AaoNtv5+k0o2pJrViHvrCbhGZNBc/R0u4s3dM53L2IX0w065LD1PeyKjaFXZO2lx3Iu3lf4L8U6oEVQ8C8eLQUOwJ8dK1fWp304Z/iwStwmTa0TZE05KKhl+31NlSOlNr2CHfWeY1So81vDAoGBAKn2lXmRSaRWvl40VkZ5pKyFQfBPnV9K+CQN3xepZcXZ/sQ4TM/CpktEMf/LoqHSWzXGwD19ZnfsD3ErxHI+AHp9SF12EITRkkvocNrZF5jBJcAvjaHDw8dPZKwhv0YqotuVtk4xs9DMOKJY/SPYpy7zYT38RhsEQ2OwG8754Q7rAoGASlPLQidZvpDs8DijQ5rfNN1PtXeoAnj+bvZy6XWTAy8unuP+HRHHq7k5spHCAIJP9Opwr2fvTg6PdO1gJKh9v5V9QlOEmCAJcSGrV+KTTPItU1RZ3U6fUQrVlaeACfBhIdsUfafTtVBYdHRQ7hdAJzoS0rm1PxMScSwzhdhaY+kCgYEAtpWlQzz7u+lurGKbKZY1cTPiFprA9PIsCtl0A5PdQ1XPnYfBgVAlB26oF9ubNy8VxpoerT7VlfILOSBRHx4n2VaUe/7iyZX4yNC+J8zKyLLq8ea0GC76d/masFMuWvZcuOk0afnBZ4VffGUxYMdjP8CEWFJjYjJpsWzW3uWB2ek=");
var ocert = atob("MIIFijCCA3KgAwIBAgIJAJhrfxuduldTMA0GCSqGSIb3DQEBCwUAMIGBMQswCQYDVQQGEwJVUzELMAkGA1UECBMCTUExDzANBgNVBAcTBkJvc3RvbjETMBEGA1UEChMKRXhhbXBsZSBDbzEQMA4GA1UECxMHdGVjaG9wczELMAkGA1UEAxMCY2ExIDAeBgkqhkiG9w0BCQEWEWNlcnRzQGV4YW1wbGUuY29tMB4XDTE1MTEyNzEyMjM1NloXDTE4MDgyMjEyMjM1NlowgYYxCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJNQTEPMA0GA1UEBxMGQm9zdG9uMRMwEQYDVQQKEwpFeGFtcGxlIENvMRAwDgYDVQQLEwd0ZWNob3BzMRAwDgYDVQQDEwdjbGllbnQxMSAwHgYJKoZIhvcNAQkBFhFjZXJ0c0BleGFtcGxlLmNvbTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANEmBWwVwLrRcIzF2Juu45tfP0CO88/80QlBMZPPAT7HbIo1YLeBGy3d12LxywT8/1zGlsxxA5xJS1wumUE3xIOAZRZG++6JshstfNPvUNbmIFNNvr3cKpppWX7rPqK39/cKniBaoLLl6RaYrIuBDcgL1Pofs5XbdsPk92fn82KyDrpyYzuI6KNjWMTtyoIDiC8vftY9JeL+IMAVQ3s+oNdxQiE1sU252BSDVXymGxoKDs8+EpbCnTkU8HdffZ4o7rWFEj9FzM/PgZmNF9c2YLsLLlh3QmMxZhfXdMmElgfCbK54uKsujFFxQI+whX2gwy1qeWkJBywSpj7g4SDizIN8jXetT5J4r/zSURKwlMeboZdUd5fs1us4JtN0Ba2D7Tch+cKenyM/iRo3HPVXvsL2FA4cuEdEwOM8kADeZqIO9yrfp3rNsKkEY/a8e96jLniRx1DD9Csk8xvXk95UBTAuSZeg3oGFPBALa6XK3PKLd1EHm4un9DO2TvgaypfSIudz0hXqapOavxz2IyOyqigpJqDR9fXe9WKa3oD0fwS5SgBmcjmy/73JTDDiv4fgCztLPZgSftMPNBy3HDJxyf1uRVyOOMebL4jfxVrgM/kIzMSz4YSMGazKLknKz9x6PtEmjEeVlJNAmoXmT6zXA9N+4+kUanG6XE2IrvD+MfnrAgMBAAEwDQYJKoZIhvcNAQELBQADggIBAAPv3w4KVca2vZeaPN4kHb7ln1ZkXimZ/jZYJMdFh0xcwnTgGQiW+P2voIJuA1GsrrdLvD27RnV1UKtDbJT+MZB5nM/mt7BMyQKdHEGy1YFFLFQz4YMaUEoif5OXFFnmunEu76C90qwbxBpUiS3lB97Gipy3VDBJKFE2kYaypYJc0XqIJcnypzsLBU/K9Bl13Xvj7QNN2VyqDGKlw6v6UJWRyYT7efqvvJ5Ljglmdn1UxX+WmfLzKtO+aMBoSuOgyFEttLLKESYXYRRcomfCRxqIH3XA3PzyDEN5R/wG38IQD3Y0Zt+UYabS6qUKtD2jMD8dL1gr7NWLraDSPAre2fBbHtjskr8vyR5PjrBFLJWOzEQKzclxW3O6cmZKyjwd092JuNn+FSjgo/glWik8jyFXJzK5bLXgGFa31YFnrmWKDrxbAWCuJL6UcRx4rX9qdPkZpwPTqN1sEh1YqdZShxDTFjbxDrE8gL5xbo62q9bdzbN/TMzhVo1BYvQytt7MbX2ZEXDXOup2QiOs23MqcQsf3yjT25OD5V9w3NWXDcd+TLsNCdKFnY+EpWOe4qs7k4UuXJMcW/zAPPBZDPEBsi+AAYsNYEo8QdsCcNtiWD818fTjHR6nmNRsMjRH9jeM9x0N/fJvsuCrrMQZF5KNpntOP0lV1ktAIcjQJUf93rN+");
var oca = atob("MIIFgDCCA2gCCQD1KANs3obrTjANBgkqhkiG9w0BAQsFADCBgTELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAk1BMQ8wDQYDVQQHEwZCb3N0b24xEzARBgNVBAoTCkV4YW1wbGUgQ28xEDAOBgNVBAsTB3RlY2hvcHMxCzAJBgNVBAMTAmNhMSAwHgYJKoZIhvcNAQkBFhFjZXJ0c0BleGFtcGxlLmNvbTAeFw0xNTExMjcxMjIyMzFaFw00MzA0MTMxMjIyMzFaMIGBMQswCQYDVQQGEwJVUzELMAkGA1UECBMCTUExDzANBgNVBAcTBkJvc3RvbjETMBEGA1UEChMKRXhhbXBsZSBDbzEQMA4GA1UECxMHdGVjaG9wczELMAkGA1UEAxMCY2ExIDAeBgkqhkiG9w0BCQEWEWNlcnRzQGV4YW1wbGUuY29tMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAwjlJ3eyrnGIiJiplY5mvIaaoMC20oR4Jx5+FOXNJJhjSz9mOoqcpEe2U6ZmmVfcpc8zdt1f9KkED5yjzpnF02CG+KYaRs/Rfj0NJejcpBN3Hn4R6+yJek2rYrKi4uZyMZrWx/8PTp/lEypAEBf/2vX9WYNgi5eWyHeHEfJ4yucRI1UgRw5W/RLYoAePAPT1ekB66NbosBIZhRXJvjqED/jOMOlpHgNPQHTUyPj5lR8ZTSduATUQac6qRx9pdYyVICVE8bxma56R0pX8Cdx/wg+5gKOXUPuXW1xTPNuH4JpNTd7huJwa8Ff0ReKTLHZk1hYB7uDzL5moc8kylYEwz2W13KyXxZbh3kClVSNZvPbrcp1eWoyJyznLRLVv3cCWQwmEMr1071Th4/6dnUZ/wl085HIjV93X9H8nzZ7VBkwHD8ZHB1foW0/jgbK0qsH2gV7frGFPxZydmk/Nrwdl3RtoM+xEpQI7cPYDf9j/CX/ynM4LfOeHhVfMrx0I3E8wNPX9MU+O+Pu6wsT4WbGkNhcuS4oE2As13obMnUebLwOxxWu4ErI8WG1ITwRVEQik72Iqj0d5vvjZw2z5TFzkMB/Tl3qNvAp9jzpNtvRUyrS6KRY667BZOJ9TJK/5+jenGEi7+UNq9ig490WnYDBPA/N9QSPHCx6TLNapayQvem5UCAwEAATANBgkqhkiG9w0BAQsFAAOCAgEAS9mpX4QgnwntvH9wutY+zOWBLejd/psjjVmZdYzeVC6fkCaw0Qj1unszq58EHlA8275ARTYyicRHIYLF3ZDYwMxUCu7iIQJUzVYJRqowV2Ap4OeMlh5sUb/Wlmhs5TauSZ1gz4LqMqnGkVMrvvU+1WX2ePFl81nnr1UMb2+dLzC0Gj2jH3tlzW76yFD4gElR8W4ypgvAw9pFKlSuOc4y6KS32jaOJk9zWSigPQadI1pOSSk+iKuPp98BBY/gDw+FBKUNARo3ci5F2s1dJZwQSCnuBhVb1r+3aHjnp4PAO7Mq7YyFf7qwSmuA++nF7TGhu3lf3hY1Jzgo+rOi+pFZtebCsewLDJjyNUxhQkOIf4TutC9wPJUtCKDpLA0iJso1AX5297iap5g7y0J0fUls16U+F0arsBHhgIN5ARifImeE+1bVVx7kLtklA23njczUt88ylgsCEnYyu0U+0+kwAkMDyPWDd3KPfDhykhQJ0Ev/44+JTDk3zydO2YvCpqMqLuhbZr9mvmV7uzJVbFnLr3sU75upv0N4JQLIn3XyTtDbWjTqA8d6qbG5BxYL5xkrWRxo3Fd6r1AyFje1ilKUkwZ1YZZCDvgv/2uEFyL0VlgfHfBhNbN2nsTTxijKc19ROeIRXl7eqWq/cyIbA/5LzEy2UbbEhKIroPGosQML4sc=");
// Actually send a form
function sendForm() {
// This uploads to https://docs.google.com/spreadsheets/d/1R1D6GKK5MvtjS-PDEPHdqIqKSYX4kG4dPHkj_lkL1P0/pubhtml
//LED1.set(); // light red LED while we're working
var content = "entry.1093163892="+encodeURIComponent(E.getTemperature());
var options = {
host: 'docs.google.com',
port: '443',
path:'/forms/d/1bBV4map47MPRWfaHYCEd1ByR4f_sm3LSd3oRdYkiVKg/formResponse',
protocol: "https:",
method:'POST',
headers: {
"Content-Type":"application/x-www-form-urlencoded",
"Content-Length":content.length
},
key : okey,
ca : oca,
cert : ocert
};
console.log("Connecting to Google");
require("http").request(options, function(res) {
console.log("Connected to Google");
var nRecv = 0;
res.on('data', function(data) { nRecv += data.length; });
res.on('close', function(data) {
//LED1.reset(); // turn red LED off when finished
console.log("Google connection closed, "+nRecv+" bytes received");
});
}).end(content);
}
sendForm();

View File

@ -0,0 +1,26 @@
I2C1.setup({"scl":D17,"sda":D16,bitrate:100000});
var lcd = require("HD44780").connectI2C(I2C1);
lcd.print("Hello ESP32!!");
/*
function isDevice(i2cBus,id) {
try {
return i2cBus.readFrom(id,1);
}
catch(err) {
return -1;
}
}
function detect(i2c,first,last) {
first = first | 0;
last = last | 0x77;
var idsOnBus = Array();
for (var id = first; id < last; id++) {
if ( isDeviceOnBus(i2c,id) != -1)
idsOnBus.push(id);
}
}
return idsOnBus;
}
console.log(detect(I2C1));
*/

View File

@ -0,0 +1,18 @@
var ssid="RASPI3";
var password="password";
var wifi=require("Wifi");
wifi.connect(ssid, {password: password}, function() {
console.log("Connected to access point");
var mqtt = require("MQTT").create("192.168.5.1");
mqtt.on("connected", function() {
console.log("MQTT connected");
mqtt.subscribe("test");
mqtt.on('publish', function (pub) {
console.log("topic: "+pub.topic);
console.log("message: "+pub.message);
});
});
console.log("Doing a connect");
mqtt.connect();
});

View File

@ -0,0 +1,6 @@
var wifi=require("Wifi");
wifi.scan(function(data) {
for (var i=0; i<data.length; i++) {
console.log(JSON.stringify(data[i]));
}
});

View File

@ -0,0 +1,7 @@
pinMode(D4,'input');
var ow = new OneWire(D4);
var sensors = ow.search().map(function (device) {
return require("DS18B20").connect(ow, device);
});
console.log(sensors);

View File

@ -0,0 +1,28 @@
var toggle = true;
function updateLed() {
digitalWrite(led, toggle);
toggle=!toggle;
}
function button_down() {
updateLed();
print('button');
}
var red = D18;
var green = D19;
var blue = D22;
var led = blue;
digitalWrite(red, 0);
digitalWrite(green, 0);
digitalWrite(blue, 0);
setInterval(function () {updateLed();}, 1000);
setWatch(button_down, "D0", { repeat:true, edge:'rising' });
digitalWrite(red, 0);
digitalWrite(green, 0);
digitalWrite(blue, 0);

View File

@ -0,0 +1,66 @@
// Start being an access point.
// Start being a web server.
// Listen on:
// - /list - Return a list of access points
// - /select?ssid=<SSID>&password=<password> - Select an SSID and supply a password.
// When a request arrives from a browser, build a page which contains the
// list of access points to which we can connect.
// When the user selects an access point with password, connect to that access point.
// 2. Configure a Web Server.
function startWebServer() {
var http = require("http");
var httpServer = http.createServer(function(request, response) {
console.log("Received a browser request looking for " + request.url);
// Handle browser requests here ...
var parsedURL = url.parse(request.url, true);
if (parsedURL.pathname == "/list") {
// Process the list request here ...
// Handle the list request
response.writeHead(200);
response.end("process /list");
return;
} else if (parsedURL.pathname == "/select") {
// Handle the select request
if (!parsedURL.query.hasOwnProperty("ssid") || !parsedURL.query.hasOwnProperty("password")) {
console.log("No ssid or no password in /select request: " + JSON.stringify(parsedURL));
response.writeHead(200);
response.end("Hello World");
return;
}
// Process the select request here...
response.writeHead(200);
response.end("Process /select");
return;
}
// Unknown service
response.writeHead(200);
response.end("Hello World");
});
httpServer.listen(80);
console.log("Web Server now started ... listening on port 80");
}
var wifi = require("Wifi");
// 1. Be an access point
wifi.startAP("MYESP32", {
"authMode": "open"
}, function(err) {
console.log("AP now started: " + err);
startWebServer();
});
//Connect to an access point and be a simple web server
//
/*
var ssid="guest";
var password="kolbanpassword";
wifi.connect(ssid, {password: password}, function() {
startWebServer();
});
*/

View File

@ -0,0 +1,14 @@
// Connect to an access point and be a simple web server
//
var ssid="guest";
var password="kolbanguest";
var wifi=require("Wifi");
wifi.connect(ssid, {password: password}, function() {
console.log("Connected to access point, listening for clients on port 8080.");
var http = require("http");
http.createServer(function (req, res) {
res.writeHead(200);
res.end("Hello World");
}).listen(8080);
});

View File

@ -0,0 +1,70 @@
/*
IO4
IO16
IO17
IO5
IO18
IO19
Display NodeMCU ESP-32 DEF Colour
LED 3V3 3V3 N/A
SCLCK D5 GPIO4 Green IO05
DN<MOSI> D7 GPIO16 Yellow
D/C D2 GPIO17 Orange
SCE D8 GPIO5 Red
RST D1 GPIO18 Brown
GND GND GND Grey
VCC 3V3 3V3 Blue
BackLight GND GND Purple
IO23 MOSI
IO022
TX0
RX0
IO21
GND
IO19 MISO
IO18 SCK
IO05 CS0
IO17
IO16
IO04
IO00
IO02
RST GPIO16 Brown
CE GPIO5 Red
DC GPIO17 Orange
DIN GPIO23 Yellow
CLK GPIO18 Green
VCC VSS Blue
LIGHT GND Purple
GND GND Grey
*/
/*
pinMode(D4, "input_pullup");
pinMode(D16, "input_pullup");
digitalWrite(D17, 0);
digitalWrite(D18, 0);
digitalWrite(D5, 0);
*/
SPI2.setup({ sck:D5, mosi:D23 });
var g = require("PCD8544").connect(SPI1,
D17 /* RS / DC */,
D18 /* CS / CE */,
D16 /*RST*/, function() {
g.clear();
g.setRotation(2); //Flip display 180
g.drawString("Hi Esp32",0,0);
g.drawLine(0,10,84,10);
g.flip();
});

View File

@ -0,0 +1,3 @@
setInterval(function() {
console.log("tick");
}, 1000);

View File

@ -0,0 +1,32 @@
// Test ESP32 WiFi event callbacks
var ssid="RASPI3";
var password="password";
var wifi=require("Wifi");
wifi.on("associated", function(details) {
console.log("Event-> associated: " + JSON.stringify(details));
});
wifi.on("connected", function(details) {
console.log("Event-> connected: " + JSON.stringify(details));
});
wifi.on("disconnected", function(details) {
console.log("Event-> disconnected: " + JSON.stringify(details));
});
wifi.on("auth_change", function(details) {
console.log("Event-> auth_change: " + JSON.stringify(details));
});
wifi.on("dhcp_timeout", function(details) {
console.log("Event-> dhcp_timeout: " + JSON.stringify(details));
});
wifi.on("probe_recv", function(details) {
console.log("Event-> probe_recv: " + JSON.stringify(details));
});
wifi.on("sta_joined", function(details) {
console.log("Event-> sta_joined: " + JSON.stringify(details));
});
wifi.on("sta_left", function(details) {
console.log("Event-> sta_left: " + JSON.stringify(details));
});
wifi.connect(ssid, {password: password}, function() {
console.log("Connect completed");
});

View File

@ -15,6 +15,9 @@ esptool.py --port [/dev/ttyUSB0|COM1] --baud 115200 write_flash \
For 1MB flash use 0xFC000/0xFE000 and for 2MB flash use 0x1FC000/0x1FE000 on the last line.
*** Erase flash before updating to a new version
esptool.py --port [/dev/ttyUSB0|COM1] --baud 115200 erase_flash
*** Get esptool.py from https://github.com/themadinventor/esptool
*** To flash a 4MB esp8266 (e.g. esp-12) via wifi use (with appropriate hostname):

View File

@ -1329,3 +1329,99 @@ unsigned int jshSetSystemClock(JsVar *options) {
*/
void _exit(int status) {
}
static inline uint32_t _getCycleCount(void) {
uint32_t ccount;
__asm__ __volatile__("rsr %0,ccount":"=a" (ccount));
return ccount;
}
bool jshNeopixelWrite(Pin pin, unsigned char *rgbData, size_t rgbSize) {
if (!jshIsPinValid(pin)) {
jsExceptionHere(JSET_ERROR, "Pin is not valid.");
return false;
}
if (!jshGetPinStateIsManual(pin))
jshPinSetState(pin, JSHPINSTATE_GPIO_OUT);
// values for 160Mhz clock
uint8_t tOne = 90; // one bit, high typ 800ns
uint8_t tZero = 40; // zero bit, high typ 300ns
uint8_t tLow = 170; // total cycle, typ 1.2us
if (system_get_cpu_freq() < 100) {
tOne = 56; // 56 cyc = 700ns
tZero = 14; // 14 cycl = 175ns
tLow = 100;
}
#define _BV(bit) (1 << (bit))
#if 1
// the loop over the RGB pixel bits below is loaded into the instruction cache from flash
// with the result that dependeing on the cache line alignment the first loop iteration
// takes too long and thereby messes up the first LED.
// The fix is to make it so the first loop iteration does nothing, i.e. just outputs the
// same "low" for the full loop as we had before entering this function. This way no LED
// gets set to the wrong value and we load the cache line so the second iteration, i.e.,
// first real LED bit, runs at full speed.
uint32_t pinMask = _BV(pin); // bit mask for GPIO pin to write to reg
uint8_t *p = (uint8_t *)rgbData; // pointer to walk through pixel array
uint8_t *end = p + rgbSize; // pointer to end of array
uint8_t pix = *p++; // current byte being shifted out
uint8_t mask = 0x80; // mask for current bit
uint32_t start; // start time of bit
// adjust things for the pre-roll
p--; // next byte we fetch will be the first byte again
mask = 0x01; // fetch the next byte at the end of the first loop iteration
pinMask = 0; // zero mask means we set or clear no I/O pin
// iterate through all bits
ets_intr_lock(); // disable most interrupts
while(1) {
uint32_t t;
if (pix & mask) t = tOne;
else t = tZero;
GPIO_REG_WRITE(GPIO_OUT_W1TS_ADDRESS, pinMask); // Set high
start = _getCycleCount(); // get start time of this bit
while (_getCycleCount()-start < t) ; // busy-wait
GPIO_REG_WRITE(GPIO_OUT_W1TC_ADDRESS, pinMask); // Set low
if (!(mask >>= 1)) { // Next bit/byte?
if (p >= end) break; // at end, we're done
pix = *p++;
mask = 0x80;
pinMask = _BV(pin);
}
while (_getCycleCount()-start < tLow) ; // busy-wait
}
while (_getCycleCount()-start < tLow) ; // wait for last bit
ets_intr_unlock();
#else
// this is the code without preloading the first bit
uint32_t pinMask = _BV(pin); // bit mask for GPIO pin to write to reg
uint8_t *p = (uint8_t *)rgbData; // pointer to walk through pixel array
uint8_t *end = p + rgbSize; // pointer to end of array
uint8_t pix = *p++; // current byte being shifted out
uint8_t mask = 0x80; // mask for current bit
uint32_t start; // start time of bit
// iterate through all bits
while(1) {
uint32_t t;
if (pix & mask) t = 56; // one bit, high typ 800ns (56 cyc = 700ns)
else t = 14; // zero bit, high typ 300ns (14 cycl = 175ns)
GPIO_REG_WRITE(GPIO_OUT_W1TS_ADDRESS, pinMask); // Set high
start = _getCycleCount(); // get start time of this bit
while (_getCycleCount()-start < t) ; // busy-wait
GPIO_REG_WRITE(GPIO_OUT_W1TC_ADDRESS, pinMask); // Set low
if (!(mask >>= 1)) { // Next bit/byte?
if (p >= end) break; // at end, we're done
pix = *p++;
mask = 0x80;
}
while (_getCycleCount()-start < 100) ; // busy-wait, 100 cyc = 1.25us
}
while (_getCycleCount()-start < 100) ; // Wait for last bit
#endif
#undef _BV
}

View File

@ -32,16 +32,8 @@ typedef long long int64_t;
#include <network_esp8266.h>
#include "jsinteractive.h" // Pull in the jsiConsolePrint function
#include <log.h>
#include <jswrap_espruino.h>
#define _BV(bit) (1 << (bit))
static uint32_t _getCycleCount(void) __attribute__((always_inline));
static inline uint32_t _getCycleCount(void) {
uint32_t ccount;
__asm__ __volatile__("rsr %0,ccount":"=a" (ccount));
return ccount;
}
// ESP8266.reboot
@ -318,110 +310,7 @@ JsVar *jswrap_ESP8266_crc32(JsVar *jsData) {
]
}*/
void jswrap_ESP8266_neopixelWrite(Pin pin, JsVar *jsArrayOfData) {
if (!jshIsPinValid(pin)) {
jsExceptionHere(JSET_ERROR, "Pin is not valid.");
return;
}
if (jsArrayOfData == NULL) {
jsExceptionHere(JSET_ERROR, "No data to send to LEDs.");
return;
}
JSV_GET_AS_CHAR_ARRAY(pixels, dataLength, jsArrayOfData);
if (!pixels) {
return;
}
if (dataLength == 0) {
jsExceptionHere(JSET_ERROR, "Data must be a non empty array.");
return;
}
if (dataLength % 3 != 0) {
jsExceptionHere(JSET_ERROR, "Data length must be a multiple of 3 (RGB).");
return;
}
if (!jshGetPinStateIsManual(pin))
jshPinSetState(pin, JSHPINSTATE_GPIO_OUT);
// values for 160Mhz clock
uint8_t tOne = 90; // one bit, high typ 800ns
uint8_t tZero = 40; // zero bit, high typ 300ns
uint8_t tLow = 170; // total cycle, typ 1.2us
if (system_get_cpu_freq() < 100) {
tOne = 56; // 56 cyc = 700ns
tZero = 14; // 14 cycl = 175ns
tLow = 100;
}
#if 1
// the loop over the RGB pixel bits below is loaded into the instruction cache from flash
// with the result that dependeing on the cache line alignment the first loop iteration
// takes too long and thereby messes up the first LED.
// The fix is to make it so the first loop iteration does nothing, i.e. just outputs the
// same "low" for the full loop as we had before entering this function. This way no LED
// gets set to the wrong value and we load the cache line so the second iteration, i.e.,
// first real LED bit, runs at full speed.
uint32_t pinMask = _BV(pin); // bit mask for GPIO pin to write to reg
uint8_t *p = (uint8_t *)pixels; // pointer to walk through pixel array
uint8_t *end = p + dataLength; // pointer to end of array
uint8_t pix = *p++; // current byte being shifted out
uint8_t mask = 0x80; // mask for current bit
uint32_t start; // start time of bit
// adjust things for the pre-roll
p--; // next byte we fetch will be the first byte again
mask = 0x01; // fetch the next byte at the end of the first loop iteration
pinMask = 0; // zero mask means we set or clear no I/O pin
// iterate through all bits
ets_intr_lock(); // disable most interrupts
while(1) {
uint32_t t;
if (pix & mask) t = tOne;
else t = tZero;
GPIO_REG_WRITE(GPIO_OUT_W1TS_ADDRESS, pinMask); // Set high
start = _getCycleCount(); // get start time of this bit
while (_getCycleCount()-start < t) ; // busy-wait
GPIO_REG_WRITE(GPIO_OUT_W1TC_ADDRESS, pinMask); // Set low
if (!(mask >>= 1)) { // Next bit/byte?
if (p >= end) break; // at end, we're done
pix = *p++;
mask = 0x80;
pinMask = _BV(pin);
}
while (_getCycleCount()-start < tLow) ; // busy-wait
}
while (_getCycleCount()-start < tLow) ; // wait for last bit
ets_intr_unlock();
#else
// this is the code without preloading the first bit
uint32_t pinMask = _BV(pin); // bit mask for GPIO pin to write to reg
uint8_t *p = (uint8_t *)pixels; // pointer to walk through pixel array
uint8_t *end = p + dataLength; // pointer to end of array
uint8_t pix = *p++; // current byte being shifted out
uint8_t mask = 0x80; // mask for current bit
uint32_t start; // start time of bit
// iterate through all bits
while(1) {
uint32_t t;
if (pix & mask) t = 56; // one bit, high typ 800ns (56 cyc = 700ns)
else t = 14; // zero bit, high typ 300ns (14 cycl = 175ns)
GPIO_REG_WRITE(GPIO_OUT_W1TS_ADDRESS, pinMask); // Set high
start = _getCycleCount(); // get start time of this bit
while (_getCycleCount()-start < t) ; // busy-wait
GPIO_REG_WRITE(GPIO_OUT_W1TC_ADDRESS, pinMask); // Set low
if (!(mask >>= 1)) { // Next bit/byte?
if (p >= end) break; // at end, we're done
pix = *p++;
mask = 0x80;
}
while (_getCycleCount()-start < 100) ; // busy-wait, 100 cyc = 1.25us
}
while (_getCycleCount()-start < 100) ; // Wait for last bit
#endif
jswrap_E_neopixelWrite(pin, jsArrayOfData);
}
//===== ESP8266.deepSleep

View File

@ -811,3 +811,8 @@ void jshFlashWrite(void *buf, uint32_t addr, uint32_t len) { }
unsigned int jshSetSystemClock(JsVar *options) {
return 0;
}
bool jshNeopixelWrite(Pin pin, unsigned char *rgbData, size_t rgbSize) {
jsExceptionHere(JSET_ERROR, "Neopixel writing not implemented");
return false;
}

View File

@ -295,6 +295,7 @@ static void on_ble_evt(ble_evt_t * p_ble_evt)
#if CENTRAL_LINK_COUNT>0
if (p_ble_evt->evt.gap_evt.params.connected.role == BLE_GAP_ROLE_CENTRAL) {
m_central_conn_handle = p_ble_evt->evt.gap_evt.conn_handle;
bleSetActiveBluetoothGattServer(bleTaskInfo);
jsvObjectSetChildAndUnLock(bleTaskInfo, "connected", jsvNewFromBool(true));
bleCompleteTaskSuccess(BLETASK_CONNECT, bleTaskInfo);
}
@ -304,7 +305,18 @@ static void on_ble_evt(ble_evt_t * p_ble_evt)
case BLE_GAP_EVT_DISCONNECTED:
#if CENTRAL_LINK_COUNT>0
if (m_central_conn_handle == p_ble_evt->evt.gap_evt.conn_handle) {
JsVar *gattServer = bleGetActiveBluetoothGattServer();
if (gattServer) {
JsVar *bluetoothDevice = jsvObjectGetChild(gattServer, "device", 0);
jsvObjectSetChildAndUnLock(gattServer, "connected", jsvNewFromBool(false));
if (bluetoothDevice) {
jsiQueueObjectCallbacks(bluetoothDevice, JS_EVENT_PREFIX"gattserverdisconnected", 0, 0);
jshHadEvent();
}
jsvUnLock2(gattServer, bluetoothDevice);
}
m_central_conn_handle = BLE_CONN_HANDLE_INVALID;
bleSetActiveBluetoothGattServer(0);
BleTask task = bleGetCurrentTask();
if (BLETASK_IS_CENTRAL(task)) {
bleCompleteTaskFailAndUnLock(task, jsvNewFromString("Disconnected."));
@ -411,13 +423,21 @@ static void on_ble_evt(ble_evt_t * p_ble_evt)
case BLE_EVT_TX_COMPLETE:
// BLE transmit finished - reset flags
//TODO: probably want to figure out *which one* finished?
bleStatus &= ~BLE_IS_SENDING;
if (bleStatus & BLE_IS_SENDING_HID) {
bleStatus &= ~BLE_IS_SENDING_HID;
jsiQueueObjectCallbacks(execInfo.root, BLE_HID_SENT_EVENT, 0, 0);
jsvObjectSetChild(execInfo.root, BLE_HID_SENT_EVENT, 0); // fire only once
jshHadEvent();
#if CENTRAL_LINK_COUNT>0
if (p_ble_evt->evt.common_evt.conn_handle == m_central_conn_handle) {
if (bleInTask(BLETASK_CHARACTERISTIC_WRITE))
bleCompleteTaskSuccess(BLETASK_CHARACTERISTIC_WRITE, 0);
}
#endif
if (p_ble_evt->evt.common_evt.conn_handle == m_conn_handle) {
//TODO: probably want to figure out *which one* finished?
bleStatus &= ~BLE_IS_SENDING;
if (bleStatus & BLE_IS_SENDING_HID) {
bleStatus &= ~BLE_IS_SENDING_HID;
jsiQueueObjectCallbacks(execInfo.root, BLE_HID_SENT_EVENT, 0, 0);
jsvObjectSetChild(execInfo.root, BLE_HID_SENT_EVENT, 0); // fire only once
jshHadEvent();
}
}
break;
@ -529,6 +549,17 @@ static void on_ble_evt(ble_evt_t * p_ble_evt)
jsvObjectSetChildAndUnLock(o,"uuid", bleUUIDToStr(p_chr->uuid));
jsvObjectSetChildAndUnLock(o,"handle_value", jsvNewFromInteger(p_chr->handle_value));
jsvObjectSetChildAndUnLock(o,"handle_decl", jsvNewFromInteger(p_chr->handle_decl));
JsVar *p = jsvNewObject();
if (p) {
jsvObjectSetChildAndUnLock(p,"broadcast",jsvNewFromBool(p_chr->char_props.broadcast));
jsvObjectSetChildAndUnLock(p,"read",jsvNewFromBool(p_chr->char_props.read));
jsvObjectSetChildAndUnLock(p,"writeWithoutResponse",jsvNewFromBool(p_chr->char_props.write_wo_resp));
jsvObjectSetChildAndUnLock(p,"write",jsvNewFromBool(p_chr->char_props.write));
jsvObjectSetChildAndUnLock(p,"notify",jsvNewFromBool(p_chr->char_props.notify));
jsvObjectSetChildAndUnLock(p,"indicate",jsvNewFromBool(p_chr->char_props.indicate));
jsvObjectSetChildAndUnLock(p,"authenticatedSignedWrites",jsvNewFromBool(p_chr->char_props.auth_signed_wr));
jsvObjectSetChildAndUnLock(o,"properties", p);
}
// char_props?
jsvArrayPushAndUnLock(bleTaskInfo, o);
}
@ -562,9 +593,34 @@ static void on_ble_evt(ble_evt_t * p_ble_evt)
}
break;
}
case BLE_GATTC_EVT_DESC_DISC_RSP:
jsiConsolePrintf("DESC\n");
case BLE_GATTC_EVT_DESC_DISC_RSP: if (bleInTask(BLETASK_CHARACTERISTIC_DESC_AND_STARTNOTIFY)) {
// trigger this with sd_ble_gattc_descriptors_discover(conn_handle, &handle_range);
uint16_t cccd_handle = 0;
ble_gattc_evt_desc_disc_rsp_t * p_desc_disc_rsp_evt = &p_ble_evt->evt.gattc_evt.params.desc_disc_rsp;
if (p_ble_evt->evt.gattc_evt.gatt_status == BLE_GATT_STATUS_SUCCESS) {
// The descriptor was found at the peer.
// If the descriptor was a CCCD, then the cccd_handle needs to be populated.
uint32_t i;
// Loop through all the descriptors to find the CCCD.
for (i = 0; i < p_desc_disc_rsp_evt->count; i++) {
if (p_desc_disc_rsp_evt->descs[i].uuid.uuid ==
BLE_UUID_DESCRIPTOR_CLIENT_CHAR_CONFIG) {
cccd_handle = p_desc_disc_rsp_evt->descs[i].handle;
}
}
}
if (cccd_handle) {
if(bleTaskInfo)
jsvObjectSetChildAndUnLock(bleTaskInfo, "handle_cccd", jsvNewFromInteger(cccd_handle));
// FIXME: we just switch task here - this is not nice...
bleSwitchTask(BLETASK_CHARACTERISTIC_NOTIFY);
jsble_central_characteristicNotify(bleTaskInfo, true);
} else {
bleCompleteTaskFailAndUnLock(BLETASK_CHARACTERISTIC_DESC_AND_STARTNOTIFY, jsvNewFromString("CCCD Handle not found"));
}
break;
}
case BLE_GATTC_EVT_READ_RSP: if (bleInTask(BLETASK_CHARACTERISTIC_READ)) {
ble_gattc_evt_read_rsp_t *p_read = &p_ble_evt->evt.gattc_evt.params.read_rsp;
@ -590,11 +646,17 @@ static void on_ble_evt(ble_evt_t * p_ble_evt)
if (handles) {
JsVar *characteristic = jsvGetArrayItem(handles, p_hvx->handle);
if (characteristic) {
// TODO: should return {target:characteristic} and set characteristic.value
JsVar *data = jsvNewStringOfLength(p_hvx->len);
if (data) jsvSetString(data, (const char*)p_hvx->data, p_hvx->len);
jsiQueueObjectCallbacks(characteristic, "characteristicvaluechanged", &data, 1);
jshHadEvent();
// Set characteristic.value, and return {target:characteristic}
jsvObjectSetChildAndUnLock(characteristic, "value",
jsvNewTypedArrayWithData(ARRAYBUFFERVIEW_UINT8, p_hvx->len, (unsigned char*)p_hvx->data));
JsVar *evt = jsvNewObject();
if (evt) {
jsvObjectSetChild(evt, "target", characteristic);
jsiQueueObjectCallbacks(characteristic, JS_EVENT_PREFIX"characteristicvaluechanged", &evt, 1);
jshHadEvent();
jsvUnLock(evt);
}
}
jsvUnLock2(characteristic, handles);
}
@ -1108,6 +1170,11 @@ void jsble_restart_softdevice() {
if (advData || advOpt) jswrap_nrf_bluetooth_setAdvertising(advData, advOpt);
jsvUnLock2(advData, advOpt);
// If we had scan response data set, update it
JsVar *scanData = jsvObjectGetChild(execInfo.hiddenRoot, BLE_NAME_SCAN_RESPONSE_DATA, 0);
if (scanData) jswrap_nrf_bluetooth_setScanResponse(scanData);
jsvUnLock(scanData);
// if we were scanning, make sure we restart
if (bleStatus & BLE_IS_SCANNING) {
JsVar *callback = jsvObjectGetChild(execInfo.root, BLE_SCAN_EVENT, 0);
@ -1347,23 +1414,22 @@ void jsble_nfc_start(const uint8_t *data, size_t len) {
#if CENTRAL_LINK_COUNT>0
void jsble_central_connect(ble_gap_addr_t peer_addr) {
uint32_t err_code;
// TODO: do these really need to be static?
static ble_gap_scan_params_t m_scan_param;
ble_gap_scan_params_t m_scan_param;
memset(&m_scan_param, 0, sizeof(m_scan_param));
m_scan_param.active = 1; // Active scanning set.
m_scan_param.interval = MSEC_TO_UNITS(100, UNIT_0_625_MS); // Scan interval.
m_scan_param.window = MSEC_TO_UNITS(50, UNIT_0_625_MS); // Scan window.
m_scan_param.window = MSEC_TO_UNITS(90, UNIT_0_625_MS); // Scan window.
m_scan_param.timeout = 4; // 4 second timeout.
static ble_gap_conn_params_t gap_conn_params;
ble_gap_conn_params_t gap_conn_params;
memset(&gap_conn_params, 0, sizeof(gap_conn_params));
gap_conn_params.min_conn_interval = MSEC_TO_UNITS(7.5, UNIT_1_25_MS);
gap_conn_params.max_conn_interval = MSEC_TO_UNITS(1000, UNIT_1_25_MS);
gap_conn_params.max_conn_interval = MSEC_TO_UNITS(500, UNIT_1_25_MS);
gap_conn_params.slave_latency = 0;
gap_conn_params.conn_sup_timeout = MSEC_TO_UNITS(4000, UNIT_10_MS);
static ble_gap_addr_t addr;
ble_gap_addr_t addr;
addr = peer_addr;
err_code = sd_ble_gap_connect(&addr, &m_scan_param, &gap_conn_params);
@ -1407,9 +1473,20 @@ void jsble_central_characteristicWrite(JsVar *characteristic, char *dataPtr, siz
return bleCompleteTaskFailAndUnLock(BLETASK_CHARACTERISTIC_WRITE, jsvNewFromString("Not connected"));
uint16_t handle = jsvGetIntegerAndUnLock(jsvObjectGetChild(characteristic, "handle_value", 0));
bool writeWithoutResponse = false;
JsVar *properties = jsvObjectGetChild(characteristic, "properties", 0);
if (properties) {
writeWithoutResponse = jsvGetBoolAndUnLock(jsvObjectGetChild(properties, "writeWithoutResponse", 0));
jsvUnLock(properties);
}
ble_gattc_write_params_t write_params;
memset(&write_params, 0, sizeof(write_params));
write_params.write_op = BLE_GATT_OP_WRITE_REQ;
if (writeWithoutResponse)
write_params.write_op = BLE_GATT_OP_WRITE_CMD; // write without response
else
write_params.write_op = BLE_GATT_OP_WRITE_REQ; // write with response
// BLE_GATT_OP_WRITE_REQ ===> BLE_GATTC_EVT_WRITE_RSP (write with response)
// or BLE_GATT_OP_WRITE_CMD ===> BLE_EVT_TX_COMPLETE (simple write)
// or send multiple BLE_GATT_OP_PREP_WRITE_REQ,...,BLE_GATT_OP_EXEC_WRITE_REQ (with offset + 18 bytes in each for 'long' write)
@ -1436,12 +1513,31 @@ void jsble_central_characteristicRead(JsVar *characteristic) {
bleCompleteTaskFail(BLETASK_CHARACTERISTIC_READ, 0);
}
void jsble_central_characteristicDescDiscover(JsVar *characteristic) {
if (!jsble_has_central_connection())
return bleCompleteTaskFailAndUnLock(BLETASK_CHARACTERISTIC_DESC_AND_STARTNOTIFY, jsvNewFromString("Not connected"));
// start discovery for our single handle only
uint16_t handle_value = (uint16_t)jsvGetIntegerAndUnLock(jsvObjectGetChild(characteristic, "handle_value", 0));
ble_gattc_handle_range_t range;
range.start_handle = handle_value+1;
range.end_handle = handle_value+1;
uint32_t err_code;
err_code = sd_ble_gattc_descriptors_discover(m_central_conn_handle, &range);
if (jsble_check_error(err_code)) {
bleCompleteTaskFail(BLETASK_CHARACTERISTIC_DESC_AND_STARTNOTIFY, 0);
}
}
void jsble_central_characteristicNotify(JsVar *characteristic, bool enable) {
if (!jsble_has_central_connection())
return bleCompleteTaskFailAndUnLock(BLETASK_CHARACTERISTIC_NOTIFY, jsvNewFromString("Not connected"));
uint16_t cccd_handle = jsvGetIntegerAndUnLock(jsvObjectGetChild(characteristic, "handle_cccd", 0));
// FIXME: we need the cccd handle to be populated for this to work
if (!cccd_handle)
return bleCompleteTaskFailAndUnLock(BLETASK_CHARACTERISTIC_NOTIFY, jsvNewFromString("handle_cccd not set"));
uint8_t buf[BLE_CCCD_VALUE_LEN];
buf[0] = enable ? BLE_GATT_HVX_NOTIFICATION : 0;

View File

@ -60,6 +60,7 @@ extern uint16_t bleAdvertisingInterval; /**< The advertising interval
extern uint16_t m_conn_handle; /**< Handle of the current connection. */
#if CENTRAL_LINK_COUNT>0
extern uint16_t m_central_conn_handle; /**< Handle for central mode connection */
#endif
/** Initialise the BLE stack */
@ -124,6 +125,8 @@ void jsble_central_getCharacteristics(JsVar *service, ble_uuid_t uuid);
void jsble_central_characteristicWrite(JsVar *characteristic, char *dataPtr, size_t dataLen);
// Read data from the given characteristic. When done call bleCompleteTask
void jsble_central_characteristicRead(JsVar *characteristic);
// Discover descriptors of characteristic
void jsble_central_characteristicDescDiscover(JsVar *characteristic);
// Set whether to notify on the given characteristic. When done call bleCompleteTask
void jsble_central_characteristicNotify(JsVar *characteristic, bool enable);
#endif

Some files were not shown because too many files have changed in this diff Show More