Merge branch 'master' into SMAQ3

This commit is contained in:
Gordon Williams 2020-10-19 10:43:57 +01:00
commit f6ca3b7fc4
81 changed files with 2056 additions and 729 deletions

9
.gitignore vendored
View File

@ -51,9 +51,18 @@ gcc-arm-none-eabi*
/targetlibs/nrf5x_15/external_tools
/targetlibs/nrf5x_15/integration
/targetlibs/nrf5x_15/modules
/targetlibs/nrf5x_15/config
/targetlibs/nrf5x_15/license.txt
/targetlibs/nrf5x_15_*
/targetlibs/nrf5x_15x
/targetlibs/nrf5x_mesh
/targetlibs/nrf5x_17/components
/targetlibs/nrf5x_17/examples
/targetlibs/nrf5x_17/external
/targetlibs/nrf5x_17/integration
/targetlibs/nrf5x_17/modules
/targetlibs/nrf5x_17/config
/targetlibs/nrf5x_17/documentation
/targetlibs/raspberrypi
/.vscode
/CURRENT_BOARD.make

View File

@ -46,15 +46,11 @@ env:
- BOARD=ESP32
- BOARD=ESP8266_BOARD
- BOARD=ESP8266_4MB
- BOARD=MICROBIT
- BOARD=RUUVITAG DFU_UPDATE_BUILD=1
- BOARD=MICROBIT2
- BOARD=WIO_LTE
- BOARD=SMARTIBOT DFU_UPDATE_BUILD=1
- BOARD=STM32L496GDISCOVERY
- BOARD=RAK8211
- BOARD=RAK8212
- BOARD=RAK5010
- BOARD=THINGY52 DFU_UPDATE_BUILD_WITH_HEX=1
script: make

View File

