mirror of
https://github.com/espruino/Espruino.git
synced 2025-12-08 19:06:15 +00:00
Merge branch 'master' into SMAQ3
This commit is contained in:
commit
f6ca3b7fc4
9
.gitignore
vendored
9
.gitignore
vendored
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
|
||||
27
ChangeLog
27
ChangeLog
@ -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
|
||||
|
||||
2
Makefile
2
Makefile
@ -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
|
||||
|
||||
@ -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',
|
||||
|
||||
@ -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',
|
||||
|
||||
@ -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',
|
||||
|
||||
@ -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',
|
||||
]
|
||||
|
||||
@ -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
167
boards/MICROBIT2.py
Normal 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
|
||||
@ -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})
|
||||
]
|
||||
}
|
||||
};
|
||||
|
||||
@ -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'
|
||||
]
|
||||
}
|
||||
|
||||
@ -34,7 +34,8 @@ info = {
|
||||
'NFC',
|
||||
'NEOPIXEL',
|
||||
'PIXLJS',
|
||||
'CRYPTO','SHA256',
|
||||
'CRYPTO',
|
||||
#'SHA256',
|
||||
#'AES',
|
||||
'FILESYSTEM',
|
||||
'TERMINAL'
|
||||
|
||||
@ -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',
|
||||
|
||||
|
Before Width: | Height: | Size: 140 KiB After Width: | Height: | Size: 140 KiB |
BIN
boards/img/MICROBIT2.jpg
Normal file
BIN
boards/img/MICROBIT2.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 140 KiB |
@ -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
|
||||
---------------
|
||||
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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*/
|
||||
|
||||
@ -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`)
|
||||
*/
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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 );
|
||||
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -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);
|
||||
|
||||
17
libs/js/microbit/microbit_play.js
Normal file
17
libs/js/microbit/microbit_play.js
Normal 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);
|
||||
})
|
||||
10
libs/js/microbit/microbit_record.js
Normal file
10
libs/js/microbit/microbit_record.js
Normal 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);
|
||||
})
|
||||
@ -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() {
|
||||
}
|
||||
|
||||
|
||||
@ -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();
|
||||
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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 \
|
||||
|
||||
@ -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']")
|
||||
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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, "")
|
||||
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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));
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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))) {
|
||||
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -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
|
||||
|
||||
55
src/jsvar.c
55
src/jsvar.c
@ -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));
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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",
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -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:"")
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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).
|
||||
*/
|
||||
|
||||
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -50,7 +50,9 @@
|
||||
|
||||
/* GPIO */
|
||||
#define GPIO_PRESENT
|
||||
#ifndef GPIO_COUNT
|
||||
#define GPIO_COUNT 1
|
||||
#endif
|
||||
|
||||
#define P0_PIN_NUM 32
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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
|
||||
*
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -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 =====
|
||||
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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/latest/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,
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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
|
||||
|
||||
51
tests/test_graphics_drawLine.js
Normal file
51
tests/test_graphics_drawLine.js
Normal 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
18
tests/test_string_pad.js
Normal 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");
|
||||
Loading…
x
Reference in New Issue
Block a user