@ -1,4 +1,26 @@
Graphics.asImage() now contains buffer when bpp != 8 (fix #1863)
2v08 : nRF52: Added option to build in I2C slave support
Fix Tensorflow aiGesture regression from 2v07 (re-add opcodes) (fix #1936)
Add support for > 1bpp custom bitmap fonts
Bangle.js: add drawLineAA and drawPolyAA for antialiased lines
Removed custom fonts for SAVE_ON_FLASH devices
Fixed BBC micro:bit show() regression from 2v07
Ensure Storage library is exposed on SAVE_ON_FLASH devices (fix micro:bit flash write)
nRF52: Fix issue where analogRead would stop E.getBattery from working
Fix setWatch debounce lastTime regression from 2v07 (fix #1902)
nRF52: CPU now sleeps when while UART/BLE data is waiting to be sent (fix #1938)
JSON.stringify now checks for potential stack overflow when stringifying (fix #1940)
Check for Stack overflow when Garbage Collecting giant linked list (fix #1765)
Added String.padStart/padEnd
Fix issue where JSON.stringify({ something: bool }) would output 'something' as a bool too
Bangle.js/Pixl.js: Ensure terminal is always the same color regardless of g.setColor()
Original Espruino Board: remove E.FFT in network-enabled builds (freeing up flash memory)
Storage compact now updates pointers stored in RAM so they still point to the correct address in Flash (fix #1881)
Bangle.js: Add debounce to the button used to wake Bangle.js up from sleep
Fix regex match with '-' that isn't a range: "1-2_A3".split(/[0-]/) (fix #1736)
Crypto: modified mbedtls SHA1 to reduce size from 3.5k to under 1k
Graphics: Fix for out of bounds ArrayBuffer scroll issue (fix #1946, #1947)
2v07 : Graphics.asImage() now contains buffer when bpp != 8 (fix #1863)
nRF52 SDK15: Fix NRF.setScan/findDevices/etc
nRF52: reduce input buffer space taken by advertising packets
Pretokenisation: reserved words can now be used as function names (fix #1868)
@ -51,6 +73,9 @@
Bangle.js: Fix backlight flicker regression if at part brightness (fix #1925)
Fix ArrayBuffer.sort with negative numbers (it's not just Array.sort!)
nRF52: Use the best available hardware timer for PWM taking frequency into account
Bangle.js: Report GPS HDOP (Horizontal Ditution of Precision => accuracy) values in 'GPS' event
Pixl.js: Remove SHA256 from build to free up a little extra code space
nRF52: Restarting softdevice no longer changes the system time by 5 mins sometimes (fix #1933)
2v06 : Allow `"ram"` keyword at the top of a function to allow it to be pretokenised and loaded to RAM
Don't store line numbers for pretokenised functions

View File

@ -43,7 +43,7 @@
# # UNSUPPORTEDMAKE=/home/mydir/unsupportedCommands
# PROJECTNAME=myBigProject# Sets projectname
# BLACKLIST=fileBlacklist # Removes javascript commands given in a file from compilation and therefore from project defined firmware
# # is used in build_jswrapper.py
# # is used in build_jswrapper.py - of the form [{class,name}...]
# # BLACKLIST=/home/mydir/myBlackList
# 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

View File

@ -40,7 +40,7 @@ info = {
'DEFINES+=-DBLUETOOTH_NAME_PREFIX=\'"Bangle.js"\'',
'DEFINES+=-DCUSTOM_GETBATTERY=jswrap_banglejs_getBattery',
'DEFINES+=-DDUMP_IGNORE_VARIABLES=\'"g\\0"\'',
'DEFINES+=-DUSE_FONT_6X8 -DGRAPHICS_PALETTED_IMAGES',
'DEFINES+=-DUSE_FONT_6X8 -DGRAPHICS_PALETTED_IMAGES -DGRAPHICS_ANTIALIAS',
'DEFINES+=-DNO_DUMP_HARDWARE_INITIALISATION', # don't dump hardware init - not used and saves 1k of flash
'DEFINES+=-DAPP_TIMER_OP_QUEUE_SIZE=5', # Bangle.js accelerometer poll handler needs something else in queue size
'DFU_PRIVATE_KEY=targets/nrf5x_dfu/dfu_private_key.pem',

View File

@ -38,7 +38,7 @@ info = {
'DEFINES += -DSPIFLASH_BASE=0x8000000 -DSPIFLASH_LENGTH=4194304',
# 'DEFINES+=-DCUSTOM_GETBATTERY=jswrap_banglejs_getBattery',
'DEFINES+=-DDUMP_IGNORE_VARIABLES=\'"g\\0"\'',
'DEFINES+=-DUSE_FONT_6X8 -DGRAPHICS_PALETTED_IMAGES -DUSE_LCD_EMSCRTIPTEN',
'DEFINES+=-DUSE_FONT_6X8 -DGRAPHICS_PALETTED_IMAGES -DGRAPHICS_ANTIALIAS -DUSE_LCD_EMSCRTIPTEN',
'INCLUDE += -I$(ROOT)/libs/banglejs -I$(ROOT)/libs/misc',
'WRAPPERSOURCES += libs/banglejs/jswrap_bangle.c',
'SOURCES += libs/misc/nmea.c',

View File

@ -27,8 +27,8 @@ info = {
'binary_name' : 'espruino_%v_espruino_1r3.bin',
'binaries' : [
{ 'filename' : 'espruino_%v_espruino_1r3.bin', 'description' : "No networking, includes all other features"},
{ 'filename' : 'espruino_%v_espruino_1r3_at.bin', 'description' : "AT Command WiFi (No vector font)"},
{ 'filename' : 'espruino_%v_espruino_1r3_wiznet.bin', 'description' : "WIZNet W5500 Ethernet Networking (No crypto lib, AT Command WiFi, vector font, debugger or tab complete)"}
{ 'filename' : 'espruino_%v_espruino_1r3_at.bin', 'description' : "AT Command WiFi (No vector font, FFT)"},
{ 'filename' : 'espruino_%v_espruino_1r3_wiznet.bin', 'description' : "WIZNet W5500 Ethernet Networking (No crypto lib, AT Command WiFi, vector font, FFT, debugger or tab complete)"}
],
'build' : {
'optimizeflags' : '-Os',

View File

@ -31,7 +31,7 @@ info = {
],
'makefile' : [
# 'DEFINES+=-DFLASH_64BITS_ALIGNMENT=1', For testing 64 bit flash writes
'DEFINES+=-DUSE_FONT_6X8 -DGRAPHICS_PALETTED_IMAGES',
'DEFINES+=-DUSE_FONT_6X8 -DGRAPHICS_PALETTED_IMAGES -DGRAPHICS_ANTIALIAS',
'DEFINES+=-DSPIFLASH_BASE=0 -DSPIFLASH_LENGTH=FLASH_SAVED_CODE_LENGTH', # For Testing Flash Strings
'LINUX=1',
]

View File

@ -16,7 +16,7 @@
import pinutils;
# placeholder
info = {
'name' : "BBC micro:bit",
'name' : "BBC micro:bit 1",
'link' : [ "https://en.wikipedia.org/wiki/Micro_Bit" ],
'espruino_page_link' : 'MicroBit',
'default_console' : "EV_SERIAL1",
@ -24,7 +24,7 @@ info = {
'default_console_rx' : "H1", # pin 25
'default_console_baudrate' : "9600",
'variables' : 300,
'binary_name' : 'espruino_%v_microbit.hex',
'binary_name' : 'espruino_%v_microbit1.hex',
'build' : {
'optimizeflags' : '-Os',
'libraries' : [
@ -35,6 +35,7 @@ info = {
'SAVE_ON_FLASH=1',
'DEFINES+=-DSAVE_ON_FLASH_EXTREME',
'DEFINES+=-DCONFIG_GPIO_AS_PINRESET', # Allow the reset pin to work
'DEFINES += -DMICROBIT', # enable microbit-specific stuff
'DEFINES+=-DNO_DUMP_HARDWARE_INITIALISATION', # don't dump hardware init - not used and saves a bunch of flash
'DEFINES+=-DUSE_TAB_COMPLETE',
# 'DEFINES+=-DUSE_DEBUGGER', # Removed due to firmware size issues
@ -92,7 +93,7 @@ board["_css"] = """
height: 562px;
top: 0px;
left : 0px;
background-image: url(img/MICROBIT.jpg);
background-image: url(img/MICROBIT1.jpg);
}
#boardcontainer {
height: 700px;

167
boards/MICROBIT2.py Normal file
View File

@ -0,0 +1,167 @@
#!/bin/false
# 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/.
#
# ----------------------------------------------------------------------------------------
# This file contains information for a specific board - the available pins, and where LEDs,
# Buttons, and other in-built peripherals are. It is used to build documentation as well
# as various source and header files for Espruino.
# ----------------------------------------------------------------------------------------
import pinutils;
# TODO:
# Move to SDK17 with proper nRF52833 support
# - expand RAM to 128k
# Proper event handling for accelerometer/etc
# Functions for sound
info = {
'name' : "BBC micro:bit 2",
'link' : [ "https://en.wikipedia.org/wiki/Micro_Bit" ],
'espruino_page_link' : 'MicroBit',
# This is the PCA10036
'default_console' : "EV_SERIAL1",
'default_console_tx' : "H1",
'default_console_rx' : "H0",
'default_console_baudrate' : "9600",
'variables' : 2050, # How many variables are allocated for Espruino to use. RAM will be overflowed if this number is too high and code won't compile.
'binary_name' : 'espruino_%v_microbit2.hex',
'build' : {
'optimizeflags' : '-Os',
'libraries' : [
'BLUETOOTH',
# 'NET',
'GRAPHICS',
'NEOPIXEL',
'TENSORFLOW'
],
'makefile' : [
'DEFINES += -DCONFIG_GPIO_AS_PINRESET', # Allow the reset pin to work
'DEFINES += -DGPIO_COUNT=2 -DP1_PIN_NUM=16 -DNRF_P1_BASE=0x50000300UL "-DNRF_P1=((NRF_GPIO_Type*)NRF_P1_BASE)"', # Hack for 52833 on SDK12
'DEFINES += -DMICROBIT', # enable microbit-specific stuff
'INCLUDE += -I$(ROOT)/libs/microbit',
'WRAPPERSOURCES += libs/microbit/jswrap_microbit.c',
'DEFINES+=-DNEOPIXEL_SCK_PIN=27' # an unused pin
]
}
};
chip = {
'part' : "NRF52832", # actually 52833 but we're using SDK12 for this at the moment, and it doesn't support it
'family' : "NRF52",
'package' : "QFN48",
'ram' : 64,
'flash' : 512,
'speed' : 64, # TODO: actually 128k
'usart' : 1,
'spi' : 1,
'i2c' : 1,
'adc' : 1,
'dac' : 0,
'saved_code' : {
'address' : ((118 - 10) * 4096), # Bootloader takes pages 120-127, FS takes 118-119
'page_size' : 4096,
'pages' : 10,
'flash_available' : 512 - ((31 + 8 + 2 + 10)*4) # Softdevice uses 31 pages of flash, bootloader 8, FS 2, code 10. Each page is 4 kb.
},
};
devices = {
'BTN1' : { 'pin' : 'D5', 'pinstate' : 'IN_PULLDOWN' }, # Pin negated in software
'BTN2' : { 'pin' : 'D11', 'pinstate' : 'IN_PULLDOWN' }, # Pin negated in software
# 'BTN3' : { 'pin' : 'H2', 'pinstate' : 'IN' }, # Pin negated in software
# 'V' pins are virtual
'LED1' : { 'pin' : 'V0' },
};
# left-right, or top-bottom order
board = {
'bottom' : [ 'D3', '','D0','','D4','D5','D6','D7','','D1','','D8','D9','D10','D11','D12','','D2','',
'D13','D14','D15','D16','3.3','','3.3','','3.3','D19','D20','GND','','GND','','GND' ],
'_hide_not_on_connectors' : True,
'_notes' : {
'D3' : "LED Row 3",
'D4' : "LED Row 1",
'D5' : "BTN1",
'D6' : "LED Row 4",
'D7' : "LED Row 2",
'D10' : "LED Row 5",
'D11' : "BTN2",
}
};
board["_css"] = """
#board {
width: 659px;
height: 562px;
top: 0px;
left : 0px;
background-image: url(img/MICROBIT2.jpg);
}
#boardcontainer {
height: 700px;
}
#bottom {
top: 490px;
left: 52px;
}
.bottompin { width: 10px; }
""";
def get_pins():
pins = [
{ "name":"PD0", "sortingname":"D00", "port":"D", "num":"2", "functions":{ "ADC1_IN0":0 }, "csv":{} }, # RING0
{ "name":"PD1", "sortingname":"D01", "port":"D", "num":"3", "functions":{ "ADC1_IN1":0 }, "csv":{} }, # RING1
{ "name":"PD2", "sortingname":"D02", "port":"D", "num":"4", "functions":{ "ADC1_IN2":0 }, "csv":{} }, # RING2
{ "name":"PD3", "sortingname":"D03", "port":"D", "num":"31", "functions":{ }, "csv":{} }, # COLR3
{ "name":"PD4", "sortingname":"D04", "port":"D", "num":"28", "functions":{ }, "csv":{} }, # COLR1
{ "name":"PD5", "sortingname":"D05", "port":"D", "num":"14", "functions":{}, "csv":{} }, # BTN1
{ "name":"PD6", "sortingname":"D06", "port":"D", "num":"37", "functions":{}, "csv":{} }, # COLR4
{ "name":"PD7", "sortingname":"D07", "port":"D", "num":"11", "functions":{}, "csv":{} }, # COLR2
{ "name":"PD8", "sortingname":"D08", "port":"D", "num":"10", "functions":{}, "csv":{} }, # GPIO1
{ "name":"PD9", "sortingname":"D09", "port":"D", "num":"9", "functions":{}, "csv":{} }, # GPIO2
{ "name":"PD10", "sortingname":"D10", "port":"D", "num":"30", "functions":{ }, "csv":{} }, # COLR5
{ "name":"PD11", "sortingname":"D11", "port":"D", "num":"23", "functions":{ }, "csv":{} }, # BTN2
{ "name":"PD12", "sortingname":"D12", "port":"D", "num":"12", "functions":{}, "csv":{} }, # GPIO4
{ "name":"PD13", "sortingname":"D13", "port":"D", "num":"17", "functions":{ "SPI1_SCK":0 }, "csv":{} },
{ "name":"PD14", "sortingname":"D14", "port":"D", "num":"1", "functions":{ "SPI1_MISO":0 }, "csv":{} },
{ "name":"PD15", "sortingname":"D15", "port":"D", "num":"13", "functions":{ "SPI1_MOSI":0 }, "csv":{} },
{ "name":"PD16", "sortingname":"D16", "port":"D", "num":"34", "functions":{}, "csv":{} }, # GPIO3
{ "name":"PD17", "sortingname":"D17", "port":"D", "num":"27", "functions":{}, "csv":{} }, # FIXME 3.3v - using an unused pin
{ "name":"PD18", "sortingname":"D18", "port":"D", "num":"27", "functions":{}, "csv":{} }, # FIXME 3.3v - using an unused pin
{ "name":"PD19", "sortingname":"D19", "port":"D", "num":"26", "functions":{ "I2C1_SCL":0 }, "csv":{} },
{ "name":"PD20", "sortingname":"D20", "port":"D", "num":"32", "functions":{ "I2C1_SDA":0 }, "csv":{} },
{ "name":"PH0", "sortingname":"H00", "port":"H", "num":"40", "functions":{"USART1_RX" : 0}, "csv":{} }, # UART_RX - receive into Espruino
{ "name":"PH1", "sortingname":"H01", "port":"H", "num":"6", "functions":{"USART1_TX" : 0}, "csv":{} }, # UART_TX
{ "name":"PH2", "sortingname":"H02", "port":"H", "num":"36", "functions":{}, "csv":{} }, # face touch
{ "name":"PH3", "sortingname":"H03", "port":"H", "num":"0", "functions":{}, "csv":{} }, # speaker
{ "name":"PH4", "sortingname":"H04", "port":"H", "num":"5", "functions":{ "ADC1_IN3":0 }, "csv":{} }, # mic_in
{ "name":"PH5", "sortingname":"H05", "port":"H", "num":"20", "functions":{}, "csv":{} }, # run_mic
{ "name":"PH6", "sortingname":"H06", "port":"H", "num":"16", "functions":{}, "csv":{} }, # INT_SDA
{ "name":"PH7", "sortingname":"H07", "port":"H", "num":"8", "functions":{}, "csv":{} }, # INT_SCL
{ "name":"PH8", "sortingname":"H08", "port":"H", "num":"25", "functions":{}, "csv":{} }, # INT
{ "name":"PV0", "sortingname":"V0", "port":"V", "num":"0", "functions":{}, "csv":{} } # LED virtual pin
];
#21 # ROW1
#22 # ROW2
#15 # ROW3
#24 # ROW4
#19 # ROW5
# Make buttons negated
pinutils.findpin(pins, "PD5", True)["functions"]["NEGATED"]=0;
pinutils.findpin(pins, "PD11", True)["functions"]["NEGATED"]=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

@ -38,7 +38,9 @@ info = {
],
'makefile' : [
'DEFINES+=-DCONFIG_GPIO_AS_PINRESET', # Allow the reset pin to work
'DEFINES += -DBOARD_PCA10040 -DPCA10040'
'DEFINES += -DBOARD_PCA10040 -DPCA10040',
#'DEFINES += -DI2C_SLAVE -DTWIS_ENABLED=1 -DTWIS1_ENABLED=1' # enable I2C slave support
# I2C slave can then be used with I2C1.setup({sda,scl,addr:42})
]
}
};

View File

@ -40,6 +40,7 @@ info = {
'DEFINES += -DCONFIG_GPIO_AS_PINRESET', # Allow the reset pin to work
'DEFINES += -DBOARD_PCA10056',
'DEFINES += -DNRF_USB=1 -DUSB',
'DEFINES += -DNEOPIXEL_SCK_PIN=22 -DNEOPIXEL_LRCK_PIN=23', # nRF52840 needs LRCK pin defined for neopixel
'NRF_SDK15=1'
]
}

View File

@ -34,7 +34,8 @@ info = {
'NFC',
'NEOPIXEL',
'PIXLJS',
'CRYPTO','SHA256',
'CRYPTO',
#'SHA256',
#'AES',
'FILESYSTEM',
'TERMINAL'

View File

@ -51,6 +51,7 @@ info = {
'JSMODULESOURCES += libs/js/banglejs/locale.min.js',
'DEFINES += -DBANGLEJS',
'DEFINES += -D\'IS_PIN_A_BUTTON(PIN)=((PIN==17)||(PIN==40)||(PIN==41))\'',
'DEFINES += -DSPIFLASH_SLEEP_CMD', # SPI flash needs to be explicitly slept and woken up
# 'DEFINES += -DBOARD_PCA10056',
# 'DEFINES += -DNRF_USB=1 -DUSB',

View File

Before

Width:  |  Height:  |  Size: 140 KiB

After

Width:  |  Height:  |  Size: 140 KiB

BIN
boards/img/MICROBIT2.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 140 KiB

View File

@ -56,10 +56,6 @@ espruino_#v##_mdbt42q.zip
- The firmware image for Espruino MDBT42Q modules
See http://www.espruino.com/MDBT42Q#firmware-updates for more information
espruino_#v##_hystm32_24_ve.bin
- 'HY'STM32F103VET6 ARM with 2.4" LCD display
This is available from eBay
espruino_#v##_stm32l496gdiscovery.bin
- STM32F496GDISCOVERY board
@ -75,19 +71,9 @@ espruino_#v##_nucleof401re.bin
espruino_#v##_nucleof411re.bin
- ST NUCLEO-F411RE board
espruino_#v##_raspberrypi
- Raspberry Pi executable (just copy it to the device and run it)
NOTE: There is GPIO support (which requires you to run Espruino as root)
however there is no Serial, SPI, OneWire or I2C support at the moment so
you're pretty limited!
espruino_#v##_microbit.hex
- Espruino for the BBC micro:bit - just copy this file onto the
flash drive that appears when you plug the micro:bit in.
espruino_#v##_ruuvitag.zip
- The firmware image for Ruuvitag Devices
See http://www.espruino.com/Ruuvitag for more information
espruino_#v##_microbit1/2.hex
- Espruino for the BBC micro:bit 1 or 2 - just copy the correct file onto the
flash drive that appears when you plug the micro:bit in.
espruino_#v##_Wio_LTE.zip
- The firmware image for Seed Wio LTE Devices
@ -109,11 +95,6 @@ espruino_#v##smartibot.zip
- The firmware image for the Smartibot robot board
See http://www.espruino.com/Smartibot for more information
espruino_#v##_thingy52.hex
- The firmware image for Nordic Thing:52 Devices
See http://www.espruino.com/Thingy52 for more information
ESP8266 / ESP32
---------------

View File

@ -36,11 +36,12 @@
#include "nrf_delay.h"
#include "nrf_soc.h"
#include "nrf_saadc.h"
#include "app_timer.h"
#include "nrf5x_utils.h"
#include "bluetooth.h" // for self-test
#include "jsi2c.h" // accelerometer/etc
#endif
#include "app_timer.h"
#include "jswrap_graphics.h"
#ifdef LCD_CONTROLLER_LPM013M126
@ -375,6 +376,8 @@ volatile uint16_t btn1Timer; // in ms
int lcdPowerTimeout; // in ms
/// If a button was pressed to wake the LCD up, which one was it?
char lcdWakeButton;
/// If a button was pressed to wake the LCD up, when should we start accepting events for it?
JsSysTime lcdWakeButtonTime;
/// Is the LCD on?
bool lcdPowerOn;
/// LCD Brightness - 255=full
@ -497,6 +500,8 @@ typedef enum {
JSBT_HRM_DATA = 1<<17, ///< Heart rate data is ready for analysis
JSBT_TWIST_EVENT = 1<<18, ///< Watch was twisted
JSBT_FACE_UP = 1<<19, ///< Watch was turned face up/down (faceUp holds the actual state)
JSBT_ACCEL_INTERVAL_DEFAULT = 1<<20, ///< reschedule accelerometer poll handler to default speed
JSBT_ACCEL_INTERVAL_POWERSAVE = 1<<21, ///< reschedule accelerometer poll handler to powersave speed
} JsBangleTasks;
JsBangleTasks bangleTasks;
@ -659,8 +664,10 @@ void peripheralPollHandler() {
if (bangleFlags & JSBF_POWER_SAVE) {
if (accdiff > POWER_SAVE_MIN_ACCEL) {
powerSaveTimer = 0;
if (pollInterval == POWER_SAVE_ACCEL_POLL_INTERVAL)
jswrap_banglejs_setPollInterval_internal(DEFAULT_ACCEL_POLL_INTERVAL);
if (pollInterval == POWER_SAVE_ACCEL_POLL_INTERVAL) {
bangleTasks |= JSBT_ACCEL_INTERVAL_DEFAULT;
jshHadEvent();
}
} else {
if (powerSaveTimer < TIMER_MAX)
powerSaveTimer += pollInterval;
@ -668,7 +675,8 @@ void peripheralPollHandler() {
pollInterval == DEFAULT_ACCEL_POLL_INTERVAL && // we are in high power mode
!(bangleFlags & JSBF_ACCEL_LISTENER) // nothing was listening to accelerometer data
) {
jswrap_banglejs_setPollInterval_internal(POWER_SAVE_ACCEL_POLL_INTERVAL);
bangleTasks |= JSBT_ACCEL_INTERVAL_POWERSAVE;
jshHadEvent();
}
}
}
@ -819,7 +827,10 @@ void btnHandlerCommon(int button, bool state, IOEventFlags flags) {
flipTimer = 0;
if (!lcdPowerOn && state) {
bangleTasks |= JSBT_LCD_ON;
// This allows us to ignore subsequent button
// rising or 'bounce' events
lcdWakeButton = button;
lcdWakeButtonTime = jshGetSystemTime() + jshGetTimeFromMilliseconds(100);
return; // don't push button event if the LCD is off
}
} else {
@ -830,15 +841,24 @@ void btnHandlerCommon(int button, bool state, IOEventFlags flags) {
return;
}
}
/* This stops the button 'up' event being
propagated if the button down was used to wake
the LCD up */
if (button == lcdWakeButton && !state) {
lcdWakeButton = 0;
return;
JsSysTime t = jshGetSystemTime();
/* This stops the button 'up' or bounces from being
propagated if the button was used to wake the LCD up */
if (button == lcdWakeButton) {
if ((t < lcdWakeButtonTime) || !state) {
/* If it's a rising edge *or* it's within our debounce
* period, reset the debounce timer and ignore it */
lcdWakeButtonTime = t + jshGetTimeFromMilliseconds(100);
return;
} else {
/* if the next event is a 'down', > 100ms after the last event, we propogate it
and subsequent events */
lcdWakeButton = 0;
lcdWakeButtonTime = 0;
}
}
// Add to the event queue for normal processing for watches
jshPushIOEvent(flags | (state?EV_EXTI_IS_HIGH:0), jshGetSystemTime());
jshPushIOEvent(flags | (state?EV_EXTI_IS_HIGH:0), t);
}
#ifdef BTN4_PININDEX
@ -1939,6 +1959,9 @@ bool jswrap_banglejs_idle() {
if (bangleTasks & JSBT_LCD_OFF) jswrap_banglejs_setLCDPower(0);
if (bangleTasks & JSBT_LCD_ON) jswrap_banglejs_setLCDPower(1);
if (bangleTasks & JSBT_RESET) jsiStatus |= JSIS_TODO_FLASH_LOAD;
if (bangleTasks & JSBT_ACCEL_INTERVAL_DEFAULT) jswrap_banglejs_setPollInterval_internal(DEFAULT_ACCEL_POLL_INTERVAL);
if (bangleTasks & JSBT_ACCEL_INTERVAL_POWERSAVE) jswrap_banglejs_setPollInterval_internal(POWER_SAVE_ACCEL_POLL_INTERVAL);
if (!bangle) {
bangleTasks = JSBT_NONE;
return false;

View File

@ -58,7 +58,7 @@ typedef struct {
#define BLE_NUS_MAX_DATA_LEN 20 //GATT_MTU_SIZE_DEFAULT - 3
#endif
#if defined(NRF52) || defined(ESP32)
#if defined(NRF52_SERIES) || defined(ESP32)
// nRF52 gets the ability to connect to other
#define CENTRAL_LINK_COUNT 1 /**<number of central links used by the application. When changing this number remember to adjust the RAM settings*/
#define PERIPHERAL_LINK_COUNT 1 /**<number of peripheral links used by the application. When changing this number remember to adjust the RAM settings*/

View File

@ -128,7 +128,7 @@ void bleSwitchTask(BleTask task) {
// ------------------------------------------------------------------------------
// ------------------------------------------------------------------------------
#ifdef NRF52
#ifdef NRF52_SERIES
void bleSetActiveBluetoothGattServer(JsVar *var) {
jsvObjectSetChild(execInfo.hiddenRoot, BLE_NAME_GATT_SERVER, var);
}
@ -336,7 +336,7 @@ See Nordic's `ble_gap_evt_auth_status_t` structure for more information.
"type" : "event",
"class" : "NRF",
"name" : "HID",
"#if" : "defined(NRF52)"
"#if" : "defined(NRF52_SERIES)"
}
Called with a single byte value when Espruino is set up as
a HID device and the computer it is connected to sends a
@ -348,7 +348,7 @@ indications such as the Caps Lock LED.
"type" : "event",
"class" : "NRF",
"name" : "servicesDiscover",
"#if" : "defined(NRF52) || defined(ESP32)"
"#if" : "defined(NRF52_SERIES) || defined(ESP32)"
}
Called with discovered services when discovery is finished
*/
@ -356,7 +356,7 @@ Called with discovered services when discovery is finished
"type" : "event",
"class" : "NRF",
"name" : "characteristicsDiscover",
"#if" : "defined(NRF52) || defined(ESP32)"
"#if" : "defined(NRF52_SERIES) || defined(ESP32)"
}
Called with discovered characteristics when discovery is finished
*/
@ -366,7 +366,7 @@ Called with discovered characteristics when discovery is finished
"type" : "event",
"class" : "NRF",
"name" : "NFCon",
"#if" : "defined(NRF52) && defined(USE_NFC)"
"#if" : "defined(NRF52_SERIES) && defined(USE_NFC)"
}
Called when an NFC field is detected
*/
@ -374,7 +374,7 @@ Called when an NFC field is detected
"type" : "event",
"class" : "NRF",
"name" : "NFCoff",
"#if" : "defined(NRF52) && defined(USE_NFC)"
"#if" : "defined(NRF52_SERIES) && defined(USE_NFC)"
}
Called when an NFC field is no longer detected
*/
@ -385,7 +385,7 @@ Called when an NFC field is no longer detected
"params" : [
["arr","JsVar","An ArrayBuffer containign the received data"]
],
"#if" : "defined(NRF52) && defined(USE_NFC)"
"#if" : "defined(NRF52_SERIES) && defined(USE_NFC)"
}
When NFC is started with `NRF.nfcStart`, this is fired
when NFC data is received. It doesn't get called if
@ -398,7 +398,7 @@ NFC is started with `NRF.nfcURL` or `NRF.nfcRaw`
"params" : [
["reason","int","The reason code reported back by the BLE stack - see Nordic's `ble_hci.h` file for more information"]
],
"ifdef" : "NRF52"
"ifdef" : "NRF52_SERIES"
}
Called when the device gets disconnected.
@ -418,7 +418,7 @@ NRF.connect("aa:bb:cc:dd:ee:ff").then(function(gatt) {
"type" : "event",
"class" : "BluetoothRemoteGATTCharacteristic",
"name" : "characteristicvaluechanged",
"ifdef" : "NRF52"
"ifdef" : "NRF52_SERIES"
}
Called when a characteristic's value changes, *after* `BluetoothRemoteGATTCharacteristic.startNotifications` has been called.
@ -561,7 +561,7 @@ JsVar *jswrap_ble_getAddress() {
"type" : "staticmethod",
"class" : "NRF",
"name" : "setAddress",
"#if" : "defined(NRF52)",
"#if" : "defined(NRF52_SERIES)",
"generate" : "jswrap_ble_setAddress",
"params" : [
["addr","JsVar","The address to use (as a string)"]
@ -585,7 +585,7 @@ To change the address, Espruino must restart the softdevice. It will only do
so when it is disconnected from other devices.
*/
void jswrap_ble_setAddress(JsVar *address) {
#ifdef NRF52
#ifdef NRF52_SERIES
ble_gap_addr_t p_addr;
if (!bleVarToAddr(address, &p_addr)) {
jsExceptionHere(JSET_ERROR, "Expecting a mac address of the form aa:bb:cc:dd:ee:ff");
@ -2010,7 +2010,7 @@ void jswrap_ble_setLowPowerConnection(bool lowPower) {
"type" : "staticmethod",
"class" : "NRF",
"name" : "nfcURL",
"#if" : "defined(NRF52) && defined(USE_NFC)",
"#if" : "defined(NRF52_SERIES) && defined(USE_NFC)",
"generate" : "jswrap_nfc_URL",
"params" : [
["url","JsVar","The URL string to expose on NFC, or `undefined` to disable NFC"]
@ -2088,7 +2088,7 @@ void jswrap_nfc_URL(JsVar *url) {
"type" : "staticmethod",
"class" : "NRF",
"name" : "nfcPair",
"#if" : "defined(NRF52) && defined(USE_NFC)",
"#if" : "defined(NRF52_SERIES) && defined(USE_NFC)",
"generate" : "jswrap_nfc_pair",
"params" : [
["key","JsVar","16 byte out of band key"]
@ -2149,7 +2149,7 @@ void jswrap_nfc_pair(JsVar *key) {
"type" : "staticmethod",
"class" : "NRF",
"name" : "nfcAndroidApp",
"#if" : "defined(NRF52) && defined(USE_NFC)",
"#if" : "defined(NRF52_SERIES) && defined(USE_NFC)",
"generate" : "jswrap_nfc_androidApp",
"params" : [
["app","JsVar","The unique identifier of the given Android App"]
@ -2208,7 +2208,7 @@ void jswrap_nfc_androidApp(JsVar *appName) {
"type" : "staticmethod",
"class" : "NRF",
"name" : "nfcRaw",
"#if" : "defined(NRF52) && defined(USE_NFC)",
"#if" : "defined(NRF52_SERIES) && defined(USE_NFC)",
"generate" : "jswrap_nfc_raw",
"params" : [
["payload","JsVar","The NFC NDEF message to deliver to the reader"]
@ -2270,7 +2270,7 @@ void jswrap_nfc_raw(JsVar *payload) {
"type" : "staticmethod",
"class" : "NRF",
"name" : "nfcStart",
"#if" : "defined(NRF52) && defined(USE_NFC)",
"#if" : "defined(NRF52_SERIES) && defined(USE_NFC)",
"generate" : "jswrap_nfc_start",
"params" : [
["payload","JsVar","Optional 7 byte UID"]
@ -2339,7 +2339,7 @@ JsVar *jswrap_nfc_start(JsVar *payload) {
"type" : "staticmethod",
"class" : "NRF",
"name" : "nfcStop",
"#if" : "defined(NRF52) && defined(USE_NFC)",
"#if" : "defined(NRF52_SERIES) && defined(USE_NFC)",
"generate" : "jswrap_nfc_stop",
"params" : [ ]
}
@ -2363,7 +2363,7 @@ void jswrap_nfc_stop() {
"type" : "staticmethod",
"class" : "NRF",
"name" : "nfcSend",
"#if" : "defined(NRF52) && defined(USE_NFC)",
"#if" : "defined(NRF52_SERIES) && defined(USE_NFC)",
"generate" : "jswrap_nfc_send",
"params" : [
["payload","JsVar","Optional tx data"]
@ -2407,7 +2407,7 @@ void jswrap_nfc_send(JsVar *payload) {
"type" : "staticmethod",
"class" : "NRF",
"name" : "sendHIDReport",
"ifdef" : "NRF52",
"ifdef" : "NRF52_SERIES",
"generate" : "jswrap_ble_sendHIDReport",
"params" : [
["data","JsVar","Input report data as an array"],
@ -2434,7 +2434,7 @@ void jswrap_ble_sendHIDReport(JsVar *data, JsVar *callback) {
"type" : "staticmethod",
"class" : "NRF",
"name" : "requestDevice",
"#if" : "defined(NRF52) || defined(ESP32)",
"#if" : "defined(NRF52_SERIES) || defined(ESP32)",
"generate" : "jswrap_ble_requestDevice",
"params" : [
["options","JsVar","Options used to filter the device to use"]
@ -2572,7 +2572,7 @@ JsVar *jswrap_ble_requestDevice(JsVar *options) {
"type" : "staticmethod",
"class" : "NRF",
"name" : "connect",
"#if" : "defined(NRF52) || defined(ESP32)",
"#if" : "defined(NRF52_SERIES) || defined(ESP32)",
"generate" : "jswrap_ble_connect",
"params" : [
["mac","JsVar","The MAC address to connect to"],
@ -2637,7 +2637,7 @@ JsVar *jswrap_ble_connect(JsVar *mac, JsVar *options) {
"type" : "staticmethod",
"class" : "NRF",
"name" : "setWhitelist",
"ifdef" : "NRF52",
"ifdef" : "NRF52_SERIES",
"generate" : "jswrap_ble_setWhitelist",
"params" : [
["whitelisting","bool","Are we using a whitelist? (default false)"]
@ -2662,7 +2662,7 @@ void jswrap_ble_setWhitelist(bool whitelist) {
"type" : "staticmethod",
"class" : "NRF",
"name" : "setConnectionInterval",
"ifdef" : "NRF52",
"ifdef" : "NRF52_SERIES",
"generate" : "jswrap_ble_setConnectionInterval",
"params" : [
["interval","JsVar","The connection interval to use (see below)"]
@ -2693,7 +2693,7 @@ to specify a connection interval.
**Note:** This overwrites any changes imposed by the deprecated `NRF.setLowPowerConnection`
*/
void jswrap_ble_setConnectionInterval(JsVar *interval) {
#if NRF52
#if NRF52_SERIES
if (jsvIsUndefined(interval) || jsvIsStringEqual(interval,"auto")) {
// allow automatic interval setting
bleStatus &= ~BLE_DISABLE_DYNAMIC_INTERVAL;
@ -2716,7 +2716,7 @@ void jswrap_ble_setConnectionInterval(JsVar *interval) {
"type" : "staticmethod",
"class" : "NRF",
"name" : "setSecurity",
"ifdef" : "NRF52",
"ifdef" : "NRF52_SERIES",
"generate" : "jswrap_ble_setSecurity",
"params" : [
["options","JsVar","An object containing security-related options (see below)"]
@ -2819,7 +2819,7 @@ void jswrap_ble_setSecurity(JsVar *options) {
"type" : "staticmethod",
"class" : "NRF",
"name" : "getSecurityStatus",
"ifdef" : "NRF52",
"ifdef" : "NRF52_SERIES",
"generate" : "jswrap_ble_getSecurityStatus",
"return" : ["JsVar", "An object" ]
}
@ -2846,7 +2846,7 @@ JsVar *jswrap_ble_getSecurityStatus(JsVar *parent) {
/*JSON{
"type" : "class",
"class" : "BluetoothDevice",
"ifdef" : "NRF52"
"ifdef" : "NRF52_SERIES"
}
A Web Bluetooth-style device - you can request one using `NRF.requestDevice(address)`
@ -2873,7 +2873,7 @@ NRF.requestDevice({ filters: [{ name: 'Puck.js abcd' }] }).then(function(device)
"type" : "property",
"class" : "BluetoothDevice",
"name" : "gatt",
"#if" : "defined(NRF52) || defined(ESP32)",
"#if" : "defined(NRF52_SERIES) || defined(ESP32)",
"generate" : "jswrap_BluetoothDevice_gatt",
"return" : ["JsVar", "A `BluetoothRemoteGATTServer` for this device" ]
}
@ -2897,7 +2897,7 @@ JsVar *jswrap_BluetoothDevice_gatt(JsVar *parent) {
"type" : "property",
"class" : "BluetoothDevice",
"name" : "rssi",
"ifdef" : "NRF52",
"ifdef" : "NRF52_SERIES",
"generate" : false,
"return" : ["bool", "The last received RSSI (signal strength) for this device" ]
}
@ -2906,7 +2906,7 @@ JsVar *jswrap_BluetoothDevice_gatt(JsVar *parent) {
"type" : "event",
"class" : "BluetoothDevice",
"name" : "passkey",
"ifdef" : "NRF52",
"ifdef" : "NRF52_SERIES",
"params" : [
["passkey","JsVar","A 6 character numeric String to be displayed"]
]
@ -2922,7 +2922,7 @@ specifically for Espruino.
"type" : "event",
"class" : "BluetoothDevice",
"name" : "passkeyRequest",
"ifdef" : "NRF52"
"ifdef" : "NRF52_SERIES"
}
Called when the device pairs, displays a passkey, and wants Espruino to tell it what the passkey was.
@ -2937,7 +2937,7 @@ specifically for Espruino.
"type" : "method",
"class" : "BluetoothDevice",
"name" : "sendPasskey",
"ifdef" : "NRF52",
"ifdef" : "NRF52_SERIES",
"generate" : "jswrap_ble_BluetoothDevice_sendPasskey",
"params" : [
["passkey","JsVar","A 6 character numeric String to be returned to the device"]
@ -2948,7 +2948,7 @@ To be used as a response when the event `BluetoothDevice.sendPasskey` has been r
**This is not part of the Web Bluetooth Specification.** It has been added
specifically for Espruino.
*/
#if NRF52
#if NRF52_SERIES
void jswrap_ble_BluetoothDevice_sendPasskey(JsVar *parent, JsVar *passkeyVar) {
char passkey[BLE_GAP_PASSKEY_LEN+1];
memset(passkey, 0, sizeof(passkey));
@ -2962,7 +2962,7 @@ void jswrap_ble_BluetoothDevice_sendPasskey(JsVar *parent, JsVar *passkeyVar) {
"type" : "method",
"class" : "BluetoothRemoteGATTServer",
"name" : "connect",
"#if" : "defined(NRF52) || defined(ESP32)",
"#if" : "defined(NRF52_SERIES) || defined(ESP32)",
"generate" : "jswrap_ble_BluetoothRemoteGATTServer_connect",
"params" : [
["options","JsVar","(Espruino-specific) An object of connection options (see below)"]
@ -3050,7 +3050,7 @@ JsVar *jswrap_ble_BluetoothRemoteGATTServer_connect(JsVar *parent, JsVar *option
/*JSON{
"type" : "class",
"class" : "BluetoothRemoteGATTServer",
"#if" : "defined(NRF52) || defined(ESP32)"
"#if" : "defined(NRF52_SERIES) || defined(ESP32)"
}
Web Bluetooth-style GATT server - get this using `NRF.connect(address)`
or `NRF.requestDevice(options)` and `response.gatt.connect`
@ -3072,7 +3072,7 @@ https://webbluetoothcg.github.io/web-bluetooth/#bluetoothremotegattserver
"generate" : "jswrap_BluetoothRemoteGATTServer_disconnect",
"return" : ["JsVar", "A `Promise` that is resolved (or rejected) when the disconnection is complete (non-standard)" ],
"return_object" : "Promise",
"#if" : "defined(NRF52) || defined(ESP32)"
"#if" : "defined(NRF52_SERIES) || defined(ESP32)"
}
Disconnect from a previously connected BLE device connected with
`BluetoothRemoteGATTServer.connect` - this does not disconnect from something that has
@ -3097,7 +3097,7 @@ JsVar *jswrap_BluetoothRemoteGATTServer_disconnect(JsVar *parent) {
return promise;
} else {
// no connection - try and cancel the connect attempt (assume we have one)
#ifdef NRF52
#ifdef NRF52_SERIES
if (bleInTask(BLETASK_CONNECT)) {
bleCompleteTaskFailAndUnLock(BLETASK_CONNECT, jsvNewFromString("Connection cancelled"));
err_code = sd_ble_gap_connect_cancel();
@ -3121,7 +3121,7 @@ JsVar *jswrap_BluetoothRemoteGATTServer_disconnect(JsVar *parent) {
"type" : "method",
"class" : "BluetoothRemoteGATTServer",
"name" : "startBonding",
"ifdef" : "NRF52",
"ifdef" : "NRF52_SERIES",
"generate" : "jswrap_ble_BluetoothRemoteGATTServer_startBonding",
"params" : [
["forceRePair","bool","If the device is already bonded, re-pair it"]
@ -3171,7 +3171,7 @@ JsVar *jswrap_ble_BluetoothRemoteGATTServer_startBonding(JsVar *parent, bool for
"type" : "method",
"class" : "BluetoothRemoteGATTServer",
"name" : "getSecurityStatus",
"ifdef" : "NRF52",
"ifdef" : "NRF52_SERIES",
"generate" : "jswrap_ble_BluetoothRemoteGATTServer_getSecurityStatus",
"return" : ["JsVar", "An object" ]
}
@ -3211,7 +3211,7 @@ JsVar *jswrap_ble_BluetoothRemoteGATTServer_getSecurityStatus(JsVar *parent) {
"params" : [ ["service","JsVar","The service UUID"] ],
"return" : ["JsVar", "A `Promise` that is resolved (or rejected) when the primary service is found (the argument contains a `BluetoothRemoteGATTService`)" ],
"return_object" : "Promise",
"#if" : "defined(NRF52) || defined(ESP32)"
"#if" : "defined(NRF52_SERIES) || defined(ESP32)"
}
See `NRF.connect` for usage examples.
*/
@ -3244,7 +3244,7 @@ JsVar *jswrap_BluetoothRemoteGATTServer_getPrimaryService(JsVar *parent, JsVar *
"generate" : "jswrap_BluetoothRemoteGATTServer_getPrimaryServices",
"return" : ["JsVar", "A `Promise` that is resolved (or rejected) when the primary services are found (the argument contains an array of `BluetoothRemoteGATTService`)" ],
"return_object" : "Promise",
"#if" : "defined(NRF52) || defined(ESP32)"
"#if" : "defined(NRF52_SERIES) || defined(ESP32)"
}
*/
JsVar *jswrap_BluetoothRemoteGATTServer_getPrimaryServices(JsVar *parent) {
@ -3271,7 +3271,7 @@ JsVar *jswrap_BluetoothRemoteGATTServer_getPrimaryServices(JsVar *parent) {
"params" : [
["callback","JsVar","The callback to call with the RSSI value, or undefined to stop"]
],
"#if" : "defined(NRF52) || defined(ESP32)"
"#if" : "defined(NRF52_SERIES) || defined(ESP32)"
}
Start/stop listening for RSSI values on the active GATT connection
@ -3305,7 +3305,7 @@ void jswrap_BluetoothRemoteGATTServer_setRSSIHandler(JsVar *parent, JsVar *callb
/*JSON{
"type" : "class",
"class" : "BluetoothRemoteGATTService",
"#if" : "defined(NRF52) || defined(ESP32)"
"#if" : "defined(NRF52_SERIES) || defined(ESP32)"
}
Web Bluetooth-style GATT service - get this using `BluetoothRemoteGATTServer.getPrimaryService(s)`
@ -3319,7 +3319,7 @@ https://webbluetoothcg.github.io/web-bluetooth/#bluetoothremotegattservice
"params" : [ ["characteristic","JsVar","The characteristic UUID"] ],
"return" : ["JsVar", "A `Promise` that is resolved (or rejected) when the characteristic is found (the argument contains a `BluetoothRemoteGATTCharacteristic`)" ],
"return_object" : "Promise",
"#if" : "defined(NRF52) || defined(ESP32)"
"#if" : "defined(NRF52_SERIES) || defined(ESP32)"
}
See `NRF.connect` for usage examples.
*/
@ -3352,7 +3352,7 @@ JsVar *jswrap_BluetoothRemoteGATTService_getCharacteristic(JsVar *parent, JsVar
"generate" : "jswrap_BluetoothRemoteGATTService_getCharacteristics",
"return" : ["JsVar", "A `Promise` that is resolved (or rejected) when the characteristic is found (the argument contains an array of `BluetoothRemoteGATTCharacteristic`)" ],
"return_object" : "Promise",
"#if" : "defined(NRF52) || defined(ESP32)"
"#if" : "defined(NRF52_SERIES) || defined(ESP32)"
}
*/
JsVar *jswrap_BluetoothRemoteGATTService_getCharacteristics(JsVar *parent) {
@ -3375,7 +3375,7 @@ JsVar *jswrap_BluetoothRemoteGATTService_getCharacteristics(JsVar *parent) {
/*JSON{
"type" : "class",
"class" : "BluetoothRemoteGATTCharacteristic",
"#if" : "defined(NRF52) || defined(ESP32)"
"#if" : "defined(NRF52_SERIES) || defined(ESP32)"
}
Web Bluetooth-style GATT characteristic - get this using `BluetoothRemoteGATTService.getCharacteristic(s)`
@ -3391,7 +3391,7 @@ https://webbluetoothcg.github.io/web-bluetooth/#bluetoothremotegattcharacteristi
],
"return" : ["JsVar", "A `Promise` that is resolved (or rejected) when the characteristic is written" ],
"return_object" : "Promise",
"#if" : "defined(NRF52) || defined(ESP32)"
"#if" : "defined(NRF52_SERIES) || defined(ESP32)"
}
Write a characteristic's value
@ -3436,7 +3436,7 @@ JsVar *jswrap_ble_BluetoothRemoteGATTCharacteristic_writeValue(JsVar *characteri
"generate" : "jswrap_ble_BluetoothRemoteGATTCharacteristic_readValue",
"return" : ["JsVar", "A `Promise` that is resolved (or rejected) with a `DataView` when the characteristic is read" ],
"return_object" : "Promise",
"#if" : "defined(NRF52) || defined(ESP32)"
"#if" : "defined(NRF52_SERIES) || defined(ESP32)"
}
Read a characteristic's value, return a promise containing a `DataView`
@ -3480,7 +3480,7 @@ JsVar *jswrap_ble_BluetoothRemoteGATTCharacteristic_readValue(JsVar *characteris
"generate" : "jswrap_ble_BluetoothRemoteGATTCharacteristic_startNotifications",
"return" : ["JsVar", "A `Promise` that is resolved (or rejected) with data when notifications have been added" ],
"return_object" : "Promise",
"ifdef" : "NRF52"
"ifdef" : "NRF52_SERIES"
}
Starts notifications - whenever this characteristic's value changes, a `characteristicvaluechanged` event is fired
and `characteristic.value` will then contain the new value as a `DataView`.
@ -3567,7 +3567,7 @@ JsVar *jswrap_ble_BluetoothRemoteGATTCharacteristic_startNotifications(JsVar *ch
"generate" : "jswrap_ble_BluetoothRemoteGATTCharacteristic_stopNotifications",
"return" : ["JsVar", "A `Promise` that is resolved (or rejected) with data when notifications have been removed" ],
"return_object" : "Promise",
"ifdef" : "NRF52"
"ifdef" : "NRF52_SERIES"
}
Stop notifications (that were requested with `BluetoothRemoteGATTCharacteristic.startNotifications`)
*/

View File

@ -44,7 +44,7 @@ void bleCompleteTaskFail(BleTask task, JsVar *data);
void bleCompleteTaskFailAndUnLock(BleTask task, JsVar *data);
void bleSwitchTask(BleTask task);
#ifdef NRF52
#ifdef NRF52_SERIES
// Set the currently active GATT server
void bleSetActiveBluetoothGattServer(JsVar *var);
// Get the currently active GATT server (the return value needs unlocking)

View File

@ -4,6 +4,8 @@
* Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Modified slightly by gw@pur3.co.uk to reduce code size at expense of speed.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
@ -110,9 +112,24 @@ void mbedtls_sha1_starts( mbedtls_sha1_context *ctx )
}
#if !defined(MBEDTLS_SHA1_PROCESS_ALT)
#define S(x,n) ((x << n) | ((x & 0xFFFFFFFF) >> (32 - n)))
uint32_t mbedtls_sha1_processR(uint32_t *W, uint32_t t) {
uint32_t temp;
return (
temp = W[( t - 3 ) & 0x0F] ^ W[( t - 8 ) & 0x0F] ^
W[( t - 14 ) & 0x0F] ^ W[ t & 0x0F],
( W[t & 0x0F] = S(temp,1) )
);
}
void mbedtls_sha1_process( mbedtls_sha1_context *ctx, const unsigned char data[64] )
{
uint32_t temp, W[16], A, B, C, D, E;
/* GW modified this to reduce code duplication caused by macro expansions. A bit slower,
* much smaller. */
uint32_t i, W[20], ABCDE[5];
GET_UINT32_BE( W[ 0], data, 0 );
GET_UINT32_BE( W[ 1], data, 4 );
@ -131,49 +148,29 @@ void mbedtls_sha1_process( mbedtls_sha1_context *ctx, const unsigned char data[6
GET_UINT32_BE( W[14], data, 56 );
GET_UINT32_BE( W[15], data, 60 );
#define S(x,n) ((x << n) | ((x & 0xFFFFFFFF) >> (32 - n)))
#define R(t) \
( \
temp = W[( t - 3 ) & 0x0F] ^ W[( t - 8 ) & 0x0F] ^ \
W[( t - 14 ) & 0x0F] ^ W[ t & 0x0F], \
( W[t & 0x0F] = S(temp,1) ) \
)
#define R(t) mbedtls_sha1_processR(W,t)
#define P(a,b,c,d,e,x) \
{ \
e += S(a,5) + F(b,c,d) + K + x; b = S(b,30); \
}
A = ctx->state[0];
B = ctx->state[1];
C = ctx->state[2];
D = ctx->state[3];
E = ctx->state[4];
for (i=0;i<5;i++)
ABCDE[i] = ctx->state[i];
#define F(x,y,z) (z ^ (x & (y ^ z)))
#define K 0x5A827999
P( A, B, C, D, E, W[0] );
P( E, A, B, C, D, W[1] );
P( D, E, A, B, C, W[2] );
P( C, D, E, A, B, W[3] );
P( B, C, D, E, A, W[4] );
P( A, B, C, D, E, W[5] );
P( E, A, B, C, D, W[6] );
P( D, E, A, B, C, W[7] );
P( C, D, E, A, B, W[8] );
P( B, C, D, E, A, W[9] );
P( A, B, C, D, E, W[10] );
P( E, A, B, C, D, W[11] );
P( D, E, A, B, C, W[12] );
P( C, D, E, A, B, W[13] );
P( B, C, D, E, A, W[14] );
P( A, B, C, D, E, W[15] );
P( E, A, B, C, D, R(16) );
P( D, E, A, B, C, R(17) );
P( C, D, E, A, B, R(18) );
P( B, C, D, E, A, R(19) );
for (i=0;i<20;i++) {
uint32_t n = i%5;
uint32_t wr;
if (i<16) {
wr = W[i];
} else {
wr = R(i);
}
P( ABCDE[(5-n)%5], ABCDE[(6-n)%5], ABCDE[(7-n)%5], ABCDE[(8-n)%5], ABCDE[4-n], wr );
}
#undef K
#undef F
@ -181,26 +178,10 @@ void mbedtls_sha1_process( mbedtls_sha1_context *ctx, const unsigned char data[6
#define F(x,y,z) (x ^ y ^ z)
#define K 0x6ED9EBA1
P( A, B, C, D, E, R(20) );
P( E, A, B, C, D, R(21) );
P( D, E, A, B, C, R(22) );
P( C, D, E, A, B, R(23) );
P( B, C, D, E, A, R(24) );
P( A, B, C, D, E, R(25) );
P( E, A, B, C, D, R(26) );
P( D, E, A, B, C, R(27) );
P( C, D, E, A, B, R(28) );
P( B, C, D, E, A, R(29) );
P( A, B, C, D, E, R(30) );
P( E, A, B, C, D, R(31) );
P( D, E, A, B, C, R(32) );
P( C, D, E, A, B, R(33) );
P( B, C, D, E, A, R(34) );
P( A, B, C, D, E, R(35) );
P( E, A, B, C, D, R(36) );
P( D, E, A, B, C, R(37) );
P( C, D, E, A, B, R(38) );
P( B, C, D, E, A, R(39) );
for (i=20;i<40;i++) {
uint32_t n = i%5;
P( ABCDE[(5-n)%5], ABCDE[(6-n)%5], ABCDE[(7-n)%5], ABCDE[(8-n)%5], ABCDE[4-n], R(i) );
}
#undef K
#undef F
@ -208,26 +189,10 @@ void mbedtls_sha1_process( mbedtls_sha1_context *ctx, const unsigned char data[6
#define F(x,y,z) ((x & y) | (z & (x | y)))
#define K 0x8F1BBCDC
P( A, B, C, D, E, R(40) );
P( E, A, B, C, D, R(41) );
P( D, E, A, B, C, R(42) );
P( C, D, E, A, B, R(43) );
P( B, C, D, E, A, R(44) );
P( A, B, C, D, E, R(45) );
P( E, A, B, C, D, R(46) );
P( D, E, A, B, C, R(47) );
P( C, D, E, A, B, R(48) );
P( B, C, D, E, A, R(49) );
P( A, B, C, D, E, R(50) );
P( E, A, B, C, D, R(51) );
P( D, E, A, B, C, R(52) );
P( C, D, E, A, B, R(53) );
P( B, C, D, E, A, R(54) );
P( A, B, C, D, E, R(55) );
P( E, A, B, C, D, R(56) );
P( D, E, A, B, C, R(57) );
P( C, D, E, A, B, R(58) );
P( B, C, D, E, A, R(59) );
for (i=40;i<60;i++) {
uint32_t n = i%5;
P( ABCDE[(5-n)%5], ABCDE[(6-n)%5], ABCDE[(7-n)%5], ABCDE[(8-n)%5], ABCDE[4-n], R(i) );
}
#undef K
#undef F
@ -235,35 +200,16 @@ void mbedtls_sha1_process( mbedtls_sha1_context *ctx, const unsigned char data[6
#define F(x,y,z) (x ^ y ^ z)
#define K 0xCA62C1D6
P( A, B, C, D, E, R(60) );
P( E, A, B, C, D, R(61) );
P( D, E, A, B, C, R(62) );
P( C, D, E, A, B, R(63) );
P( B, C, D, E, A, R(64) );
P( A, B, C, D, E, R(65) );
P( E, A, B, C, D, R(66) );
P( D, E, A, B, C, R(67) );
P( C, D, E, A, B, R(68) );
P( B, C, D, E, A, R(69) );
P( A, B, C, D, E, R(70) );
P( E, A, B, C, D, R(71) );
P( D, E, A, B, C, R(72) );
P( C, D, E, A, B, R(73) );
P( B, C, D, E, A, R(74) );
P( A, B, C, D, E, R(75) );
P( E, A, B, C, D, R(76) );
P( D, E, A, B, C, R(77) );
P( C, D, E, A, B, R(78) );
P( B, C, D, E, A, R(79) );
for (i=60;i<80;i++) {
uint32_t n = i%5;
P( ABCDE[(5-n)%5], ABCDE[(6-n)%5], ABCDE[(7-n)%5], ABCDE[(8-n)%5], ABCDE[4-n], R(i) );
}
#undef K
#undef F
ctx->state[0] += A;
ctx->state[1] += B;
ctx->state[2] += C;
ctx->state[3] += D;
ctx->state[4] += E;
for (i=0;i<5;i++)
ctx->state[i] += ABCDE[i];
}
#endif /* !MBEDTLS_SHA1_PROCESS_ALT */
@ -307,14 +253,6 @@ void mbedtls_sha1_update( mbedtls_sha1_context *ctx, const unsigned char *input,
memcpy( (void *) (ctx->buffer + left), input, ilen );
}
static const unsigned char sha1_padding[64] =
{
0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
/*
* SHA-1 final digest
*/
@ -334,6 +272,9 @@ void mbedtls_sha1_finish( mbedtls_sha1_context *ctx, unsigned char output[20] )
last = ctx->total[0] & 0x3F;
padn = ( last < 56 ) ? ( 56 - last ) : ( 120 - last );
unsigned char sha1_padding[64];
memset(sha1_padding, 0, 64);
sha1_padding[0] = 0x80;
mbedtls_sha1_update( ctx, sha1_padding, padn );
mbedtls_sha1_update( ctx, msglen, 8 );

View File

@ -276,6 +276,29 @@ JsGraphicsSetPixelFn graphicsGetSetPixelUnclippedFn(JsGraphics *gfx, int x1, int
return gfx->setPixel; // fast
}
/// Merge one color into another based on current bit depth (amt is 0..256)
uint32_t graphicsBlendColor(JsGraphics *gfx, int iamt) {
unsigned int amt = (iamt>0) ? (unsigned)iamt : 0;
if (amt>256) amt=255;
if (gfx->data.bpp==2 || gfx->data.bpp==4 || gfx->data.bpp==8) {
return (gfx->data.bgColor*(256-amt) + gfx->data.fgColor*amt) >> 8;
} else if (gfx->data.bpp==16) { // Blend from bg to fg
unsigned int b = gfx->data.bgColor;
unsigned int br = (b>>8)&0xF8;
unsigned int bg = (b>>3)&0xFC;
unsigned int bb = (b<<3)&0xF8;
unsigned int f = gfx->data.fgColor;
unsigned int fr = (f>>8)&0xF8;
unsigned int fg = (f>>3)&0xFC;
unsigned int fb = (f<<3)&0xF8;
unsigned int ri = (br*(256-amt) + fr*amt) >> 8;
unsigned int gi = (bg*(256-amt) + fg*amt) >> 8;
unsigned int bi = (bb*(256-amt) + fb*amt) >> 8;
return (uint16_t)((bi>>3) | (gi>>2)<<5 | (ri>>3)<<11);
}
return (amt>=128) ? gfx->data.fgColor : gfx->data.bgColor;
}
// ----------------------------------------------------------------------------------------------
static void graphicsSetPixelDevice(JsGraphics *gfx, int x, int y, unsigned int col) {
@ -471,6 +494,73 @@ void graphicsDrawLine(JsGraphics *gfx, int x1, int y1, int x2, int y2) {
}
}
// In 16x accuracy
void graphicsDrawLineAA(JsGraphics *gfx, int ix1, int iy1, int ix2, int iy2) {
// https://en.wikipedia.org/wiki/Xiaolin_Wu%27s_line_algorithm
graphicsToDeviceCoordinates16x(gfx, &ix1, &iy1);
graphicsToDeviceCoordinates16x(gfx, &ix2, &iy2);
int x0 = ix1*16;
int y0 = iy1*16;
int x1 = ix2*16;
int y1 = iy2*16;
bool steep = abs(y1 - y0) > abs(x1 - x0);
if (steep) {
int t;
t=x0;x0=y0;y0=t;
t=x1;x1=y1;y1=t;
}
if (x0 > x1) {
int t;
t=x0;x0=x1;x1=t;
t=y0;y0=y1;y1=t;
}
int dx = x1 - x0;
int dy = y1 - y0;
int gradient = dx ? ((dy<<8) / dx) : 256;
// handle first endpoint
int xend = x0 + 128;
int yend = y0 + ((gradient * (xend - x0)) >> 8);
int xgap = 256 - ((x0 + 128) & 255);
int xpxl1 = xend >> 8; // this will be used in the main loop
int ypxl1 = yend >> 8;
int c = yend & 255;
if (steep) {
graphicsSetPixelDevice(gfx, ypxl1, xpxl1, graphicsBlendColor(gfx, ((256-c)*xgap)>>8));
graphicsSetPixelDevice(gfx, ypxl1+1, xpxl1, graphicsBlendColor(gfx, (c*xgap)>>8));
} else {
graphicsSetPixelDevice(gfx, xpxl1, ypxl1 , graphicsBlendColor(gfx, ((256-c)*xgap)>>8));
graphicsSetPixelDevice(gfx, xpxl1, ypxl1+1, graphicsBlendColor(gfx, (c*xgap)>>8));
}
int intery = yend + gradient; // first y-intersection for the main loop
// handle second endpoint
xend = x1 + 128;
yend = y1 + ((gradient * (xend - x1)) >> 8);
xgap = (x1 + 128) & 255;
int xpxl2 = xend>>8; //this will be used in the main loop
int ypxl2 = yend>>8;
c = yend & 255;
if (steep) {
graphicsSetPixelDevice(gfx, ypxl2 , xpxl2, graphicsBlendColor(gfx, ((256-c)*xgap)>>8));
graphicsSetPixelDevice(gfx, ypxl2+1, xpxl2, graphicsBlendColor(gfx, (c*xgap)>>8));
} else {
graphicsSetPixelDevice(gfx, xpxl2, ypxl2, graphicsBlendColor(gfx, ((256-c)*xgap)>>8));
graphicsSetPixelDevice(gfx, xpxl2, ypxl2+1, graphicsBlendColor(gfx, (c*xgap)>>8));
}
// main loop
for (int x=xpxl1+1;x<xpxl2;x++) {
int y = intery>>8;
c = intery & 255;
if (steep) {
graphicsSetPixelDevice(gfx, y , x, graphicsBlendColor(gfx, 256-c));
graphicsSetPixelDevice(gfx, y+1, x, graphicsBlendColor(gfx, c));
} else {
graphicsSetPixelDevice(gfx, x, y, graphicsBlendColor(gfx, 256-c));
graphicsSetPixelDevice(gfx, x, y+1, graphicsBlendColor(gfx, c));
}
intery += gradient;
}
}
// Fill poly - each member of vertices is 1/16th pixel
void graphicsFillPoly(JsGraphics *gfx, int points, short *vertices) {
@ -575,8 +665,14 @@ void graphicsScroll(JsGraphics *gfx, int xdir, int ydir) {
graphicsToDeviceCoordinates(gfx, &x2, &y2);
xdir = x2-x1;
ydir = y2-y1;
// range check - if too big no point scrolling
bool scroll = true;
if (xdir>gfx->data.width) { xdir=gfx->data.width; scroll=false; }
if (xdir<-gfx->data.width) { xdir=-gfx->data.width; scroll=false; }
if (ydir>gfx->data.height) { ydir=gfx->data.height; scroll=false; }
if (ydir<-gfx->data.height) { ydir=-gfx->data.height; scroll=false; }
// do the scrolling
gfx->scroll(gfx, xdir, ydir);
if (scroll) gfx->scroll(gfx, xdir, ydir);
// fill the new area
if (xdir>0) gfx->fillRect(gfx,0,0,xdir-1,gfx->data.height-1, gfx->data.bgColor);
else if (xdir<0) gfx->fillRect(gfx,gfx->data.width+xdir,0,gfx->data.width-1,gfx->data.height-1, gfx->data.bgColor);

View File

@ -69,7 +69,12 @@ typedef enum {
#ifdef USE_FONT_6X8
JSGRAPHICS_FONTSIZE_6X8 = 2 << 13, // a bitmap font
#endif
JSGRAPHICS_FONTSIZE_CUSTOM = 3 << 13,// a custom bitmap font made from fields in the graphics object (See below)
#ifndef SAVE_ON_FLASH
JSGRAPHICS_FONTSIZE_CUSTOM_1BPP = 4 << 13,// a custom bitmap font made from fields in the graphics object (See below)
JSGRAPHICS_FONTSIZE_CUSTOM_2BPP = 5 << 13,// a custom bitmap font made from fields in the graphics object (See below)
JSGRAPHICS_FONTSIZE_CUSTOM_4BPP = 6 << 13,// a custom bitmap font made from fields in the graphics object (See below)
JSGRAPHICS_FONTSIZE_CUSTOM_BIT = 4 << 13 // all custom fonts have this bit set
#endif
} JsGraphicsFontSize;
@ -107,10 +112,10 @@ typedef struct JsGraphics {
JsGraphicsData data;
void *backendData; ///< Data used by the graphics backend
void (*setPixel)(struct JsGraphics *gfx, int x, int y, unsigned int col);
void (*fillRect)(struct JsGraphics *gfx, int x1, int y1, int x2, int y2, unsigned int col);
unsigned int (*getPixel)(struct JsGraphics *gfx, int x, int y);
void (*scroll)(struct JsGraphics *gfx, int xdir, int ydir); // scroll - leave unscrolled area undefined
void (*setPixel)(struct JsGraphics *gfx, int x, int y, unsigned int col); ///< x/y guaranteed to be in range
void (*fillRect)(struct JsGraphics *gfx, int x1, int y1, int x2, int y2, unsigned int col); ///< x/y guaranteed to be in range
unsigned int (*getPixel)(struct JsGraphics *gfx, int x, int y); ///< x/y guaranteed to be in range
void (*scroll)(struct JsGraphics *gfx, int xdir, int ydir); ///< scroll - leave unscrolled area undefined (xdir/ydir guaranteed to be in range)
} PACKED_FLAGS JsGraphics;
typedef void (*JsGraphicsSetPixelFn)(struct JsGraphics *gfx, int x, int y, unsigned int col);
@ -139,6 +144,8 @@ bool graphicsSetModifiedAndClip(JsGraphics *gfx, int *x1, int *y1, int *x2, int
JsGraphicsSetPixelFn graphicsGetSetPixelFn(JsGraphics *gfx);
/// Get a setPixel function and set modified area (assuming no clipping) (inclusive of x2,y2) - if all is ok it can choose a faster draw function
JsGraphicsSetPixelFn graphicsGetSetPixelUnclippedFn(JsGraphics *gfx, int x1, int y1, int x2, int y2);
/// Merge one color into another based on current bit depth (amt is 0..256)
uint32_t graphicsBlendColor(JsGraphics *gfx, int amt);
// drawing functions - all coordinates are in USER coordinates, not DEVICE coordinates
void graphicsSetPixel(JsGraphics *gfx, int x, int y, unsigned int col);
@ -150,7 +157,8 @@ void graphicsDrawRect(JsGraphics *gfx, int x1, int y1, int x2, int y2);
void graphicsDrawEllipse(JsGraphics *gfx, int x, int y, int x2, int y2);
void graphicsFillEllipse(JsGraphics *gfx, int x, int y, int x2, int y2);
void graphicsDrawLine(JsGraphics *gfx, int x1, int y1, int x2, int y2);
void graphicsFillPoly(JsGraphics *gfx, int points, short *vertices); // each pixel is 1/16th a pixel may overwrite vertices...
void graphicsDrawLineAA(JsGraphics *gfx, int ix1, int iy1, int ix2, int iy2); ///< antialiased drawline. each pixel is 1/16th
void graphicsFillPoly(JsGraphics *gfx, int points, short *vertices); ///< each pixel is 1/16th a pixel may overwrite vertices...
#ifndef NO_VECTOR_FONT
unsigned int graphicsFillVectorChar(JsGraphics *gfx, int x1, int y1, int size, char ch); ///< prints character, returns width
unsigned int graphicsVectorCharWidth(JsGraphics *gfx, unsigned int size, char ch); ///< returns the width of a character

View File

@ -1035,13 +1035,15 @@ JsVar *jswrap_graphics_setFontSizeX(JsVar *parent, int size, bool isVectorFont)
if (size<1) size=1;
if (size>1023) size=1023;
}
if ((gfx.data.fontSize&JSGRAPHICS_FONTSIZE_FONT_MASK) == JSGRAPHICS_FONTSIZE_CUSTOM &&
(size&JSGRAPHICS_FONTSIZE_FONT_MASK) != JSGRAPHICS_FONTSIZE_CUSTOM) {
#ifndef SAVE_ON_FLASH
if ((gfx.data.fontSize&JSGRAPHICS_FONTSIZE_CUSTOM_BIT) &&
!(size&JSGRAPHICS_FONTSIZE_CUSTOM_BIT)) {
jsvObjectRemoveChild(parent, JSGRAPHICS_CUSTOMFONT_BMP);
jsvObjectRemoveChild(parent, JSGRAPHICS_CUSTOMFONT_WIDTH);
jsvObjectRemoveChild(parent, JSGRAPHICS_CUSTOMFONT_HEIGHT);
jsvObjectRemoveChild(parent, JSGRAPHICS_CUSTOMFONT_FIRSTCHAR);
}
#endif
gfx.data.fontSize = (unsigned short)size;
graphicsSetVar(&gfx);
#endif
@ -1051,12 +1053,13 @@ JsVar *jswrap_graphics_setFontSizeX(JsVar *parent, int size, bool isVectorFont)
"type" : "method",
"class" : "Graphics",
"name" : "setFontCustom",
"ifndef" : "SAVE_ON_FLASH",
"generate" : "jswrap_graphics_setFontCustom",
"params" : [
["bitmap","JsVar","A column-first, MSB-first, 1bpp bitmap containing the font bitmap"],
["firstChar","int32","The first character in the font - usually 32 (space)"],
["width","JsVar","The width of each character in the font. Either an integer, or a string where each character represents the width"],
["height","int32","The height as an integer (max 255). Bits 8-15 represent the scale factor (eg. `2<<8` is twice the size)"]
["height","int32","The height as an integer (max 255). Bits 8-15 represent the scale factor (eg. `2<<8` is twice the size). Bits 16-23 represent the BPP (0,1=1 bpp, 2=2 bpp, 4=4 bpp)"]
],
"return" : ["JsVar","The instance of Graphics this was called on, to allow call chaining"],
"return_object" : "Graphics"
@ -1064,6 +1067,7 @@ JsVar *jswrap_graphics_setFontSizeX(JsVar *parent, int size, bool isVectorFont)
Make subsequent calls to `drawString` use a Custom Font of the given height. See the [Fonts page](http://www.espruino.com/Fonts) for more
information about custom fonts and how to create them.
*/
#ifndef SAVE_ON_FLASH
JsVar *jswrap_graphics_setFontCustom(JsVar *parent, JsVar *bitmap, int firstChar, JsVar *width, int height) {
JsGraphics gfx; if (!graphicsGetFromVar(&gfx, parent)) return 0;
@ -1079,17 +1083,28 @@ JsVar *jswrap_graphics_setFontCustom(JsVar *parent, JsVar *bitmap, int firstChar
jsExceptionHere(JSET_ERROR, "Font width must be a String or an integer");
return 0;
}
int scale = height>>8;
int scale = (height>>8)&255;
if (scale<1) scale=1;
int bpp = height>>16;
if (bpp<1) bpp=1;
JsGraphicsFontSize fontType;
if (bpp==1) fontType = JSGRAPHICS_FONTSIZE_CUSTOM_1BPP;
else if (bpp==2) fontType = JSGRAPHICS_FONTSIZE_CUSTOM_2BPP;
else if (bpp==4) fontType = JSGRAPHICS_FONTSIZE_CUSTOM_4BPP;
else {
jsExceptionHere(JSET_ERROR, "Invalid BPP - 1,2,4 supported");
return 0;
}
height = height&255;
jsvObjectSetChild(parent, JSGRAPHICS_CUSTOMFONT_BMP, bitmap);
jsvObjectSetChild(parent, JSGRAPHICS_CUSTOMFONT_WIDTH, width);
jsvObjectSetChildAndUnLock(parent, JSGRAPHICS_CUSTOMFONT_HEIGHT, jsvNewFromInteger(height));
jsvObjectSetChildAndUnLock(parent, JSGRAPHICS_CUSTOMFONT_FIRSTCHAR, jsvNewFromInteger(firstChar));
gfx.data.fontSize = (unsigned short)(scale + JSGRAPHICS_FONTSIZE_CUSTOM);
gfx.data.fontSize = (unsigned short)(scale + fontType);
graphicsSetVar(&gfx);
return jsvLockAgain(parent);
}
#endif
/*JSON{
"type" : "method",
"class" : "Graphics",
@ -1162,16 +1177,18 @@ JsVar *jswrap_graphics_setFont(JsVar *parent, JsVar *name, int size) {
if (jsvIsStringEqual(name, "6x8"))
sz = (unsigned short)(size + JSGRAPHICS_FONTSIZE_6X8);
#endif
// TODO: if function named 'setFontXYZ' exists, run it
#ifndef SAVE_ON_FLASH
// if function named 'setFontXYZ' exists, run it
if (sz==0xFFFF) {
JsVar *setterName = jsvVarPrintf("setFont%v",name);
JsVar *fontSetter = jspGetVarNamedField(parent,setterName,false);
if (fontSetter) {
jsvUnLock(jspExecuteFunction(fontSetter,parent,0,NULL));
sz = (unsigned short)(size + JSGRAPHICS_FONTSIZE_CUSTOM);
sz = (unsigned short)(size + JSGRAPHICS_FONTSIZE_CUSTOM_1BPP);
}
jsvUnLock2(fontSetter,setterName);
}
#endif
if (sz==0xFFFF) {
jsExceptionHere(JSET_ERROR, "Unknown font %j", name);
}
@ -1206,12 +1223,14 @@ JsVar *jswrap_graphics_getFont(JsVar *parent) {
if (f == JSGRAPHICS_FONTSIZE_6X8)
return jsvNewFromString("6x8");
#endif
if (f == JSGRAPHICS_FONTSIZE_CUSTOM) {
#ifndef SAVE_ON_FLASH
if (f & JSGRAPHICS_FONTSIZE_CUSTOM_BIT) {
// not implemented yet because it's painful trying to pass 5 arguments into setFontCustom
/*JsVar *n = jsvObjectGetChild(parent, JSGRAPHICS_CUSTOMFONT_NAME, 0);
if (n) return n;*/
return jsvNewFromString("Custom");
}
#endif
return jsvNewFromInteger(gfx.data.fontSize);
#else
return 0;
@ -1282,8 +1301,10 @@ static int jswrap_graphics_getFontHeightInternal(JsGraphics *gfx) {
} else if (f == JSGRAPHICS_FONTSIZE_6X8) {
return 8*scale;
#endif
} else if (f == JSGRAPHICS_FONTSIZE_CUSTOM) {
#ifndef SAVE_ON_FLASH
} else if (f & JSGRAPHICS_FONTSIZE_CUSTOM_BIT) {
return scale*(int)jsvGetIntegerAndUnLock(jsvObjectGetChild(gfx->graphicsVar, JSGRAPHICS_CUSTOMFONT_HEIGHT, 0));
#endif
}
return 0;
}
@ -1316,17 +1337,23 @@ Draw a string of text in the current font
JsVar *jswrap_graphics_drawString(JsVar *parent, JsVar *var, int x, int y, bool solidBackground) {
JsGraphics gfx; if (!graphicsGetFromVar(&gfx, parent)) return 0;
JsVar *customBitmap = 0, *customWidth = 0;
int customHeight = jswrap_graphics_getFontHeightInternal(&gfx);
int customFirstChar = 0;
JsGraphicsFontSize font = gfx.data.fontSize & JSGRAPHICS_FONTSIZE_FONT_MASK;
unsigned short scale = gfx.data.fontSize & JSGRAPHICS_FONTSIZE_SCALE_MASK;
int fontHeight = jswrap_graphics_getFontHeightInternal(&gfx);
if (font == JSGRAPHICS_FONTSIZE_CUSTOM) {
#ifndef SAVE_ON_FLASH
JsVar *customBitmap = 0, *customWidth = 0;
int customBPP = 1;
int customFirstChar = 0;
if (font & JSGRAPHICS_FONTSIZE_CUSTOM_BIT) {
if (font==JSGRAPHICS_FONTSIZE_CUSTOM_2BPP) customBPP = 2;
if (font==JSGRAPHICS_FONTSIZE_CUSTOM_4BPP) customBPP = 4;
customBitmap = jsvObjectGetChild(parent, JSGRAPHICS_CUSTOMFONT_BMP, 0);
customWidth = jsvObjectGetChild(parent, JSGRAPHICS_CUSTOMFONT_WIDTH, 0);
customFirstChar = (int)jsvGetIntegerAndUnLock(jsvObjectGetChild(parent, JSGRAPHICS_CUSTOMFONT_FIRSTCHAR, 0));
}
#endif
#ifndef SAVE_ON_FLASH
// Handle text rotation
JsGraphicsFlags oldFlags = gfx.data.flags;
@ -1349,7 +1376,7 @@ JsVar *jswrap_graphics_drawString(JsVar *parent, JsVar *var, int x, int y, bool
if (gfx.data.fontAlignX<2) // 0=center, 1=right, 2=undefined, 3=left
x -= jswrap_graphics_stringWidth(parent, var) * (gfx.data.fontAlignX+1)/2;
if (gfx.data.fontAlignY<2) // 0=center, 1=bottom, 2=undefined, 3=top
y -= customHeight * (gfx.data.fontAlignY+1)/2;
y -= fontHeight * (gfx.data.fontAlignY+1)/2;
int minX = (gfx.data.flags & JSGRAPHICSFLAGS_SWAP_XY) ? gfx.data.clipRect.y1 : gfx.data.clipRect.x1;
int minY = (gfx.data.flags & JSGRAPHICSFLAGS_SWAP_XY) ? gfx.data.clipRect.x1 : gfx.data.clipRect.y1;
@ -1369,7 +1396,7 @@ JsVar *jswrap_graphics_drawString(JsVar *parent, JsVar *var, int x, int y, bool
char ch = jsvStringIteratorGetCharAndNext(&it);
if (ch=='\n') {
x = startx;
y += customHeight;
y += fontHeight;
continue;
}
if (font == JSGRAPHICS_FONTSIZE_VECTOR) {
@ -1389,7 +1416,9 @@ JsVar *jswrap_graphics_drawString(JsVar *parent, JsVar *var, int x, int y, bool
graphicsDrawChar6x8(&gfx, x, y, ch, scale, solidBackground);
x+=6*scale;
#endif
} else if (font == JSGRAPHICS_FONTSIZE_CUSTOM) {
#ifndef SAVE_ON_FLASH
} else if (font & JSGRAPHICS_FONTSIZE_CUSTOM_BIT) {
int customBPPRange = (1<<customBPP)-1;
// get char width and offset in string
int width = 0, bmpOffset = 0;
if (jsvIsString(customWidth)) {
@ -1406,39 +1435,47 @@ JsVar *jswrap_graphics_drawString(JsVar *parent, JsVar *var, int x, int y, bool
width = (int)jsvGetInteger(customWidth);
bmpOffset = width*(ch-customFirstChar);
}
if (ch>=customFirstChar && (x>minX-width) && (x<maxX) && (y>minY-customHeight) && y<maxY) {
int ch = customHeight/scale;
bmpOffset *= ch;
if (ch>=customFirstChar && (x>minX-width) && (x<maxX) && (y>minY-fontHeight) && y<maxY) {
int ch = fontHeight/scale;
bmpOffset *= ch * customBPP;
// now render character
JsvStringIterator cit;
jsvStringIteratorNew(&cit, customBitmap, (size_t)bmpOffset>>3);
jsvStringIteratorNew(&cit, customBitmap, (size_t)(bmpOffset>>3));
bmpOffset &= 7;
int cx,cy;
int citdata = jsvStringIteratorGetChar(&cit);
citdata <<= customBPP*bmpOffset;
for (cx=0;cx<width;cx++) {
for (cy=0;cy<ch;cy++) {
bool set = (jsvStringIteratorGetChar(&cit)<<bmpOffset)&128;
if (solidBackground || set)
int col = ((citdata&255)>>(8-customBPP));
if (solidBackground || col)
graphicsFillRect(&gfx,
(x + cx*scale),
(y + cy*scale),
(x + cx*scale + scale-1),
(y + cy*scale + scale-1),
set ? gfx.data.fgColor : gfx.data.bgColor);
bmpOffset++;
if (bmpOffset==8) {
graphicsBlendColor(&gfx, (256*col)/customBPPRange));
bmpOffset += customBPP;
citdata <<= customBPP;
if (bmpOffset>=8) {
bmpOffset=0;
jsvStringIteratorNext(&cit);
citdata = jsvStringIteratorGetChar(&cit);
}
}
}
jsvStringIteratorFree(&cit);
}
x += width*scale;
#endif
}
if (jspIsInterrupted()) break;
}
jsvStringIteratorFree(&it);
jsvUnLock3(str, customBitmap, customWidth);
jsvUnLock(str);
#ifndef SAVE_ON_FLASH
jsvUnLock2(customBitmap, customWidth);
#endif
#ifndef SAVE_ON_FLASH
gfx.data.flags = oldFlags; // restore flags because of text rotation
graphicsSetVar(&gfx); // gfx data changed because modified area
@ -1467,14 +1504,16 @@ Return the size in pixels of a string of text in the current font
JsVarInt jswrap_graphics_stringWidth(JsVar *parent, JsVar *var) {
JsGraphics gfx; if (!graphicsGetFromVar(&gfx, parent)) return 0;
JsVar *customWidth = 0;
int customFirstChar = 0;
JsGraphicsFontSize font = gfx.data.fontSize & JSGRAPHICS_FONTSIZE_FONT_MASK;
unsigned short scale = gfx.data.fontSize & JSGRAPHICS_FONTSIZE_SCALE_MASK;
if (font == JSGRAPHICS_FONTSIZE_CUSTOM) {
#ifndef SAVE_ON_FLASH
JsVar *customWidth = 0;
int customFirstChar = 0;
if (font & JSGRAPHICS_FONTSIZE_CUSTOM_BIT) {
customWidth = jsvObjectGetChild(parent, JSGRAPHICS_CUSTOMFONT_WIDTH, 0);
customFirstChar = (int)jsvGetIntegerAndUnLock(jsvObjectGetChild(parent, JSGRAPHICS_CUSTOMFONT_FIRSTCHAR, 0));
}
#endif
JsVar *str = jsvAsString(var);
JsvStringIterator it;
@ -1497,17 +1536,22 @@ JsVarInt jswrap_graphics_stringWidth(JsVar *parent, JsVar *var) {
} else if (font == JSGRAPHICS_FONTSIZE_6X8) {
width += 6*scale;
#endif
} else if (font == JSGRAPHICS_FONTSIZE_CUSTOM) {
#ifndef SAVE_ON_FLASH
} else if (font & JSGRAPHICS_FONTSIZE_CUSTOM_BIT) {
if (jsvIsString(customWidth)) {
if (ch>=customFirstChar)
width += scale*(unsigned char)jsvGetCharInString(customWidth, (size_t)(ch-customFirstChar));
} else
width += scale*(int)jsvGetInteger(customWidth);
#endif
}
jsvStringIteratorNext(&it);
}
jsvStringIteratorFree(&it);
jsvUnLock2(str, customWidth);
#ifndef SAVE_ON_FLASH
jsvUnLock(customWidth);
#endif
jsvUnLock(str);
return width>maxWidth ? width : maxWidth;
}
@ -1534,6 +1578,34 @@ JsVar *jswrap_graphics_drawLine(JsVar *parent, int x1, int y1, int x2, int y2) {
return jsvLockAgain(parent);
}
/*JSON{
"type" : "method",
"class" : "Graphics",
"name" : "drawLineAA",
"ifdef" : "GRAPHICS_ANTIALIAS",
"generate" : "jswrap_graphics_drawLineAA",
"params" : [
["x1","float","The left"],
["y1","float","The top"],
["x2","float","The right"],
["y2","float","The bottom"]
],
"return" : ["JsVar","The instance of Graphics this was called on, to allow call chaining"],
"return_object" : "Graphics"
}
Draw a line between x1,y1 and x2,y2 in the current foreground color
*/
JsVar *jswrap_graphics_drawLineAA(JsVar *parent, double x1, double y1, double x2, double y2) {
JsGraphics gfx; if (!graphicsGetFromVar(&gfx, parent)) return 0;
graphicsDrawLineAA(&gfx,
(int)(x1*16+0.5),
(int)(y1*16+0.5),
(int)(x2*16+0.5),
(int)(y2*16+0.5));
graphicsSetVar(&gfx); // gfx data changed because modified area
return jsvLockAgain(parent);
}
/*JSON{
"type" : "method",
"class" : "Graphics",
@ -1584,7 +1656,7 @@ JsVar *jswrap_graphics_moveTo(JsVar *parent, int x, int y) {
"class" : "Graphics",
"name" : "drawPoly",
"ifndef" : "SAVE_ON_FLASH",
"generate" : "jswrap_graphics_drawPoly",
"generate_full" : "jswrap_graphics_drawPoly_X(parent, poly, closed, false)",
"params" : [
["poly","JsVar","An array of vertices, of the form ```[x1,y1,x2,y2,x3,y3,etc]```"],
["closed","bool","Draw another line between the last element of the array and the first"]
@ -1594,35 +1666,65 @@ JsVar *jswrap_graphics_moveTo(JsVar *parent, int x, int y) {
}
Draw a polyline (lines between each of the points in `poly`) in the current foreground color
*/
JsVar *jswrap_graphics_drawPoly(JsVar *parent, JsVar *poly, bool closed) {
/*JSON{
"type" : "method",
"class" : "Graphics",
"name" : "drawPolyAA",
"ifdef" : "GRAPHICS_ANTIALIAS",
"generate_full" : "jswrap_graphics_drawPoly_X(parent, poly, closed, true)",
"params" : [
["poly","JsVar","An array of vertices, of the form ```[x1,y1,x2,y2,x3,y3,etc]```"],
["closed","bool","Draw another line between the last element of the array and the first"]
],
"return" : ["JsVar","The instance of Graphics this was called on, to allow call chaining"],
"return_object" : "Graphics"
}
Draw an **antialiased** polyline (lines between each of the points in `poly`) in the current foreground color
*/
JsVar *jswrap_graphics_drawPoly_X(JsVar *parent, JsVar *poly, bool closed, bool antiAlias) {
JsGraphics gfx; if (!graphicsGetFromVar(&gfx, parent)) return 0;
if (!jsvIsIterable(poly)) return 0;
int x,y;
int scale;
void (*drawFn)(JsGraphics *gfx, int x1, int y1, int x2, int y2);
#ifdef GRAPHICS_ANTIALIAS
if (antiAlias) {
scale = 16;
drawFn = graphicsDrawLineAA;
} else
#endif
{
scale = 1;
drawFn = graphicsDrawLine;
}
int lx,ly;
int startx, starty;
int idx = 0;
JsvIterator it;
jsvIteratorNew(&it, poly, JSIF_EVERY_ARRAY_ELEMENT);
while (jsvIteratorHasElement(&it)) {
int el = jsvIteratorGetIntegerValue(&it);
if (idx&1) {
y = el;
if (idx==1) { // save xy positions of first point
startx = x;
starty = y;
} else {
// only start drawing between the first 2 points
graphicsDrawLine(&gfx, gfx.data.cursorX, gfx.data.cursorY, x, y);
}
gfx.data.cursorX = (short)x;
gfx.data.cursorY = (short)y;
} else x = el;
idx++;
int x,y;
x = (int)((jsvIteratorGetFloatValue(&it)*scale)+0.5);
jsvIteratorNext(&it);
y = (int)((jsvIteratorGetFloatValue(&it)*scale)+0.5);
jsvIteratorNext(&it);
if (idx==0) { // save xy positions of first point
startx = x;
starty = y;
} else {
// only start drawing between the first 2 points
drawFn(&gfx, lx, ly, x, y);
}
lx = x;
ly = y;
idx++;
}
jsvIteratorFree(&it);
gfx.data.cursorX = (short)(lx/scale);
gfx.data.cursorY = (short)(ly/scale);
// if closed, draw between first and last points
if (closed)
graphicsDrawLine(&gfx, gfx.data.cursorX, gfx.data.cursorY, startx, starty);
drawFn(&gfx, lx, ly, startx, starty);
graphicsSetVar(&gfx); // gfx data changed because modified area
return jsvLockAgain(parent);
@ -2688,7 +2790,7 @@ Transformation can be:
x: float, // x offset (default 0)
y: float, // y offset (default 0)
scale: float, // scale factor (default 1)
rotation: float, // angle in radians (default 0)
rotate: float, // angle in radians (default 0)
}
```
* A six-element array of the form `[a,b,c,d,e,f]`, which represents the 2D transformation matrix

View File

@ -73,9 +73,10 @@ JsVar *jswrap_graphics_drawString(JsVar *parent, JsVar *str, int x, int y, bool
void jswrap_graphics_drawCString(JsGraphics *gfx, int x, int y, char *str); /// Convenience function for using drawString from C code
JsVarInt jswrap_graphics_stringWidth(JsVar *parent, JsVar *var);
JsVar *jswrap_graphics_drawLine(JsVar *parent, int x1, int y1, int x2, int y2);
JsVar *jswrap_graphics_drawLineAA(JsVar *parent, double x1, double y1, double x2, double y2);
JsVar *jswrap_graphics_lineTo(JsVar *parent, int x, int y);
JsVar *jswrap_graphics_moveTo(JsVar *parent, int x, int y);
JsVar *jswrap_graphics_drawPoly(JsVar *parent, JsVar *poly, bool closed);
JsVar *jswrap_graphics_drawPoly_X(JsVar *parent, JsVar *poly, bool closed, bool antiAlias);
JsVar *jswrap_graphics_fillPoly(JsVar *parent, JsVar *poly);
JsVar *jswrap_graphics_setRotation(JsVar *parent, int rotation, bool reflect);
JsVar *jswrap_graphics_drawImage(JsVar *parent, JsVar *image, int xPos, int yPos, JsVar *options);

View File

@ -89,7 +89,10 @@ void terminalScroll() {
terminalY--;
JsGraphics gfx;
if (terminalGetGFX(&gfx)) {
graphicsScroll(&gfx, 0, -TERMINAL_CHAR_H);
unsigned int cb = gfx.data.bgColor;
gfx.data.bgColor = 0;
graphicsScroll(&gfx, 0, -TERMINAL_CHAR_H); // always fill background in black
gfx.data.bgColor = cb;
terminalSetGFX(&gfx); // save
// if we're not in an IRQ, flip this now
if (!jshIsInInterrupt())
@ -118,7 +121,12 @@ void terminalSendChar(char chn) {
short cx = (short)(TERMINAL_OFFSET_X + terminalX*TERMINAL_CHAR_W);
short cy = (short)(TERMINAL_OFFSET_Y + terminalY*TERMINAL_CHAR_H + gfx.data.height - LCD_HEIGHT);
// draw char
unsigned int cf = gfx.data.fgColor, cb = gfx.data.bgColor;
cf = -1; // always white on black
cb = 0;
TERMINAL_CHAR_CMD(&gfx, cx, cy, chn, 1, true/*solid background - so no need to clear*/);
gfx.data.fgColor = cf;
gfx.data.bgColor = cb;
terminalSetGFX(&gfx);
}
if (terminalX<255) terminalX++;
@ -152,8 +160,8 @@ void terminalSendChar(char chn) {
short w = (gfx.data.flags & JSGRAPHICSFLAGS_SWAP_XY) ? gfx.data.height : gfx.data.width;
short h = (gfx.data.flags & JSGRAPHICSFLAGS_SWAP_XY) ? gfx.data.width : gfx.data.height;
// Clear to right and down
graphicsFillRect(&gfx, cx, cy, w-1, cy+TERMINAL_CHAR_H-1, gfx.data.bgColor); // current line
graphicsFillRect(&gfx, TERMINAL_OFFSET_X, cy+TERMINAL_CHAR_H, w-1, h-1, gfx.data.bgColor); // everything under
graphicsFillRect(&gfx, cx, cy, w-1, cy+TERMINAL_CHAR_H-1, 0/*black*/); // current line
graphicsFillRect(&gfx, TERMINAL_OFFSET_X, cy+TERMINAL_CHAR_H, w-1, h-1, 0/*black*/); // everything under
terminalSetGFX(&gfx);
}
} break;

View File

@ -1,7 +1,7 @@
/*
* This file is part of Espruino, a JavaScript interpreter for Microcontrollers
*
* Copyright (C) 2020 Gordon Williams <gw@pur3.co.uk>, atc1441, MaBecker
* Copyright (C) 2020 Gordon Williams <gw@pur3.co.uk>, atc1441, MaBecker, Jeffmer
*
* 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
@ -20,15 +20,20 @@
#include "lcd_spi_unbuf.h"
#include "jsutils.h"
#include "jsinteractive.h"
#include "jswrapper.h"
#include "jswrap_graphics.h"
#include "jshardware.h"
int _pin_mosi;
int _pin_clk;
int _pin_cs;
int _pin_dc;
int _colstart;
int _rowstart;
static int _pin_mosi;
static int _pin_clk;
static int _pin_cs;
static int _pin_dc;
static int _colstart;
static int _rowstart;
static int _lastx=-1;
static int _lasty=-1;
static uint16_t _chunk_buffer[LCD_SPI_UNBUF_LEN];
static int _chunk_index = 0;
IOEventFlags _device;
static void spi_cmd(const uint8_t cmd)
@ -38,12 +43,34 @@ static void spi_cmd(const uint8_t cmd)
jshPinSetValue(_pin_dc, 1);
}
static void spi_data(const uint8_t *data, int len)
static inline void spi_data(const uint8_t *data, int len)
{
if (len==0) return;
jshSPISendMany(_device, data, NULL, len, NULL);
}
static void flush_chunk_buffer(){
if(_chunk_index == 0) return;
spi_data((uint8_t *)&_chunk_buffer, _chunk_index*2);
_chunk_index = 0;
}
static inline bool willFlush(){
return _chunk_index == LCD_SPI_UNBUF_LEN - 1;
}
static inline _put_pixel( uint16_t c) {
_chunk_buffer[_chunk_index++] = c;
if (_chunk_index==LCD_SPI_UNBUF_LEN) flush_chunk_buffer();
}
/// flush chunk buffer to screen
void lcd_flip(JsVar *parent) {
if(_chunk_index == 0) return;
jshPinSetValue(_pin_cs, 0);
flush_chunk_buffer();
jshPinSetValue(_pin_cs, 1);
}
void jshLCD_SPI_UNBUFInitInfo(JshLCD_SPI_UNBUFInfo *inf) {
inf->pinCS = PIN_UNDEFINED;
inf->pinDC = PIN_UNDEFINED;
@ -64,15 +91,17 @@ bool jsspiPopulateOptionsInfo( JshLCD_SPI_UNBUFInfo *inf, JsVar *options){
{"rowstart", JSV_INTEGER , &inf->rowstart},
};
if (jsvReadConfigObject(options, configs, sizeof(configs) / sizeof(jsvConfigObject))) {
if ( inf->pinDC == PIN_UNDEFINED ) {
return false;
}
return true;
}
else {
return jsvReadConfigObject(options, configs, sizeof(configs) / sizeof(jsvConfigObject))
&& inf->pinDC != PIN_UNDEFINED;
}
/*JSON{
"type" : "idle",
"generate" : "jswrap_lcd_spi_unbuf_idle"
}*/
bool jswrap_lcd_spi_unbuf_idle() {
lcd_flip(NULL);
return false;
}
}
/*JSON{
@ -99,19 +128,19 @@ JsVar *jswrap_lcd_spi_unbuf_connect(JsVar *device, JsVar *options) {
if (!jsspiPopulateOptionsInfo(&inf, options)) {
jsExceptionHere(JSET_ERROR,"pins not supplied correctly");
jsvUnLock(parent);
return NULL;
return NULL;
}
_pin_cs = inf.pinCS;
_pin_dc = inf.pinDC;
_colstart = inf.colstart;
_rowstart = inf.rowstart;
_device = jsiGetDeviceFromClass(device);
if (!DEVICE_IS_SPI(_device)) {
jsExceptionHere(JSET_ERROR,"Software SPI is not supported for now");
jsvUnLock(parent);
jsExceptionHere(JSET_ERROR,"Software SPI is not supported for now");
jsvUnLock(parent);
return NULL;
}
}
JsGraphics gfx;
graphicsStructInit(&gfx,inf.width,inf.height,16);
@ -125,12 +154,19 @@ JsVar *jswrap_lcd_spi_unbuf_connect(JsVar *device, JsVar *options) {
jshPinSetValue(_pin_cs, 1);
lcd_spi_unbuf_setCallbacks(&gfx);
graphicsSetVar(&gfx);
graphicsSetVar(&gfx);
// Create 'flip' fn
JsVar *fn;
fn = jsvNewNativeFunction((void (*)(void))lcd_flip, JSWAT_VOID|JSWAT_THIS_ARG);
jsvObjectSetChildAndUnLock(parent,"flip",fn);
return parent;
}
void disp_spi_transfer_addrwin(int x1, int y1, int x2, int y2) {
unsigned char wd[4];
flush_chunk_buffer();
x1 += _colstart;
y1 += _rowstart;
x2 += _colstart;
@ -150,38 +186,36 @@ void disp_spi_transfer_addrwin(int x1, int y1, int x2, int y2) {
spi_cmd(0x2C);
}
void disp_spi_transfer_color_many(uint16_t color, uint32_t len)
{
uint16_t buffer_color[BUFFER];
uint8_t idx = 0;
uint32_t count = 0;
while (count < len) {
buffer_color[idx] = (color>>8) | (color<<8);
idx++;
count++;
if (idx == BUFFER) {
spi_data((uint8_t *)&buffer_color, idx*2);
idx = 0;
}
}
if (idx > 0)
spi_data((uint8_t *)&buffer_color, idx*2);
}
void lcd_spi_unbuf_setPixel(JsGraphics *gfx, int x, int y, unsigned int col) {
uint16_t color = (col>>8) | (col<<8);
jshPinSetValue(_pin_cs, 0);
disp_spi_transfer_addrwin(x, y, x+1, y+1);
spi_data((uint8_t *)&color, 2);
jshPinSetValue(_pin_cs, 1);
if (x!=_lastx+1 || y!=_lasty) {
jshPinSetValue(_pin_cs, 0);
disp_spi_transfer_addrwin(x, y, gfx->data.width, y+1);
jshPinSetValue(_pin_cs, 1); //will never flush after
_put_pixel(color);
_lastx = x;
_lasty = y;
} else {
_lastx++;
if (willFlush()){
jshPinSetValue(_pin_cs, 0);
_put_pixel(color);
jshPinSetValue(_pin_cs, 1);
} else {
_put_pixel(color);
}
}
}
void lcd_spi_unbuf_fillRect(JsGraphics *gfx, int x1, int y1, int x2, int y2, unsigned int col) {
int pixels = (1+x2-x1)*(1+y2-y1);
int pixels = (1+x2-x1)*(1+y2-y1);
uint16_t color = (col>>8) | (col<<8);
jshPinSetValue(_pin_cs, 0);
disp_spi_transfer_addrwin(x1, y1, x2, y2);
disp_spi_transfer_color_many(col, pixels);
for (int i=0; i<pixels; i++) _put_pixel(color);
jshPinSetValue(_pin_cs, 1);
_lastx=-1;
_lasty=-1;
}
void lcd_spi_unbuf_setCallbacks(JsGraphics *gfx) {

View File

@ -1,7 +1,7 @@
/*
* This file is part of Espruino, a JavaScript interpreter for Microcontrollers
*
* Copyright (C) 2020 Gordon Williams <gw@pur3.co.uk>, atc1441, MaBecker
* Copyright (C) 2020 Gordon Williams <gw@pur3.co.uk>, atc1441, MaBecker, Jeffmer
*
* 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
@ -16,8 +16,7 @@
#include "jsvariterator.h"
#include "jshardware.h"
// #define BUFFER 128
#define BUFFER SPISENDMANY_BUFFER_SIZE
#define LCD_SPI_UNBUF_LEN SPISENDMANY_BUFFER_SIZE
typedef struct {
Pin pinCS; //!< Pin to use for cs.
@ -28,5 +27,6 @@ typedef struct {
int rowstart; //!< Aditional starting address some pixels dont begin at 0
} JshLCD_SPI_UNBUFInfo;
bool jswrap_lcd_spi_unbuf_idle();
JsVar *jswrap_lcd_spi_unbuf_connect(JsVar *device, JsVar *options);
void lcd_spi_unbuf_setCallbacks(JsGraphics *gfx);

View File

@ -0,0 +1,17 @@
(function(waveform, pitch, callback) {
if (!isFinite(pitch)) pitch=4000;
if (!Microbit.sounds) this.sounds=0;
if (Microbit.sounds>2) throw new Error("Too many sounds playing at once");
var w = new Waveform(waveform.length);
w.buffer.set(waveform);
w.on("finish", function(buf) {
Microbit.sounds--;
if (!Microbit.sounds) { /* TODO: stop output */ }
if (callback) callback();
});
if (!Microbit.sounds) {
analogWrite(Microbit.SPEAKER, 0.5, {freq:40000});
}
Microbit.sounds++;
w.startOutput(Microbit.SPEAKER, pitch);
})

View File

@ -0,0 +1,10 @@
(function(pitch, callback, length) {
if (!isFinite(length)) length=6000;
var w = new Waveform(length);
w.on("finish", function(buf) {
Microbit.MIC_ENABLE.reset();
if (callback) callback(w.buffer);
});
Microbit.MIC_ENABLE.set();
w.startInput(Microbit.MIC, pitch);
})

View File

@ -19,40 +19,19 @@
#include "jstimer.h"
#include "jsparse.h"
#include "jsvariterator.h"
#include "jsinteractive.h"
#include "jswrap_io.h"
#include "nrf_gpio.h" // just go direct
/*
g = Graphics.createArrayBuffer(5,5,1);
g.drawString("E");
show((new Uint32Array(g.buffer))[0])
*/
uint32_t microbitLEDState = 0;
uint8_t microbitRow = 0;
// Do we have the new version with the different magnetometer?
bool microbitLSM303;
// real NRF pins 4,5,6,7,8,9,10,11,12 (column pull down)
// real NRF pins 13,14,15 (row pull up)
static const int MB_LED_COL1 = 4;
static const int MB_LED_COL2 = 5;
static const int MB_LED_COL3 = 6;
static const int MB_LED_COL4 = 7;
static const int MB_LED_COL5 = 8;
static const int MB_LED_COL6 = 9;
static const int MB_LED_COL7 = 10;
static const int MB_LED_COL8 = 11;
static const int MB_LED_COL9 = 12;
static const int MB_LED_ROW1 = 13;
static const int MB_LED_ROW2 = 14;
static const int MB_LED_ROW3 = 15;
#ifdef MICROBIT2
#include "jsi2c.h" // accelerometer/etc
// we use software I2C
JshI2CInfo i2cInfo;
// All microbit 2's have the new mmagnetometer
const bool microbitLSM303 = true;
int accel_watch = 0;
#else
// 32 means not used
static const uint8_t MB_LED_MAPPING[] = {
0, 2, 4, 19, 18, 17, 16, 15, 11,
@ -62,14 +41,42 @@ static const uint8_t MB_LED_MAPPING[] = {
const int MMA8652_ADDR = 0x1D;
const int MAG3110_ADDR = 0x0E;
// Do we have the new version with the different magnetometer?
bool microbitLSM303;
#endif
const int LSM303_ACC_ADDR = 0b0011001;
const int LSM303_MAG_ADDR = 0b0011110;
uint32_t microbitLEDState = 0;
uint8_t microbitRow = 0;
// called on a timer to scan rows out
void jswrap_microbit_display_callback() {
#ifdef MICROBIT2
microbitRow++;
if (microbitRow>5) microbitRow=0;
uint32_t s = (~microbitLEDState) >> microbitRow*5;
nrf_gpio_pin_clear(MB_LED_ROW1);
nrf_gpio_pin_clear(MB_LED_ROW2);
nrf_gpio_pin_clear(MB_LED_ROW3);
nrf_gpio_pin_clear(MB_LED_ROW4);
nrf_gpio_pin_clear(MB_LED_ROW5);
nrf_gpio_pin_write(MB_LED_COL1, s & 1);
nrf_gpio_pin_write(MB_LED_COL2, s & 2);
nrf_gpio_pin_write(MB_LED_COL3, s & 4);
nrf_gpio_pin_write(MB_LED_COL4, s & 8);
nrf_gpio_pin_write(MB_LED_COL5, s & 16);
nrf_gpio_pin_write(MB_LED_ROW1, microbitRow==0);
nrf_gpio_pin_write(MB_LED_ROW2, microbitRow==1);
nrf_gpio_pin_write(MB_LED_ROW3, microbitRow==2);
nrf_gpio_pin_write(MB_LED_ROW4, microbitRow==3);
nrf_gpio_pin_write(MB_LED_ROW5, microbitRow==4);
#else
microbitRow++;
if (microbitRow>2) microbitRow=0;
int n = microbitRow*9;
uint32_t s = ~microbitLEDState;
nrf_gpio_pin_clear(MB_LED_ROW1);
@ -87,6 +94,7 @@ void jswrap_microbit_display_callback() {
nrf_gpio_pin_write(MB_LED_ROW1, microbitRow==0);
nrf_gpio_pin_write(MB_LED_ROW2, microbitRow==1);
nrf_gpio_pin_write(MB_LED_ROW3, microbitRow==2);
#endif
}
void jswrap_microbit_stopDisplay() {
@ -99,59 +107,99 @@ void jswrap_microbit_stopDisplay() {
nrf_gpio_cfg_default(MB_LED_COL3);
nrf_gpio_cfg_default(MB_LED_COL4);
nrf_gpio_cfg_default(MB_LED_COL5);
#ifdef MICROBIT2
nrf_gpio_cfg_default(MB_LED_ROW4);
nrf_gpio_cfg_default(MB_LED_ROW5);
#else
nrf_gpio_cfg_default(MB_LED_COL6);
nrf_gpio_cfg_default(MB_LED_COL7);
nrf_gpio_cfg_default(MB_LED_COL8);
nrf_gpio_cfg_default(MB_LED_COL9);
#endif
nrf_gpio_cfg_default(MB_LED_ROW1);
nrf_gpio_cfg_default(MB_LED_ROW2);
nrf_gpio_cfg_default(MB_LED_ROW3);
}
}
void mb_i2c_write(unsigned int addr, int count, const unsigned char *data) {
#ifdef MICROBIT2
jsi2cWrite(&i2cInfo, addr, count, data, true);
#else
jshI2CWrite(EV_I2C1, addr, count, data, true);
#endif
}
void mb_i2c_read(unsigned int addr, int count, unsigned char *data) {
#ifdef MICROBIT2
jsi2cRead(&i2cInfo, addr, count, data, true);
#else
jshI2CRead(EV_I2C1, addr, count, data, true);
#endif
}
/*JSON{
"type" : "init",
"generate" : "jswrap_microbit_init"
}*/
void jswrap_microbit_init() {
// enable I2C (for accelerometers, etc)
JshI2CInfo inf;
jshI2CInitInfo(&inf);
inf.pinSCL = JSH_PORTD_OFFSET+19; // 'D19'
inf.pinSDA = JSH_PORTD_OFFSET+20; // 'D20'
jshI2CSetup(EV_I2C1, &inf);
#ifndef MICROBIT2
JshI2CInfo i2cInfo;
#endif
jshI2CInitInfo(&i2cInfo);
#ifdef MICROBIT2
accel_watch = 0;
i2cInfo.bitrate = 0x7FFFFFFF; // make it as fast as we can go
i2cInfo.clockStretch = false;
#endif
i2cInfo.pinSCL = INTERNAL_I2C_SCL_PIN;
i2cInfo.pinSDA = INTERNAL_I2C_SDA_PIN;
jshI2CSetup(EV_I2C1, &i2cInfo);
unsigned char d[2];
#ifndef MICROBIT2
d[0] = 0x07; // WHO_AM_I
jshI2CWrite(EV_I2C1, MAG3110_ADDR, 1, d, true);
jshI2CRead(EV_I2C1, MAG3110_ADDR, 1, d, true);
mb_i2c_write(MAG3110_ADDR, 1, d);
mb_i2c_read(MAG3110_ADDR, 1, d);
jsvUnLock(jspGetException());
if (d[0]==0xC4) {
microbitLSM303 = false;
// Enable MMA8652 Accelerometer
d[0] = 0x2A; d[1] = 0x19; // CTRL_REG1, 100Hz, turn on
jshI2CWrite(EV_I2C1, MMA8652_ADDR, 2, d, true);
mb_i2c_write(MMA8652_ADDR, 2, d);
// Enable MAG3110 magnetometer, 80Hz
d[0] = 0x11; d[1] = 0x80; // CTRL_REG2, AUTO_MRST_EN
jshI2CWrite(EV_I2C1, MAG3110_ADDR, 2, d, true);
mb_i2c_write(MAG3110_ADDR, 2, d);
d[0] = 0x10; d[1] = 0x01; // CTRL_REG1, active mode 80 Hz ODR with OSR = 1
jshI2CWrite(EV_I2C1, MAG3110_ADDR, 2, d, true);
mb_i2c_write(MAG3110_ADDR, 2, d);
#else
if (false) {
#endif
} else {
#ifndef MICROBIT2
microbitLSM303 = true;
#endif
// LSM303_ACC_ADDR,0x0F => 51 // WHO_AM_I
// Init accelerometer
d[0] = 0x20; d[1] = 0b00110111; // CTRL_REG1_A, 25Hz
jshI2CWrite(EV_I2C1, LSM303_ACC_ADDR, 2, d, true);
d[0] = 0x22; d[1] = 0x10; // CTRL_REG3_A
jshI2CWrite(EV_I2C1, LSM303_ACC_ADDR, 2, d, true);
mb_i2c_write(LSM303_ACC_ADDR, 2, d);
d[0] = 0x22; d[1] = 0x10; // CTRL_REG3_A - DRDY1 on INT1
mb_i2c_write(LSM303_ACC_ADDR, 2, d);
d[0] = 0x23; d[1] = 0b11011000; // CTRL_REG4_A - 4g range, MSB at low address, high res
jshI2CWrite(EV_I2C1, LSM303_ACC_ADDR, 2, d, true);
mb_i2c_write(LSM303_ACC_ADDR, 2, d);
#ifdef MICROBIT2
d[0] = 0x30; d[1] = 0; // INT1_CFG_A - OR events
mb_i2c_write(LSM303_ACC_ADDR, 2, d);
#endif
// Init magnetometer
d[0] = 0x60; d[1] = 0x04; // CFG_REG_A_M, 20Hz
jshI2CWrite(EV_I2C1, LSM303_MAG_ADDR, 2, d, true);
d[0] = 0x62; d[1] = 0b00001001; // CFG_REG_C_M - enable data ready IRQ (not that we use this), swap block order to match MAG3110
jshI2CWrite(EV_I2C1, LSM303_MAG_ADDR, 2, d, true);
mb_i2c_write(LSM303_MAG_ADDR, 2, d);
//d[0] = 0x62; d[1] = 0b00001001; // CFG_REG_C_M - enable data ready IRQ (not that we use this), swap block order to match MAG3110
d[0] = 0x62; d[1] = 0b00001000; // CFG_REG_C_M - swap block order to match MAG3110 (no IRQ)
mb_i2c_write(LSM303_MAG_ADDR, 2, d);
}
}
/*JSON{
@ -160,6 +208,9 @@ void jswrap_microbit_init() {
}*/
void jswrap_microbit_kill() {
jswrap_microbit_stopDisplay();
#ifdef MICROBIT2
jswrap_microbit_accelOff();
#endif
}
@ -205,7 +256,7 @@ show(g.buffer)
void jswrap_microbit_show_raw(uint32_t newState) {
if ((newState!=0) && (microbitLEDState==0)) {
// we want to display something but we don't have an interval
JsSysTime period = jshGetTimeFromMilliseconds(5);
JsSysTime period = jshGetTimeFromMilliseconds(MB_LED_UPDATE_MS);
jstExecuteFn(jswrap_microbit_display_callback, 0, jshGetSystemTime()+period, (uint32_t)period);
// and also set pins to outputs
nrf_gpio_cfg_output(MB_LED_COL1);
@ -213,10 +264,15 @@ void jswrap_microbit_show_raw(uint32_t newState) {
nrf_gpio_cfg_output(MB_LED_COL3);
nrf_gpio_cfg_output(MB_LED_COL4);
nrf_gpio_cfg_output(MB_LED_COL5);
#ifdef MICROBIT2
nrf_gpio_cfg_output(MB_LED_ROW4);
nrf_gpio_cfg_output(MB_LED_ROW5);
#else
nrf_gpio_cfg_output(MB_LED_COL6);
nrf_gpio_cfg_output(MB_LED_COL7);
nrf_gpio_cfg_output(MB_LED_COL8);
nrf_gpio_cfg_output(MB_LED_COL9);
#endif
nrf_gpio_cfg_output(MB_LED_ROW1);
nrf_gpio_cfg_output(MB_LED_ROW2);
nrf_gpio_cfg_output(MB_LED_ROW3);
@ -254,9 +310,18 @@ void jswrap_microbit_show(JsVar *image) {
jsError("Expecting a number, got %t\n", image);
return;
}
jswrap_microbit_show_raw(newState);
}
JsVar *getXYZ(int x, int y, int z, JsVarFloat range) {
JsVar *xyz = jsvNewObject();
if (xyz) {
jsvObjectSetChildAndUnLock(xyz, "x", jsvNewFromFloat(((JsVarFloat)x) / range));
jsvObjectSetChildAndUnLock(xyz, "y", jsvNewFromFloat(((JsVarFloat)y) / range));
jsvObjectSetChildAndUnLock(xyz, "z", jsvNewFromFloat(((JsVarFloat)z) / range));
}
return xyz;
}
/*JSON{
"type" : "function",
@ -268,35 +333,33 @@ void jswrap_microbit_show(JsVar *image) {
**Note:** This function is only available on the [BBC micro:bit](/MicroBit) board
Get the current acceleration of the micro:bit from the on-board accelerometer
**This is deprecated.** Please use `Microbit.accel` instead.
*/
JsVar *jswrap_microbit_acceleration() {
unsigned char d[7];
JsVarFloat range;
if (microbitLSM303) {
d[0] = 0x28 | 0x80;
jshI2CWrite(EV_I2C1, LSM303_ACC_ADDR, 1, d, true);
jshI2CRead(EV_I2C1, LSM303_ACC_ADDR, 6, &d[1], true);
d[0] = 0x27 | 0x80;
mb_i2c_write(LSM303_ACC_ADDR, 1, d);
mb_i2c_read(LSM303_ACC_ADDR, 7, &d[0]);
range = 8192;
} else {
#ifndef MICROBIT2
d[0] = 1;
jshI2CWrite(EV_I2C1, MMA8652_ADDR, 1, d, true);
jshI2CRead(EV_I2C1, MMA8652_ADDR, 7, d, true);
mb_i2c_write(MMA8652_ADDR, 1, d);
mb_i2c_read(MMA8652_ADDR, 7, d);
range = 16384;
#endif
}
JsVar *xyz = jsvNewObject();
if (xyz) {
int x = (d[1]<<8) | d[2];
if (x>>15) x-=65536;
int y = (d[3]<<8) | d[4];
if (y>>15) y-=65536;
int z = (d[5]<<8) | d[6];
if (z>>15) z-=65536;
// something is very broken here - why doesn't this work?
jsvObjectSetChildAndUnLock(xyz, "x", jsvNewFromFloat(((JsVarFloat)x) / range));
jsvObjectSetChildAndUnLock(xyz, "y", jsvNewFromFloat(((JsVarFloat)y) / range));
jsvObjectSetChildAndUnLock(xyz, "z", jsvNewFromFloat(((JsVarFloat)z) / range));
}
return xyz;
int x = (d[1]<<8) | d[2];
if (x>>15) x-=65536;
int y = (d[3]<<8) | d[4];
if (y>>15) y-=65536;
int z = (d[5]<<8) | d[6];
if (z>>15) z-=65536;
return getXYZ(x,y,z,range);
}
/*JSON{
@ -309,17 +372,21 @@ JsVar *jswrap_microbit_acceleration() {
**Note:** This function is only available on the [BBC micro:bit](/MicroBit) board
Get the current compass position for the micro:bit from the on-board magnetometer
**This is deprecated.** Please use `Microbit.mag` instead.
*/
JsVar *jswrap_microbit_compass() {
unsigned char d[6];
if (microbitLSM303) {
d[0] = 0x68 | 0x80;
jshI2CWrite(EV_I2C1, LSM303_MAG_ADDR, 1, d, true);
jshI2CRead(EV_I2C1, LSM303_MAG_ADDR, 6, d, true);
mb_i2c_write(LSM303_MAG_ADDR, 1, d);
mb_i2c_read(LSM303_MAG_ADDR, 6, d);
} else {
#ifndef MICROBIT2
d[0] = 1;
jshI2CWrite(EV_I2C1, MAG3110_ADDR, 1, d, true);
jshI2CRead(EV_I2C1, MAG3110_ADDR, 6, d, true);
mb_i2c_write(MAG3110_ADDR, 1, d);
mb_i2c_read(MAG3110_ADDR, 6, d);
#endif
}
JsVar *xyz = jsvNewObject();
if (xyz) {
@ -336,8 +403,290 @@ JsVar *jswrap_microbit_compass() {
return xyz;
}
#define ACCEL_HISTORY_LEN 50 ///< Number of samples of accelerometer history
//------------------------ virtuial pins allow us to have a LED1
/// how big a difference before we consider a gesture started?
int accelGestureStartThresh = 800*800;
/// how small a difference before we consider a gesture ended?
int accelGestureEndThresh = 2000*2000;
/// how many samples do we keep after a gesture has ended
int accelGestureInactiveCount = 4;
/// how many samples must a gesture have before we notify about it?
int accelGestureMinLength = 10;
typedef struct {
short x,y,z;
} Vector3;
/// accelerometer data
Vector3 acc;
/// squared accelerometer magnitude
int accMagSquared;
/// accelerometer difference since last reading
int accdiff;
/// History of accelerometer readings
int8_t accHistory[ACCEL_HISTORY_LEN*3];
/// Index in accelerometer history of the last sample
volatile uint8_t accHistoryIdx;
/// How many samples have we been recording a gesture for? If 0, we're not recoding a gesture
volatile uint8_t accGestureCount;
/// How many samples have been recorded? Used when putting data into an array
volatile uint8_t accGestureRecordedCount;
/// How many samples has the accelerometer movement been less than accelGestureEndThresh for?
volatile uint8_t accIdleCount;
char clipi8(int x) {
if (x<-128) return -128;
if (x>127) return 127;
return (char)x;
}
// called to handle IRQs from accelerometer
void jswrap_microbit_accelHandler() {
// read data, clear IRQ flags
unsigned char d[7];
d[0] = 0x27 | 0x80;
mb_i2c_write(LSM303_ACC_ADDR, 1, d);
mb_i2c_read(LSM303_ACC_ADDR, 7, &d[0]);
// work out current reading in 16 bit
int newx = (d[1]<<8) | d[2];
if (newx>>15) newx-=65536;
int newy = (d[3]<<8) | d[4];
if (newy>>15) newy-=65536;
int newz = (d[5]<<8) | d[6];
if (newz>>15) newz-=65536;
int dx = newx-acc.x;
int dy = newy-acc.y;
int dz = newz-acc.z;
acc.x = newx;
acc.y = newy;
acc.z = newz;
accMagSquared = acc.x*acc.x + acc.y*acc.y + acc.z*acc.z;
accdiff = dx*dx + dy*dy + dz*dz;
// save history
accHistoryIdx = (accHistoryIdx+3) % sizeof(accHistory);
accHistory[accHistoryIdx ] = clipi8(newx>>7);
accHistory[accHistoryIdx+1] = clipi8(newy>>7);
accHistory[accHistoryIdx+2] = clipi8(newz>>7);
// Push 'accel' event
JsVar *xyz = getXYZ(newx, newy, newz, 8192);
JsVar *microbit = jsvObjectGetChild(execInfo.root, "Microbit", 0);
if (microbit)
jsiQueueObjectCallbacks(microbit, JS_EVENT_PREFIX"accel", &xyz, 1);
jsvUnLock2(microbit, xyz);
// checking for gestures
bool hasGesture = false;
if (accGestureCount==0) { // no gesture yet
// if movement is eniugh, start one
if (accdiff > accelGestureStartThresh) {
accIdleCount = 0;
accGestureCount = 1;
}
} else { // we're recording a gesture
// keep incrementing gesture size
if (accGestureCount < 255)
accGestureCount++;
// if idle for long enough...
if (accdiff < accelGestureEndThresh) {
if (accIdleCount<255) accIdleCount++;
if (accIdleCount==accelGestureInactiveCount) {
// inactive for long enough for a gesture, but not too long
accGestureRecordedCount = accGestureCount;
if ((accGestureCount >= accelGestureMinLength) &&
(accGestureCount < ACCEL_HISTORY_LEN)) {
hasGesture = true;
}
accGestureCount = 0; // stop the gesture
}
} else if (accIdleCount < accelGestureInactiveCount)
accIdleCount = 0; // it was inactive but not long enough to trigger a gesture
}
if (!hasGesture) return;
JsVar *arr = jsvNewTypedArray(ARRAYBUFFERVIEW_INT8, accGestureRecordedCount*3);
if (arr) {
int idx = accHistoryIdx - (accGestureRecordedCount*3);
while (idx<0) idx+=sizeof(accHistory);
JsvArrayBufferIterator it;
jsvArrayBufferIteratorNew(&it, arr, 0);
for (int i=0;i<accGestureRecordedCount*3;i++) {
jsvArrayBufferIteratorSetByteValue(&it, accHistory[idx++]);
jsvArrayBufferIteratorNext(&it);
if (idx>=(int)sizeof(accHistory)) idx-=sizeof(accHistory);
}
jsvArrayBufferIteratorFree(&it);
JsVar *microbit = jsvObjectGetChild(execInfo.root, "Microbit", 0);
if (microbit)
jsiQueueObjectCallbacks(microbit, JS_EVENT_PREFIX"gesture", &arr, 1);
jsvUnLock2(microbit, arr);
}
}
/*JSON{
"type" : "staticproperty",
"class" : "Microbit",
"name" : "SPEAKER",
"generate_full" : "SPEAKER_PIN",
"ifdef" : "MICROBIT2",
"return" : ["pin",""]
}
The micro:bit's speaker pin
*/
/*JSON{
"type" : "staticproperty",
"class" : "Microbit",
"name" : "MIC",
"generate_full" : "MIC_PIN",
"ifdef" : "MICROBIT2",
"return" : ["pin",""]
}
The micro:bit's microphone pin
`MIC_ENABLE` should be set to 1 before using this
*/
/*JSON{
"type" : "staticproperty",
"class" : "Microbit",
"name" : "MIC_ENABLE",
"generate_full" : "MIC_ENABLE_PIN",
"ifdef" : "MICROBIT2",
"return" : ["pin",""]
}
The micro:bit's microphone enable pin
*/
/*JSON{
"type": "class",
"class" : "Microbit",
"ifdef" : "MICROBIT"
}
Class containing [micro:bit's](https://www.espruino.com/MicroBit) utility functions.
*/
/*JSON{
"type" : "event",
"class" : "Microbit",
"name" : "gesture",
"params" : [
["gesture","JsVar","An Int8Array containing the accelerations (X,Y,Z) from the last gesture detected by the accelerometer"]
],
"ifdef" : "MICROBIT2"
}
Called when the Micro:bit is moved in a deliberate fashion, and includes data on the detected gesture.
*/
/*JSON{
"type" : "staticmethod",
"class" : "Microbit",
"name" : "mag",
"ifdef" : "MICROBIT",
"generate" : "jswrap_microbit_compass",
"return" : ["JsVar", "An Object `{x,y,z}` of magnetometer readings as integers" ]
}*/
/*JSON{
"type" : "staticmethod",
"class" : "Microbit",
"name" : "accel",
"ifdef" : "MICROBIT",
"generate" : "jswrap_microbit_acceleration",
"return" : ["JsVar", "An Object `{x,y,z}` of acceleration readings in G" ]
}*/
/*JSON{
"type" : "staticmethod",
"class" : "Microbit",
"name" : "accelWr",
"generate" : "jswrap_microbit_accelWr",
"params" : [
["addr","int","Accelerometer address"],
["data","int","Data to write"]
],
"ifdef" : "MICROBIT2"
}
**Note:** This function is only available on the [BBC micro:bit](/MicroBit) board
Write the given value to the accelerometer
*/
void jswrap_microbit_accelWr(int a, int data) {
unsigned char d[2];
d[0] = a;
d[1] = data;
if (microbitLSM303) {
mb_i2c_write(LSM303_ACC_ADDR, 2, d);
} else {
#ifndef MICROBIT2
mb_i2c_write(MMA8652_ADDR, 2, d);
#endif
}
}
#ifdef MICROBIT2
/*JSON{
"type" : "staticmethod",
"class" : "Microbit",
"name" : "accelOn",
"generate" : "jswrap_microbit_accelOn",
"ifdef" : "MICROBIT2"
}
Turn on the accelerometer, and create `Microbit.accel` and `Microbit.gesture` events.
**Note:** The accelerometer is currently always enabled - this code
just responds to interrupts and reads
*/
void jswrap_microbit_accelOn() {
if (accel_watch) return;
accel_watch = jswrap_interface_setWatch_int(jswrap_microbit_accelHandler, INTERNAL_INT_PIN, true, -1); // falling edge
jshPinSetState(INTERNAL_INT_PIN, JSHPINSTATE_GPIO_IN_PULLUP);
// Call once to read any existing accelerometer data (which should make the IRQ line rise again)
jswrap_microbit_accelHandler();
}
/*JSON{
"type" : "staticmethod",
"class" : "Microbit",
"name" : "accelOff",
"generate" : "jswrap_microbit_accelOff",
"ifdef" : "MICROBIT2"
}
Turn off events from the accelerometer (started with `Microbit.accelOn`)
*/
void jswrap_microbit_accelOff() {
if (!accel_watch) return;
jswrap_interface_clearWatch_int(accel_watch);
accel_watch = 0;
jshPinSetState(INTERNAL_INT_PIN, JSHPINSTATE_GPIO_IN);
}
#endif
/*JSON{
"type" : "staticmethod",
"class" : "Microbit",
"name" : "play",
"generate_js" : "libs/js/microbit/microbit_play.js",
"params" : [
["waveform","JsVar","An array of data to play (unsigned 8 bit)"],
["samplesPerSecond","JsVar","The number of samples per second for playback default is 4000"],
["callback","JsVar","A function to call when playback is finished"]
],
"ifdef" : "MICROBIT2"
}
Play a waveform on the Micro:bit's speaker
*/
/*JSON{
"type" : "staticmethod",
"class" : "Microbit",
"name" : "record",
"generate_js" : "libs/js/microbit/microbit_record.js",
"params" : [
["samplesPerSecond","JsVar","The number of samples per second for recording - 4000 is recommended"],
["callback","JsVar","A function to call with the result of recording (unsigned 8 bit ArrayBuffer)"],
["samples","JsVar","[optional] How many samples to record (6000 default)"]
],
"ifdef" : "MICROBIT2"
}
Records sound from the micro:bit's onboard microphone and returns the result
*/
//------------------------ virtual pins allow us to have a LED1
void jshVirtualPinInitialise() {
}

View File

@ -14,9 +14,56 @@
#include "jsvar.h"
#ifdef MICROBIT2
#define SPEAKER_PIN (JSH_PORTH_OFFSET+3)
#define MIC_PIN (JSH_PORTH_OFFSET+4)
#define MIC_ENABLE_PIN (JSH_PORTH_OFFSET+5)
#define MIC_ENABLE_PIN (JSH_PORTH_OFFSET+5)
#define INTERNAL_I2C_SCL_PIN (JSH_PORTH_OFFSET+7)
#define INTERNAL_I2C_SDA_PIN (JSH_PORTH_OFFSET+6)
#define INTERNAL_INT_PIN (JSH_PORTH_OFFSET+8)
#define MB_LED_UPDATE_MS (3) // how often do we update the micro:bit's display in ms?
// real NRF pins for row (pull up) / column (pull down)
#define MB_LED_COL1 (28)
#define MB_LED_COL2 (11)
#define MB_LED_COL3 (31)
#define MB_LED_COL4 (37)
#define MB_LED_COL5 (30)
#define MB_LED_ROW1 (21)
#define MB_LED_ROW2 (22)
#define MB_LED_ROW3 (15)
#define MB_LED_ROW4 (24)
#define MB_LED_ROW5 (19)
#else // MICROBIT1
#define INTERNAL_I2C_SCL_PIN (JSH_PORTD_OFFSET+19)
#define INTERNAL_I2C_SDA_PIN (JSH_PORTD_OFFSET+20)
#define MB_LED_UPDATE_MS (5) // how often do we update the micro:bit's display in ms?
// real NRF pins 4,5,6,7,8,9,10,11,12 (column pull down)
// real NRF pins 13,14,15 (row pull up)
#define MB_LED_COL1 (4)
#define MB_LED_COL2 (5)
#define MB_LED_COL3 (6)
#define MB_LED_COL4 (7)
#define MB_LED_COL5 (8)
#define MB_LED_COL6 (9)
#define MB_LED_COL7 (10)
#define MB_LED_COL8 (11)
#define MB_LED_COL9 (12)
#define MB_LED_ROW1 (13)
#define MB_LED_ROW2 (14)
#define MB_LED_ROW3 (15)
#endif
void jswrap_microbit_init();
void jswrap_microbit_kill();
void jswrap_microbit_show(JsVar *image);
JsVar *jswrap_microbit_acceleration();
void jswrap_microbit_accelWr(int a, int d);
void jswrap_microbit_accelOn();
void jswrap_microbit_accelOff();
JsVar *jswrap_microbit_compass();

View File

@ -108,6 +108,7 @@ bool nmea_decode(NMEAFixInfo *gpsFix, const char *nmeaLine) {
gpsFix->satellites = nmea_decode_2(nmea);
nmea = nextComma+1; nextComma = nmea_next_comma(nmea);
// dilution of precision
gpsFix->hdop = nmea_decode_float(nmea, nextComma);
nmea = nextComma+1; nextComma = nmea_next_comma(nmea);
// altitude
gpsFix->alt = nmea_decode_float(nmea, nextComma);
@ -151,6 +152,7 @@ JsVar *nmea_to_jsVar(NMEAFixInfo *gpsFix) {
}
jsvObjectSetChildAndUnLock(o, "satellites", jsvNewFromInteger(gpsFix->satellites));
jsvObjectSetChildAndUnLock(o, "fix", jsvNewFromInteger(gpsFix->quality));
jsvObjectSetChildAndUnLock(o, "hdop", jsvNewFromFloat(gpsFix->hdop));
}
return o;
}

View File

@ -22,6 +22,7 @@ typedef struct {
uint8_t day,month,year; // 1-base day, month and year (eg. as written)
uint8_t quality; // from GGA packet, 0 = no fix
uint8_t satellites; // how many satellites
double hdop; // GGA HDOP - Relative accuracy of horizontal position
} NMEAFixInfo;
#define NMEA_MAX_SIZE 82 // 82 is the max for NMEA

View File

@ -14,7 +14,7 @@
* ----------------------------------------------------------------------------
*/
#ifdef NRF52
#ifdef NRF52_SERIES
#include "i2s_ws2812b_drive.h"
#endif
#ifdef ESP8266
@ -174,10 +174,10 @@ bool neopixelWrite(Pin pin, unsigned char *rgbData, size_t rgbSize) {
}
#elif defined(NRF52) // ----------------------------------------------------------------
#elif defined(NRF52_SERIES) // ----------------------------------------------------------------
bool neopixelWrite(Pin pin, unsigned char *rgbData, size_t rgbSize) {
#ifdef NRF52
#ifdef NRF52_SERIES
if (!jshIsPinValid(pin)) {
jsExceptionHere(JSET_ERROR, "Pin is not valid.");
return false;

View File

@ -522,6 +522,10 @@ Called after `Puck.magOn()` every time magnetometer data
is sampled. There is one argument which is an object
of the form `{x,y,z}` containing magnetometer readings
as integers (for more information see `Puck.mag()`).
Check out [the Puck.js page on the magnetometer](http://www.espruino.com/Puck.js#on-board-peripherals)
for more information.
*/
/*JSON{
@ -537,7 +541,8 @@ is sampled. There is one argument which is an object
of the form `{acc:{x,y,z}, gyro:{x,y,z}}` containing the data.
The data is as it comes off the accelerometer and is not
scaled to 1g. For more information see `Puck.accel()`
scaled to 1g. For more information see `Puck.accel()` or
[the Puck.js page on the magnetometer](http://www.espruino.com/Puck.js#on-board-peripherals).
*/
/*JSON{
@ -755,6 +760,17 @@ Accepted values are:
* 833 Hz (with Gyro) (not recommended)
* 1660 Hz (with Gyro) (not recommended)
Once `Puck.accelOn()` is called, the `Puck.accel` event will be called each time data is received. `Puck.accelOff()` can be called to turn the accelerometer off.
For instance to light the red LED whenever Puck.js is face up:
```
Puck.on('accel', function(d) {
digitalWrite(LED1, a.acc.z > 0);
});
Puck.accelOn();
```
Check out [the Puck.js page on the accelerometer](http://www.espruino.com/Puck.js#on-board-peripherals)
for more information.
@ -785,7 +801,10 @@ void jswrap_puck_accelOn(JsVarFloat hz) {
"ifdef" : "PUCKJS",
"generate" : "jswrap_puck_accelOff"
}
Turn the accelerometer off
Turn the accelerometer off after it has been turned on by `Puck.accelOn()`.
Check out [the Puck.js page on the accelerometer](http://www.espruino.com/Puck.js#on-board-peripherals)
for more information.
*/
void jswrap_puck_accelOff() {
if (!isPuckV2) {
@ -813,6 +832,8 @@ The values reported are the raw values from the chip. In normal configuration:
* accelerometer: full-scale (32768) is 4g, so you need to divide by 8192 to get correctly scaled values
* gyro: full-scale (32768) is 245 dps, so you need to divide by 134 to get correctly scaled values
If taking more than one reading, we'd suggest you use `Puck.accelOn()` and the `Puck.accel` event.
*/
JsVar *jswrap_puck_accel() {
/* If not enabled, turn on and read. If enabled,

View File

@ -52,7 +52,7 @@ typedef struct {
#ifdef TENSORFLOW_ALL_OPS
alignas(16) tflite::ops::micro::AllOpsResolver resolver;
#else
#define TENSORFLOW_OP_COUNT 6
#define TENSORFLOW_OP_COUNT 9
alignas(16) tflite::MicroMutableOpResolver<TENSORFLOW_OP_COUNT> resolver;
#endif
// Build an interpreter to run the model with
@ -94,6 +94,9 @@ bool tf_create(void *dataPtr, size_t arena_size, const char *model_data) {
tf->resolver.AddMaxPool2D();
tf->resolver.AddFullyConnected();
tf->resolver.AddSoftmax();
tf->resolver.AddQuantize();
tf->resolver.AddDequantize();
tf->resolver.AddReshape();
#endif
// Build an interpreter to run the model with

View File

@ -108,6 +108,7 @@ INCLUDE += -I$(NRF5X_SDK_PATH)/components/drivers_nrf/common
INCLUDE += -I$(NRF5X_SDK_PATH)/components/ble/peer_manager
INCLUDE += -I$(NRF5X_SDK_PATH)/components/softdevice/common/softdevice_handler
INCLUDE += -I$(NRF5X_SDK_PATH)/components/drivers_nrf/twi_master
INCLUDE += -I$(NRF5X_SDK_PATH)/components/drivers_nrf/twis_slave
INCLUDE += -I$(NRF5X_SDK_PATH)/components/drivers_nrf/spi_master
INCLUDE += -I$(NRF5X_SDK_PATH)/components/drivers_nrf/ppi
INCLUDE += -I$(NRF5X_SDK_PATH)/components/drivers_nrf/hal/nrf_pwm
@ -164,6 +165,7 @@ $(NRF5X_SDK_PATH)/components/drivers_nrf/gpiote/nrf_drv_gpiote.c \
$(NRF5X_SDK_PATH)/components/drivers_nrf/uart/nrf_drv_uart.c \
$(NRF5X_SDK_PATH)/components/drivers_nrf/hal/nrf_nvmc.c \
$(NRF5X_SDK_PATH)/components/drivers_nrf/twi_master/nrf_drv_twi.c \
$(NRF5X_SDK_PATH)/components/drivers_nrf/twis_slave/nrf_drv_twis.c \
$(NRF5X_SDK_PATH)/components/drivers_nrf/spi_master/nrf_drv_spi.c \
$(NRF5X_SDK_PATH)/components/drivers_nrf/ppi/nrf_drv_ppi.c \
$(NRF5X_SDK_PATH)/components/drivers_nrf/clock/nrf_drv_clock.c

View File

@ -7,8 +7,9 @@ ESP32=1
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 -mfix-esp32-psram-cache-issue
SOURCES += targets/esp32/jshardware.c
SOURCES += targets/esp32/esp32_neopixel.c
SOURCES += targets/esp32/jshardware.c \
targets/esp32/jshardwareESP32.c \
targets/esp32/esp32_neopixel.c
INCLUDE += -I$(ROOT)/targets/esp32
ifndef ESP_IDF_PATH
@ -135,8 +136,7 @@ SOURCES+= targets/esp32/bluetooth.c \
targets/esp32/BLE/esp32_bluetooth_utils.c \
targets/esp32/BLE/esp32_gap_func.c \
targets/esp32/BLE/esp32_gatts_func.c \
targets/esp32/BLE/esp32_gattc_func.c \
targets/esp32/jshardwareESP32.c
targets/esp32/BLE/esp32_gattc_func.c
INCLUDE+= -I$(ESP_IDF_PATH)/components/bt/bluedroid/include \
-I$(ESP_IDF_PATH)/components/bt/bluedroid/api/include \
-I$(ESP_IDF_PATH)/components/bt/bluedroid/bta/include \

View File

@ -14,7 +14,7 @@ INCLUDE += -I$(NRF5X_SDK_PATH)/components/softdevice/s130/headers/nrf51
TARGETSOURCES += $(NRF5X_SDK_PATH)/components/toolchain/system_nrf51.c
PRECOMPILED_OBJS += $(NRF5X_SDK_PATH)/components/toolchain/gcc/gcc_startup_nrf51.o
DEFINES += -DNRF51 -DSWI_DISABLE0 -DSOFTDEVICE_PRESENT -DS130 -DBLE_STACK_SUPPORT_REQD # SoftDevice included by default.
DEFINES += -DNRF51 -DNRF51_SERIES -DSWI_DISABLE0 -DSOFTDEVICE_PRESENT -DS130 -DBLE_STACK_SUPPORT_REQD # SoftDevice included by default.
LINKER_RAM:=$(shell python scripts/get_board_info.py $(BOARD) "board.chip['ram']")

View File

@ -67,10 +67,16 @@ INCLUDE += -I$(SOFTDEVICE_PATH)/headers/nrf52
DEFINES += -DBLE_STACK_SUPPORT_REQD
DEFINES += -DSWI_DISABLE0 -DSOFTDEVICE_PRESENT -DFLOAT_ABI_HARD
DEFINES += -DNRF52_SERIES
# Nordic screwed over anyone who used -DNRF52 in new SDK versions
# but then old SDKs won't work without it
ifneq ($(or $(NRF5X_SDK_12),$(NRF5X_SDK_11)),)
DEFINES += -DNRF52
endif
# NOTE: nrf.h needs tweaking as Nordic randomly changed NRF52 to NRF52_SERIES
ifeq ($(CHIP),NRF52840)
DEFINES += -DNRF52 -DNRF52840_XXAA
DEFINES += -DNRF52840_XXAA
ifdef USE_BOOTLOADER
NRF_BOOTLOADER = $(BOOTLOADER_PROJ_NAME).hex
ifdef BOOTLOADER
@ -102,7 +108,7 @@ TARGETSOURCES += $(NRF5X_SDK_PATH)/integration/nrfx/legacy/nrf_drv_power.c
TARGETSOURCES += $(NRF5X_SDK_PATH)/modules/nrfx/drivers/src/nrfx_clock.c
TARGETSOURCES += $(NRF5X_SDK_PATH)/modules/nrfx/drivers/src/nrfx_power.c
else # NRF52832
DEFINES += -DNRF52 -DNRF52832_XXAA -DNRF52_PAN_74
DEFINES += -DNRF52832_XXAA -DNRF52_PAN_74
ifdef USE_BOOTLOADER
NRF_BOOTLOADER = $(BOOTLOADER_PROJ_NAME).hex

View File

@ -10,6 +10,9 @@ $(TENSOR_ROOT)/tensorflow/lite/micro/kernels/conv.cc \
$(TENSOR_ROOT)/tensorflow/lite/micro/kernels/pooling.cc \
$(TENSOR_ROOT)/tensorflow/lite/micro/kernels/softmax.cc \
$(TENSOR_ROOT)/tensorflow/lite/micro/kernels/fully_connected.cc \
$(TENSOR_ROOT)/tensorflow/lite/micro/kernels/quantize.cc \
$(TENSOR_ROOT)/tensorflow/lite/micro/kernels/dequantize.cc \
$(TENSOR_ROOT)/tensorflow/lite/micro/kernels/reshape.cc \
$(TENSOR_ROOT)/tensorflow/lite/micro/memory_planner/linear_memory_planner.cc \
$(TENSOR_ROOT)/tensorflow/lite/micro/memory_planner/greedy_memory_planner.cc \
$(TENSOR_ROOT)/tensorflow/lite/core/api/error_reporter.cc \
@ -23,9 +26,6 @@ $(TENSOR_ROOT)/tensorflow.cc
# unused kernels
#$(TENSOR_ROOT)/tensorflow/lite/micro/kernels/pack.cc \
#$(TENSOR_ROOT)/tensorflow/lite/micro/kernels/logical.cc \
#$(TENSOR_ROOT)/tensorflow/lite/micro/kernels/reshape.cc \
#$(TENSOR_ROOT)/tensorflow/lite/micro/kernels/quantize.cc \
#$(TENSOR_ROOT)/tensorflow/lite/micro/kernels/dequantize.cc \
#$(TENSOR_ROOT)/tensorflow/lite/micro/kernels/logistic.cc \
#$(TENSOR_ROOT)/tensorflow/lite/micro/kernels/prelu.cc \
#$(TENSOR_ROOT)/tensorflow/lite/micro/kernels/ceil.cc \
@ -66,7 +66,8 @@ INCLUDE += \
-I$(TENSOR_ROOT)/tensorflow \
-I$(TENSOR_ROOT)/third_party/gemmlowp \
-I$(TENSOR_ROOT)/third_party/kissfft \
-I$(TENSOR_ROOT)/third_party/flatbuffers/include
-I$(TENSOR_ROOT)/third_party/flatbuffers/include \
-I$(TENSOR_ROOT)/third_party/ruy
CCFLAGS += -DNDEBUG -g -DTF_LITE_STATIC_MEMORY --std=c++11 -g -fno-rtti -fpermissive -Wno-sign-compare -Wno-conversion -Wno-sign-conversion -Wno-missing-field-initializers -Wno-type-limits -Wno-unused-parameter -Wno-unused-variable
DEFINES += -DUSE_TENSORFLOW=1

View File

@ -331,7 +331,8 @@ for jsondata in detail:
text = ""
for j in instances:
text = text + " * [`"+j["name"]+"`](#l__global_"+j["name"]+")";
if "description" in j: text = text + " " + j["description"]
if "description" in j:
text = text + " " + j["description"].split("\n")[0]
text = text + "\n"
html_description(text, "")

View File

@ -34,9 +34,19 @@ print("STORAGE: "+str(storageStart)+" -> "+str(storageEnd));
text = subprocess.check_output('arm-none-eabi-objdump -h '+ELF+' | grep "\\.text"', shell=True).strip().split()
codeSize = int(text[2], 16)
codeStart = int(text[3], 16)
codeStart = int(text[4], 16)
codeEnd = codeSize + codeStart
# nRF52 builds have this extra data dumped on the end - need to check this doesn't overlap too!
fsdata = subprocess.check_output('arm-none-eabi-objdump -h '+ELF+' | grep "\\.fs_data" || true', shell=True).strip().split()
if len(fsdata):
fsSize = int(fsdata[2], 16)
fsStart = int(fsdata[4], 16)
fsEnd = fsStart + fsSize
if (fsEnd > codeEnd):
print("FS DATA: "+str(fsStart)+" -> "+str(fsEnd)+" ("+str(fsSize)+" bytes)");
codeEnd = fsEnd
print("CODE: "+str(codeStart)+" -> "+str(codeEnd)+" ("+str(codeSize)+" bytes)");
if codeEnd<storageStart and codeStart<storageStart:
@ -44,5 +54,8 @@ if codeEnd<storageStart and codeStart<storageStart:
elif codeEnd>storageEnd and codeStart>storageEnd:
print("Code area Fits after Storage Area")
else:
print("CODE AND STORAGE OVERLAP")
print("==========================")
print(" CODE AND STORAGE OVERLAP")
print(" by "+ str(codeEnd-storageStart) + " bytes")
print("==========================")
exit(1)

View File

@ -409,7 +409,7 @@ def get_ifdef_description(d):
if d=="SAVE_ON_FLASH_EXTREME": return "devices with extremely low flash memory (eg. HYSTM32_28)"
if d=="STM32": return "STM32 devices (including Espruino Original, Pico and WiFi)"
if d=="STM32F1": return "STM32F1 devices (including Original Espruino Board)"
if d=="NRF52": return "NRF52 devices (like Puck.js, Pixl.js, Bangle.js and MDBT42Q)"
if d=="NRF52_SERIES": return "NRF52 devices (like Puck.js, Pixl.js, Bangle.js and MDBT42Q)"
if d=="PUCKJS": return "Puck.js devices"
if d=="PIXLJS": return "Pixl.js boards"
if d=="ESPRUINOWIFI": return "Espruino WiFi boards"
@ -437,6 +437,7 @@ def get_ifdef_description(d):
if d=="USE_TELNET": return "devices with Telnet enabled (Linux, ESP8266 and ESP32)"
if d=="USE_WIZNET": return "builds with support for WIZnet Ethernet modules built in"
if d=="USE_NFC": return "NFC (Puck.js, Pixl.js, MDBT42Q)"
if d=="GRAPHICS_ANTIALIAS": return "devices with Antialiasing support included (Bangle.js or Linux)"
print("WARNING: Unknown ifdef '"+d+"' in common.get_ifdef_description")
return d

View File

@ -42,9 +42,9 @@ echo ------------------------------------------------------
echo Building Version $VERSION
echo ------------------------------------------------------
# The following have been removed because it's too hard to keep the build going:
# STM32F3DISCOVERY OLIMEXINO_STM32 HYSTM32_32 HYSTM32_28
# STM32F3DISCOVERY OLIMEXINO_STM32 HYSTM32_32 HYSTM32_28 HYSTM32_24 RAK8211 RAK8212 RUUVITAG THINGY52 RASPBERRYPI
#
for BOARDNAME in ESPRUINO_1V3 ESPRUINO_1V3_AT ESPRUINO_1V3_WIZ PICO_1V3 PICO_1V3_CC3000 PICO_1V3_WIZ ESPRUINOWIFI PUCKJS PIXLJS BANGLEJS MDBT42Q NUCLEOF401RE NUCLEOF411RE STM32VLDISCOVERY STM32F4DISCOVERY STM32L496GDISCOVERY HYSTM32_24 RASPBERRYPI MICROBIT ESP8266_BOARD ESP8266_4MB RUUVITAG ESP32 WIO_LTE RAK8211 RAK8212 RAK5010 SMARTIBOT THINGY52
for BOARDNAME in ESPRUINO_1V3 ESPRUINO_1V3_AT ESPRUINO_1V3_WIZ PICO_1V3 PICO_1V3_CC3000 PICO_1V3_WIZ ESPRUINOWIFI PUCKJS PIXLJS BANGLEJS MDBT42Q NUCLEOF401RE NUCLEOF411RE STM32VLDISCOVERY STM32F4DISCOVERY STM32L496GDISCOVERY MICROBIT1 MICROBIT2 ESP8266_BOARD ESP8266_4MB ESP32 WIO_LTE RAK5010 SMARTIBOT
do
echo ------------------------------
echo $BOARDNAME
@ -57,12 +57,12 @@ do
fi
if [ "$BOARDNAME" == "ESPRUINO_1V3_AT" ]; then
BOARDNAME=ESPRUINOBOARD
EXTRADEFS="USE_NET=1 DEFINES=-DNO_VECTOR_FONT=1"
EXTRADEFS="USE_NET=1 DEFINES=-DNO_VECTOR_FONT=1 BLACKLIST=boards/ESPRUINOBOARD.net.blocklist"
EXTRANAME=_at
fi
if [ "$BOARDNAME" == "ESPRUINO_1V3_WIZ" ]; then
BOARDNAME=ESPRUINOBOARD
EXTRADEFS="USE_NET=1 WIZNET=1 USE_CRYPTO=0 USE_DEBUGGER=0 USE_TAB_COMPLETE=0 USE_NETWORK_JS=0 DEFINES=-DNO_VECTOR_FONT=1"
EXTRADEFS="USE_NET=1 WIZNET=1 USE_CRYPTO=0 USE_DEBUGGER=0 USE_TAB_COMPLETE=0 USE_NETWORK_JS=0 DEFINES='-DNO_VECTOR_FONT=1 -DNO_DUMP_HARDWARE_INITIALISATION=1' BLACKLIST=boards/ESPRUINOBOARD.net.blocklist"
# we must now disable crypto in order to get WIZnet support in on the Original board
EXTRANAME=_wiznet
fi

View File

@ -329,6 +329,8 @@ static bool jsfCompactInternal(uint32_t startAddress, char *swapBuffer, uint32_t
if (jsfGetFileHeader(addr, &header, true)) do {
if (header.name.firstChars != 0) { // if not replaced
jsDebug(DBG_INFO,"compact> copying file at 0x%08x\n", addr);
// Rewrite file position in any JsVars that used this file
jsvUpdateMemoryAddress(addr, sizeof(JsfFileHeader) + jsfGetFileSize(&header), writeAddress);
// Copy the file into the circular buffer, one bit at a time.
// Write the header
memcpy_circular(swapBuffer, &swapBufferHead, swapBufferSize, (char*)&header, sizeof(JsfFileHeader));

View File

@ -175,6 +175,9 @@ void jshPinSetState(Pin pin, JshPinState state);
* (like JSHPINSTATE_PIN_IS_ON if pin was set to output) */
JshPinState jshPinGetState(Pin pin);
/// Check if state is default - return true if default
bool jshIsPinStateDefault(Pin pin, JshPinState state);
/** Returns an analog value between 0 and 1. 0 is expected to be 0v, and
* 1 means jshReadVRef() volts. On most devices jshReadVRef() would return
* around 3.3, so a reading of 1 represents 3.3v. */
@ -323,6 +326,9 @@ typedef struct {
Pin pinSDA;
bool started; ///< Has I2C 'start' condition been sent so far?
bool clockStretch; ///< In software I2C, should we wait for the device to respond, or do we just soldier on regardless?
#ifdef I2C_SLAVE
int slaveAddr; ///< if >=0 this is a slave, otherwise master
#endif
} PACKED_FLAGS JshI2CInfo;
/// Initialise a JshI2CInfo struct to default settings
@ -406,7 +412,7 @@ int jshGetRTCPrescalerValue(bool calibrate);
void jshResetRTCTimer();
#endif
#if defined(NRF51) || defined(NRF52)
#if defined(NRF51_SERIES) || defined(NRF52_SERIES)
/// Called when we have had an event that means we should execute JS
extern void jshHadEvent();
#else

View File

@ -45,6 +45,9 @@ void jshI2CInitInfo(JshI2CInfo *inf) {
inf->bitrate = 100000;
inf->started = false;
inf->clockStretch = true;
#ifdef I2C_SLAVE
inf->slaveAddr = -1; // master default
#endif
}
void jshFlashWriteAligned(void *buf, uint32_t addr, uint32_t len) {
@ -116,3 +119,8 @@ __attribute__((weak)) bool jshSPISendMany(IOEventFlags device, unsigned char *tx
// Only define this if it's not used elsewhere
__attribute__((weak)) void jshBusyIdle() {
}
// Only define this if it's not used elsewhere
__attribute__((weak)) bool jshIsPinStateDefault(Pin pin, JshPinState state) {
return state == JSHPINSTATE_GPIO_IN || state == JSHPINSTATE_ADC_IN;
}

View File

@ -31,6 +31,9 @@ bool jsi2cPopulateI2CInfo(
jsvConfigObject configs[] = {
{"scl", JSV_PIN, &inf->pinSCL},
{"sda", JSV_PIN, &inf->pinSDA},
#ifdef I2C_SLAVE
{"addr", JSV_INTEGER, &inf->slaveAddr},
#endif
{"bitrate", JSV_INTEGER, &inf->bitrate}
};
if (jsvReadConfigObject(options, configs, sizeof(configs) / sizeof(jsvConfigObject))) {

View File

@ -703,7 +703,7 @@ void jsiDumpHardwareInitialisation(vcbprintf_callback user_callback, void *user_
#endif
// don't bother with normal inputs, as they come up in this state (ish) anyway
if (statem != JSHPINSTATE_GPIO_IN && statem != JSHPINSTATE_ADC_IN) {
if (!jshIsPinStateDefault(pin, statem)) {
// use getPinMode to get the correct string (remove some duplication)
JsVar *s = jswrap_io_getPinMode(pin);
if (s) cbprintf(user_callback, user_data, "pinMode(%p, %q%s);\n",pin,s,jshGetPinStateIsManual(pin)?"":", true");
@ -1886,7 +1886,7 @@ void jsiIdle() {
console device. It slows us down and just causes pain. */
} else if (DEVICE_IS_SERIAL(eventType)) {
// ------------------------------------------------------------------------ SERIAL CALLBACK
JsVar *usartClass = jsvSkipNameAndUnLock(jsiGetClassNameFromDevice(IOEVENTFLAGS_GETTYPE(event.flags)));
JsVar *usartClass = jsvSkipNameAndUnLock(jsiGetClassNameFromDevice(eventType));
if (jsvIsObject(usartClass)) {
maxEvents -= jsiHandleIOEventForUSART(usartClass, &event);
}
@ -1904,6 +1904,23 @@ void jsiIdle() {
#ifdef BLUETOOTH
} else if ((eventType == EV_BLUETOOTH_PENDING) || (eventType == EV_BLUETOOTH_PENDING_DATA)) {
maxEvents -= jsble_exec_pending(&event);
#endif
#ifdef I2C_SLAVE
} else if (DEVICE_IS_I2C(eventType)) {
// ------------------------------------------------------------------------ I2C CALLBACK
JsVar *i2cClass = jsvSkipNameAndUnLock(jsiGetClassNameFromDevice(eventType));
if (jsvIsObject(i2cClass)) {
uint8_t addr = event.data.time&0xff;
int len = event.data.time>>8;
JsVar *obj = jsvNewObject();
if (obj) {
jsvObjectSetChildAndUnLock(obj, "addr", jsvNewFromInteger(addr&0x7F));
jsvObjectSetChildAndUnLock(obj, "length", jsvNewFromInteger(len));
jsiExecuteObjectCallbacks(i2cClass, (addr&0x80) ? JS_EVENT_PREFIX"read" : JS_EVENT_PREFIX"write", &obj, 1);
jsvUnLock(obj);
}
}
jsvUnLock(i2cClass);
#endif
} else if (DEVICE_IS_EXTI(eventType)) { // ---------------------------------------------------------------- PIN WATCH
// we have an event... find out what it was for...
@ -1952,7 +1969,11 @@ void jsiIdle() {
executeNow = true;
eventTime = timeoutTime - debounce;
jsvObjectSetChildAndUnLock(watchPtr, "state", jsvNewFromBool(pinIsHigh));
// TODO: remove timer?
// Remove the timeout
JsVar *idArr = jsvNewArray(&timeout, 1);
jswrap_interface_clearTimeout(idArr);
jsvUnLock(idArr);
jsvObjectRemoveChild(watchPtr, "timeout");
}
} else if (pinIsHigh!=oldWatchState) { // else create a new timeout
timeout = jsvNewObject();
@ -2038,7 +2059,6 @@ void jsiIdle() {
// Go through all intervals and decrement time
jsvObjectIteratorNew(&it, timerArrayPtr);
while (jsvObjectIteratorHasValue(&it)) {
bool hasDeletedTimer = false;
JsVar *timerPtr = jsvObjectIteratorGetValue(&it);
JsSysTime timerTime = (JsSysTime)jsvGetLongIntegerAndUnLock(jsvObjectGetChild(timerPtr, "time", 0));
JsSysTime timeUntilNext = timerTime - timePassed;
@ -2068,23 +2088,27 @@ void jsiIdle() {
bool timerState = jsvGetBoolAndUnLock(jsvObjectGetChild(timerPtr, "state", 0));
jsvObjectSetChildAndUnLock(watchPtr, "state", jsvNewFromBool(timerState));
exec = false;
if (watchState!=timerState && jsiShouldExecuteWatch(watchPtr, timerState)) {
data = jsvNewObject();
// if we were from a watch then we were delayed by the debounce time...
if (data) {
exec = true;
JsVarInt delay = jsvGetIntegerAndUnLock(jsvObjectGetChild(watchPtr, "debounce", 0));
// Create the 'time' variable that will be passed to the user
JsVar *timePtr = jsvNewFromFloat(jshGetMillisecondsFromTime(jsiLastIdleTime+timerTime-delay)/1000);
// if it was a watch, set the last state up
jsvObjectSetChildAndUnLock(data, "state", jsvNewFromBool(timerState));
// set up the lastTime variable of data to what was in the watch
jsvObjectSetChildAndUnLock(data, "lastTime", jsvObjectGetChild(watchPtr, "lastTime", 0));
// set up the watches lastTime to this one
jsvObjectSetChild(watchPtr, "lastTime", timePtr); // don't unlock
jsvObjectSetChildAndUnLock(data, "time", timePtr);
jsvObjectSetChildAndUnLock(data, "pin", jsvObjectGetChild(watchPtr, "pin", 0));
if (watchState!=timerState) {
// Create the 'time' variable that will be passed to the user and stored as last time
JsVarInt delay = jsvGetIntegerAndUnLock(jsvObjectGetChild(watchPtr, "debounce", 0));
JsVar *timePtr = jsvNewFromFloat(jshGetMillisecondsFromTime(jsiLastIdleTime+timerTime-delay)/1000);
// If it's the right edge...
if (jsiShouldExecuteWatch(watchPtr, timerState)) {
data = jsvNewObject();
// if we were from a watch then we were delayed by the debounce time...
if (data) {
exec = true;
// if it was a watch, set the last state up
jsvObjectSetChildAndUnLock(data, "state", jsvNewFromBool(timerState));
// set up the lastTime variable of data to what was in the watch
jsvObjectSetChildAndUnLock(data, "lastTime", jsvObjectGetChild(watchPtr, "lastTime", 0));
// set up the watches lastTime to this one
jsvObjectSetChild(data, "time", timePtr); // don't unlock - use this later
jsvObjectSetChildAndUnLock(data, "pin", jsvObjectGetChild(watchPtr, "pin", 0));
}
}
// Update lastTime regardless of which edge we're watching
jsvObjectSetChildAndUnLock(watchPtr, "lastTime", timePtr);
}
}
bool removeTimer = false;
@ -2254,9 +2278,8 @@ void jsiIdle() {
#if defined(USB) && !defined(EMSCRIPTEN)
!jshIsUSBSERIALConnected() && // if USB is on, no point sleeping (later, sleep might be more drastic)
#endif
!jshHasEvents() && //no events have arrived in the mean time
!jshHasTransmitData()/* && //nothing left to send over serial?
minTimeUntilNext > SYSTICK_RANGE*5/4*/) { // we are sure we won't miss anything - leave a little leeway (SysTick will wake us up!)
!jshHasEvents() //no events have arrived in the mean time
) {
jshSleep(minTimeUntilNext);
}
}

View File

@ -26,9 +26,9 @@
#include <math.h>
#ifndef BUILDNUMBER
#define JS_VERSION "2v06"
#define JS_VERSION "2v08"
#else
#define JS_VERSION "2v06." BUILDNUMBER
#define JS_VERSION "2v08." BUILDNUMBER
#endif
/*
In code:
@ -352,7 +352,7 @@ typedef int64_t JsSysTime;
#define NIBBLEFIELD_CLEAR(BITFIELD) memset(BITFIELD, 0, sizeof(BITFIELD)) ///< Clear all elements
*/
#if defined(NRF51)
#if defined(NRF51_SERIES)
// Cortex-M0 does not support unaligned reads
#define UNALIGNED_UINT16(addr) ((((uint16_t)*((uint8_t*)(addr)+1)) << 8) | (*(uint8_t*)(addr)))
#else

View File

@ -99,7 +99,7 @@ bool jsvIsName(const JsVar *v) { return v && (v->flags&JSV_VARTYPEMASK)>=_JSV_NA
bool jsvIsBasicName(const JsVar *v) { return v && (v->flags&JSV_VARTYPEMASK)>=JSV_NAME_STRING_0 && (v->flags&JSV_VARTYPEMASK)<=JSV_NAME_STRING_MAX; } ///< Simple NAME that links to a variable via firstChild
/// Names with values have firstChild set to a value - AND NOT A REFERENCE
bool jsvIsNameWithValue(const JsVar *v) { return v && (v->flags&JSV_VARTYPEMASK)>=_JSV_NAME_WITH_VALUE_START && (v->flags&JSV_VARTYPEMASK)<=_JSV_NAME_WITH_VALUE_END; }
bool jsvIsNameInt(const JsVar *v) { return v && ((v->flags&JSV_VARTYPEMASK)==JSV_NAME_INT_INT || ((v->flags&JSV_VARTYPEMASK)>=JSV_NAME_STRING_INT_0 && (v->flags&JSV_VARTYPEMASK)<=JSV_NAME_STRING_INT_MAX)); }
bool jsvIsNameInt(const JsVar *v) { return v && ((v->flags&JSV_VARTYPEMASK)==JSV_NAME_INT_INT || ((v->flags&JSV_VARTYPEMASK)>=JSV_NAME_STRING_INT_0 && (v->flags&JSV_VARTYPEMASK)<=JSV_NAME_STRING_INT_MAX)); } ///< Is this a NAME pointing to an Integer value
bool jsvIsNameIntInt(const JsVar *v) { return v && (v->flags&JSV_VARTYPEMASK)==JSV_NAME_INT_INT; }
bool jsvIsNameIntBool(const JsVar *v) { return v && (v->flags&JSV_VARTYPEMASK)==JSV_NAME_INT_BOOL; }
/// What happens when we access a variable that doesn't exist. We get a NAME where the next + previous siblings point to the object that may one day contain them
@ -304,8 +304,7 @@ JsVar *jsvFindOrCreateRoot() {
/// Get number of memory records (JsVars) used
unsigned int jsvGetMemoryUsage() {
unsigned int usage = 0;
unsigned int i;
for (i=1;i<=jsVarsSize;i++) {
for (unsigned int i=1;i<=jsVarsSize;i++) {
JsVar *v = jsvGetAddressOf((JsVarRef)i);
if ((v->flags&JSV_VARTYPEMASK) != JSV_UNUSED) {
usage++;
@ -354,6 +353,20 @@ void jsvSetMemoryTotal(unsigned int jsNewVarCount) {
#endif
}
/// Scan memory to find any JsVar that references a specific memory range, and if so update what it points to to p[oint to the new address
void jsvUpdateMemoryAddress(size_t oldAddr, size_t length, size_t newAddr) {
for (unsigned int i=1;i<=jsVarsSize;i++) {
JsVar *v = jsvGetAddressOf((JsVarRef)i);
if (jsvIsNativeString(v) || jsvIsFlashString(v)) {
size_t p = (size_t)v->varData.nativeStr.ptr;
if (p>=oldAddr && p<oldAddr+length)
v->varData.nativeStr.ptr = (char*)(p+newAddr-oldAddr);
} else if (jsvIsFlatString(v)) {
i += (unsigned int)jsvGetFlatStringBlocks(v);
}
}
}
bool jsvMoreFreeVariablesThan(unsigned int vars) {
if (!vars) return false;
JsVarRef r = jsVarFirstEmpty;
@ -1232,7 +1245,7 @@ const char *jsvGetConstString(const JsVar *v) {
return "undefined";
} else if (jsvIsNull(v)) {
return "null";
} else if (jsvIsBoolean(v)) {
} else if (jsvIsBoolean(v) && !jsvIsNameIntBool(v)) {
return jsvGetBool(v) ? "true" : "false";
}
return 0;
@ -3702,15 +3715,16 @@ void jsvTrace(JsVar *var, int indent) {
}
/** Recursively mark the variable */
static void jsvGarbageCollectMarkUsed(JsVar *var) {
/** Recursively mark the variable. Return false if it fails due to stack. */
static bool jsvGarbageCollectMarkUsed(JsVar *var) {
var->flags &= (JsVarFlags)~JSV_GARBAGE_COLLECT;
JsVarRef child;
JsVar *childVar;
if (jsvHasCharacterData(var)) {
// non-recursively scan strings
JsVarRef child = jsvGetLastChild(var);
child = jsvGetLastChild(var);
while (child) {
JsVar *childVar;
childVar = jsvGetAddressOf(child);
childVar->flags &= (JsVarFlags)~JSV_GARBAGE_COLLECT;
child = jsvGetLastChild(childVar);
@ -3719,25 +3733,28 @@ static void jsvGarbageCollectMarkUsed(JsVar *var) {
// intentionally no else
if (jsvHasSingleChild(var)) {
if (jsvGetFirstChild(var)) {
JsVar *childVar = jsvGetAddressOf(jsvGetFirstChild(var));
childVar = jsvGetAddressOf(jsvGetFirstChild(var));
if (childVar->flags & JSV_GARBAGE_COLLECT)
jsvGarbageCollectMarkUsed(childVar);
if (!jsvGarbageCollectMarkUsed(childVar)) return false;
}
} else if (jsvHasChildren(var)) {
JsVarRef child = jsvGetFirstChild(var);
if (jsuGetFreeStack() < 256) return false;
child = jsvGetFirstChild(var);
while (child) {
JsVar *childVar;
childVar = jsvGetAddressOf(child);
if (childVar->flags & JSV_GARBAGE_COLLECT)
jsvGarbageCollectMarkUsed(childVar);
if (!jsvGarbageCollectMarkUsed(childVar)) return false;
child = jsvGetNextSibling(childVar);
}
}
return true;
}
/** Run a garbage collection sweep - return nonzero if things have been freed */
int jsvGarbageCollect() {
if (isMemoryBusy) return false;
if (isMemoryBusy) return 0;
isMemoryBusy = MEMBUSY_GC;
JsVarRef i;
// Add GC flags to anything that is currently used
@ -3754,8 +3771,14 @@ int jsvGarbageCollect() {
for (i=1;i<=jsVarsSize;i++) {
JsVar *var = jsvGetAddressOf(i);
if ((var->flags & JSV_GARBAGE_COLLECT) && // not already GC'd
jsvGetLocks(var)>0) // or it is locked
jsvGarbageCollectMarkUsed(var);
jsvGetLocks(var)>0) { // or it is locked
if (!jsvGarbageCollectMarkUsed(var)) {
// this could fail due to stack exhausted (eg big linked list)
// JSV_GARBAGE_COLLECT are left set, but not a big problem as next GC will clear them
isMemoryBusy = MEM_NOT_BUSY;
return 0;
}
}
// if we have a flat string, skip that many blocks
if (jsvIsFlatString(var))
i = (JsVarRef)(i+jsvGetFlatStringBlocks(var));

View File

@ -321,6 +321,8 @@ bool jsvMoreFreeVariablesThan(unsigned int vars); ///< Return whether there are
void jsvShowAllocated(); ///< Show what is still allocated, for debugging memory problems
/// Try and allocate more memory - only works if RESIZABLE_JSVARS is defined
void jsvSetMemoryTotal(unsigned int jsNewVarCount);
/// Scan memory to find any JsVar that references a specific memory range, and if so update what it points to to p[oint to the new address
void jsvUpdateMemoryAddress(size_t oldAddr, size_t length, size_t newAddr);
// Note that jsvNew* don't REF a variable for you, but the do LOCK it
@ -429,7 +431,7 @@ extern bool jsvIsName(const JsVar *v); ///< NAMEs are what's used to name a vari
bool jsvIsBasicName(const JsVar *v); ///< Simple NAME that links to a variable via firstChild
/// Names with values have firstChild set to a value - AND NOT A REFERENCE
extern bool jsvIsNameWithValue(const JsVar *v);
extern bool jsvIsNameInt(const JsVar *v);
extern bool jsvIsNameInt(const JsVar *v); ///< Is this a NAME pointing to an Integer value
extern bool jsvIsNameIntInt(const JsVar *v);
extern bool jsvIsNameIntBool(const JsVar *v);
/// What happens when we access a variable that doesn't exist. We get a NAME where the next + previous siblings point to the object that may one day contain them

View File

@ -1127,7 +1127,7 @@ Show fragmentation.
*/
void jswrap_e_dumpFragmentation() {
int l = 0;
for (int i=0;i<jsvGetMemoryTotal();i++) {
for (unsigned int i=0;i<jsvGetMemoryTotal();i++) {
JsVar *v = _jsvGetAddressOf(i+1);
if ((v->flags&JSV_VARTYPEMASK)==JSV_UNUSED) {
jsiConsolePrint(" ");
@ -1163,7 +1163,7 @@ to visualise where memory is used.
void jswrap_e_dumpVariables() {
int l = 0;
jsiConsolePrintf("ref,size,name,links...\n");
for (int i=0;i<jsvGetMemoryTotal();i++) {
for (unsigned int i=0;i<jsvGetMemoryTotal();i++) {
JsVarRef ref = i+1;
JsVar *v = _jsvGetAddressOf(ref);
if ((v->flags&JSV_VARTYPEMASK)==JSV_UNUSED) continue;

View File

@ -139,7 +139,9 @@ void jswrap_interface_trace(JsVar *root) {
}
Output current interpreter state in a text form such that it can be copied to a new device
Note: 'Internal' functions are currently not handled correctly. You will need to recreate these in the `onInit` function.
Espruino keeps its current state in RAM (even if the function code is stored in Flash). When you type `dump()` it dumps the current state of code in RAM plus the hardware state, then if there's code saved in flash it writes "// Code saved with E.setBootCode" and dumps that too.
**Note:** 'Internal' functions are currently not handled correctly. You will need to recreate these in the `onInit` function.
*/
/*JSON{
"type" : "function",

View File

@ -16,6 +16,7 @@
#include "jswrap_io.h"
#include "jsvar.h"
#include "jswrap_arraybuffer.h" // for jswrap_io_peek
#include "jswrapper.h" // for JSWAT_VOID
#ifdef ESP32
#include "freertos/FreeRTOS.h"
@ -813,3 +814,21 @@ void jswrap_interface_clearWatch(JsVar *idVarArr) {
jsvUnLock(idVar);
}
}
/// function for internal use
int jswrap_interface_setWatch_int(void(*callback)(), Pin pin, bool repeat, int edge) {
JsVar *fn = jsvNewNativeFunction(callback, JSWAT_VOID);
JsVar *options = jsvNewObject();
jsvObjectSetChildAndUnLock(options, "repeat", jsvNewFromBool(repeat));
jsvObjectSetChildAndUnLock(options, "edge", jsvNewFromInteger(edge));
int id = jsvGetIntegerAndUnLock(jswrap_interface_setWatch(fn, pin, options));
jsvUnLock2(fn, options);
return id;
}
/// function for internal use
void jswrap_interface_clearWatch_int(int watchNumber) {
JsVar *id = jsvNewFromInteger(watchNumber);
JsVar *idArray = jsvNewArray(&id, 1);
jswrap_interface_clearWatch(idArray);
jsvUnLock2(id, idArray);
}

View File

@ -27,3 +27,7 @@ void jswrap_io_shiftOut(JsVar *pins, JsVar *options, JsVar *data);
JsVar *jswrap_interface_setWatch(JsVar *funcVar, Pin pin, JsVar *repeatOrObject);
void jswrap_interface_clearWatch(JsVar *idVarArr);
/// function for internal use
int jswrap_interface_setWatch_int(void(*callback)(), Pin pin, bool repeat, int edge);
/// function for internal use
void jswrap_interface_clearWatch_int(int watchNumber);

View File

@ -295,189 +295,190 @@ void jsfGetJSONWithCallback(JsVar *var, JsVar *varName, JSONFlags flags, const c
if (jsvIsUndefined(var)) {
cbprintf(user_callback, user_data, "undefined");
} else {
// Use IS_RECURSING flag to stop recursion
if (var->flags & JSV_IS_RECURSING) {
cbprintf(user_callback, user_data, " ... ");
return;
}
var->flags |= JSV_IS_RECURSING;
return;
}
// Use IS_RECURSING flag to stop recursion
if ((var->flags & JSV_IS_RECURSING) || (jsuGetFreeStack() < 512) || jspIsInterrupted()) {
// also check for stack overflow/interruption
cbprintf(user_callback, user_data, " ... ");
return;
}
var->flags |= JSV_IS_RECURSING;
if (jsvIsArray(var)) {
JsVarInt length = jsvGetArrayLength(var);
bool limited = (flags&JSON_LIMIT) && (length>(JsVarInt)JSON_LIMIT_AMOUNT);
bool needNewLine = false;
cbprintf(user_callback, user_data, (flags&JSON_PRETTY)?"[ ":"[");
JsVarInt lastIndex = -1;
bool numeric = true;
bool first = true;
JsvObjectIterator it;
jsvObjectIteratorNew(&it, var);
while (lastIndex+1<length && numeric && !jspIsInterrupted()) {
JsVar *key = jsvObjectIteratorGetKey(&it);
if (!jsvObjectIteratorHasValue(&it) || jsvIsNumeric(key)) {
JsVarInt index = jsvObjectIteratorHasValue(&it) ? jsvGetInteger(key) : length-1;
JsVar *item = jsvObjectIteratorGetValue(&it);
while (lastIndex < index) {
lastIndex++;
if (!limited || lastIndex<(JsVarInt)JSON_LIMITED_AMOUNT || lastIndex>=length-(JsVarInt)JSON_LIMITED_AMOUNT) {
if (!first) cbprintf(user_callback, user_data, (flags&JSON_PRETTY)?", ":",");
first = false;
if (limited && lastIndex==length-(JsVarInt)JSON_LIMITED_AMOUNT) cbprintf(user_callback, user_data, JSON_LIMIT_TEXT);
bool newNeedsNewLine = ((flags&JSON_SOME_NEWLINES) && jsonNeedsNewLine(item));
if (flags&JSON_ALL_NEWLINES) {
needNewLine = true;
newNeedsNewLine = true;
}
if (needNewLine || newNeedsNewLine) {
jsonNewLine(nflags, whitespace, user_callback, user_data);
needNewLine = false;
}
if (lastIndex == index) {
JsVar *indexVar = jsvNewFromInteger(index);
jsfGetJSONWithCallback(item, indexVar, nflags, whitespace, user_callback, user_data);
jsvUnLock(indexVar);
} else
cbprintf(user_callback, user_data, (flags&JSON_NO_UNDEFINED)?"null":"undefined");
needNewLine = newNeedsNewLine;
if (jsvIsArray(var)) {
JsVarInt length = jsvGetArrayLength(var);
bool limited = (flags&JSON_LIMIT) && (length>(JsVarInt)JSON_LIMIT_AMOUNT);
bool needNewLine = false;
cbprintf(user_callback, user_data, (flags&JSON_PRETTY)?"[ ":"[");
JsVarInt lastIndex = -1;
bool numeric = true;
bool first = true;
JsvObjectIterator it;
jsvObjectIteratorNew(&it, var);
while (lastIndex+1<length && numeric && !jspIsInterrupted()) {
JsVar *key = jsvObjectIteratorGetKey(&it);
if (!jsvObjectIteratorHasValue(&it) || jsvIsNumeric(key)) {
JsVarInt index = jsvObjectIteratorHasValue(&it) ? jsvGetInteger(key) : length-1;
JsVar *item = jsvObjectIteratorGetValue(&it);
while (lastIndex < index) {
lastIndex++;
if (!limited || lastIndex<(JsVarInt)JSON_LIMITED_AMOUNT || lastIndex>=length-(JsVarInt)JSON_LIMITED_AMOUNT) {
if (!first) cbprintf(user_callback, user_data, (flags&JSON_PRETTY)?", ":",");
first = false;
if (limited && lastIndex==length-(JsVarInt)JSON_LIMITED_AMOUNT) cbprintf(user_callback, user_data, JSON_LIMIT_TEXT);
bool newNeedsNewLine = ((flags&JSON_SOME_NEWLINES) && jsonNeedsNewLine(item));
if (flags&JSON_ALL_NEWLINES) {
needNewLine = true;
newNeedsNewLine = true;
}
if (needNewLine || newNeedsNewLine) {
jsonNewLine(nflags, whitespace, user_callback, user_data);
needNewLine = false;
}
if (lastIndex == index) {
JsVar *indexVar = jsvNewFromInteger(index);
jsfGetJSONWithCallback(item, indexVar, nflags, whitespace, user_callback, user_data);
jsvUnLock(indexVar);
} else
cbprintf(user_callback, user_data, (flags&JSON_NO_UNDEFINED)?"null":"undefined");
needNewLine = newNeedsNewLine;
}
jsvUnLock(item);
jsvObjectIteratorNext(&it);
} else {
numeric = false;
}
jsvUnLock(key);
jsvUnLock(item);
jsvObjectIteratorNext(&it);
} else {
numeric = false;
}
jsvUnLock(key);
}
// non-numeric - but NOT for standard JSON
if ((flags&JSON_PRETTY))
jsfGetJSONForObjectItWithCallback(&it, flags, whitespace, nflags, user_callback, user_data, first);
jsvObjectIteratorFree(&it);
if (needNewLine) jsonNewLine(flags, whitespace, user_callback, user_data);
cbprintf(user_callback, user_data, (flags&JSON_PRETTY)?" ]":"]");
} else if (jsvIsArrayBuffer(var)) {
JsvArrayBufferIterator it;
bool allZero = true;
jsvArrayBufferIteratorNew(&it, var, 0);
while (jsvArrayBufferIteratorHasElement(&it)) {
if (jsvArrayBufferIteratorGetFloatValue(&it)!=0)
allZero = false;
jsvArrayBufferIteratorNext(&it);
}
jsvArrayBufferIteratorFree(&it);
bool asArray = flags&JSON_ARRAYBUFFER_AS_ARRAY;
if (allZero && !asArray) {
cbprintf(user_callback, user_data, "new %s(%d)", jswGetBasicObjectName(var), jsvGetArrayBufferLength(var));
} else {
const char *aname = jswGetBasicObjectName(var);
/* You can't do `new ArrayBuffer([1,2,3])` so we have to output
* `new Uint8Array([1,2,3]).buffer`! */
bool isBasicArrayBuffer = strcmp(aname,"ArrayBuffer")==0;
if (isBasicArrayBuffer) {
aname="Uint8Array";
}
cbprintf(user_callback, user_data, asArray?"[":"new %s([", aname);
if (flags&JSON_ALL_NEWLINES) jsonNewLine(nflags, whitespace, user_callback, user_data);
size_t length = jsvGetArrayBufferLength(var);
bool limited = (flags&JSON_LIMIT) && (length>JSON_LIMIT_AMOUNT);
// no newlines needed for array buffers as they only contain simple stuff
// non-numeric - but NOT for standard JSON
if ((flags&JSON_PRETTY))
jsfGetJSONForObjectItWithCallback(&it, flags, whitespace, nflags, user_callback, user_data, first);
jsvObjectIteratorFree(&it);
if (needNewLine) jsonNewLine(flags, whitespace, user_callback, user_data);
cbprintf(user_callback, user_data, (flags&JSON_PRETTY)?" ]":"]");
} else if (jsvIsArrayBuffer(var)) {
JsvArrayBufferIterator it;
bool allZero = true;
jsvArrayBufferIteratorNew(&it, var, 0);
while (jsvArrayBufferIteratorHasElement(&it)) {
if (jsvArrayBufferIteratorGetFloatValue(&it)!=0)
allZero = false;
while (jsvArrayBufferIteratorHasElement(&it) && !jspIsInterrupted()) {
if (!limited || it.index<JSON_LIMITED_AMOUNT || it.index>=length-JSON_LIMITED_AMOUNT) {
if (it.index>0) cbprintf(user_callback, user_data, (flags&JSON_PRETTY)?", ":",");
if (flags&JSON_ALL_NEWLINES) jsonNewLine(nflags, whitespace, user_callback, user_data);
if (limited && it.index==length-JSON_LIMITED_AMOUNT) cbprintf(user_callback, user_data, JSON_LIMIT_TEXT);
JsVar *item = jsvArrayBufferIteratorGetValue(&it);
jsfGetJSONWithCallback(item, NULL, nflags, whitespace, user_callback, user_data);
jsvUnLock(item);
}
jsvArrayBufferIteratorNext(&it);
}
if (flags&JSON_ALL_NEWLINES) jsonNewLine(flags, whitespace, user_callback, user_data);
jsvArrayBufferIteratorFree(&it);
bool asArray = flags&JSON_ARRAYBUFFER_AS_ARRAY;
if (allZero && !asArray) {
cbprintf(user_callback, user_data, "new %s(%d)", jswGetBasicObjectName(var), jsvGetArrayBufferLength(var));
} else {
const char *aname = jswGetBasicObjectName(var);
/* You can't do `new ArrayBuffer([1,2,3])` so we have to output
* `new Uint8Array([1,2,3]).buffer`! */
bool isBasicArrayBuffer = strcmp(aname,"ArrayBuffer")==0;
if (isBasicArrayBuffer) {
aname="Uint8Array";
}
cbprintf(user_callback, user_data, asArray?"[":"new %s([", aname);
if (flags&JSON_ALL_NEWLINES) jsonNewLine(nflags, whitespace, user_callback, user_data);
size_t length = jsvGetArrayBufferLength(var);
bool limited = (flags&JSON_LIMIT) && (length>JSON_LIMIT_AMOUNT);
// no newlines needed for array buffers as they only contain simple stuff
jsvArrayBufferIteratorNew(&it, var, 0);
while (jsvArrayBufferIteratorHasElement(&it) && !jspIsInterrupted()) {
if (!limited || it.index<JSON_LIMITED_AMOUNT || it.index>=length-JSON_LIMITED_AMOUNT) {
if (it.index>0) cbprintf(user_callback, user_data, (flags&JSON_PRETTY)?", ":",");
if (flags&JSON_ALL_NEWLINES) jsonNewLine(nflags, whitespace, user_callback, user_data);
if (limited && it.index==length-JSON_LIMITED_AMOUNT) cbprintf(user_callback, user_data, JSON_LIMIT_TEXT);
JsVar *item = jsvArrayBufferIteratorGetValue(&it);
jsfGetJSONWithCallback(item, NULL, nflags, whitespace, user_callback, user_data);
jsvUnLock(item);
}
jsvArrayBufferIteratorNext(&it);
}
if (flags&JSON_ALL_NEWLINES) jsonNewLine(flags, whitespace, user_callback, user_data);
jsvArrayBufferIteratorFree(&it);
cbprintf(user_callback, user_data, asArray?"]":"])");
if (isBasicArrayBuffer && !asArray) cbprintf(user_callback, user_data, ".buffer");
}
} else if (jsvIsObject(var)) {
IOEventFlags device = (flags & JSON_SHOW_DEVICES) ? jsiGetDeviceFromClass(var) : EV_NONE;
if (device!=EV_NONE) {
cbprintf(user_callback, user_data, "%s", jshGetDeviceString(device));
} else {
bool showContents = true;
if (flags & JSON_SHOW_OBJECT_NAMES) {
JsVar *proto = jsvObjectGetChild(var, JSPARSE_INHERITS_VAR, 0);
if (jsvHasChildren(proto)) {
JsVar *constr = jsvObjectGetChild(proto, JSPARSE_CONSTRUCTOR_VAR, 0);
if (constr) {
JsVar *p = jsvGetIndexOf(execInfo.root, constr, true);
if (p) cbprintf(user_callback, user_data, "%v: ", p);
jsvUnLock2(p,constr);
/* We had the constructor - now if there was a non-default toString function
* we'll execute it and print the result */
JsVar *toStringFn = jspGetNamedField(var, "toString", false);
if (jsvIsFunction(toStringFn) && toStringFn->varData.native.ptr != (void (*)(void))jswrap_object_toString) {
// Function found and it's not the default one - execute it
JsVar *result = jspExecuteFunction(toStringFn,var,0,0);
cbprintf(user_callback, user_data, "%v", result);
jsvUnLock(result);
showContents = false; // we already printed something
}
jsvUnLock(toStringFn);
}
}
jsvUnLock(proto);
}
if (showContents) {
JsVar *toStringFn = 0;
if (flags & JSON_ALLOW_TOJSON)
toStringFn = jspGetNamedField(var, "toJSON", false);
if (jsvIsFunction(toStringFn)) {
JsVar *varNameStr = varName ? jsvAsString(varName) : 0;
JsVar *result = jspExecuteFunction(toStringFn,var,1,&varNameStr);
jsvUnLock(varNameStr);
if (result==var) var->flags &= ~JSV_IS_RECURSING;
jsfGetJSONWithCallback(result, NULL, flags&~JSON_ALLOW_TOJSON, whitespace, user_callback, user_data);
jsvUnLock(result);
} else {
JsvObjectIterator it;
jsvObjectIteratorNew(&it, var);
cbprintf(user_callback, user_data, (flags&JSON_PRETTY)?"{ ":"{");
bool needNewLine = jsfGetJSONForObjectItWithCallback(&it, flags, whitespace, nflags, user_callback, user_data, true);
jsvObjectIteratorFree(&it);
if (needNewLine) jsonNewLine(flags, whitespace, user_callback, user_data);
cbprintf(user_callback, user_data, (flags&JSON_PRETTY)?" }":"}");
}
jsvUnLock(toStringFn);
}
}
} else if (jsvIsFunction(var)) {
if (flags & JSON_IGNORE_FUNCTIONS) {
cbprintf(user_callback, user_data, "undefined");
} else {
cbprintf(user_callback, user_data, "function ");
jsfGetJSONForFunctionWithCallback(var, nflags, user_callback, user_data);
}
} else if (jsvIsString(var) && !jsvIsName(var)) {
if ((flags&JSON_LIMIT) && jsvGetStringLength(var)>JSON_LIMIT_STRING_AMOUNT) {
// if the string is too big, split it and put dots in the middle
JsVar *var1 = jsvNewFromStringVar(var, 0, JSON_LIMITED_STRING_AMOUNT);
JsVar *var2 = jsvNewFromStringVar(var, jsvGetStringLength(var)-JSON_LIMITED_STRING_AMOUNT, JSON_LIMITED_STRING_AMOUNT);
cbprintf(user_callback, user_data, "%q%s%q", var1, JSON_LIMIT_TEXT, var2);
jsvUnLock2(var1, var2);
} else {
cbprintf(user_callback, user_data, (flags&JSON_JSON_COMPATIBILE)?"%Q":"%q", var);
}
} else if ((flags&JSON_JSON_COMPATIBILE) && jsvIsFloat(var) && !isfinite(jsvGetFloat(var))) {
cbprintf(user_callback, user_data, "null");
} else {
cbprintf(user_callback, user_data, "%v", var);
cbprintf(user_callback, user_data, asArray?"]":"])");
if (isBasicArrayBuffer && !asArray) cbprintf(user_callback, user_data, ".buffer");
}
var->flags &= ~JSV_IS_RECURSING;
} else if (jsvIsObject(var)) {
IOEventFlags device = (flags & JSON_SHOW_DEVICES) ? jsiGetDeviceFromClass(var) : EV_NONE;
if (device!=EV_NONE) {
cbprintf(user_callback, user_data, "%s", jshGetDeviceString(device));
} else {
bool showContents = true;
if (flags & JSON_SHOW_OBJECT_NAMES) {
JsVar *proto = jsvObjectGetChild(var, JSPARSE_INHERITS_VAR, 0);
if (jsvHasChildren(proto)) {
JsVar *constr = jsvObjectGetChild(proto, JSPARSE_CONSTRUCTOR_VAR, 0);
if (constr) {
JsVar *p = jsvGetIndexOf(execInfo.root, constr, true);
if (p) cbprintf(user_callback, user_data, "%v: ", p);
jsvUnLock2(p,constr);
/* We had the constructor - now if there was a non-default toString function
* we'll execute it and print the result */
JsVar *toStringFn = jspGetNamedField(var, "toString", false);
if (jsvIsFunction(toStringFn) && toStringFn->varData.native.ptr != (void (*)(void))jswrap_object_toString) {
// Function found and it's not the default one - execute it
JsVar *result = jspExecuteFunction(toStringFn,var,0,0);
cbprintf(user_callback, user_data, "%v", result);
jsvUnLock(result);
showContents = false; // we already printed something
}
jsvUnLock(toStringFn);
}
}
jsvUnLock(proto);
}
if (showContents) {
JsVar *toStringFn = 0;
if (flags & JSON_ALLOW_TOJSON)
toStringFn = jspGetNamedField(var, "toJSON", false);
if (jsvIsFunction(toStringFn)) {
JsVar *varNameStr = varName ? jsvAsString(varName) : 0;
JsVar *result = jspExecuteFunction(toStringFn,var,1,&varNameStr);
jsvUnLock(varNameStr);
if (result==var) var->flags &= ~JSV_IS_RECURSING;
jsfGetJSONWithCallback(result, NULL, flags&~JSON_ALLOW_TOJSON, whitespace, user_callback, user_data);
jsvUnLock(result);
} else {
JsvObjectIterator it;
jsvObjectIteratorNew(&it, var);
cbprintf(user_callback, user_data, (flags&JSON_PRETTY)?"{ ":"{");
bool needNewLine = jsfGetJSONForObjectItWithCallback(&it, flags, whitespace, nflags, user_callback, user_data, true);
jsvObjectIteratorFree(&it);
if (needNewLine) jsonNewLine(flags, whitespace, user_callback, user_data);
cbprintf(user_callback, user_data, (flags&JSON_PRETTY)?" }":"}");
}
jsvUnLock(toStringFn);
}
}
} else if (jsvIsFunction(var)) {
if (flags & JSON_IGNORE_FUNCTIONS) {
cbprintf(user_callback, user_data, "undefined");
} else {
cbprintf(user_callback, user_data, "function ");
jsfGetJSONForFunctionWithCallback(var, nflags, user_callback, user_data);
}
} else if (jsvIsString(var) && !jsvIsName(var)) {
if ((flags&JSON_LIMIT) && jsvGetStringLength(var)>JSON_LIMIT_STRING_AMOUNT) {
// if the string is too big, split it and put dots in the middle
JsVar *var1 = jsvNewFromStringVar(var, 0, JSON_LIMITED_STRING_AMOUNT);
JsVar *var2 = jsvNewFromStringVar(var, jsvGetStringLength(var)-JSON_LIMITED_STRING_AMOUNT, JSON_LIMITED_STRING_AMOUNT);
cbprintf(user_callback, user_data, "%q%s%q", var1, JSON_LIMIT_TEXT, var2);
jsvUnLock2(var1, var2);
} else {
cbprintf(user_callback, user_data, (flags&JSON_JSON_COMPATIBILE)?"%Q":"%q", var);
}
} else if ((flags&JSON_JSON_COMPATIBILE) && jsvIsFloat(var) && !isfinite(jsvGetFloat(var))) {
cbprintf(user_callback, user_data, "null");
} else {
cbprintf(user_callback, user_data, "%v", var);
}
var->flags &= ~JSV_IS_RECURSING;
}
void jsfGetJSONWhitespace(JsVar *var, JsVar *result, JSONFlags flags, const char *whitespace) {

View File

@ -48,7 +48,6 @@ process.on('uncaughtException', function(e) {
lastError=e;
print(e,e.stack?"\n"+e.stack:"")
});
function checkError() {
if (!lastError) return print("No Error");
print(lastError,lastError.stack?"\n"+lastError.stack:"")

View File

@ -160,7 +160,7 @@ bool matchcharacter(char *regexp, JsvStringIterator *txtIt, int *length, matchIn
}
}
haveCode:
if (info->rangeMatch && regexp[*length] == '-') { // Character set range start
if (info->rangeMatch && regexp[*length] == '-' && regexp[1+*length] != ']') { // Character set range start
info->rangeFirstChar = cH;
(*length)++;
int matchLen;

View File

@ -178,8 +178,7 @@ A loopback serial device. Data sent to `LoopbackA` comes out of `LoopbackB` and
"instanceof" : "Serial",
"#if" : "defined(USE_TELNET)"
}
A telnet serial device that maps to the built-in telnet console server (devices that have
built-in wifi only).
A telnet serial device that maps to the built-in telnet console server (devices that have built-in wifi only).
*/

View File

@ -565,8 +565,18 @@ void jswrap_i2c_setup(JsVar *parent, JsVar *options) {
JshI2CInfo inf;
if (jsi2cPopulateI2CInfo(&inf, options)) {
if (DEVICE_IS_I2C(device)) {
#ifdef I2C_SLAVE
if (inf.slaveAddr>=0) {
jsvObjectSetChildAndUnLock(parent, "buffer", jsvNewTypedArray(ARRAYBUFFERVIEW_UINT8, 64));
}
#endif
jshI2CSetup(device, &inf);
} else if (device == EV_NONE) {
#ifdef I2C_SLAVE
if (inf.slaveAddr>=0) {
jsExceptionHere(JSET_ERROR, "I2C Slave not implemented on software I2C");
}
#endif
#ifndef SAVE_ON_FLASH
// software mode - at least configure pins properly
if (inf.pinSCL != PIN_UNDEFINED) {

View File

@ -33,8 +33,7 @@ const int STORAGEFILE_CHUNKSIZE = (((FLASH_PAGE_SIZE<4096)?FLASH_PAGE_SIZE:4096)
/*JSON{
"type" : "library",
"class" : "Storage",
"ifndef" : "SAVE_ON_FLASH"
"class" : "Storage"
}
This module allows you to read and write part of the nonvolatile flash

View File

@ -223,7 +223,6 @@ Returns `null` if no match, or:
index: 1, // the start index of the match
input: "b" // the input string
]
"abcdefabcdef".match(/bcd/) == [
"bcd", index: 1,
input: "abcdefabcdef"
@ -330,7 +329,7 @@ JsVar *jswrap_string_replace(JsVar *parent, JsVar *subStr, JsVar *newSubStr) {
JsVarInt idx = jsvGetIntegerAndUnLock(jsvObjectGetChild(match,"index",0));
JsVarInt len = (JsVarInt)jsvGetStringLength(matchStr);
// do the replacement
jsvStringIteratorAppendString(&dst, str, lastIndex, (idx-lastIndex)); // the string before the match
jsvStringIteratorAppendString(&dst, str, (size_t)lastIndex, (idx-lastIndex)); // the string before the match
if (jsvIsFunction(replace)) {
unsigned int argCount = 0;
JsVar *args[13];
@ -377,7 +376,7 @@ JsVar *jswrap_string_replace(JsVar *parent, JsVar *subStr, JsVar *newSubStr) {
match = jswrap_regexp_exec(subStr, str);
}
}
jsvStringIteratorAppendString(&dst, str, lastIndex, JSVAPPENDSTRINGVAR_MAXLENGTH); // append the rest of the string
jsvStringIteratorAppendString(&dst, str, (size_t)lastIndex, JSVAPPENDSTRINGVAR_MAXLENGTH); // append the rest of the string
jsvStringIteratorFree(&dst);
jsvUnLock3(match,replace,str);
// reset lastIndex if global
@ -509,7 +508,7 @@ JsVar *jswrap_string_split(JsVar *parent, JsVar *split) {
#ifndef SAVE_ON_FLASH
// Use RegExp if one is passed in
if (jsvIsInstanceOf(split, "RegExp")) {
unsigned int last = 0;
int last = 0;
JsVar *match;
jsvObjectSetChildAndUnLock(split, "lastIndex", jsvNewFromInteger(0));
match = jswrap_regexp_exec(split, parent);
@ -517,7 +516,7 @@ JsVar *jswrap_string_split(JsVar *parent, JsVar *split) {
// get info about match
JsVar *matchStr = jsvGetArrayItem(match,0);
JsVarInt idx = jsvGetIntegerAndUnLock(jsvObjectGetChild(match,"index",0));
JsVarInt len = (JsVarInt)jsvGetStringLength(matchStr);
int len = (int)jsvGetStringLength(matchStr);
jsvUnLock(matchStr);
// do the replacement
jsvArrayPushAndUnLock(array, jsvNewFromStringVar(parent, (size_t)last, (size_t)(idx-last)));
@ -530,7 +529,7 @@ JsVar *jswrap_string_split(JsVar *parent, JsVar *split) {
jsvUnLock(match);
jsvObjectSetChildAndUnLock(split, "lastIndex", jsvNewFromInteger(0));
// add remaining string after last match
if (last<=jsvGetStringLength(parent))
if (last <= (int)jsvGetStringLength(parent))
jsvArrayPushAndUnLock(array, jsvNewFromStringVar(parent, (size_t)last, JSVAPPENDSTRINGVAR_MAXLENGTH));
return array;
}
@ -658,8 +657,8 @@ bool jswrap_string_startsWith(JsVar *parent, JsVar *search, int position) {
JsVar *searchStr = jsvAsString(search);
bool match = false;
if (position >= 0 &&
jsvGetStringLength(searchStr)+position <= jsvGetStringLength(parent))
match = jsvCompareString(parent, searchStr, position,0,true)==0;
(int)jsvGetStringLength(searchStr)+position <= (int)jsvGetStringLength(parent))
match = jsvCompareString(parent, searchStr, (size_t)position,0,true)==0;
jsvUnLock(searchStr);
return match;
}
@ -681,11 +680,11 @@ bool jswrap_string_endsWith(JsVar *parent, JsVar *search, JsVar *length) {
if (!jsvIsString(parent)) return false;
int position = jsvIsNumeric(length) ? jsvGetInteger(length) : (int)jsvGetStringLength(parent);
JsVar *searchStr = jsvAsString(search);
position -= jsvGetStringLength(searchStr);
position -= (int)jsvGetStringLength(searchStr);
bool match = false;
if (position >= 0 &&
jsvGetStringLength(searchStr)+position <= jsvGetStringLength(parent))
match = jsvCompareString(parent, searchStr, position,0,true)==0;
(int)jsvGetStringLength(searchStr)+position <= (int)jsvGetStringLength(parent))
match = jsvCompareString(parent, searchStr, (size_t)position,0,true)==0;
jsvUnLock(searchStr);
return match;
}
@ -729,3 +728,63 @@ JsVar *jswrap_string_repeat(JsVar *parent, int count) {
jsvAppendStringVarComplete(result, parent);
return result;
}
/*JSON{
"type" : "method",
"class" : "String",
"name" : "padStart",
"ifndef" : "SAVE_ON_FLASH",
"generate_full" : "jswrap_string_padX(parent, targetLength, padString, true)",
"params" : [
["targetLength","int","The length to pad this string to"],
["padString","JsVar","[optional] The string to pad with, default is `' '`"]
],
"return" : ["JsVar","A string containing this string padded to the correct length"],
"return_object" : "String"
}
Pad this string at the beginnind to the required number of characters
```
"Hello".padStart(10) == " Hello"
"123".padStart(10,".-") == ".-.-.-.123"
```
*/
/*JSON{
"type" : "method",
"class" : "String",
"name" : "padEnd",
"ifndef" : "SAVE_ON_FLASH",
"generate_full" : "jswrap_string_padX(parent, targetLength, padString, false)",
"params" : [
["targetLength","int","The length to pad this string to"],
["padString","JsVar","[optional] The string to pad with, default is `' '`"]
],
"return" : ["JsVar","A string containing this string padded to the correct length"],
"return_object" : "String"
}
Pad this string at the end to the required number of characters
```
"Hello".padEnd(10) == "Hello "
"123".padEnd(10,".-") == "123.-.-.-."
```
*/
JsVar *jswrap_string_padX(JsVar *str, int targetLength, JsVar *padString, bool padStart) {
if (!jsvIsString(str) || (int)jsvGetStringLength(str)>=targetLength)
return jsvLockAgain(str);
int padChars = targetLength - (int)jsvGetStringLength(str);
JsVar *result = padStart ? jsvNewFromEmptyString() : jsvNewFromStringVar(str,0,JSVAPPENDSTRINGVAR_MAXLENGTH);
if (!result) return 0;
padString = padString ? jsvAsString(padString) : jsvNewFromString(" ");
int padLength = (int)jsvGetStringLength(padString);
while (padChars > 0) {
jsvAppendStringVar(result, padString, 0, (size_t)((padLength > padChars) ? padChars : padLength));
padChars -= padLength;
}
if (padStart) jsvAppendStringVarComplete(result, str);
jsvUnLock(padString);
return result;
}

View File

@ -29,3 +29,4 @@ JsVar *jswrap_string_trim(JsVar *parent);
bool jswrap_string_startsWith(JsVar *parent, JsVar *search, int position);
bool jswrap_string_endsWith(JsVar *parent, JsVar *search, JsVar *length);
JsVar *jswrap_string_repeat(JsVar *parent, int count);
JsVar *jswrap_string_padX(JsVar *str, int targetLength, JsVar *padString, bool padStart);

View File

@ -45,8 +45,10 @@
/* Define NRF52_SERIES for common use in nRF52 series devices. */
#if defined (NRF52832_XXAA) || defined (NRF52840_XXAA)
#ifndef NRF52_SERIES
#define NRF52_SERIES
#endif
#endif
#if defined(_WIN32)

View File

@ -50,7 +50,9 @@
/* GPIO */
#define GPIO_PRESENT
#ifndef GPIO_COUNT
#define GPIO_COUNT 1
#endif
#define P0_PIN_NUM 32

View File

@ -48,6 +48,9 @@
#include "nrf_assert.h"
#include "app_util_platform.h"
#include "nrf_delay.h"
#if TWIS_ENABLED==1
#include "nrf_drv_twis.h"
#endif
#include <stdio.h>
@ -1112,6 +1115,12 @@ static void irq_handler_twi(NRF_TWI_Type * p_twi, twi_control_block_t * p_cb)
#if NRF_MODULE_ENABLED(TWI0)
IRQ_HANDLER(0)
{
#if (TWIS0_ENABLED == 1)
bool nrf_drv_twis_is_enabled(int p_instance_index);
void nrf_drv_twis_state_machine(uint8_t instNr);
if (nrf_drv_twis_is_enabled(TWIS0_INSTANCE_INDEX))
return nrf_drv_twis_state_machine(TWIS0_INSTANCE_INDEX);
#endif
#if (TWI0_USE_EASY_DMA == 1)
irq_handler_twim(NRF_TWIM0,
#else
@ -1124,6 +1133,12 @@ IRQ_HANDLER(0)
#if NRF_MODULE_ENABLED(TWI1)
IRQ_HANDLER(1)
{
#if (TWIS1_ENABLED == 1)
bool nrf_drv_twis_is_enabled(int p_instance_index);
void nrf_drv_twis_state_machine(uint8_t instNr);
if (nrf_drv_twis_is_enabled(TWIS1_INSTANCE_INDEX))
return nrf_drv_twis_state_machine(TWIS1_INSTANCE_INDEX);
#endif
#if (TWI1_USE_EASY_DMA == 1)
irq_handler_twim(NRF_TWIM1,
#else

View File

@ -373,7 +373,7 @@ static inline void nrf_drv_twis_process_error(
* It makes it possible to use it either in interrupt or in polling mode.
* @param instNr Driver instance number that has called this runtime.
*/
static void nrf_drv_twis_state_machine(uint8_t instNr)
void nrf_drv_twis_state_machine(uint8_t instNr)
{
if (!TWIS_NO_SYNC_MODE)
{
@ -734,6 +734,11 @@ void nrf_drv_twis_disable(nrf_drv_twis_t const * const p_instance)
m_var_inst[instNr].state = NRF_DRV_STATE_INITIALIZED;
}
bool nrf_drv_twis_is_enabled(int p_instance_index) {
nrf_drv_twis_var_inst_t * const p_var_inst = &m_var_inst[p_instance_index];
return p_var_inst->state == NRF_DRV_STATE_POWERED_ON;
}
/* ARM recommends not using the LDREX and STREX instructions in C code.
* This is because the compiler might generate loads and stores between
* LDREX and STREX, potentially clearing the exclusive monitor set by LDREX.

View File

@ -246,6 +246,9 @@ void nrf_drv_twis_enable(nrf_drv_twis_t const * const p_instance);
*/
void nrf_drv_twis_disable(nrf_drv_twis_t const * const p_instance);
// GW hack for TWIM and TWIS
bool nrf_drv_twis_is_enabled(int p_instance_index);
/**
* @brief Get and clear last error flags
*

View File

@ -309,6 +309,13 @@ JshPinState jshPinGetState(Pin pin) {
return g_pinState[pin];
}
/**
* Check if state is default - return true if default
*/
bool jshIsPinStateDefault(Pin pin, JshPinState state) {
return state == JSHPINSTATE_GPIO_IN_PULLUP || state == JSHPINSTATE_ADC_IN;
}
//===== GPIO and PIN stuff =====
/**
@ -405,13 +412,17 @@ void jshSetOutputValue(JshPinFunction func, int value) {
*/
void jshEnableWatchDog(JsVarFloat timeout) {
UNUSED(timeout);
#ifdef DEBUG
jsError(">> jshEnableWatchDog Not implemented,using taskwatchdog from RTOS");
#endif
}
// Kick the watchdog
void jshKickWatchDog() {
#ifdef DEBUG
jsError(">> jshKickWatchDog Not implemented,using taskwatchdog from RTOS");
#endif
}

View File

@ -493,6 +493,10 @@ JshPinState jshPinGetState(Pin pin) {
}
return rc;
}
/// Check if state is default - return true if default
bool jshIsPinStateDefault(Pin pin, JshPinState state) {
return state == JSHPINSTATE_GPIO_IN_PULLUP || state == JSHPINSTATE_ADC_IN;
}
//===== GPIO and PIN stuff =====

View File

@ -186,7 +186,7 @@ uint8_t nusTxBuf[BLE_NUS_MAX_DATA_LEN];
/// Number of bytes ready to send inside nusTxBuf
uint16_t nuxTxBufLength = 0;
#ifdef NRF52
#ifdef NRF52_SERIES
#define DYNAMIC_INTERVAL_ADJUSTMENT
#endif
/* Dynamic interval adjustment kicks Espruino into a low power mode after
@ -1033,7 +1033,7 @@ void SWI1_IRQHandler(bool radio_evt) {
}
#endif
#ifndef NRF52
#ifndef NRF52_SERIES
/* NRF52 has a systick. On nRF51 we just hook on
to this, since it happens quite often */
void SysTick_Handler(void);
@ -2230,7 +2230,7 @@ static void ble_stack_init() {
&ble_enable_params);
APP_ERROR_CHECK(err_code);
#ifdef NRF52
#ifdef NRF52_SERIES
ble_enable_params.common_enable_params.vs_uuid_count = 10;
#else
ble_enable_params.common_enable_params.vs_uuid_count = 3;
@ -2435,7 +2435,7 @@ void jsble_advertising_stop() {
uint32_t err_code;
ble_stack_init();
err_code = radio_notification_init(
#ifdef NRF52
#ifdef NRF52_SERIES
6, /* IRQ Priority - Must be 6 on nRF52. 7 doesn't work */
#else
3, /* IRQ Priority - nRF51 has different IRQ structure */
@ -2444,7 +2444,7 @@ void jsble_advertising_stop() {
NRF_RADIO_NOTIFICATION_DISTANCE_NONE);
APP_ERROR_CHECK(err_code);
#ifdef NRF52
#ifdef NRF52_SERIES
// Set MAC address
JsVar *v = jsvObjectGetChild(execInfo.hiddenRoot, BLE_NAME_MAC_ADDRESS,0);
if (v) {

View File

@ -45,7 +45,12 @@ ret_code_t i2s_ws2812b_drive_xfer(rgb_led_t *led_array, uint16_t num_leds, uint8
#else
config.sck_pin = 22;
#endif
#ifdef NEOPIXEL_LRCK_PIN
// On nRF52840 lrck needs defining too - http://forum.espruino.com/conversations/354468/
config.lrck_pin = NEOPIXEL_LRCK_PIN;
#else
config.lrck_pin = NRF_DRV_I2S_PIN_NOT_USED;
#endif
config.mck_pin = NRF_DRV_I2S_PIN_NOT_USED;
config.sdout_pin = drive_pin;
config.sdin_pin = NRF_DRV_I2S_PIN_NOT_USED;

View File

@ -62,7 +62,7 @@ void app_error_fault_handler(uint32_t id, uint32_t pc, uint32_t info) {
#include "nrf_timer.h"
#include "nrf_delay.h"
#include "nrf_nvic.h"
#ifdef NRF52
#ifdef NRF52_SERIES
#include "nrf_saadc.h"
#include "nrf_pwm.h"
#else
@ -71,6 +71,9 @@ void app_error_fault_handler(uint32_t id, uint32_t pc, uint32_t info) {
#include "nrf_drv_uart.h"
#include "nrf_drv_twi.h"
#ifdef I2C_SLAVE
#include "nrf_drv_twis.h"
#endif
#include "nrf_drv_gpiote.h"
#include "nrf_drv_ppi.h"
#include "nrf_drv_spi.h"
@ -79,6 +82,9 @@ void app_error_fault_handler(uint32_t id, uint32_t pc, uint32_t info) {
#if NRF_SD_BLE_API_VERSION<5
#include "softdevice_handler.h"
#endif
#ifdef MICROBIT
#include "jswrap_microbit.h"
#endif
void WDT_IRQHandler() {
}
@ -264,6 +270,11 @@ unsigned int ticksSinceStart = 0;
JshPinFunction pinStates[JSH_PIN_COUNT];
#ifdef NRF52_SERIES
/// This is used to handle the case where an analog read happens in an IRQ interrupts one being done outside
volatile bool nrf_analog_read_interrupted = false;
#endif
#if SPI_ENABLED
static const nrf_drv_spi_t spi0 = NRF_DRV_SPI_INSTANCE(0);
bool spi0Initialised = false;
@ -303,8 +314,14 @@ void spi0EvtHandler(nrf_drv_spi_evt_t const * p_event
#endif
static const nrf_drv_twi_t TWI1 = NRF_DRV_TWI_INSTANCE(1);
#ifdef I2C_SLAVE
static const nrf_drv_twis_t TWIS1 = NRF_DRV_TWIS_INSTANCE(1);
static uint8_t twisRxBuf[32]; // receive buffer for I2C slave data
static uint8_t twisAddr;
#endif
bool twi1Initialised = false;
#ifdef NRF5X_SDK_11
#include <nrf_drv_config.h>
// UART in SDK11 does not support instance numbers
@ -361,8 +378,6 @@ void jshUSARTUnSetup(IOEventFlags device);
and we're in the middle of reading We'd never be at 0
anyway because we're always expecting to have read something. */
uint32_t spiFlashLastAddress = 0;
/// Is SPI flash awake?
bool spiFlashAwake = false;
/// Read data while sending 0
static void spiFlashRead(unsigned char *rx, unsigned int len) {
nrf_gpio_pin_clear((uint32_t)pinInfo[SPIFLASH_PIN_MOSI].pin);
@ -400,6 +415,11 @@ static unsigned char spiFlashStatus() {
nrf_gpio_pin_set((uint32_t)pinInfo[SPIFLASH_PIN_CS].pin);
return buf;
}
#ifdef SPIFLASH_SLEEP_CMD
/// Is SPI flash awake?
bool spiFlashAwake = false;
static void spiFlashWakeUp() {
/*unsigned char buf[4];
int tries = 10;
@ -427,6 +447,7 @@ void spiFlashSleep() {
spiFlashWriteCS(buf,1);
}
#endif
#endif
@ -435,6 +456,14 @@ const nrf_drv_twi_t *jshGetTWI(IOEventFlags device) {
return 0;
}
#ifdef I2C_SLAVE
const nrf_drv_twis_t *jshGetTWIS(IOEventFlags device) {
if (device == EV_I2C1) return &TWIS1;
return 0;
}
#endif
/// Called when we have had an event that means we should execute JS
void jshHadEvent() {
hadEvent = true;
@ -470,7 +499,7 @@ void SysTick_Handler(void) {
}
}
#ifdef NRF52
#ifdef NRF52_SERIES
NRF_PWM_Type *nrf_get_pwm(JshPinFunction func) {
if ((func&JSH_MASK_TYPE) == JSH_TIMER1) return NRF_PWM0;
else if ((func&JSH_MASK_TYPE) == JSH_TIMER2) return NRF_PWM1;
@ -489,7 +518,7 @@ static NO_INLINE void jshPinSetFunction_int(JshPinFunction func, uint32_t pin) {
JshPinFunction fInfo = func&JSH_MASK_INFO;
switch (fType) {
case JSH_NOTHING: break;
#ifdef NRF52
#ifdef NRF52_SERIES
case JSH_TIMER1:
case JSH_TIMER2:
case JSH_TIMER3: {
@ -604,8 +633,10 @@ void jshResetPeripherals() {
#endif
spiFlashLastAddress = 0;
jshDelayMicroseconds(100);
#ifdef SPIFLASH_SLEEP_CMD
spiFlashWakeUp();
spiFlashAwake = true;
#endif
// disable lock bits
// wait for write enable
@ -619,6 +650,9 @@ void jshResetPeripherals() {
buf[1] = 0;
spiFlashWriteCS(buf,2);
#endif
#ifdef NRF52_SERIES
nrf_analog_read_interrupted = false;
#endif
}
void jshInit() {
@ -647,17 +681,28 @@ void jshInit() {
jshDelayMicroseconds(10);
#ifdef MICROBIT
nrf_gpio_pin_set(MB_LED_ROW1);
nrf_gpio_pin_set(MB_LED_COL1);
nrf_gpio_pin_set(MB_LED_COL2);
nrf_gpio_pin_set(MB_LED_COL3);
nrf_gpio_pin_set(MB_LED_COL4);
nrf_gpio_pin_set(MB_LED_COL5);
/* We must wait ~1 second for the USB interface to initialise
* or it won't raise the RX pin and we won't think anything
* is connected. */
bool waitForUART = !jshPinGetValue(DEFAULT_CONSOLE_RX_PIN);
for (int i=0;i<10 && !jshPinGetValue(DEFAULT_CONSOLE_RX_PIN);i++) {
nrf_gpio_pin_write(MB_LED_COL1, i&1);
nrf_delay_ms(100);
ticksSinceStart = 0;
}
#endif
#ifdef MICROBIT2
if (true) {
#else
if (jshPinGetValue(DEFAULT_CONSOLE_RX_PIN)) {
#endif
JshUSARTInfo inf;
jshUSARTInitInfo(&inf);
inf.pinRX = DEFAULT_CONSOLE_RX_PIN;
@ -671,6 +716,7 @@ void jshInit() {
* the UART wasn't powered when we connected. */
if (waitForUART) {
for (int i=0;i<30;i++) {
nrf_gpio_pin_write(MB_LED_COL2, i&1);
nrf_delay_ms(100);
ticksSinceStart = 0;
}
@ -684,7 +730,7 @@ void jshInit() {
// Enable and sort out the timer
nrf_timer_mode_set(NRF_TIMER1, NRF_TIMER_MODE_TIMER);
#ifdef NRF52
#ifdef NRF52_SERIES
nrf_timer_bit_width_set(NRF_TIMER1, NRF_TIMER_BIT_WIDTH_32);
nrf_timer_frequency_set(NRF_TIMER1, NRF_TIMER_FREQ_1MHz);
#define NRF_TIMER_FREQ 1000000
@ -745,7 +791,7 @@ void jshInit() {
// Enable PPI driver
err_code = nrf_drv_ppi_init();
APP_ERROR_CHECK(err_code);
#ifdef NRF52
#ifdef NRF52_SERIES
// Turn on SYSTICK - used for handling Ctrl-C behaviour
SysTick_Config(0xFFFFFF);
#endif
@ -787,6 +833,12 @@ void jshKill() {
spiFlashLastAddress = 0;
}
#endif
#ifdef I2C_SLAVE
if (nrf_drv_twis_is_enabled(TWIS1_INSTANCE_INDEX)) {
nrf_drv_twis_disable(&TWIS1);
nrf_drv_twis_uninit(&TWIS1);
}
#endif
}
// stuff to do on idle
@ -837,6 +889,10 @@ JsSysTime jshGetSystemTime() {
void jshSetSystemTime(JsSysTime time) {
// Set baseSystemTime to 0 so 'jshGetSystemTime' isn't affected
baseSystemTime = 0;
// If the RTC has changed (eg softdevice reboot) ensure
// we don't end up incrementing baseSystemTime and then
// getting an invalid time when we call jshGetSystemTime (fixes #1933)
lastSystemTime = 0;
// now set baseSystemTime based on the value from jshGetSystemTime()
baseSystemTime = time - jshGetSystemTime();
}
@ -852,7 +908,7 @@ JsVarFloat jshGetMillisecondsFromTime(JsSysTime time) {
}
void jshInterruptOff() {
#if defined(BLUETOOTH) && defined(NRF52)
#if defined(BLUETOOTH) && defined(NRF52_SERIES)
// disable non-softdevice IRQs. This only seems available on Cortex M3 (not the nRF51's M0)
__set_BASEPRI(4<<5); // Disabling interrupts completely is not reasonable when using one of the SoftDevices.
#else
@ -861,7 +917,7 @@ void jshInterruptOff() {
}
void jshInterruptOn() {
#if defined(BLUETOOTH) && defined(NRF52)
#if defined(BLUETOOTH) && defined(NRF52_SERIES)
__set_BASEPRI(0);
#else
__enable_irq();
@ -1047,9 +1103,7 @@ JshPinState jshPinGetState(Pin pin) {
}
}
#ifdef NRF52
volatile bool nrf_analog_read_interrupted = false;
#ifdef NRF52_SERIES
nrf_saadc_value_t nrf_analog_read() {
nrf_saadc_value_t result;
@ -1101,6 +1155,27 @@ void nrf_analog_read_end(bool adcInUse) {
}
#endif
#ifdef NRF52_SERIES
static void jshPinAnalogSetConfig(nrf_saadc_channel_config_t *config, Pin pin) {
nrf_saadc_input_t ain = 1 + (pinInfo[pin].analog & JSH_MASK_ANALOG_CH);
config->acq_time = NRF_SAADC_ACQTIME_3US;
config->gain = NRF_SAADC_GAIN1_4; // 1/4 of input volts
config->reference = NRF_SAADC_REFERENCE_VDD4; // VDD/4 as reference.
#ifdef MICROBIT2
if (pin == MIC_PIN) {
config->gain = NRF_SAADC_GAIN4; // the mic needs highest gain
config->reference = NRF_SAADC_REFERENCE_INTERNAL; // 0.6v reference.
}
#endif
config->mode = NRF_SAADC_MODE_SINGLE_ENDED;
config->pin_p = ain;
config->pin_n = ain;
config->resistor_p = NRF_SAADC_RESISTOR_DISABLED;
config->resistor_n = NRF_SAADC_RESISTOR_DISABLED;
}
#endif
// Returns an analog value between 0 and 1
JsVarFloat jshPinAnalog(Pin pin) {
#if JSH_PORTV_COUNT>0
@ -1111,22 +1186,15 @@ JsVarFloat jshPinAnalog(Pin pin) {
if (pinInfo[pin].analog == JSH_ANALOG_NONE) return NAN;
if (!jshGetPinStateIsManual(pin))
jshPinSetState(pin, JSHPINSTATE_ADC_IN);
#ifdef NRF52
#ifdef NRF52_SERIES
int channel = pinInfo[pin].analog & JSH_MASK_ANALOG_CH;
assert(NRF_SAADC_INPUT_AIN0 == 1);
assert(NRF_SAADC_INPUT_AIN1 == 2);
assert(NRF_SAADC_INPUT_AIN2 == 3);
nrf_saadc_input_t ain = channel+1;
nrf_saadc_channel_config_t config;
config.acq_time = NRF_SAADC_ACQTIME_3US;
config.gain = NRF_SAADC_GAIN1_4; // 1/4 of input volts
config.mode = NRF_SAADC_MODE_SINGLE_ENDED;
config.pin_p = ain;
config.pin_n = ain;
config.reference = NRF_SAADC_REFERENCE_VDD4; // VDD/4 as reference.
config.resistor_p = NRF_SAADC_RESISTOR_DISABLED;
config.resistor_n = NRF_SAADC_RESISTOR_DISABLED;
jshPinAnalogSetConfig(&config, pin);
bool adcInUse = nrf_analog_read_start();
// make reading
@ -1162,22 +1230,14 @@ JsVarFloat jshPinAnalog(Pin pin) {
int jshPinAnalogFast(Pin pin) {
if (pinInfo[pin].analog == JSH_ANALOG_NONE) return 0;
#ifdef NRF52
#ifdef NRF52_SERIES
// sanity checks for channel
assert(NRF_SAADC_INPUT_AIN0 == 1);
assert(NRF_SAADC_INPUT_AIN1 == 2);
assert(NRF_SAADC_INPUT_AIN2 == 3);
nrf_saadc_input_t ain = 1 + (pinInfo[pin].analog & JSH_MASK_ANALOG_CH);
nrf_saadc_channel_config_t config;
config.acq_time = NRF_SAADC_ACQTIME_3US;
config.gain = NRF_SAADC_GAIN1_4; // 1/4 of input volts
config.mode = NRF_SAADC_MODE_SINGLE_ENDED;
config.pin_p = ain;
config.pin_n = ain;
config.reference = NRF_SAADC_REFERENCE_VDD4; // VDD/4 as reference.
config.resistor_p = NRF_SAADC_RESISTOR_DISABLED;
config.resistor_n = NRF_SAADC_RESISTOR_DISABLED;
jshPinAnalogSetConfig(&config, pin);
bool adcInUse = nrf_analog_read_start();
// make reading
@ -1239,7 +1299,7 @@ JshPinFunction jshPinAnalogOutput(Pin pin, JsVarFloat value, JsVarFloat freq, Js
if (value>1) value=1;
if (value<0) value=0;
bool alreadyConfigured = false;
#ifdef NRF52
#ifdef NRF52_SERIES
// Try and use existing pin function
JshPinFunction func = pinStates[pin];
// Work out what speed we need this timer to be
@ -1301,7 +1361,7 @@ JshPinFunction jshPinAnalogOutput(Pin pin, JsVarFloat value, JsVarFloat freq, Js
if (freq<=0) freq=50;
jstPinPWM(freq, value, pin);
return JSH_NOTHING;
#ifdef NRF52
#ifdef NRF52_SERIES
}
if (!func) {
@ -1356,7 +1416,7 @@ JshPinFunction jshPinAnalogOutput(Pin pin, JsVarFloat value, JsVarFloat freq, Js
/// Given a pin function, set that pin to the 16 bit value (used mainly for DACs and PWM)
void jshSetOutputValue(JshPinFunction func, int value) {
#ifdef NRF52
#ifdef NRF52_SERIES
if (!JSH_PINFUNCTION_IS_TIMER(func))
return;
@ -1696,7 +1756,7 @@ int jshSPISend(IOEventFlags device, int data) {
#if SPI_ENABLED
if (device!=EV_SPI1 || !jshIsDeviceInitialised(device)) return -1;
jshSPIWait(device);
#if defined(SPI0_USE_EASY_DMA)
#if defined(SPI0_USE_EASY_DMA) && (SPI0_USE_EASY_DMA==1)
// Hack for https://infocenter.nordicsemi.com/topic/­errata_nRF52832_Rev2/ERR/nRF52832/Rev2/l­atest/anomaly_832_58.html?cp=4_2_1_0_1_8
// Can't use DMA for single bytes as it's broken
#if NRF_SD_BLE_API_VERSION>5
@ -1807,6 +1867,67 @@ void jshSPIWait(IOEventFlags device) {
WAIT_UNTIL(!spi0Sending, "SPI0");
#endif
}
#ifdef I2C_SLAVE
static void twis_event_handler(nrf_drv_twis_evt_t const * const p_event)
{
switch (p_event->type)
{
case TWIS_EVT_READ_REQ:
if (p_event->data.buf_req) {
JsVar *i2c = jsvObjectGetChild(execInfo.root,"I2C1",0);
if (i2c) {
JsVar *buf = jsvObjectGetChild(i2c,"buffer",0);
size_t bufLen;
char *bufPtr = jsvGetDataPointer(buf, &bufLen);
if (bufPtr && bufLen>twisAddr)
nrf_drv_twis_tx_prepare(&TWIS1, bufPtr + twisAddr, bufLen - twisAddr);
else
nrf_drv_twis_tx_prepare(&TWIS1, twisRxBuf, 0);
jsvUnLock2(i2c,buf);
}
}
break;
case TWIS_EVT_READ_DONE:
jshPushIOEvent(EV_I2C1, twisAddr|0x80|(p_event->data.tx_amount<<8)); // send event to indicate a read
jshHadEvent();
twisAddr += p_event->data.tx_amount;
break;
case TWIS_EVT_WRITE_REQ:
if (p_event->data.buf_req)
nrf_drv_twis_rx_prepare(&TWIS1, twisRxBuf, sizeof(twisRxBuf));
break;
case TWIS_EVT_WRITE_DONE:
if (p_event->data.rx_amount>0) {
twisAddr = twisRxBuf[0];
if (p_event->data.rx_amount>1) {
jshPushIOEvent(EV_I2C1, twisAddr|((p_event->data.rx_amount-1)<<8)); // send event to indicate a write
jshHadEvent();
JsVar *i2c = jsvObjectGetChild(execInfo.root,"I2C1",0);
if (i2c) {
JsVar *buf = jsvObjectGetChild(i2c,"buffer",0);
size_t bufLen;
char *bufPtr = jsvGetDataPointer(buf, &bufLen);
for (unsigned int i=1;i<p_event->data.rx_amount;i++) {
if (bufPtr && twisAddr<bufLen)
bufPtr[twisAddr] = twisRxBuf[i];
twisAddr++;
}
jsvUnLock2(i2c,buf);
}
}
}
break;
case TWIS_EVT_READ_ERROR:
case TWIS_EVT_WRITE_ERROR:
case TWIS_EVT_GENERAL_ERROR:
//m_error_flag = true;
break;
default:
break;
}
}
#endif
/** Set up I2C, if pins are -1 they will be guessed */
void jshI2CSetup(IOEventFlags device, JshI2CInfo *inf) {
@ -1814,21 +1935,50 @@ void jshI2CSetup(IOEventFlags device, JshI2CInfo *inf) {
jsError("SDA and SCL pins must be valid, got %d and %d\n", inf->pinSDA, inf->pinSCL);
return;
}
const nrf_drv_twi_t *twi = jshGetTWI(device);
if (!twi) return;
// http://infocenter.nordicsemi.com/index.jsp?topic=%2Fcom.nordic.infocenter.sdk51.v9.0.0%2Fhardware_driver_twi.html&cp=4_1_0_2_10
nrf_drv_twi_config_t p_twi_config;
p_twi_config.scl = (uint32_t)pinInfo[inf->pinSCL].pin;
p_twi_config.sda = (uint32_t)pinInfo[inf->pinSDA].pin;
p_twi_config.frequency = (inf->bitrate<175000) ? NRF_TWI_FREQ_100K : ((inf->bitrate<325000) ? NRF_TWI_FREQ_250K : NRF_TWI_FREQ_400K);
p_twi_config.interrupt_priority = APP_IRQ_PRIORITY_LOW;
if (twi1Initialised) nrf_drv_twi_uninit(twi);
twi1Initialised = true;
uint32_t err_code = nrf_drv_twi_init(twi, &p_twi_config, NULL, NULL);
if (err_code != NRF_SUCCESS)
jsExceptionHere(JSET_INTERNALERROR, "I2C Initialisation Error %d\n", err_code);
else
nrf_drv_twi_enable(twi);
uint32_t err_code;
#ifdef I2C_SLAVE
if ((device == EV_I2C1) && nrf_drv_twis_is_enabled(TWIS1_INSTANCE_INDEX)) {
nrf_drv_twis_disable(&TWIS1);
nrf_drv_twis_uninit(&TWIS1);
}
if (inf->slaveAddr >=0) {
const nrf_drv_twis_t *twis = jshGetTWIS(device);
if (!twis) return;
const nrf_drv_twis_config_t config =
{
.addr = {inf->slaveAddr, 0},
.scl = (uint32_t)pinInfo[inf->pinSCL].pin,
.scl_pull = NRF_GPIO_PIN_PULLUP,
.sda = (uint32_t)pinInfo[inf->pinSDA].pin,
.sda_pull = NRF_GPIO_PIN_PULLUP,
.interrupt_priority = APP_IRQ_PRIORITY_HIGH
};
err_code = nrf_drv_twis_init(twis, &config, twis_event_handler);
if (err_code != NRF_SUCCESS)
jsExceptionHere(JSET_INTERNALERROR, "I2C Initialisation Error %d\n", err_code);
else
nrf_drv_twis_enable(twis);
} else
#endif
{
const nrf_drv_twi_t *twi = jshGetTWI(device);
if (!twi) return;
// http://infocenter.nordicsemi.com/index.jsp?topic=%2Fcom.nordic.infocenter.sdk51.v9.0.0%2Fhardware_driver_twi.html&cp=4_1_0_2_10
nrf_drv_twi_config_t p_twi_config;
p_twi_config.scl = (uint32_t)pinInfo[inf->pinSCL].pin;
p_twi_config.sda = (uint32_t)pinInfo[inf->pinSDA].pin;
p_twi_config.frequency = (inf->bitrate<175000) ? NRF_TWI_FREQ_100K : ((inf->bitrate<325000) ? NRF_TWI_FREQ_250K : NRF_TWI_FREQ_400K);
p_twi_config.interrupt_priority = APP_IRQ_PRIORITY_LOW;
if (twi1Initialised) nrf_drv_twi_uninit(twi);
twi1Initialised = true;
err_code = nrf_drv_twi_init(twi, &p_twi_config, NULL, NULL);
if (err_code != NRF_SUCCESS)
jsExceptionHere(JSET_INTERNALERROR, "I2C Initialisation Error %d\n", err_code);
else
nrf_drv_twi_enable(twi);
}
// nrf_drv_spi_init will set pins, but this ensures we know so can reset state later
if (jshIsPinValid(inf->pinSCL)) {
@ -1937,7 +2087,9 @@ void jshFlashErasePage(uint32_t addr) {
#ifdef SPIFLASH_BASE
if ((addr >= SPIFLASH_BASE) && (addr < (SPIFLASH_BASE+SPIFLASH_LENGTH))) {
addr &= 0xFFFFFF;
#ifdef SPIFLASH_SLEEP_CMD
if (!spiFlashAwake) spiFlashWakeUp();
#endif
// disable CS if jshFlashRead had left it set
if (spiFlashLastAddress) {
nrf_gpio_pin_set((uint32_t)pinInfo[SPIFLASH_PIN_CS].pin);
@ -1984,8 +2136,19 @@ void jshFlashRead(void * buf, uint32_t addr, uint32_t len) {
if ((addr >= SPIFLASH_BASE) && (addr < (SPIFLASH_BASE+SPIFLASH_LENGTH))) {
addr &= 0xFFFFFF;
//jsiConsolePrintf("SPI Read %d %d\n",addr,len);
#ifdef SPIFLASH_SLEEP_CMD
if (!spiFlashAwake) spiFlashWakeUp();
if (spiFlashLastAddress==0 || spiFlashLastAddress!=addr) {
#endif
if (
spiFlashLastAddress!=addr
#ifdef SPIFLASH_SHARED_SPI
/* with shared SPI someone might interrupt us and pull our CS pin high (also jshFlashWrite/Erase does this too) */
|| (nrf_gpio_pin_out_read((uint32_t)pinInfo[SPIFLASH_PIN_CS].pin))
#else
/* our internal state that no read is pending = CS is high */
|| spiFlashLastAddress==0
#endif
) {
nrf_gpio_pin_set((uint32_t)pinInfo[SPIFLASH_PIN_CS].pin);
unsigned char b[4];
// Read
@ -2012,7 +2175,9 @@ void jshFlashWrite(void * buf, uint32_t addr, uint32_t len) {
#ifdef SPIFLASH_BASE
if ((addr >= SPIFLASH_BASE) && (addr < (SPIFLASH_BASE+SPIFLASH_LENGTH))) {
addr &= 0xFFFFFF;
#ifdef SPIFLASH_SLEEP_CMD
if (!spiFlashAwake) spiFlashWakeUp();
#endif
// disable CS if jshFlashRead had left it set
if (spiFlashLastAddress) {
nrf_gpio_pin_set((uint32_t)pinInfo[SPIFLASH_PIN_CS].pin);
@ -2094,7 +2259,7 @@ void jshFlashWrite(void * buf, uint32_t addr, uint32_t len) {
uint32_t wordOffset = 0;
while (len>0 && !jspIsInterrupted()) {
uint32_t l = len;
#ifdef NRF51
#ifdef NRF51_SERIES
if (l>1024) l=1024; // max write size
#else
if (l>4096) l=4096; // max write size
@ -2147,10 +2312,12 @@ bool jshSleep(JsSysTime timeUntilWake) {
nrf_gpio_pin_set((uint32_t)pinInfo[SPIFLASH_PIN_CS].pin);
spiFlashLastAddress = 0;
}
#ifdef SPIFLASH_SLEEP_CMD
if (spiFlashAwake) {
spiFlashSleep();
spiFlashAwake = false;
}
#endif
#endif
if (timeUntilWake < JSSYSTIME_MAX) {
@ -2169,7 +2336,7 @@ bool jshSleep(JsSysTime timeUntilWake) {
}
jsiSetSleep(JSI_SLEEP_ASLEEP);
while (!hadEvent) {
#ifdef NRF52
#ifdef NRF52_SERIES
/*
* Clear FPU exceptions.
* Without this step, the FPU interrupt is marked as pending,
@ -2253,7 +2420,7 @@ JsVarFloat jshReadTemperature() {
// The voltage that a reading of 1 from `analogRead` actually represents
JsVarFloat jshReadVRef() {
#ifdef NRF52
#ifdef NRF52_SERIES
nrf_saadc_channel_config_t config;
config.acq_time = NRF_SAADC_ACQTIME_3US;
config.gain = NRF_SAADC_GAIN1_6; // 1/6 of input volts
@ -2264,12 +2431,21 @@ JsVarFloat jshReadVRef() {
config.resistor_p = NRF_SAADC_RESISTOR_DISABLED;
config.resistor_n = NRF_SAADC_RESISTOR_DISABLED;
// make reading
nrf_saadc_enable();
nrf_saadc_resolution_set(NRF_SAADC_RESOLUTION_14BIT);
nrf_saadc_channel_init(0, &config);
bool adcInUse = nrf_analog_read_start();
return 6.0 * (nrf_analog_read() * 0.6 / 16384.0);
// make reading
JsVarFloat f;
do {
nrf_analog_read_interrupted = false;
nrf_saadc_enable();
nrf_saadc_resolution_set(NRF_SAADC_RESOLUTION_14BIT);
nrf_saadc_channel_init(0, &config);
f = nrf_analog_read() * (6.0 * 0.6 / 16384.0);
} while (nrf_analog_read_interrupted);
nrf_analog_read_end(adcInUse);
return f;
#else
const nrf_adc_config_t nrf_adc_config = {
NRF_ADC_CONFIG_RES_10BIT,

View File

@ -42,9 +42,9 @@ STATIC_ASSERT(DFU_SIGNED_COMMAND_SIZE <= INIT_COMMAND_MAX_SIZE);
*
* @note If not set, this will default to 51 or 52 according to the architecture
*/
#if defined ( NRF51 ) && !defined(NRF_DFU_HW_VERSION)
#if defined ( NRF51_SERIES ) && !defined(NRF_DFU_HW_VERSION)
#define NRF_DFU_HW_VERSION (51)
#elif defined ( NRF52 ) && !defined(NRF_DFU_HW_VERSION)
#elif defined ( NRF52_SERIES ) && !defined(NRF_DFU_HW_VERSION)
#define NRF_DFU_HW_VERSION (52)
#else
#error No target set for HW version.
@ -312,9 +312,9 @@ static nrf_dfu_res_code_t dfu_handle_prevalidate(dfu_signed_command_t const * p_
}
m_firmware_size_req += p_init->bl_size;
// check that the size of the bootloader is not larger than the present one.
#if defined ( NRF51 )
#if defined ( NRF51_SERIES )
if (p_init->bl_size > BOOTLOADER_SETTINGS_ADDRESS - BOOTLOADER_START_ADDR)
#elif defined ( NRF52 )
#elif defined ( NRF52_SERIES )
if (p_init->bl_size > NRF_MBR_PARAMS_PAGE_ADDRESS - BOOTLOADER_START_ADDR)
#endif
{
@ -342,9 +342,9 @@ static nrf_dfu_res_code_t dfu_handle_prevalidate(dfu_signed_command_t const * p_
}
// check that the size of the bootloader is not larger than the present one.
#if defined ( NRF51 )
#if defined ( NRF51_SERIES )
if (p_init->bl_size > BOOTLOADER_SETTINGS_ADDRESS - BOOTLOADER_START_ADDR)
#elif defined ( NRF52 )
#elif defined ( NRF52_SERIES )
if (p_init->bl_size > NRF_MBR_PARAMS_PAGE_ADDRESS - BOOTLOADER_START_ADDR)
#endif
{
@ -502,7 +502,7 @@ static nrf_dfu_res_code_t nrf_dfu_postvalidate(dfu_init_command_t * p_init)
// Store the settings to flash and reset after that
while (nrf_dfu_settings_write(on_dfu_complete) == NRF_ERROR_BUSY)
{
#ifdef NRF52
#ifdef NRF52_SERIES
nrf_delay_us(100*1000);
#endif
nrf_dfu_wait();
@ -715,7 +715,7 @@ static nrf_dfu_res_code_t nrf_dfu_data_req(void * p_context, nrf_dfu_req_t * p_r
uint32_t const * p_write_addr;
nrf_dfu_res_code_t ret_val = NRF_DFU_RES_CODE_SUCCESS;
#ifndef NRF51
#ifndef NRF51_SERIES
if(p_req == NULL)
{
return NRF_DFU_RES_CODE_INVALID_PARAMETER;

View File

@ -1081,7 +1081,11 @@ static void jshResetPeripherals() {
}
}
// Initialise UART if we have a default console device on it
#ifdef USB
if (DEFAULT_CONSOLE_DEVICE != EV_USBSERIAL) {
#else
if (true) {
#endif
JshUSARTInfo inf;
jshUSARTInitInfo(&inf);
#ifdef DEFAULT_CONSOLE_TX_PIN

View File

@ -0,0 +1,51 @@
var g = Graphics.createArrayBuffer(16,16,8);
g.dump = _=>{
var s = "";
var b = new Uint8Array(g.buffer);
var n = 0;
for (var y=0;y<g.getHeight();y++) {
s+="\n";
for (var x=0;x<g.getWidth();x++)
s+= " .:-=+*#%@"[b[n++]];
}
return s;
}
g.print = _=>{
print("`"+g.dump()+"`");
}
var ok = true;
function SHOULD_BE(a) {
var b = g.dump();
if (a!=b) {
console.log("GOT :"+b+"\nSHOULD BE:"+a+"\n================");
ok = false;
}
}
g.clear();
g.setColor(9).setBgColor(0);
g.drawLine(1,1,14,8);
g.drawLineAA(1,1+4,14,8+4);
g.print();
SHOULD_BE(`
@
@@
@@
@@
== @@
=%- @@
+#: @@
.**: @
:**.
:#+
-%=
==
`);
result = ok;

18
tests/test_string_pad.js Normal file
View File

@ -0,0 +1,18 @@
function test(a,b) {
var ea = eval(a);
if (JSON.stringify(ea)!=JSON.stringify(b)) {
console.log(JSON.stringify(a)+" should be "+JSON.stringify(b)+", got "+JSON.stringify(ea))
result = 0;
}
}
result = 1;
test("'abc'.padStart(10); "," abc");
test("'abc'.padStart(10, 'foo'); ","foofoofabc");
test("'abc'.padStart(6,'123465'); ","123abc");
test("'abc'.padStart(8, '0'); ","00000abc");
test("'abc'.padStart(1); ","abc");
test("'abc'.padEnd(10); ", "abc ");
test("'abc'.padEnd(10, 'foo'); ", "abcfoofoof");
test("'abc'.padEnd(6, '123456'); ", "abc123");
test("'abc'.padEnd(1); ", "abc");