Fixed comflicts with master.

This commit is contained in:
Owen McAteer 2016-09-12 16:08:40 +02:00
commit cfa49a4dc7
63 changed files with 2852 additions and 1254 deletions

View File

@ -7,6 +7,15 @@
Make sure execution stops for native functions if there's an error when parsing arguments
NRF5x: remove setName and add functionality to setAdvertising, along with advertising interval
NRF5x: allow raw advertising data in setAdvertising
Add E.setPassword - allows Espruino console to be locked
Fix pin header numbering for BBC micro:bit (it changed for the production version) (fix #896)
Allow Magnetometer speed to be specified for Puck.js
Fix out of memory when appending a string to itself
Allow members of the same name as function arguments to be added to a function (fix #913)
Fix STM32F4 RTC stopping if reset during first 1 sec of boot, also fix Espruino WiFi board clock startup
Fix issue where native functions couldn't be replaced by non-native fns (fix #879)
If statements now return values (fix #909)
Fix >8 bit SPI when sending single elements with SPI.send (fix #897)
1v86 : Compile Telnet server into linux by default, Add '--telnet' command-line option to enable it
Fix lock 'leak' in Telnet when Telnet is turned off

157
Makefile
View File

@ -75,6 +75,7 @@
# # 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
# NO_COMPILE=1 # skips compiling and linking part, used to echo WRAPPERSOURCES only
ifndef GENDIR
GENDIR=$(shell pwd)/gen
@ -481,10 +482,11 @@ EMBEDDED=1
BOARD=NRF52832DK
OPTIMIZEFLAGS+=-O3
USE_BLUETOOTH=1
DEFINES += -DBOARD_PCA10040
USE_NET=1
USE_GRAPHICS=1
DEFINES += -DBOARD_PCA10040 -DPCA10040
# Uncomment to build Espruino to be transferred over DFU instead of flashed to the device.
#DFU_UPDATE_BUILD=1
# DFU_UPDATE_BUILD=1 # Uncomment this to build Espruino for a device firmware update over the air.
else ifdef PUCKJS
EMBEDDED=1
@ -497,6 +499,8 @@ USE_GRAPHICS=1
USE_FILESYSTEM=1
USE_CRYPTO=1
#USE_TLS=1
USE_NFC=1
USE_CUSTOM_BOOTLOADER=1
else ifdef LPC1768
EMBEDDED=1
@ -637,10 +641,10 @@ ifneq ("$(wildcard /usr/local/include/wiringPi.h)","")
USE_WIRINGPI=1
else
DEFINES+=-DSYSFS_GPIO_DIR="\"/sys/class/gpio\""
#$(info *************************************************************)
#$(info * WIRINGPI NOT FOUND, and you probably want it *)
#$(info * see http://wiringpi.com/download-and-install/ *)
#$(info *************************************************************)
$(info *************************************************************)
$(info * WIRINGPI NOT FOUND, and you probably want it *)
$(info * see http://wiringpi.com/download-and-install/ *)
$(info *************************************************************)
endif
else ifdef BEAGLEBONE
@ -1047,6 +1051,11 @@ ifeq ($(BOARD),MICROBIT)
WRAPPERSOURCES += libs/microbit/jswrap_microbit.c
endif
ifeq ($(BOARD),PUCKJS)
INCLUDE += -I$(ROOT)/libs/puckjs
WRAPPERSOURCES += libs/puckjs/jswrap_puck.c
endif
ifdef USE_CRYPTO
DEFINES += -DUSE_CRYPTO
INCLUDE += -I$(ROOT)/libs/crypto
@ -1306,13 +1315,17 @@ ifeq ($(FAMILY), NRF51)
SOFTDEVICE = $(NRF5X_SDK_PATH)/components/softdevice/s130/hex/s130_nrf51_2.0.0_softdevice.hex
LINKER_FILE = $(NRF5X_SDK_PATH)/../nrf5x_linkers/linker_nrf51_ble_espruino_$(LINKER_RAM).ld
ifdef USE_BOOTLOADER
ifdef USE_CUSTOM_BOOTLOADER
NRF_BOOTLOADER = $(BOOTLOADER_PROJ_NAME).hex
else
NRF_BOOTLOADER = $(ROOT)/targetlibs/nrf5x/nrf5_singlebank_bl_hex/nrf51_s130_singlebank_bl.hex
NFR_BL_START_ADDR = 0x3C000
endif
NFR_BL_START_ADDR = 0x3C000# see dfu_gcc_nrf51.ld
NRF_BOOTLOADER_SETTINGS = $(ROOT)/targetlibs/nrf5x/nrf5_singlebank_bl_hex/bootloader_settings_nrf51.hex # This file writes 0x3FC00 with 0x01 so we can flash the application with the bootloader.
LINKER_FILE = $(NRF5X_SDK_PATH)/../nrf5x_linkers/linker_nrf51_ble_espruino_$(LINKER_RAM).ld
else
LINKER_FILE = $(NRF5X_SDK_PATH)/../nrf5x_linkers/linker_nrf51_ble_espruino_$(LINKER_RAM).ld
endif
endif # FAMILY == NRF51
@ -1337,25 +1350,33 @@ ifeq ($(FAMILY), NRF52)
SOFTDEVICE = $(NRF5X_SDK_PATH)/components/softdevice/s132/hex/s132_nrf52_2.0.0_softdevice.hex
LINKER_FILE = $(NRF5X_SDK_PATH)/../nrf5x_linkers/linker_nrf52_ble_espruino.ld # TODO: Should have separate linkers like is done in nrf_bootloader branch.
ifdef USE_BOOTLOADER
ifdef USE_CUSTOM_BOOTLOADER
NRF_BOOTLOADER = $(BOOTLOADER_PROJ_NAME).hex
else
NRF_BOOTLOADER = $(ROOT)/targetlibs/nrf5x/nrf5_singlebank_bl_hex/nrf52_s132_singlebank_bl.hex
NFR_BL_START_ADDR = 0x7A000
endif
NFR_BL_START_ADDR = 0x79000 # see Makefile, dfu_gcc_nrf52.ld, linker_nrf52_ble_espruino_bootloader.ld and dfu_types.h
NRF_BOOTLOADER_SETTINGS = $(ROOT)/targetlibs/nrf5x/nrf5_singlebank_bl_hex/bootloader_settings_nrf52.hex # Writes address 0x7F000 with 0x01.
ifdef BOOTLOADER
# we're trying to compile the bootloader itself
LINKER_FILE = $(NRF5X_SDK_PATH)/../nrf5x_linkers/dfu_gcc_nrf52.ld
OPTIMIZEFLAGS=-Os # try to reduce bootloader size
else
LINKER_FILE = $(NRF5X_SDK_PATH)/../nrf5x_linkers/linker_nrf52_ble_espruino_bootloader.ld
endif
else
LINKER_FILE = $(NRF5X_SDK_PATH)/../nrf5x_linkers/linker_nrf52_ble_espruino.ld
endif
endif #FAMILY == NRF52
ifdef NFC
ifdef USE_NFC
DEFINES += -DUSE_NFC
INCLUDE += -I$(NRF5X_SDK_PATH)/components/drivers_nrf/clock
INCLUDE += -I$(NRF5X_SDK_PATH)/components/nfc/t2t_lib
INCLUDE += -I$(NRF5X_SDK_PATH)/components/nfc/ndef/uri
INCLUDE += -I$(NRF5X_SDK_PATH)/components/nfc/ndef/generic/message
INCLUDE += -I$(NRF5X_SDK_PATH)/components/nfc/ndef/generic/record
TARGETSOURCES += $(NRF5X_SDK_PATH)/components/libraries/util/app_util_platform.c
TARGETSOURCES += $(NRF5X_SDK_PATH)/components/drivers_nrf/clock/nrf_drv_clock.c
TARGETSOURCES += $(NRF5X_SDK_PATH)/components/nfc/ndef/uri/nfc_uri_msg.c
TARGETSOURCES += $(NRF5X_SDK_PATH)/components/nfc/ndef/uri/nfc_uri_rec.c
TARGETSOURCES += $(NRF5X_SDK_PATH)/components/nfc/ndef/generic/message/nfc_ndef_msg.c
@ -1441,7 +1462,6 @@ ifeq ($(FAMILY), EFM32GG)
endif #FAMILY == EFM32
ifdef NRF5X
# Just try and get rid of the compile warnings.
CFLAGS += -Wno-sign-conversion -Wno-conversion -Wno-unused-parameter -fomit-frame-pointer #this is for device manager in nordic sdk
DEFINES += -DBLUETOOTH -D$(BOARD)
@ -1455,10 +1475,19 @@ ifdef NRF5X
# These files are the Espruino HAL implementation.
INCLUDE += -I$(ROOT)/targets/nrf5x
SOURCES += \
targets/nrf5x/main.c \
targets/nrf5x/jshardware.c \
targets/nrf5x/nrf5x_utils.c
ifdef BOOTLOADER
BUILD_LINKER_FLAGS+=--bootloader
PROJ_NAME=$(BOOTLOADER_PROJ_NAME)
WRAPPERSOURCES =
SOURCES = \
targets/nrf5x_dfu/main.c \
targets/nrf5x_dfu/dfu_ble_svc.c
else
SOURCES += \
targets/nrf5x/main.c \
targets/nrf5x/jshardware.c \
targets/nrf5x/nrf5x_utils.c
endif
# Careful here.. All these includes and sources assume a SoftDevice. Not efficeint/clean if softdevice (ble) is not enabled...
INCLUDE += -I$(NRF5X_SDK_PATH)/components
@ -1486,7 +1515,9 @@ ifdef NRF5X
INCLUDE += -I$(NRF5X_SDK_PATH)/components/libraries/trace
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/hal/nrf_pwm
INCLUDE += -I$(NRF5X_SDK_PATH)/components/drivers_nrf/ppi
INCLUDE += -I$(NRF5X_SDK_PATH)/components/drivers_nrf/hal/nrf_pwm
INCLUDE += -I$(NRF5X_SDK_PATH)/components/drivers_nrf/clock
TARGETSOURCES += \
$(NRF5X_SDK_PATH)/components/libraries/util/app_error.c \
@ -1508,9 +1539,14 @@ ifdef NRF5X
$(NRF5X_SDK_PATH)/components/softdevice/common/softdevice_handler/softdevice_handler.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/hal/nrf_adc.c
$(NRF5X_SDK_PATH)/components/drivers_nrf/ppi/nrf_drv_ppi.c \
$(NRF5X_SDK_PATH)/components/drivers_nrf/hal/nrf_adc.c \
$(NRF5X_SDK_PATH)/components/drivers_nrf/clock/nrf_drv_clock.c
# $(NRF5X_SDK_PATH)/components/libraries/util/nrf_log.c
TARGETSOURCES += $(NRF5X_SDK_PATH)/components/libraries/util/app_util_platform.c
ifdef USE_BOOTLOADER
INCLUDE += -I$(NRF5X_SDK_PATH)/components/ble/device_manager
INCLUDE += -I$(NRF5X_SDK_PATH)/components/ble/ble_services/ble_dfu
@ -1520,6 +1556,40 @@ ifdef NRF5X
$(NRF5X_SDK_PATH)/components/ble/ble_services/ble_dfu/ble_dfu.c \
$(NRF5X_SDK_PATH)/components/libraries/bootloader_dfu/bootloader_util.c \
$(NRF5X_SDK_PATH)/components/libraries/bootloader_dfu/dfu_app_handler.c
ifdef BOOTLOADER
DEFINES += -DBOOTLOADER
INCLUDE += -I$(NRF5X_SDK_PATH)/components/libraries/crc16
INCLUDE += -I$(NRF5X_SDK_PATH)/components/libraries/scheduler
INCLUDE += -I$(NRF5X_SDK_PATH)/components/libraries/hci
INCLUDE += -I$(NRF5X_SDK_PATH)/components/libraries/bootloader_dfu/ble_transport
TARGETSOURCES = # Make sure we don't include existing files (thanks to pstorage)
TARGETSOURCES += $(NRF5X_SDK_PATH)/components/libraries/util/app_error.c
TARGETSOURCES += $(NRF5X_SDK_PATH)/components/libraries/scheduler/app_scheduler.c
TARGETSOURCES += $(NRF5X_SDK_PATH)/components/libraries/timer/app_timer.c
TARGETSOURCES += $(NRF5X_SDK_PATH)/components/libraries/timer/app_timer_appsh.c
TARGETSOURCES += $(NRF5X_SDK_PATH)/components/libraries/util/app_util_platform.c
TARGETSOURCES += $(NRF5X_SDK_PATH)/components/libraries/bootloader_dfu/bootloader.c
TARGETSOURCES += $(NRF5X_SDK_PATH)/components/libraries/bootloader_dfu/bootloader_settings.c
TARGETSOURCES += $(NRF5X_SDK_PATH)/components/libraries/bootloader_dfu/bootloader_util.c
TARGETSOURCES += $(NRF5X_SDK_PATH)/components/libraries/crc16/crc16.c
TARGETSOURCES += $(NRF5X_SDK_PATH)/components/libraries/bootloader_dfu/dfu_single_bank.c
TARGETSOURCES += $(NRF5X_SDK_PATH)/components/libraries/bootloader_dfu/dfu_init_template.c
TARGETSOURCES += $(NRF5X_SDK_PATH)/components/libraries/bootloader_dfu/dfu_transport_ble.c
TARGETSOURCES += $(NRF5X_SDK_PATH)/components/libraries/hci/hci_mem_pool.c
TARGETSOURCES += $(NRF5X_SDK_PATH)/components/libraries/util/nrf_assert.c
TARGETSOURCES += $(NRF5X_SDK_PATH)/components/drivers_nrf/delay/nrf_delay.c
TARGETSOURCES += $(NRF5X_SDK_PATH)/components/drivers_nrf/common/nrf_drv_common.c
TARGETSOURCES += $(NRF5X_SDK_PATH)/components/drivers_nrf/pstorage/pstorage_raw.c
TARGETSOURCES += $(NRF5X_SDK_PATH)/components/ble/common/ble_advdata.c
TARGETSOURCES += $(NRF5X_SDK_PATH)/components/ble/common/ble_conn_params.c
TARGETSOURCES += $(NRF5X_SDK_PATH)/components/ble/ble_services/ble_dfu/ble_dfu.c
TARGETSOURCES += $(NRF5X_SDK_PATH)/components/ble/common/ble_srv_common.c
TARGETSOURCES += $(NRF5X_SDK_PATH)/components/toolchain/system_nrf52.c
TARGETSOURCES += $(NRF5X_SDK_PATH)/components/softdevice/common/softdevice_handler/softdevice_handler.c
TARGETSOURCES += $(NRF5X_SDK_PATH)/components/softdevice/common/softdevice_handler/softdevice_handler_appsh.c
TARGETSOURCES += $(NRF5X_SDK_PATH)/components/drivers_nrf/clock/nrf_drv_clock.c
endif
endif
endif #NRF5X
@ -2004,14 +2074,20 @@ $(PROJ_NAME).hex: $(PROJ_NAME).elf
ifdef SOFTDEVICE # Shouldn't do this when we want to be able to perform DFU OTA!
ifdef USE_BOOTLOADER
ifdef DFU_UPDATE_BUILD
echo Not merging softdevice or bootloader with application
@echo Not merging softdevice or bootloader with application
scripts/nrfutil.exe dfu genpkg $(PROJ_NAME).zip --application $(PROJ_NAME).hex --application-version 0xff --dev-revision 1 --dev-type 1 --sd-req 0x81
else
echo Merging SoftDevice and Bootloader
scripts/hexmerge.py $(SOFTDEVICE) $(NRF_BOOTLOADER):$(NFR_BL_START_ADDR): $(PROJ_NAME).hex $(NRF_BOOTLOADER_SETTINGS) -o tmp.hex
ifdef BOOTLOADER
@echo Not merging anything with bootloader
else
@echo Merging SoftDevice and Bootloader
@echo FIXME - had to set --overlap=replace
scripts/hexmerge.py --overlap=replace $(SOFTDEVICE) $(NRF_BOOTLOADER) $(PROJ_NAME).hex $(NRF_BOOTLOADER_SETTINGS) -o tmp.hex
mv tmp.hex $(PROJ_NAME).hex
endif
endif
else
echo Merging SoftDevice
@echo Merging SoftDevice
scripts/hexmerge.py $(SOFTDEVICE) $(PROJ_NAME).hex -o tmp.hex
mv tmp.hex $(PROJ_NAME).hex
endif # USE_BOOTLOADER
@ -2028,7 +2104,11 @@ ifndef TRAVIS
bash scripts/check_size.sh $(PROJ_NAME).bin
endif
ifdef NRF5X
proj: $(PROJ_NAME).lst $(PROJ_NAME).hex
else
proj: $(PROJ_NAME).lst $(PROJ_NAME).bin $(PROJ_NAME).hex
endif
#proj: $(PROJ_NAME).lst $(PROJ_NAME).hex $(PROJ_NAME).srec $(PROJ_NAME).bin
@ -2036,7 +2116,7 @@ flash: all
ifdef USE_DFU
sudo dfu-util -a 0 -s 0x08000000 -D $(PROJ_NAME).bin
else ifdef OLIMEXINO_STM32_BOOTLOADER
echo Olimexino Serial bootloader
@echo Olimexino Serial bootloader
dfu-util -a1 -d 0x1EAF:0x0003 -D $(PROJ_NAME).bin
else ifdef NUCLEO
if [ -d "/media/$(USER)/NUCLEO" ]; then cp $(PROJ_NAME).bin /media/$(USER)/NUCLEO;sync; fi
@ -2048,21 +2128,21 @@ else ifdef NRF5X
if [ -d "/media/$(USER)/JLINK" ]; then cp $(PROJ_NAME).hex /media/$(USER)/JLINK;sync; fi
if [ -d "/media/JLINK" ]; then cp $(PROJ_NAME).hex /media/JLINK;sync; fi
else
echo ST-LINK flash
@echo ST-LINK flash
st-flash --reset write $(PROJ_NAME).bin $(BASEADDRESS)
endif
serialflash: all
echo STM32 inbuilt serial bootloader, set BOOT0=1, BOOT1=0
@echo STM32 inbuilt serial bootloader, set BOOT0=1, BOOT1=0
python scripts/stm32loader.py -b 460800 -a $(BASEADDRESS) -ew $(STM32LOADER_FLAGS) $(PROJ_NAME).bin
# python scripts/stm32loader.py -b 460800 -a $(BASEADDRESS) -ewv $(STM32LOADER_FLAGS) $(PROJ_NAME).bin
gdb:
echo "target extended-remote :4242" > gdbinit
echo "file $(PROJ_NAME).elf" >> gdbinit
@echo "target extended-remote :4242" > gdbinit
@echo "file $(PROJ_NAME).elf" >> gdbinit
#echo "load" >> gdbinit
echo "break main" >> gdbinit
echo "break HardFault_Handler" >> gdbinit
@echo "break main" >> gdbinit
@echo "break HardFault_Handler" >> gdbinit
$(GDB) -x gdbinit
rm gdbinit
endif # ---------------------------------------------------
@ -2082,3 +2162,8 @@ clean:
$(Q)rm -f $(PROJ_NAME).bin
$(Q)rm -f $(PROJ_NAME).srec
$(Q)rm -f $(PROJ_NAME).lst
# start make like this "make varsonly" to get all variables created and used during make process without compiling
# this helps to better understand linking, or to find oddities
varsonly:
$(foreach v, $(.VARIABLES), $(info $(v) = $($(v))))

View File

@ -43,7 +43,7 @@ info = {
chip = {
'part' : "STM32F411CEU6",
'family' : "STM32F4",
'package' : "UQFN48",
'package' : "UQFN48",
'ram' : 96,
'flash' : 512,
'speed' : 100,
@ -66,31 +66,35 @@ devices = {
'pin_out' : 'H1' }, # checked
'OSC_RTC' : { 'pin_in' : 'C14', # checked
'pin_out' : 'C15' }, # checked
'BTN1' : { 'pin' : 'C13', 'pinstate' : 'IN_PULLDOWN' },
'LED1' : { 'pin' : 'B2' },
'BTN1' : { 'pin' : 'C13', 'pinstate' : 'IN_PULLDOWN' },
'LED1' : { 'pin' : 'B2' },
'LED2' : { 'pin' : 'B12' },
'USB' : { 'pin_vsense' : 'A9',
'pin_dm' : 'A11', # checked
'pin_dp' : 'A12' }, # checked
'JTAG' : {
'pin_MS' : 'A13',
'pin_CK' : 'A14',
# 'pin_DI' : 'A15'
'pin_CK' : 'A14',
# 'pin_DI' : 'A15'
},
'ESP8266' : { 'pin_rx' : 'A2',
'pin_tx' : 'A3',
'pin_tx' : 'A3',
'pin_cts' : 'A15',
'pin_ch_pd' : 'A14',
'pin_gpio0' : 'A13',
},
};
def rev(x):
x.reverse();
return x;
# left-right, or top-bottom order
board = {
'top' : [ 'B15', 'B14', 'B13', 'B10', 'B1', 'A7', 'A6', 'A5', 'A4', 'A1', 'A0' ],
'bottom' : [ 'GND', 'VBAT', '3.3', 'B3', 'B4', 'B5', 'B6', 'B7','B8', 'B9', 'B0'],
'left' : rev([ 'B15', 'B14', 'B13', 'B10', 'B1', 'A7', 'A6', 'A5', 'A4', 'A1', 'A0' ]),
'right' : rev([ 'GND', 'VBAT', '3.3', 'B3', 'B4', 'B5', 'B6', 'B7','B8', 'B9', 'B0']),
'right' : ['A10','A8'],
'left2' : ['A10','A8'],
'_notes' : {
'A2' : 'ESP8266 RX',
'A3' : 'ESP8266 TX',
@ -101,32 +105,30 @@ board = {
};
board["_css"] = """
#board {
width: 550px;
height: 272px;
top: 300px;
left : 100px;
width: 371px;
height: 450px;
top: 25px;
left : 200px;
background-image: url(img/ESPRUINOWIFI.png);
}
#boardcontainer {
height: 800px;
height: 500px;
}
#top {
bottom: 253px;
left: 194px;
#left {
top: 10px;
right: 370px;
}
#bottom {
top: 255px;
left: 192px;
#right {
top: 10px;
left: 370px;
}
#right {
top: 60px;
left: 540px;
#left2 {
top: 380px;
left: 60px;
}
.toppin { width: 32px; }
.bottompin { width: 32px; }
.rightpin { height: 17px; }
.leftpin { height: 39px; }
.rightpin { height: 39px; }
.left2pin { height: 39px; }
""";

View File

@ -55,20 +55,8 @@ chip = {
};
devices = {
'BTN1' : { 'pin' : 'D4' }, # 'P0_17'
'BTN1' : { 'pin' : 'D5' }, # 'P0_17'
'BTN2' : { 'pin' : 'D11' }, # 'P0_26'
'LED_COL1' : { 'pin': 'D4' },
'LED_COL2' : { 'pin': 'D5' },
'LED_COL3' : { 'pin': 'D6' },
'LED_COL4' : { 'pin': 'D7' },
'LED_COL5' : { 'pin': 'D8' },
'LED_COL6' : { 'pin': 'D9' },
'LED_COL7' : { 'pin': 'D10' },
'LED_COL8' : { 'pin': 'D11' },
'LED_COL9' : { 'pin': 'D12' },
'LED_ROW1' : { 'pin': 'D13' },
'LED_ROW2' : { 'pin': 'D14' },
'LED_ROW3' : { 'pin': 'D15' },
};
# left-right, or top-bottom order
@ -77,18 +65,12 @@ board = {
'D13','D14','D15','D16','3.3','','3.3','','3.3','D19','D20','GND','','GND','','GND' ],
'_hide_not_on_connectors' : True,
'_notes' : {
'D4' : "LED Matrix Column 1",
'D5' : "LED Matrix Column 2",
'D6' : "LED Matrix Column 3",
'D7' : "LED Matrix Column 4",
'D8' : "LED Matrix Column 5",
'D9' : "LED Matrix Column 6",
'D10' : "LED Matrix Column 7",
'D11' : "LED Matrix Column 8",
'D12' : "LED Matrix Column 9",
'D13' : "LED Matrix Row 1",
'D14' : "LED Matrix Row 2",
'D15' : "LED Matrix Row 3"
'D3' : "LED Col 1",
'D4' : "LED Col 2",
'D6' : "LED Col 9",
'D7' : "LED Col 8",
'D9' : "LED Col 7",
'D10' : "LED Col 3"
}
};
board["_css"] = """
@ -117,16 +99,16 @@ board["_css"] = """
def get_pins():
pins = [
{ "name":"PD0", "sortingname":"D00", "port":"D", "num":"3", "functions":{ "ADC1_IN4":0 }, "csv":{} },
{ "name":"PD0", "sortingname":"D00", "port":"D", "num":"1", "functions":{ "ADC1_IN4":0 }, "csv":{} },
{ "name":"PD1", "sortingname":"D01", "port":"D", "num":"2", "functions":{ "ADC1_IN3":0 }, "csv":{} },
{ "name":"PD2", "sortingname":"D02", "port":"D", "num":"1", "functions":{ "ADC1_IN2":0 }, "csv":{} },
{ "name":"PD3", "sortingname":"D03", "port":"D", "num":"4", "functions":{ "ADC1_IN5":0 }, "csv":{} }, # LED col 1
{ "name":"PD4", "sortingname":"D04", "port":"D", "num":"17", "functions":{}, "csv":{} }, # BTNA
{ "name":"PD5", "sortingname":"D05", "port":"D", "num":"5", "functions":{ "ADC1_IN6":0 }, "csv":{} }, # LED col 2
{ "name":"PD6", "sortingname":"D06", "port":"D", "num":"14", "functions":{}, "csv":{} }, # LED row 2
{ "name":"PD7", "sortingname":"D07", "port":"D", "num":"13", "functions":{}, "csv":{} }, # LED row 1
{ "name":"PD8", "sortingname":"D08", "port":"D", "num":"18", "functions":{}, "csv":{} },
{ "name":"PD9", "sortingname":"D09", "port":"D", "num":"15", "functions":{}, "csv":{} }, # LED row 3
{ "name":"PD2", "sortingname":"D02", "port":"D", "num":"3", "functions":{ "ADC1_IN2":0 }, "csv":{} },
{ "name":"PD3", "sortingname":"D03", "port":"D", "num":"4", "functions":{ "ADC1_IN5":0 }, "csv":{} }, # LED col 1
{ "name":"PD4", "sortingname":"D04", "port":"D", "num":"5", "functions":{}, "csv":{} }, # BTNA
{ "name":"PD5", "sortingname":"D05", "port":"D", "num":"17", "functions":{ "ADC1_IN6":0 }, "csv":{} }, # LED col 2
{ "name":"PD6", "sortingname":"D06", "port":"D", "num":"12", "functions":{}, "csv":{} }, # LED row 2
{ "name":"PD7", "sortingname":"D07", "port":"D", "num":"11", "functions":{}, "csv":{} }, # LED row 1
{ "name":"PD8", "sortingname":"D08", "port":"D", "num":"18", "functions":{}, "csv":{} },
{ "name":"PD9", "sortingname":"D09", "port":"D", "num":"10", "functions":{}, "csv":{} }, # LED row 3
{ "name":"PD10", "sortingname":"D10", "port":"D", "num":"6", "functions":{ "ADC1_IN7":0 }, "csv":{} }, # LED col 3
{ "name":"PD11", "sortingname":"D11", "port":"D", "num":"26", "functions":{}, "csv":{} }, # BTNB
{ "name":"PD12", "sortingname":"D12", "port":"D", "num":"20", "functions":{}, "csv":{} },
@ -134,8 +116,8 @@ def get_pins():
{ "name":"PD14", "sortingname":"D14", "port":"D", "num":"22", "functions":{ "SPI1_MISO":0 }, "csv":{} },
{ "name":"PD15", "sortingname":"D15", "port":"D", "num":"21", "functions":{ "SPI1_MOSI":0 }, "csv":{} },
{ "name":"PD16", "sortingname":"D16", "port":"D", "num":"16", "functions":{}, "csv":{} },
{ "name":"PD17", "sortingname":"D17", "port":"D", "num":"31", "functions":{}, "csv":{} }, # FIXME 3.3v
{ "name":"PD18", "sortingname":"D18", "port":"D", "num":"31", "functions":{}, "csv":{} }, # FIXME 3.3v
{ "name":"PD17", "sortingname":"D17", "port":"D", "num":"31", "functions":{}, "csv":{} }, # FIXME 3.3v
{ "name":"PD18", "sortingname":"D18", "port":"D", "num":"31", "functions":{}, "csv":{} }, # FIXME 3.3v
{ "name":"PD19", "sortingname":"D19", "port":"D", "num":"0", "functions":{ "I2C1_SCL":0, "ADC1_IN0":0 }, "csv":{} },
{ "name":"PD20", "sortingname":"D20", "port":"D", "num":"30", "functions":{ "I2C1_SDA":0 }, "csv":{} },
{ "name":"PH0", "sortingname":"H0", "port":"D", "num":"24", "functions":{}, "csv":{} },

View File

@ -49,7 +49,7 @@ chip = {
'saved_code' : {
'address' : ((256 - 3) * 1024),
'page_size' : 1024,
'pages' : 0,
'pages' : 3,
'flash_available' : (256 - 108 - 16) # total flash pages - softdevice - bootloader
}
};

View File

@ -48,7 +48,7 @@ chip = {
'saved_code' : {
'address' : ((256 - 3) * 1024),
'page_size' : 1024,
'pages' : 0,
'pages' : 3,
'flash_available' : (256 - 108 - 16) # total flash pages - softdevice - bootloader
}
};

View File

@ -25,7 +25,7 @@ info = {
'default_console_baudrate' : "9600",
# Number of variables can be WAY higher on this board
'variables' : 2040, # How many variables are allocated for Espruino to use. RAM will be overflowed if this number is too high and code won't compile.
'bootloader' : 1,
# 'bootloader' : 1,
'binary_name' : 'espruino_%v_nrf52832.bin',
'build' : {
'defines' : [

View File

@ -38,7 +38,7 @@ chip = {
'ram' : 96, # 0x0001 8000 long, from 0x2000 0000 to 0x2001 7FFF
'flash' : 512, # 0x0008 0000 long, from 0x0800 0000 to 0x0807 FFFF
'speed' : 84,
'usart' : 3,
'usart' : 6,
'spi' : 4,
'i2c' : 3,
'adc' : 1,

View File

@ -38,7 +38,7 @@ chip = {
'ram' : 128, # 0x0001 8000 long, from 0x2000 0000 to 0x2001 7FFF
'flash' : 512, # 0x0008 0000 long, from 0x0800 0000 to 0x0807 FFFF
'speed' : 100,
'usart' : 3,
'usart' : 6,
'spi' : 4,
'i2c' : 3,
'adc' : 1,

View File

@ -23,7 +23,8 @@ info = {
'default_console_rx' : "D29",
'default_console_baudrate' : "9600",
# Number of variables can be WAY higher on this board
'variables' : 1020, # How many variables are allocated for Espruino to use. RAM will be overflowed if this number is too high and code won't compile.
'variables' : 2000, # How many variables are allocated for Espruino to use. RAM will be overflowed if this number is too high and code won't compile.
'bootloader' : 1,
'binary_name' : 'espruino_%v_puckjs.bin',
'build' : {
'defines' : [
@ -39,16 +40,16 @@ chip = {
'ram' : 64,
'flash' : 512,
'speed' : 64,
'usart' : 1,
'usart' : 1,
'spi' : 3,
'i2c' : 2,
'adc' : 1,
'dac' : 0,
'saved_code' : {
'address' : ((128 - 3) * 4096),
'address' : ((121 - 3) * 4096), # Bootloader takes pages 121-127
'page_size' : 4096,
'pages' : 3,
'flash_available' : (512 - 124 - 12) # Softdevice uses 31 plages of flash. Each page is 4 kb.
'flash_available' : 512 - ((31 + 7 + 3)*4) # Softdevice uses 31 pages of flash, bootloader 7, code 3. Each page is 4 kb.
},
};
@ -56,15 +57,17 @@ devices = {
'LED1' : { 'pin' : 'D5' },
'LED2' : { 'pin' : 'D4' },
'LED3' : { 'pin' : 'D3' },
'LED4' : { 'pin' : 'D25', 'pin2' : 'D26' },
'BTN1' : { 'pin' : 'D0', 'pinstate' : 'IN_PULLDOWN' }
# CAPSENSE D8
'IR' : { 'pin_anode' : 'D26', 'pin_cathode' : 'D25' },
'BTN1' : { 'pin' : 'D0', 'pinstate' : 'IN_PULLDOWN' },
'CAPSENSE' : { 'pin_rx' : 'D11', 'pin_tx' : 'D12' }
# NFC D9/D10
};
# left-right, or top-bottom order
board = {
'left' : [ 'PD28', 'PD29', 'PD30', 'PD31'],
'right' : [ 'GND', '3V', 'D4', 'D5' ],
'right' : [ 'GND', '3V', 'D2', 'D1' ],
};
def get_pins():

BIN
boards/img/ESPRUINOWIFI.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 172 KiB

View File

@ -46,7 +46,14 @@ You can add more files here if you need. It's up to you!
## Modify the `Makefile`
Go to line [606](https://github.com/espruino/Espruino/blob/master/Makefile#L606) and append
Find the text
```
# ---------------------------------------------------------------------------------
# When adding stuff here, also remember build_pininfo, platform_config.h, jshardware.c
# TODO: Load more of this out of the BOARDNAME.py files if at all possible (see next section)
# ---------------------------------------------------------------------------------
```
and add those two lines just before it
```make
INCLUDE += -I$(ROOT)/libs/hello

View File

@ -13,6 +13,7 @@
#include "jswrap_bluetooth.h"
#include "jsinteractive.h"
#include "jsdevices.h"
#include "nrf5x_utils.h"
#include <stdint.h>
#include <string.h>
@ -33,6 +34,11 @@
bool nfcEnabled = false;
#endif
#undef USE_BOOTLOADER // FIXME - this now errors with 0x4001 - not sure why
//... but then IMO we don't want to be able to enable DFU directly from BLE
//... much better to
#ifdef USE_BOOTLOADER
#include "device_manager.h"
#include "pstorage.h"
@ -115,9 +121,10 @@ typedef enum {
BLE_NONE = 0,
BLE_IS_SENDING = 1,
BLE_IS_SCANNING = 2,
BLE_IS_ADVERTISING = 4,
} BLEStatus;
static volatile BLEStatus bleStatus;
static volatile BLEStatus bleStatus = 0;
#define BLE_SCAN_EVENT JS_EVENT_PREFIX"blescan"
#define BLE_WRITE_EVENT JS_EVENT_PREFIX"blew"
@ -134,7 +141,7 @@ bool jswrap_nrf_transmit_string();
"generate" : "jswrap_nrf_idle"
}*/
bool jswrap_nrf_idle() {
return jswrap_nrf_transmit_string()>0; // return true if we sent anything
return false;
}
/*JSON{
@ -234,7 +241,7 @@ void ble_app_error_handler(uint32_t error_code, uint32_t line_num, const uint8_t
*
* @details This function will be called in case of an assert in the SoftDevice.
*
* @warning This handler is an example only and does not fit a final product. You need to analyse
* @warning This handler is an example only and does not fit a final product. You need to analyse
* how your product is supposed to react in case of Assert.
* @warning On assert from the SoftDevice, the system can only recover on reset.
*
@ -246,11 +253,17 @@ void assert_nrf_callback(uint16_t line_num, const uint8_t * p_file_name) {
}
void app_error_fault_handler(uint32_t id, uint32_t pc, uint32_t info) {
ble_app_error_handler(id, pc, 0);
if (id == NRF_FAULT_ID_SDK_ERROR) {
error_info_t *error_info = (error_info_t *)info;
ble_app_error_handler(error_info->err_code, error_info->line_num, error_info->p_file_name);
} else
ble_app_error_handler(id, pc, 0);
}
void advertising_start(void) {
uint32_t err_code = 0;
if (bleStatus & BLE_IS_ADVERTISING) return;
// Actually start advertising
ble_gap_adv_params_t adv_params;
memset(&adv_params, 0, sizeof(adv_params));
@ -262,14 +275,17 @@ void advertising_start(void) {
adv_params.interval = advertising_interval;
err_code = sd_ble_gap_adv_start(&adv_params);
APP_ERROR_CHECK(err_code);
// APP_ERROR_CHECK(err_code); // don't bother checking
bleStatus |= BLE_IS_ADVERTISING;
}
static void advertising_stop(void) {
uint32_t err_code;
uint32_t err_code;
err_code = sd_ble_gap_adv_stop();
APP_ERROR_CHECK(err_code);
if (!(bleStatus & BLE_IS_ADVERTISING)) return;
err_code = sd_ble_gap_adv_stop();
APP_ERROR_CHECK(err_code);
bleStatus &= ~BLE_IS_ADVERTISING;
}
#ifdef USE_BOOTLOADER
@ -359,7 +375,7 @@ static void reset_prepare(void)
/**@brief Function for the GAP initialization.
*
* @details This function will set up all the necessary GAP (Generic Access Profile) parameters of
* @details This function will set up all the necessary GAP (Generic Access Profile) parameters of
* the device. It also sets the permissions and appearance.
*/
static void gap_params_init(void)
@ -439,7 +455,36 @@ bool jswrap_nrf_transmit_string() {
}
return idx>0;
}
/**@snippet [Handling the data received over BLE] */
uint32_t radio_notification_init(uint32_t irq_priority, uint8_t notification_type, uint8_t notification_distance)
{
uint32_t err_code;
err_code = sd_nvic_ClearPendingIRQ(SWI1_IRQn);
if (err_code != NRF_SUCCESS)
{
return err_code;
}
err_code = sd_nvic_SetPriority(SWI1_IRQn, irq_priority);
if (err_code != NRF_SUCCESS)
{
return err_code;
}
err_code = sd_nvic_EnableIRQ(SWI1_IRQn);
if (err_code != NRF_SUCCESS)
{
return err_code;
}
// Configure the event
return sd_radio_notification_cfg_set(notification_type, notification_distance);
}
void SWI1_IRQHandler(bool radio_evt) {
jswrap_nrf_transmit_string();
}
/**@brief Function for initializing services that will be used by the application.
@ -448,11 +493,11 @@ static void services_init(void)
{
uint32_t err_code;
ble_nus_init_t nus_init;
memset(&nus_init, 0, sizeof(nus_init));
nus_init.data_handler = nus_data_handler;
err_code = ble_nus_init(&m_nus, &nus_init);
APP_ERROR_CHECK(err_code);
@ -489,7 +534,7 @@ static void services_init(void)
*/
static void on_conn_params_evt(ble_conn_params_evt_t * p_evt) {
uint32_t err_code;
if(p_evt->evt_type == BLE_CONN_PARAMS_EVT_FAILED) {
err_code = sd_ble_gap_disconnect(m_conn_handle, BLE_HCI_CONN_INTERVAL_UNACCEPTABLE);
APP_ERROR_CHECK(err_code);
@ -511,7 +556,7 @@ static void conn_params_error_handler(uint32_t nrf_error) {
static void conn_params_init(void) {
uint32_t err_code;
ble_conn_params_init_t cp_init;
memset(&cp_init, 0, sizeof(cp_init));
cp_init.p_conn_params = NULL;
@ -522,7 +567,7 @@ static void conn_params_init(void) {
cp_init.disconnect_on_fail = false;
cp_init.evt_handler = on_conn_params_evt;
cp_init.error_handler = conn_params_error_handler;
err_code = ble_conn_params_init(&cp_init);
APP_ERROR_CHECK(err_code);
}
@ -559,20 +604,20 @@ JsVar *bleAddrToStr(ble_gap_addr_t addr) {
addr.addr[0]);
}
/* Convert a JsVar to a UUID - true if handled
/* Convert a JsVar to a UUID - 0 if handled, a string showing the error if not
* Converts:
* Integers -> 16 bit BLE UUID
* "0xABCD" -> 16 bit BLE UUID
* "ABCDABCD-ABCD-ABCD-ABCD-ABCDABCDABCD" -> vendor specific BLE UUID
*/
bool bleVarToUUID(ble_uuid_t *uuid, JsVar *v) {
const char *bleVarToUUID(ble_uuid_t *uuid, JsVar *v) {
if (jsvIsInt(v)) {
JsVarInt i = jsvGetInteger(v);
if (i<0 || i>0xFFFF) return false;
if (i<0 || i>0xFFFF) return "Integer out of range";
BLE_UUID_BLE_ASSIGN((*uuid), i);
return true;
return 0;
}
if (!jsvIsString(v)) return false;
if (!jsvIsString(v)) return "Not a String or Integer";
unsigned int expectedLength = 16;
unsigned int startIdx = 0;
if (jsvIsStringEqualOrStartsWith(v,"0x",true)) {
@ -595,29 +640,33 @@ bool bleVarToUUID(ble_uuid_t *uuid, JsVar *v) {
jsvStringIteratorNext(&it);
if (hi<0 || lo<0) {
jsvStringIteratorFree(&it);
return false; // not hex chars
return "String should only contain hex characters and dashes";
}
data[expectedLength - (dataLen+1)] = (unsigned)((hi<<4) | lo);
dataLen++;
}
if (jsvStringIteratorHasChar(&it)) dataLen++; // make sure we fail is string too long
jsvStringIteratorFree(&it);
if (dataLen!=expectedLength) return false;
if (dataLen!=expectedLength) {
return "Not the right length (16)";
}
// now try and decode the UUID
uint32_t err_code;
err_code = sd_ble_uuid_decode(dataLen, data, uuid);
// Not found - add it
if (err_code == NRF_ERROR_NOT_FOUND) {
uuid->uuid = ((data[12]<<8) | data[13]);
uuid->uuid = ((data[13]<<8) | data[12]);
data[12] = 0; // these 2 not needed, but let's zero them anyway
data[13] = 0;
err_code = sd_ble_uuid_vs_add((ble_uuid128_t*)data, &uuid->type);
if (err_code == NRF_ERROR_NO_MEM)
return "Too many custom UUIDs already";
}
return !err_code;
return err_code ? "BLE device error" : 0;
}
bool bleVarToUUIDAndUnLock(ble_uuid_t *uuid, JsVar *v) {
bool r = bleVarToUUID(uuid, v);
const char *bleVarToUUIDAndUnLock(ble_uuid_t *uuid, JsVar *v) {
const char *r = bleVarToUUID(uuid, v);
jsvUnLock(v);
return r;
}
@ -645,7 +694,7 @@ static void on_ble_evt(ble_evt_t * p_ble_evt)
{
uint32_t err_code;
//jsiConsolePrintf("\n[%d]\n", p_ble_evt->header.evt_id);
switch (p_ble_evt->header.evt_id) {
case BLE_GAP_EVT_TIMEOUT:
// the timeout for sd_ble_gap_adv_start expired - kick it off again
@ -656,6 +705,7 @@ static void on_ble_evt(ble_evt_t * p_ble_evt)
if (p_ble_evt->evt.gap_evt.params.connected.role == BLE_GAP_ROLE_PERIPH) {
m_conn_handle = p_ble_evt->evt.gap_evt.conn_handle;
bleStatus &= ~BLE_IS_SENDING; // reset state - just in case
bleStatus &= ~BLE_IS_ADVERTISING; // we're not advertising now we're connected
if (!jsiIsConsoleDeviceForced()) jsiSetConsoleDevice(EV_BLUETOOTH, false);
jshHadEvent();
}
@ -693,7 +743,6 @@ static void on_ble_evt(ble_evt_t * p_ble_evt)
case BLE_EVT_TX_COMPLETE:
// UART Transmit finished - we can try and send more data
bleStatus &= ~BLE_IS_SENDING;
jswrap_nrf_transmit_string();
break;
case BLE_GAP_EVT_ADV_REPORT: {
@ -808,10 +857,10 @@ static void on_ble_evt(ble_evt_t * p_ble_evt)
}
/**@brief Function for dispatching a SoftDevice event to all modules with a SoftDevice
/**@brief Function for dispatching a SoftDevice event to all modules with a SoftDevice
* event handler.
*
* @details This function is called from the SoftDevice event interrupt handler after a
* @details This function is called from the SoftDevice event interrupt handler after a
* SoftDevice event has been received.
*
* @param[in] p_ble_evt SoftDevice event.
@ -848,7 +897,7 @@ static void sys_evt_dispatch(uint32_t sys_evt)
#ifdef USE_NFC
/// Sigh - NFC has lots of these, so we need to define it to build
void log_uart_printf(const char * format_msg, ...) {
jsiConsolePrintf("NFC: %s\n", format_msg);
// jsiConsolePrintf("NFC: %s\n", format_msg);
}
/**
@ -880,7 +929,7 @@ void nfc_callback(void *context, NfcEvent event, const char *data, size_t dataLe
static void ble_stack_init(void)
{
uint32_t err_code;
// TODO: enable if we're on a device with 32kHz xtal
/*nrf_clock_lf_cfg_t clock_lf_cfg = {
.source = NRF_CLOCK_LF_SRC_XTAL,
@ -895,15 +944,20 @@ static void ble_stack_init(void)
// Initialize SoftDevice.
SOFTDEVICE_HANDLER_INIT(&clock_lf_cfg, false);
ble_enable_params_t ble_enable_params;
err_code = softdevice_enable_get_default_config(CENTRAL_LINK_COUNT,
PERIPHERAL_LINK_COUNT,
&ble_enable_params);
APP_ERROR_CHECK(err_code);
int softdevice_extra_ram_hack = 0;
ble_enable_params.common_enable_params.vs_uuid_count = 3;
softdevice_extra_ram_hack += 256; // now we have more UUIDs, SD needs more RAM
#ifdef USE_BOOTLOADER
ble_enable_params.common_enable_params.vs_uuid_count = 2;
ble_enable_params.gatts_enable_params.service_changed = 1;
#endif
@ -911,15 +965,15 @@ static void ble_stack_init(void)
CHECK_RAM_START_ADDR(CENTRAL_LINK_COUNT, PERIPHERAL_LINK_COUNT);
extern int __data_start__; // should be 'void', but 'int' avoids warnings
if (IDEAL_RAM_START_ADDRESS(CENTRAL_LINK_COUNT, PERIPHERAL_LINK_COUNT) != (uint32_t)&__data_start__) {
jsiConsolePrintf("WARNING: BLE RAM start address not correct - is 0x%x, should be 0x%x\n\n", (uint32_t)&__data_start__, IDEAL_RAM_START_ADDRESS(CENTRAL_LINK_COUNT, PERIPHERAL_LINK_COUNT));
if (IDEAL_RAM_START_ADDRESS(CENTRAL_LINK_COUNT, PERIPHERAL_LINK_COUNT)+softdevice_extra_ram_hack != (uint32_t)&__data_start__) {
jsiConsolePrintf("WARNING: BLE RAM start address not correct - is 0x%x, should be 0x%x\n\n", (uint32_t)&__data_start__, IDEAL_RAM_START_ADDRESS(CENTRAL_LINK_COUNT, PERIPHERAL_LINK_COUNT)+softdevice_extra_ram_hack);
jshTransmitFlush();
}
// Enable BLE stack.
err_code = softdevice_enable(&ble_enable_params);
APP_ERROR_CHECK(err_code);
// Subscribe for BLE events.
err_code = softdevice_ble_evt_handler_set(ble_evt_dispatch);
APP_ERROR_CHECK(err_code);
@ -1035,7 +1089,7 @@ void jswrap_nrf_bluetooth_init(void) {
// Initialize.
APP_TIMER_INIT(APP_TIMER_PRESCALER, APP_TIMER_OP_QUEUE_SIZE, false);
ble_stack_init();
#ifdef USE_BOOTLOADER
bool erase_bonds = false;
device_manager_init(erase_bonds);
@ -1047,6 +1101,15 @@ void jswrap_nrf_bluetooth_init(void) {
conn_params_init();
jswrap_nrf_bluetooth_wake();
radio_notification_init(
#ifdef NRF52
6, /* IRQ Priority - Must be 6 on nRF52. 7 doesn't work */
#else
3, /* IRQ Priority - nRF51 has different IRQ structure */
#endif
NRF_RADIO_NOTIFICATION_TYPE_INT_ON_INACTIVE,
NRF_RADIO_NOTIFICATION_DISTANCE_5500US);
}
/*JSON{
@ -1068,7 +1131,8 @@ void jswrap_nrf_bluetooth_sleep(void) {
}
// Stop advertising
err_code = sd_ble_gap_adv_stop();
if (bleStatus & BLE_IS_ADVERTISING)
advertising_stop();
NRF_RADIO->TASKS_DISABLE = (1UL);
}
@ -1150,7 +1214,7 @@ Or you could report the current temperature:
```
setInterval(function() {
NRF.setAdvertising({
0x1809 : [Math,round(E.getTemperature())]
0x1809 : [Math.round(E.getTemperature())]
});
}, 30000);
```
@ -1189,7 +1253,8 @@ void jswrap_nrf_bluetooth_setAdvertising(JsVar *data, JsVar *options) {
uint32_t err_code;
ble_advdata_t advdata;
setup_advdata(&advdata);
bool bleChanged;
bool bleChanged = false;
bool isAdvertising = bleStatus & BLE_IS_ADVERTISING;
if (jsvIsObject(options)) {
JsVar *v;
@ -1242,12 +1307,12 @@ void jswrap_nrf_bluetooth_setAdvertising(JsVar *data, JsVar *options) {
return;
}
if (bleChanged)
if (bleChanged && isAdvertising)
advertising_stop();
err_code = sd_ble_gap_adv_data_set(dPtr, dLen, NULL, 0);
if (err_code)
jsExceptionHere(JSET_ERROR, "Got BLE error code %d", err_code);
if (bleChanged)
if (bleChanged && isAdvertising)
advertising_start();
return; // we're done here now
} else if (jsvIsObject(data)) {
@ -1274,12 +1339,12 @@ void jswrap_nrf_bluetooth_setAdvertising(JsVar *data, JsVar *options) {
return;
}
if (bleChanged)
if (bleChanged && isAdvertising)
advertising_stop();
err_code = ble_advdata_set(&advdata, NULL);
if (err_code)
jsExceptionHere(JSET_ERROR, "Got BLE error code %d", err_code);
if (bleChanged)
if (bleChanged && isAdvertising)
advertising_start();
}
@ -1306,6 +1371,7 @@ NRF.setServices({
broadcast : false, // optional, default is false
readable : true, // optional, default is false
writable : true, // optional, default is false
notify : true, // optional, default is false
onWrite : function(evt) { // optional
console.log("Got ", evt.data);
}
@ -1322,7 +1388,8 @@ the form `"0xABCD"`, or strings of the form `""ABCDABCD-ABCD-ABCD-ABCD-ABCDABCDA
void jswrap_nrf_bluetooth_setServices(JsVar *data) {
uint32_t err_code;
// TODO: Reset services
// TODO: Reset services (esp. removing Nordic UART if not needed)
// TODO: Reset services on kill
if (jsvIsObject(data)) {
JsvObjectIterator it;
@ -1333,8 +1400,9 @@ void jswrap_nrf_bluetooth_setServices(JsVar *data) {
// Add the service
if (!bleVarToUUIDAndUnLock(&ble_uuid, jsvObjectIteratorGetKey(&it))) {
jsExceptionHere(JSET_ERROR, "Invalid Service UUID");
const char *errorStr;
if ((errorStr=bleVarToUUIDAndUnLock(&ble_uuid, jsvObjectIteratorGetKey(&it)))) {
jsExceptionHere(JSET_ERROR, "Invalid Service UUID: %s", errorStr);
break;
}
err_code = sd_ble_gatts_service_add(BLE_GATTS_SRVC_TYPE_PRIMARY,
@ -1357,8 +1425,8 @@ void jswrap_nrf_bluetooth_setServices(JsVar *data) {
ble_gatts_attr_md_t attr_md;
ble_gatts_char_handles_t characteristic_handles;
if (!bleVarToUUIDAndUnLock(&char_uuid, jsvObjectIteratorGetKey(&serviceit))) {
jsExceptionHere(JSET_ERROR, "Invalid Characteristic UUID");
if ((errorStr=bleVarToUUIDAndUnLock(&char_uuid, jsvObjectIteratorGetKey(&serviceit)))) {
jsExceptionHere(JSET_ERROR, "Invalid Characteristic UUID: %s", errorStr);
break;
}
JsVar *charVar = jsvObjectIteratorGetValue(&serviceit);
@ -1366,6 +1434,8 @@ void jswrap_nrf_bluetooth_setServices(JsVar *data) {
memset(&char_md, 0, sizeof(char_md));
if (jsvGetBoolAndUnLock(jsvObjectGetChild(charVar, "broadcast", 0)))
char_md.char_props.broadcast = 1;
if (jsvGetBoolAndUnLock(jsvObjectGetChild(charVar, "notify", 0)))
char_md.char_props.notify = 1;
if (jsvGetBoolAndUnLock(jsvObjectGetChild(charVar, "readable", 0)))
char_md.char_props.read = 1;
if (jsvGetBoolAndUnLock(jsvObjectGetChild(charVar, "writable", 0))) {
@ -1796,7 +1866,6 @@ void jswrap_nrf_nfcURL(JsVar *url) {
#endif
}
/* ---------------------------------------------------------------------
* TESTING
* ---------------------------------------------------------------------
@ -1847,5 +1916,3 @@ NRF.setServices({
});
*/

View File

@ -37,6 +37,5 @@ void jswrap_nrf_blecharacteristic_write(JsVar *characteristic, JsVar *data);
void jswrap_nrf_nfcURL(JsVar *url);
bool jswrap_nrf_idle();
void jswrap_nrf_kill();

View File

@ -201,6 +201,37 @@ void graphicsDrawRect(JsGraphics *gfx, short x1, short y1, short x2, short y2) {
graphicsFillRectDevice(gfx,x1,y2,x1,y1);
}
void graphicsDrawCircle(JsGraphics *gfx, short posX, short posY, short rad) {
graphicsToDeviceCoordinates(gfx, &posX, &posY);
int radY = 0,
radX = rad;
// Decision criterion divided by 2 evaluated at radX=radX, radY=0
int decisionOver2 = 1 - radX;
while (radX >= radY) {
graphicsSetPixelDevice(gfx, radX + posX, radY + posY, gfx->data.fgColor);
graphicsSetPixelDevice(gfx, radY + posX, radX + posY, gfx->data.fgColor);
graphicsSetPixelDevice(gfx, -radX + posX, radY + posY, gfx->data.fgColor);
graphicsSetPixelDevice(gfx, -radY + posX, radX + posY, gfx->data.fgColor);
graphicsSetPixelDevice(gfx, -radX + posX, -radY + posY, gfx->data.fgColor);
graphicsSetPixelDevice(gfx, -radY + posX, -radX + posY, gfx->data.fgColor);
graphicsSetPixelDevice(gfx, radX + posX, -radY + posY, gfx->data.fgColor);
graphicsSetPixelDevice(gfx, radY + posX, -radX + posY, gfx->data.fgColor);
radY++;
if (decisionOver2 <= 0) {
// Change in decision criterion for radY -> radY+1
decisionOver2 += 2 * radY + 1;
}
else {
radX--;
// Change for radY -> radY+1, radX -> radX-1
decisionOver2 += 2 * (radY - radX) + 1;
}
}
}
void graphicsFillCircle(JsGraphics *gfx, short x, short y, short rad) {
graphicsToDeviceCoordinates(gfx, &x, &y);

View File

@ -99,6 +99,7 @@ void graphicsClear(JsGraphics *gfx);
void graphicsFillRect(JsGraphics *gfx, short x1, short y1, short x2, short y2);
void graphicsFallbackFillRect(JsGraphics *gfx, short x1, short y1, short x2, short y2); // Simple fillrect - doesn't call device-specific FR
void graphicsDrawRect(JsGraphics *gfx, short x1, short y1, short x2, short y2);
void graphicsDrawCircle(JsGraphics *gfx, short posX, short posY, short rad);
void graphicsFillCircle(JsGraphics *gfx, short x, short y, short rad);
void graphicsDrawString(JsGraphics *gfx, short x1, short y1, const char *str);
void graphicsDrawLine(JsGraphics *gfx, short x1, short y1, short x2, short y2);

View File

@ -351,6 +351,25 @@ void jswrap_graphics_drawRect(JsVar *parent, int x1, int y1, int x2, int y2) {
graphicsSetVar(&gfx); // gfx data changed because modified area
}
/*JSON{
"type" : "method",
"class" : "Graphics",
"name" : "drawCircle",
"generate" : "jswrap_graphics_drawCircle",
"params" : [
["x","int32","The X axis"],
["y","int32","The Y axis"],
["rad","int32","The circle radius"]
]
}
Draw an unfilled circle 1px wide in the Foreground Color
*/
void jswrap_graphics_drawCircle(JsVar *parent, int x, int y, int rad) {
JsGraphics gfx; if (!graphicsGetFromVar(&gfx, parent)) return;
graphicsDrawCircle(&gfx, (short)x,(short)y,(short)rad);
graphicsSetVar(&gfx); // gfx data changed because modified area
}
/*JSON{
"type" : "method",
"class" : "Graphics",

View File

@ -32,6 +32,7 @@ int jswrap_graphics_getWidthOrHeight(JsVar *parent, bool height);
void jswrap_graphics_clear(JsVar *parent);
void jswrap_graphics_fillRect(JsVar *parent, int x1, int y1, int x2, int y2);
void jswrap_graphics_drawRect(JsVar *parent, int x1, int y1, int x2, int y2);
void jswrap_graphics_drawCircle(JsVar *parent, int x, int y, int rad);
void jswrap_graphics_fillCircle(JsVar *parent, int x, int y, int rad);
int jswrap_graphics_getPixel(JsVar *parent, int x, int y);
void jswrap_graphics_setPixel(JsVar *parent, int x, int y, JsVar *color);

View File

@ -205,7 +205,8 @@ void jswrap_microbit_show(JsVar *image) {
if ((newState!=0) && (microbitLEDState==0)) {
// we want to display something but we don't have an interval
jstExecuteFn(jswrap_microbit_display_callback, jshGetTimeFromMilliseconds(5), true /* repeat */);
JsSysTime period = jshGetTimeFromMilliseconds(5);
jstExecuteFn(jswrap_microbit_display_callback, jshGetSystemTime()+period, (uint32_t)period);
// and also set pins to outputs
nrf_gpio_cfg_output(MB_LED_COL1);
nrf_gpio_cfg_output(MB_LED_COL2);

View File

@ -314,7 +314,7 @@ JsVar *jswrap_http_get(JsVar *options, JsVar *callback) {
if (jsvIsObject(options)) {
// if options is a string - it will be parsed, and GET will be set automatically
JsVar *method = jsvNewFromString("GET");
jsvUnLock2(jsvAddNamedChild(options, method, "method"), method);
jsvUnLock2(jsvSetNamedChild(options, method, "method"), method);
}
JsVar *skippedCallback = jsvSkipName(callback);
if (!jsvIsUndefined(skippedCallback) && !jsvIsFunction(skippedCallback)) {

426
libs/puckjs/jswrap_puck.c Normal file
View File

@ -0,0 +1,426 @@
/*
* 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 is designed to be parsed during the build process
*
* Contains JavaScript interface for Puck.js
* ----------------------------------------------------------------------------
*/
#include "jswrap_puck.h"
#include "jsinteractive.h"
#include "jsdevices.h"
#include "jshardware.h"
#include "jsdevices.h"
#include "jspin.h"
#include "jstimer.h"
#include "nrf_gpio.h"
#include "nrf5x_utils.h"
#define MAG_PWR 18
#define MAG_INT 17
#define MAG_SDA 20
#define MAG_SCL 19
#define MAG3110_ADDR 0x0E
#define I2C_TIMEOUT 100000
// Has the magnetometer been turned on?
bool mag_enabled = false;
void wr(int pin, bool state) {
if (state) {
nrf_gpio_pin_set(pin); nrf_gpio_cfg_output(pin);
nrf_gpio_cfg_input(pin, NRF_GPIO_PIN_PULLUP);
} else {
nrf_gpio_pin_clear(pin);
nrf_gpio_cfg_output(pin);
}
}
bool rd(int pin) {
return nrf_gpio_pin_read(pin);
}
void dly() {
volatile int i;
for (i=0;i<10;i++);
}
void err(const char *s) {
jsiConsolePrintf("I2C: %s\n", s);
}
bool started = false;
void i2c_start() {
if (started) {
// reset
wr(MAG_SDA, 1);
dly();
wr(MAG_SCL, 1);
int timeout = I2C_TIMEOUT;
while (!rd(MAG_SCL) && --timeout); // clock stretch
if (!timeout) err("Timeout (start)");
dly();
}
if (!rd(MAG_SDA)) err("Arbitration (start)");
wr(MAG_SDA, 0);
dly();
wr(MAG_SCL, 0);
dly();
started = true;
}
void i2c_stop() {
wr(MAG_SDA, 0);
dly();
wr(MAG_SCL, 1);
int timeout = I2C_TIMEOUT;
while (!rd(MAG_SCL) && --timeout); // clock stretch
if (!timeout) err("Timeout (stop)");
dly();
wr(MAG_SDA, 1);
dly();
if (!rd(MAG_SDA)) err("Arbitration (stop)");
dly();
started = false;
}
void i2c_wr_bit(bool b) {
wr(MAG_SDA, b);
dly();
wr(MAG_SCL, 1);
dly();
int timeout = I2C_TIMEOUT;
while (!rd(MAG_SCL) && --timeout); // clock stretch
if (!timeout) err("Timeout (wr)");
wr(MAG_SCL, 0);
wr(MAG_SDA, 1); // stop forcing SDA (needed?)
}
bool i2c_rd_bit() {
wr(MAG_SDA, 1); // stop forcing SDA
dly();
wr(MAG_SCL, 1); // stop forcing SDA
int timeout = I2C_TIMEOUT;
while (!rd(MAG_SCL) && --timeout); // clock stretch
if (!timeout) err("Timeout (rd)");
dly();
bool b = rd(MAG_SDA);
wr(MAG_SCL, 0);
return b;
}
// true on ack, false on nack
bool i2c_wr(uint8_t data) {
int i;
for (i=0;i<8;i++) {
i2c_wr_bit(data&128);
data <<= 1;
}
return !i2c_rd_bit();
}
uint8_t i2c_rd(bool nack) {
int i;
int data = 0;
for (i=0;i<8;i++)
data = (data<<1) | (i2c_rd_bit()?1:0);
i2c_wr_bit(nack);
return data;
}
// Turn magnetometer on and configure
bool mag_on(int milliHz) {
int reg1 = 0;
if (milliHz == 80000) reg1 = (0x00)<<3; // 900uA
else if (milliHz == 40000) reg1 = (0x04)<<3; // 550uA
else if (milliHz == 20000) reg1 = (0x08)<<3; // 275uA
else if (milliHz == 10000) reg1 = (0x0C)<<3; // 137uA
else if (milliHz == 5000) reg1 = (0x10)<<3; // 69uA
else if (milliHz == 2500) reg1 = (0x14)<<3; // 34uA
else if (milliHz == 1250) reg1 = (0x18)<<3; // 17uA
else if (milliHz == 630) reg1 = (0x1C)<<3; // 8uA
else if (milliHz == 310) reg1 = (0x1D)<<3; // 8uA
else if (milliHz == 160) reg1 = (0x1E)<<3; // 8uA
else if (milliHz == 80) reg1 = (0x1F)<<3; // 8uA
else return false;
nrf_gpio_pin_set(MAG_PWR);
nrf_gpio_cfg_output(MAG_PWR);
nrf_gpio_cfg_input(MAG_INT, NRF_GPIO_PIN_NOPULL);
wr(MAG_SDA, 1);
wr(MAG_SCL, 1);
jshDelayMicroseconds(2000); // 1.7ms from power on to ok
i2c_start();
i2c_wr(MAG3110_ADDR<<1); // CTRL_REG2, AUTO_MRST_EN
i2c_wr(0x11);
i2c_wr(0x80/*AUTO_MRST_EN*/ + 0x20/*RAW*/);
i2c_stop();
i2c_start();
i2c_wr(MAG3110_ADDR<<1); // CTRL_REG1, active mode 80 Hz ODR with OSR = 0
i2c_wr(0x10);
reg1 |= 1; // Active bit
i2c_wr(reg1);
i2c_stop();
return true;
}
// Wait for magnetometer IRQ line to be set
void mag_wait() {
int timeout = I2C_TIMEOUT*2;
while (!nrf_gpio_pin_read(MAG_INT) && --timeout);
if (!timeout) err("Timeout (wait reading)");
}
// Read a value
void mag_read(int16_t d[3]) {
i2c_start();
i2c_wr(MAG3110_ADDR<<1);
i2c_wr(1);
i2c_start();
i2c_wr(1|(MAG3110_ADDR<<1));
d[0] = i2c_rd(false)<<8;
d[0] |= i2c_rd(false);
d[1] = i2c_rd(false)<<8;
d[1] |= i2c_rd(false);
d[2] = i2c_rd(false)<<8;
d[2] |= i2c_rd(true);
i2c_stop();
}
// Turn magnetometer off
void mag_off() {
nrf_gpio_cfg_input(MAG_SDA, NRF_GPIO_PIN_NOPULL);
nrf_gpio_cfg_input(MAG_SCL, NRF_GPIO_PIN_NOPULL);
nrf_gpio_cfg_input(MAG_PWR, NRF_GPIO_PIN_NOPULL);
}
JsVar *mag_to_xyz(int16_t d[3]) {
JsVar *obj = jsvNewObject();
if (!obj) return 0;
jsvObjectSetChildAndUnLock(obj,"x",jsvNewFromInteger(d[0]));
jsvObjectSetChildAndUnLock(obj,"y",jsvNewFromInteger(d[1]));
jsvObjectSetChildAndUnLock(obj,"z",jsvNewFromInteger(d[2]));
return obj;
}
/*JSON{
"type": "class",
"class" : "NRF"
}
Class containing [Puck.js's](http://www.puck-js.com) utility functions.
*/
/*JSON{
"type" : "staticmethod",
"class" : "Puck",
"name" : "mag",
"generate" : "jswrap_puck_mag",
"return" : ["JsVar", "An Object `{x,y,z}` of magnetometer readings as integers" ]
}
Turn on the magnetometer, take a single reading, and then turn it off again.
*/
JsVar *jswrap_puck_mag() {
if (!mag_enabled) mag_on(80000);
mag_wait();
int16_t d[3];
mag_read(d);
if (!mag_enabled) mag_off();
return mag_to_xyz(d);
}
/*JSON{
"type" : "event",
"class" : "Puck",
"name" : "mag"
}
Called after `Puck.magOn()` every time magnetometer data
is discovered. There is one argument which is an object
of the form `{x,y,z}' containing magnetometer readings
as integers.
*/
void _jswrap_mag_irq() {
}
/*JSON{
"type" : "staticmethod",
"class" : "Puck",
"name" : "magOn",
"generate" : "jswrap_puck_magOn",
"params" : [
["samplerate","float","The Samplerate in Hz, or undefined"]
]
}
Turn the magnetometer on and configure it. Samples will then cause
a 'mag' event on 'Puck':
```
Puck.magOn();
Puck.on('mag', function(xyz) {
console.log(xyz);
});
// Turn events off with Puck.magOff();
```
This call will be ignored if the magnetometer is already on.
If given an argument, the sample rate is set (if not, it's at 0.63Hz). The sample rate should be one of the following:
* 80 Hz - 900uA
* 40 Hz - 550uA
* 20 Hz - 275uA
* 10 Hz - 137uA
* 5 Hz - 69uA
* 2.5 Hz - 34uA
* 1.25 Hz - 17uA
* 0.63 Hz - 8uA
* 0.31 Hz - 8uA
* 0.16 Hz - 8uA
* 0.08 Hz - 8uA
*/
void jswrap_puck_magOn(JsVarFloat hz) {
if (!mag_enabled) {
int milliHz = (int)((hz*1000)+0.5);
if (milliHz==0) milliHz=630;
if (!mag_on(milliHz)) {
jsExceptionHere(JSET_ERROR, "Invalid sample rate %f - see docs for valid rates", hz);
}
jshPinWatch(MAG_INT, true);
}
mag_enabled = true;
}
/*JSON{
"type" : "staticmethod",
"class" : "Puck",
"name" : "magOff",
"generate" : "jswrap_puck_magOff"
}
Turn the magnetometer off
*/
void jswrap_puck_magOff() {
if (mag_enabled) {
jshPinWatch(MAG_INT, false);
mag_off();
}
mag_enabled = false;
}
// Called when we're done with the IR transmission
void _jswrap_puck_IR_done(JsSysTime t) {
// set as input - so no signal
jshPinSetState(IR_ANODE_PIN, JSHPINSTATE_GPIO_IN);
// this one also stops the PWM
jshPinSetState(IR_CATHODE_PIN, JSHPINSTATE_GPIO_IN);
}
/*JSON{
"type" : "staticmethod",
"class" : "Puck",
"name" : "IR",
"generate" : "jswrap_puck_IR",
"params" : [
["data","JsVar","An array of pulse lengths, in milliseconds"]
]
}
Transmit the given set of IR pulses - data should be an array of pulse times
in milliseconds (as `[on, off, on, off, on, etc]`).
*/
void jswrap_puck_IR(JsVar *data) {
if (!jsvIsIterable(data)) {
jsExceptionHere(JSET_TYPEERROR, "Expecting an array, got %t", data);
return;
}
Pin pin = IR_ANODE_PIN;
jshPinAnalogOutput(IR_CATHODE_PIN, 0.5, 38000, 0);
JsSysTime time = jshGetSystemTime();
bool hasPulses = false;
bool pulsePolarity = false;
jshPinSetValue(IR_ANODE_PIN, pulsePolarity);
JsvIterator it;
jsvIteratorNew(&it, data);
while (jsvIteratorHasElement(&it)) {
JsVarFloat pulseTime = jsvIteratorGetFloatValue(&it);
if (hasPulses) jstPinOutputAtTime(time, &pin, 1, pulsePolarity);
else jshPinSetState(IR_ANODE_PIN, JSHPINSTATE_GPIO_OUT);
hasPulses = true;
time += jshGetTimeFromMilliseconds(pulseTime);
pulsePolarity = !pulsePolarity;
jsvIteratorNext(&it);
}
jsvIteratorFree(&it);
if (hasPulses) {
jstExecuteFn(_jswrap_puck_IR_done, time, 0);
}
}
/*JSON{
"type" : "staticmethod",
"class" : "Puck",
"name" : "capSense",
"#ifdef" : "NRF52",
"generate" : "jswrap_puck_capSense",
"params" : [
["tx","pin",""],
["rx","pin",""]
],
"return" : ["int", "Capacitive sense counter" ]
}
Capacitive sense. TX must be connected to RX pin and sense plate via 1MOhm resistor.
If no pins are supplied, the NFC ring is used for capacitive sense.
*/
int jswrap_puck_capSense(Pin tx, Pin rx) {
if (jshIsPinValid(tx) && jshIsPinValid(rx)) {
return (int)nrf_utils_cap_sense(tx, rx);
}
return (int)nrf_utils_cap_sense(CAPSENSE_TX_PIN, CAPSENSE_RX_PIN);
}
/*JSON{
"type" : "kill",
"generate" : "jswrap_puck_kill"
}*/
void jswrap_puck_kill() {
if (mag_enabled) {
mag_off();
mag_enabled = false;
}
}
/*JSON{
"type" : "idle",
"generate" : "jswrap_puck_idle"
}*/
bool jswrap_puck_idle() {
if (mag_enabled && nrf_gpio_pin_read(MAG_INT)) {
int16_t d[3];
mag_read(d);
JsVar *xyz = mag_to_xyz(d);
JsVar *puck = jsvObjectGetChild(execInfo.root, "Puck", 0);
if (jsvHasChildren(puck))
jsiQueueObjectCallbacks(puck, JS_EVENT_PREFIX"mag", &xyz, 1);
jsvUnLock2(puck, xyz);
return true; // don't sleep - handle this now
}
return false;
}

23
libs/puckjs/jswrap_puck.h Normal file
View File

@ -0,0 +1,23 @@
/*
* This file is part of Espruino, a JavaScript interpreter for Microcontrollers
*
* Copyright (C) 2016 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/.
*
* ----------------------------------------------------------------------------
* Contains JavaScript interface for Puck.js
* ----------------------------------------------------------------------------
*/
#include "jspin.h"
void jswrap_puck_magOn();
void jswrap_puck_magOff();
JsVar *jswrap_puck_mag();
void jswrap_puck_IR(JsVar *data);
int jswrap_puck_capSense(Pin tx, Pin rx);
void jswrap_puck_kill();
bool jswrap_puck_idle();

10
scripts/build_js_hardware.js Normal file → Executable file
View File

@ -3,10 +3,10 @@
the values of the bits in each register. Can be used for quickly building
ways to access the underlying hardware from JS */
var INPUTFILE = "targetlibs/stm32f1/lib/stm32f10x.h";
var definitions = {"STM32F10X_XL":true};
//var INPUTFILE = "targetlibs/stm32f4/lib/stm32f4xx.h";
//var definitions = {"STM32F401xx":true};
//var INPUTFILE = "targetlibs/stm32f1/lib/stm32f10x.h";
//var definitions = {"STM32F10X_XL":true};
var INPUTFILE = "targetlibs/stm32f4/lib/stm32f411xe.h";
var definitions = {"STM32F401xx":true};
var fs = require('fs');
var structContents = undefined;
@ -110,7 +110,7 @@ for (var def in definitions) {
}
}
var peripherals = ["RCC","DMA"];
var peripherals = ["RCC","RTC","PWR"];
function out(s) {

View File

@ -176,6 +176,14 @@ def removeBlacklistForWrapper(blacklistfile,datas):
if jsondata["class"] == black["class"]:
if jsondata["name"] == black["name"]:
toremove.append(idx)
# extension by jumjum
else:
if "name" in jsondata:
for black in blacklist:
if black["class"] == "__":
if jsondata["name"] == black["name"]:
toremove.append(idx)
# end extensioin by jumjum
return delete_by_indices( datas, toremove)
# ------------------------------------------------------------------------------------------------------
# ------------------------------------------------------------------------------------------------------

View File

@ -380,8 +380,15 @@ if "SD" in board.devices:
if spiNum==0: die("No SPI peripheral found for SD card's CLK pin")
codeOut("#define SD_SPI EV_SPI"+str(spiNum))
if "IR" in board.devices:
codeOutDevicePin("IR", "pin_anode", "IR_ANODE_PIN")
codeOutDevicePin("IR", "pin_cathode", "IR_CATHODE_PIN")
for device in ["USB","SD","LCD","JTAG","ESP8266"]:
if "CAPSENSE" in board.devices:
codeOutDevicePin("CAPSENSE", "pin_rx", "CAPSENSE_RX_PIN")
codeOutDevicePin("CAPSENSE", "pin_tx", "CAPSENSE_TX_PIN")
for device in ["USB","SD","LCD","JTAG","ESP8266","IR"]:
if device in board.devices:
for entry in board.devices[device]:
if entry[:3]=="pin": usedPinChecks.append("(PIN)==" + toPinDef(board.devices[device][entry])+"/* "+device+" */")

View File

@ -104,5 +104,5 @@ cp $DIR/dist_licences.txt $ZIPDIR/licences.txt
rm -f $ZIPFILE
cd zipcontents
echo zip $ZIPFILE *
zip $ZIPFILE *
echo zip -r $ZIPFILE *
zip -r $ZIPFILE *

View File

@ -846,7 +846,7 @@ class IntelHex(object):
else: # conflict
if overlap == 'error':
raise AddressOverlapError(
'Starting addresses are different')
'Starting addresses are different - existing '+str(self.start_addr)+' vs new '+str(other.start_addr))
elif overlap == 'replace':
self.start_addr = other.start_addr
#/IntelHex

View File

@ -81,6 +81,7 @@ DEVICES = {
"MEMS":"MEMS",
"GYRO":"GYRO",
"JTAG":"JTAG",
"ESP8266":"ESP8266"
};
for i in range(0,7):
@ -116,12 +117,12 @@ def isvalidpin(pinname):
pinnum = pinname[2:]
return pinnum.isdigit()
return False
# Find/populate a pin
def haspin(pins, pinname):
for pin in pins:
if pin["name"]==pinname:
if pin["name"]==pinname:
return True
return False
@ -129,7 +130,7 @@ def haspin(pins, pinname):
def findpin(pins, pinname, force):
if pinname.find('-')!=-1: pinname = pinname[:pinname.find('-')]
for pin in pins:
if pin["name"]==pinname:
if pin["name"]==pinname:
return pin
if force:
print("ERROR: pin "+pinname+" not found")
@ -154,8 +155,8 @@ def scan_pin_af_file(pins, filename, nameoffset, afoffset):
pinname = pindata[nameoffset].strip()
if pinname.find('(')>0: pinname = pinname[:pinname.find('(')]
if not isvalidpin(pinname): continue
pin = findpin(pins, pinname, False)
#print(json.dumps(pin, sort_keys=True, indent=2))
pin = findpin(pins, pinname, False)
#print(json.dumps(pin, sort_keys=True, indent=2))
for af in range(0, len(pindata)-afoffset):
fnames = pindata[af+afoffset].split("/")
for fname in fnames:
@ -166,29 +167,29 @@ def scan_pin_af_file(pins, filename, nameoffset, afoffset):
return pins
# Code for scanning normal file
def scan_pin_file(pins, filename, nameoffset, functionoffset, altfunctionoffset):
def scan_pin_file(pins, filename, nameoffset, functionoffset, altfunctionoffset):
f = open(os.path.dirname(os.path.realpath(__file__))+'/../boards/pins/'+filename)
lines = f.readlines()
lines = f.readlines()
f.close()
headings = lines[0].split(",")
for line in lines:
pindata = line.split(",")
pinname = pindata[nameoffset].strip()
extrafunction = ""
if "BOOT1" in line: extrafunction="BOOT1"
extrafunction = ""
if "BOOT1" in line: extrafunction="BOOT1"
if pinname.find('(')>0: pinname = pinname[:pinname.find('(')]
if not isvalidpin(pinname): continue
pin = findpin(pins, pinname, False)
for i,head in enumerate(headings):
pin["csv"][head] = pindata[i].strip()
pin["csv"][head] = pindata[i].strip()
if extrafunction!="":
pin["functions"][extrafunction] = 0
for fn in pindata[functionoffset].strip().split("/"):
for fn in pindata[functionoffset].strip().split("/"):
fname = fn.strip()
pin["functions"][fname] = 0
pin["functions"][fname] = 0
if altfunctionoffset>=0:
for fn in pindata[altfunctionoffset].strip().split("/"):
for fn in pindata[altfunctionoffset].strip().split("/"):
fname = fn.strip()
pin["functions"][fname] = 1
# print pin["name"]+" : "+', '.join(pin["functions"])
@ -247,10 +248,9 @@ def get_device_pins(board):
# If devices are used by a board, fill in their details for each pin
def append_devices_to_pin_list(pins, board):
devicepins = get_device_pins(board)
for i,pin in enumerate(pins):
if pin["name"] in devicepins:
pins[i]["functions"][devicepins[pin["name"]]["device"]] = devicepins[pin["name"]]["function"]
# print pins[i]["functions"][devicepins[pin["name"]]["device"]]
# print pins[i]["functions"][devicepins[pin["name"]]["device"]]
return pins

View File

@ -261,8 +261,7 @@ void jshPushIOCharEvent(
) {
// Check for a CTRL+C
if (charData==3 && channel==jsiGetConsoleDevice()) {
// Ctrl-C - force interrupt
execInfo.execute |= EXEC_CTRL_C;
jsiCtrlC(); // Ctrl-C - force interrupt of execution
return;
}
// Check for existing buffer (we must have at least 2 in the queue to avoid dropping chars though!)

View File

@ -101,8 +101,12 @@ NO_INLINE bool jsiEcho() {
return ((jsiStatus&JSIS_ECHO_OFF_MASK)==0);
}
NO_INLINE bool jsiPasswordProtected() {
return ((jsiStatus&JSIS_PASSWORD_PROTECTED)!=0);
}
static bool jsiShowInputLine() {
return jsiEcho() && !inputLineRemoved;
return jsiEcho() && !inputLineRemoved && !jsiPasswordProtected();
}
/** Called when the input line/cursor is modified *and its iterator should be reset
@ -371,6 +375,8 @@ void jsiConsoleReturnInputLine() {
if (jsiStatus & JSIS_IN_DEBUGGER)
jsiConsolePrint("debug");
#endif
if (jsiPasswordProtected())
jsiConsolePrint("password");
jsiConsolePrintChar('>'); // show the prompt
jsiConsolePrintStringVarWithNewLineChar(inputLine, 0, ':');
jsiMoveCursorChar(inputLine, jsvGetStringLength(inputLine), inputCursorPos);
@ -379,14 +385,18 @@ void jsiConsoleReturnInputLine() {
}
/**
* Clear the input line of data.
* Clear the input line of data. If updateConsole is set, it
* sends VT100 characters to physically remove the line from
* the user's terminal.
*/
void jsiClearInputLine() {
jsiConsoleRemoveInputLine();
void jsiClearInputLine(bool updateConsole) {
if (updateConsole)
jsiConsoleRemoveInputLine();
// clear input line
jsiInputLineCursorMoved();
jsvUnLock(inputLine);
inputLine = jsvNewFromEmptyString();
inputCursorPos = 0;
}
/**
@ -723,7 +733,7 @@ void jsiSemiInit(bool autoLoad) {
// Set state
interruptedDuringEvent = false;
// Set defaults
jsiStatus = JSIS_NONE;
jsiStatus &= ~JSIS_SOFTINIT_MASK;
pinBusyIndicator = DEFAULT_BUSY_PIN_INDICATOR;
/* If flash contains any code, then we should
@ -737,6 +747,12 @@ void jsiSemiInit(bool autoLoad) {
jspSoftInit();
}
// If a password was set, apply the lock
JsVar *pwd = jsvObjectGetChild(execInfo.hiddenRoot, PASSWORD_VARIABLE_NAME, 0);
if (pwd)
jsiStatus |= JSIS_PASSWORD_PROTECTED;
jsvUnLock(pwd);
// Softinit may run initialisation code that will overwrite defaults
jsiSoftInit(!autoLoad);
@ -779,6 +795,8 @@ void jsiSemiInit(bool autoLoad) {
// The 'proper' init function - this should be called only once at bootup
void jsiInit(bool autoLoad) {
jsiStatus = JSIS_NONE;
#if defined(LINUX) || !defined(USB)
consoleDevice = DEFAULT_CONSOLE_DEVICE;
#else
@ -1273,10 +1291,7 @@ void jsiHandleNewLine(bool execute) {
// Get line to execute, and reset inputLine
JsVar *lineToExecute = jsvStringTrimRight(inputLine);
jsiInputLineCursorMoved();
jsvUnLock(inputLine);
inputLine = jsvNewFromEmptyString();
inputCursorPos = 0;
jsiClearInputLine(false);
#ifdef USE_DEBUGGER
if (jsiStatus & JSIS_IN_DEBUGGER) {
jsiDebuggerLine(lineToExecute);
@ -1357,6 +1372,30 @@ void jsiHandleChar(char ch) {
// 27 then 79 then 72 - end
// 27 then 10 - alt enter
if (jsiPasswordProtected()) {
if (ch=='\r' || ch==10) {
JsVar *pwd = jsvObjectGetChild(execInfo.hiddenRoot, PASSWORD_VARIABLE_NAME, 0);
// check password
if (pwd && jsvCompareString(inputLine, pwd, 0, 0, false)==0)
jsiStatus &= ~JSIS_PASSWORD_PROTECTED;
jsvUnLock(pwd);
jsiClearInputLine(false);
if (jsiPasswordProtected()) {
jsiConsolePrint("\n Invalid password\npassword>");
} else {
jsiConsolePrint("\n Logged in.\n");
inputLineRemoved = true;
jsiConsoleReturnInputLine();
}
} else {
char str[2];
str[0] = ch;
str[1] = 0;
if (jsvGetStringLength(inputLine)<20)
jsiAppendToInputLine(str);
}
return;
}
if (ch == 0) {
inputState = IS_NONE; // ignore 0 - it's scary
@ -1367,7 +1406,7 @@ void jsiHandleChar(char ch) {
} else if (ch == 5) { // Ctrl-e
jsiHandleEnd();
} else if (ch == 21 || ch == 23) { // Ctrl-u or Ctrl-w
jsiClearInputLine();
jsiClearInputLine(true);
} else if (ch == 27) {
inputState = IS_HAD_27;
} else if (inputState==IS_HAD_27) {
@ -1425,7 +1464,7 @@ void jsiHandleChar(char ch) {
} else {
if (ch=='d') jsiLineNumberOffset = inputStateNumber;
else if (ch=='H' /* 75 */) {
if (inputStateNumber==2) jsiClearInputLine(); // Erase current line
if (inputStateNumber==2) jsiClearInputLine(true); // Erase current line
} else if (ch==126) {
if (inputStateNumber==1) jsiHandleHome(); // Numpad Home
else if (inputStateNumber==3) jsiHandleDelete(false/*not backspace*/); // Numpad (forwards) Delete
@ -1607,6 +1646,14 @@ bool jsiIsWatchingPin(Pin pin) {
return isWatched;
}
void jsiCtrlC() {
// If password protected, don't let Ctrl-C break out of running code!
if (jsiPasswordProtected())
return;
// Force a break...
execInfo.execute |= EXEC_CTRL_C;
}
/** Take an event for a UART and handle the chareacters we're getting, potentially
* grabbing more characters as well if it's easy. If more character events are
* grabbed, the number of extra events (not characters) is returned */
@ -2040,7 +2087,7 @@ bool jsiLoop() {
#endif
jsiTimeSinceCtrlC = 0;
}
jsiClearInputLine();
jsiClearInputLine(true);
}
// return console (if it was gone!)
@ -2171,7 +2218,7 @@ void jsiDebuggerLoop() {
EXEC_DEBUGGER_NEXT_LINE |
EXEC_DEBUGGER_STEP_INTO |
EXEC_DEBUGGER_FINISH_FUNCTION);
jsiClearInputLine();
jsiClearInputLine(true);
jsiConsoleRemoveInputLine();
jsiStatus = (jsiStatus & ~JSIS_ECHO_OFF_MASK) | JSIS_IN_DEBUGGER;

View File

@ -42,6 +42,8 @@ bool jsiFreeMoreMemory();
bool jsiHasTimers(); // are there timers still left to run?
bool jsiIsWatchingPin(Pin pin); // are there any watches for the given pin?
void jsiCtrlC(); // Ctrl-C - force interrupt of execution
/// Queue a function, string, or array (of funcs/strings) to be executed next time around the idle loop
void jsiQueueEvents(JsVar *object, JsVar *callback, JsVar **args, int argCount);
/// Return true if the object has callbacks...
@ -122,6 +124,7 @@ void jsiSetSleep(JsiSleepType isSleep);
#define USART_BAUDRATE_NAME "_baudrate"
#define DEVICE_OPTIONS_NAME "_options"
#define INIT_CALLBACK_NAME JS_EVENT_PREFIX"init" ///< Callback for `E.on('init'`
#define PASSWORD_VARIABLE_NAME "pwd"
typedef enum {
JSIS_NONE,
@ -139,8 +142,10 @@ typedef enum {
JSIS_TODO_MASK = JSIS_TODO_FLASH_SAVE|JSIS_TODO_FLASH_LOAD|JSIS_TODO_RESET,
JSIS_CONSOLE_FORCED = 512, // see jsiSetConsoleDevice
JSIS_WATCHDOG_AUTO = 1024, // Automatically kick the watchdog timer on idle
JSIS_PASSWORD_PROTECTED = 2048, // Password protected
JSIS_ECHO_OFF_MASK = JSIS_ECHO_OFF|JSIS_ECHO_OFF_FOR_LINE
JSIS_ECHO_OFF_MASK = JSIS_ECHO_OFF|JSIS_ECHO_OFF_FOR_LINE,
JSIS_SOFTINIT_MASK = JSIS_PASSWORD_PROTECTED // stuff that DOESN'T get reset on softinit
} PACKED_FLAGS JsiStatus;
extern JsiStatus jsiStatus;

View File

@ -325,7 +325,10 @@ NO_INLINE bool jspeFunctionArguments(JsVar *funcVar) {
JSP_MATCH('(');
while (lex->tk!=')') {
if (funcVar) {
JsVar *param = jsvAddNamedChild(funcVar, 0, jslGetTokenValueAsString(lex));
char buf[JSLEX_MAX_TOKEN_LENGTH+1];
buf[0] = '\xFF';
strcpy(&buf[1], jslGetTokenValueAsString(lex));
JsVar *param = jsvAddNamedChild(funcVar, 0, buf);
if (!param) { // out of memory
jspSetError(false);
return false;
@ -614,7 +617,7 @@ NO_INLINE JsVar *jspeFunctionCall(JsVar *function, JsVar *functionName, JsVar *t
JsVar *param = jsvObjectIteratorGetKey(&it);
JsVar *value = jsvObjectIteratorGetValue(&it);
while (jsvIsFunctionParameter(param) && value) {
JsVar *paramName = jsvCopy(param);
JsVar *paramName = jsvNewFromStringVar(param,1,JSVAPPENDSTRINGVAR_MAXLENGTH);
if (paramName) { // could be out of memory
jsvMakeFunctionParameter(paramName); // force this to be called a function parameter
jsvSetValueOfName(paramName, value);
@ -643,7 +646,7 @@ NO_INLINE JsVar *jspeFunctionCall(JsVar *function, JsVar *functionName, JsVar *t
value = jspeAssignmentExpression();
// and if execute, copy it over
value = jsvSkipNameAndUnLock(value);
JsVar *paramName = paramDefined ? jsvCopyNameOnly(param,false,true) : jsvNewFromEmptyString();
JsVar *paramName = paramDefined ? jsvNewFromStringVar(param,1,JSVAPPENDSTRINGVAR_MAXLENGTH) : jsvNewFromEmptyString();
if (paramName) { // could be out of memory
jsvMakeFunctionParameter(paramName); // force this to be called a function parameter
jsvSetValueOfName(paramName, value);
@ -663,7 +666,7 @@ NO_INLINE JsVar *jspeFunctionCall(JsVar *function, JsVar *functionName, JsVar *t
while (args<argCount) {
JsVar *param = jsvObjectIteratorGetKey(&it);
bool paramDefined = jsvIsFunctionParameter(param);
JsVar *paramName = paramDefined ? jsvCopyNameOnly(param,false,true) : jsvNewFromEmptyString();
JsVar *paramName = paramDefined ? jsvNewFromStringVar(param,1,JSVAPPENDSTRINGVAR_MAXLENGTH) : jsvNewFromEmptyString();
if (paramName) {
jsvMakeFunctionParameter(paramName); // force this to be called a function parameter
jsvSetValueOfName(paramName, argPtr[args]);
@ -688,9 +691,12 @@ NO_INLINE JsVar *jspeFunctionCall(JsVar *function, JsVar *functionName, JsVar *t
thisVar = jsvSkipName(param);
} else if (jsvIsStringEqual(param, JSPARSE_FUNCTION_LINENUMBER_NAME)) functionLineNumber = (uint16_t)jsvGetIntegerAndUnLock(jsvSkipName(param));
else if (jsvIsFunctionParameter(param)) {
JsVar *paramName = jsvCopy(param);
JsVar *paramName = jsvNewFromStringVar(param,1,JSVAPPENDSTRINGVAR_MAXLENGTH);
// paramName is already a name (it's a function parameter)
if (paramName) {// could be out of memory - or maybe just not supplied!
jsvMakeFunctionParameter(paramName);
JsVar *defaultVal = jsvSkipName(param);
if (defaultVal) jsvUnLock(jsvSetValueOfName(paramName, defaultVal));
jsvAddName(functionRoot, paramName);
jsvUnLock(paramName);
}
@ -1649,9 +1655,10 @@ NO_INLINE JsVar *__jspeAssignmentExpression(JsVar *lhs) {
else if (op==LEX_RSHIFTUNSIGNEDEQUAL) op=LEX_RSHIFTUNSIGNED;
if (op=='+' && jsvIsName(lhs)) {
JsVar *currentValue = jsvSkipName(lhs);
if (jsvIsString(currentValue) && !jsvIsFlatString(currentValue) && jsvGetRefs(currentValue)==1) {
/* A special case for string += where this is the only use of the string,
* as we may be able to do a simple append (rather than clone + append)*/
if (jsvIsString(currentValue) && !jsvIsFlatString(currentValue) && jsvGetRefs(currentValue)==1 && rhs!=currentValue) {
/* A special case for string += where this is the only use of the string
* and we're not appending to ourselves. In this case we can do a
* simple append (rather than clone + append)*/
JsVar *str = jsvAsString(rhs, false);
jsvAppendStringVarComplete(currentValue, str);
jsvUnLock(str);
@ -1796,7 +1803,7 @@ NO_INLINE JsVar *jspeStatementVar() {
NO_INLINE JsVar *jspeStatementIf() {
bool cond;
JsVar *var;
JsVar *var, *result;
JSP_ASSERT_MATCH(LEX_R_IF);
JSP_MATCH('(');
var = jspeExpression();
@ -1807,16 +1814,26 @@ NO_INLINE JsVar *jspeStatementIf() {
JSP_SAVE_EXECUTE();
if (!cond) jspSetNoExecute();
jsvUnLock(jspeBlockOrStatement());
if (!cond) JSP_RESTORE_EXECUTE();
JsVar *a = jspeBlockOrStatement();
if (!cond) {
jsvUnLock(a);
JSP_RESTORE_EXECUTE();
} else {
result = a;
}
if (lex->tk==LEX_R_ELSE) {
JSP_ASSERT_MATCH(LEX_R_ELSE);
JSP_SAVE_EXECUTE();
if (cond) jspSetNoExecute();
jsvUnLock(jspeBlockOrStatement());
if (cond) JSP_RESTORE_EXECUTE();
JsVar *a = jspeBlockOrStatement();
if (cond) {
jsvUnLock(a);
JSP_RESTORE_EXECUTE();
} else {
result = a;
}
}
return 0;
return result;
}
NO_INLINE JsVar *jspeStatementSwitch() {

View File

@ -429,13 +429,14 @@ bool jstPinPWM(JsVarFloat freq, JsVarFloat dutyCycle, Pin pin) {
}
/// Execute the given function repeatedly after the given time period
bool jstExecuteFn(void (*fn)(JsSysTime), JsSysTime period, bool repeat) {
bool jstExecuteFn(void (*fn)(JsSysTime), JsSysTime startTime, uint32_t period) {
UtilTimerTask task;
task.time = jshGetSystemTime() + period;
task.repeatInterval = repeat ? (uint32_t)period : 0;
task.time = startTime;
task.repeatInterval = period;
task.type = UET_EXECUTE;
task.data.execute = fn;
WAIT_UNTIL(!utilTimerIsFull(), "Utility Timer");
return utilTimerInsertTask(&task);
}

View File

@ -108,8 +108,8 @@ bool jstPinOutputAtTime(JsSysTime time, Pin *pins, int pinCount, uint8_t value);
// Do software PWM on the given pin, using the timer IRQs
bool jstPinPWM(JsVarFloat freq, JsVarFloat dutyCycle, Pin pin);
/// Execute the given function repeatedly after the given time period
bool jstExecuteFn(void (*fn)(JsSysTime), JsSysTime period, bool repeat);
/// Execute the given function repeatedly after the given time period. If periof=0, don't repeat
bool jstExecuteFn(void (*fn)(JsSysTime), JsSysTime startTime, uint32_t period);
/// Stop executing the given function
bool jstStopExecuteFn(void (*fn)(JsSysTime));

View File

@ -289,8 +289,8 @@ unsigned int jsvGetMemoryTotal() {
void jsvSetMemoryTotal(unsigned int jsNewVarCount) {
#ifdef RESIZABLE_JSVARS
assert(!isMemoryBusy);
isMemoryBusy = true;
if (jsNewVarCount <= jsVarsSize) return; // never allow us to have less!
isMemoryBusy = true;
// When resizing, we just allocate a bunch more
unsigned int oldSize = jsVarsSize;
unsigned int oldBlockCount = jsVarsSize >> JSVAR_BLOCK_SHIFT;

View File

@ -1117,6 +1117,34 @@ JsVarInt jswrap_espruino_HSBtoRGB(JsVarFloat hue, JsVarFloat sat, JsVarFloat bri
}
}
/*JSON{
"type" : "staticmethod",
"class" : "E",
"name" : "setPassword",
"generate" : "jswrap_espruino_setPassword",
"params" : [
["opts","JsVar","The password - max 20 chars"]
]
}
Set a password on the console (REPL). When powered on, Espruino will
then demand a password before the console can be used.
To remove the password, call this function with no arguments.
**Note:** There is no protection against multiple password attempts, so someone
could conceivably try every password in a dictionary.
**Note:** This password is stored in memory in plain text. If someone is able
to execute arbitrary JavaScript code on the device (eg, you use `eval` on input
from unknown sources) or read the device's firmware then they may be able to
obtain it.
*/
void jswrap_espruino_setPassword(JsVar *pwd) {
if (pwd)
pwd = jsvAsString(pwd, false);
jsvUnLock(jsvObjectSetChild(execInfo.hiddenRoot, PASSWORD_VARIABLE_NAME, pwd));
}
// ----------------------------------------- USB Specific Stuff
#ifdef USE_USB_HID

View File

@ -41,6 +41,7 @@ JsVar *jswrap_espruino_getSizeOf(JsVar *v, int depth);
void jswrap_espruino_mapInPlace(JsVar *from, JsVar *to, JsVar *map, JsVarInt bits);
JsVar *jswrap_e_dumpStr();
JsVarInt jswrap_espruino_HSBtoRGB(JsVarFloat hue, JsVarFloat sat, JsVarFloat bri);
void jswrap_espruino_setPassword(JsVar *pwd);
void jswrap_espruino_setUSBHID(JsVar *arr);
bool jswrap_espruino_sendUSBHID(JsVar *arr);

View File

@ -160,7 +160,7 @@ void jswrap_flash_write(JsVar *data, int addr) {
"generate" : "jswrap_flash_read",
"params" : [
["length","int","The amount of data to read (in bytes)"],
["addr","int","The address to start writing from"]
["addr","int","The address to start reading from"]
],
"return" : ["JsVar","A Uint8Array of data"]
}

View File

@ -71,13 +71,14 @@ JsVar *jswrap_function_constructor(JsVar *args) {
if (s) {
// copy the string - if a string was supplied already we want to make
// sure we have a new (unreferenced) string
JsVar *paramName = jsvNewFromStringVar(s, 0, JSVAPPENDSTRINGVAR_MAXLENGTH);
jsvUnLock(s);
JsVar *paramName = jsvNewFromString("\xFF");
if (paramName) {
jsvAppendStringVarComplete(paramName, s);
jsvMakeFunctionParameter(paramName); // force this to be called a function parameter
jsvAddName(fn, paramName);
jsvUnLock(paramName);
}
jsvUnLock(s);
}
jsvUnLock(v);

View File

@ -170,7 +170,9 @@ void jsfGetJSONForFunctionWithCallback(JsVar *var, JSONFlags flags, vcbprintf_ca
firstParm=false;
else
cbprintf(user_callback, user_data, ",");
cbprintf(user_callback, user_data, "%v", child);
JsVar *name = jsvNewFromStringVar(child, 1, JSVAPPENDSTRINGVAR_MAXLENGTH);
cbprintf(user_callback, user_data, "%v", name);
jsvUnLock(name);
} else if (jsvIsString(child) && jsvIsStringEqual(child, JSPARSE_FUNCTION_CODE_NAME)) {
codeVar = jsvObjectIteratorGetValue(&it);
}

View File

@ -778,6 +778,14 @@ void jswrap_function_replaceWith(JsVar *oldFunc, JsVar *newFunc) {
jsWarn("First argument of replaceWith should be a function - ignoring");
return;
}
// If old was native or vice versa...
if (jsvIsNativeFunction(oldFunc) != jsvIsNativeFunction(newFunc)) {
if (jsvIsNativeFunction(newFunc))
oldFunc->flags |= JSV_NATIVE;
else
oldFunc->flags &= ~JSV_NATIVE;
}
// Grab scope - the one thing we want to keep
JsVar *scope = jsvFindChildFromString(oldFunc, JSPARSE_FUNCTION_SCOPE_NAME, false);
// so now remove all existing entries

View File

@ -214,7 +214,9 @@ JsVar *jswrap_spi_send(
// Handle the data being a single byte value
if (jsvIsNumeric(srcdata)) {
int r = data.spiSend((unsigned char)jsvGetInteger(srcdata), &data.spiSendData);
int d = jsvGetInteger(srcdata);
if (d<0) d = 0; // protect against -1 as we use this in the jshardware SPI implementation
int r = data.spiSend(d, &data.spiSendData);
if (r<0) r = data.spiSend(-1, &data.spiSendData);
dst = jsvNewFromInteger(r); // retrieve the byte (no send!)
}
@ -242,9 +244,8 @@ JsVar *jswrap_spi_send(
unsigned char out = (unsigned char)data.spiSend(-1, &data.spiSendData);
jsvAppendStringBuf(dst, (char*)&out, 1);
}
}
// Handle the data being an iterable.
else {
} else {
// Handle the data being an iterable.
int nBytes = jsvIterateCallbackCount(srcdata);
dst = jsvNewTypedArray(ARRAYBUFFERVIEW_UINT8, nBytes);
if (dst) {

View File

@ -27,7 +27,7 @@
#define PERIPHERAL_RESOURCE_SHARING_ENABLED 0
/* CLOCK */
#define CLOCK_ENABLED 0
#define CLOCK_ENABLED 1
// CLOCK_ENABLED is for enabling the clock driver in the SDK
// Seems not to be needed is using SoftDevice?
// http://infocenter.nordicsemi.com/index.jsp?topic=%2Fcom.nordic.infocenter.sdk5.v11.0.0%2Fhardware_driver_clock.html&cp=4_0_0_2_1

View File

@ -40,17 +40,30 @@ static __INLINE uint32_t pstorage_flash_page_end()
#define PSTORAGE_FLASH_PAGE_END pstorage_flash_page_end()
#define PSTORAGE_NUM_OF_PAGES 1 /**< Number of flash pages allocated for the pstorage module excluding the swap page, configurable based on system requirements. */
/**< Number of flash pages allocated for the pstorage module excluding the swap page, configurable based on system requirements. */
#ifdef BOOTLOADER
#define PSTORAGE_NUM_OF_PAGES 3
#else
#define PSTORAGE_NUM_OF_PAGES 1
#endif
#define PSTORAGE_MIN_BLOCK_SIZE 0x0010 /**< Minimum size of block that can be registered with the module. Should be configured based on system requirements, recommendation is not have this value to be at least size of word. */
#define PSTORAGE_DATA_START_ADDR ((PSTORAGE_FLASH_PAGE_END - PSTORAGE_NUM_OF_PAGES - 1) \
#define PSTORAGE_DATA_START_ADDR ((PSTORAGE_FLASH_PAGE_END - PSTORAGE_NUM_OF_PAGES) \
* PSTORAGE_FLASH_PAGE_SIZE) /**< Start address for persistent data, configurable according to system requirements. */
#define PSTORAGE_DATA_END_ADDR ((PSTORAGE_FLASH_PAGE_END - 1) * PSTORAGE_FLASH_PAGE_SIZE) /**< End address for persistent data, configurable according to system requirements. */
#define PSTORAGE_SWAP_ADDR PSTORAGE_DATA_END_ADDR /**< Top-most page is used as swap area for clear and update. */
#define PSTORAGE_DATA_END_ADDR (PSTORAGE_FLASH_PAGE_END * PSTORAGE_FLASH_PAGE_SIZE) /**< End address for persistent data, configurable according to system requirements. */
#define PSTORAGE_SWAP_ADDR PSTORAGE_DATA_END_ADDR
#define PSTORAGE_MAX_BLOCK_SIZE PSTORAGE_FLASH_PAGE_SIZE /**< Maximum size of block that can be registered with the module. Should be configured based on system requirements. And should be greater than or equal to the minimum size. */
#define PSTORAGE_CMD_QUEUE_SIZE 10 /**< Maximum number of flash access commands that can be maintained by the module for all applications. Configurable. */
#ifdef BOOTLOADER
/**@breif Define this flag in case Raw access to persistent memory is to be enabled. Raw mode
* unlike the data mode is for uses other than storing data from various mode. This mode is
* employed when unpdating firmware or similar uses. Therefore, this mode shall be enabled
* only for these special usecases and typically disabled.
*/
#define PSTORAGE_RAW_MODE_ENABLE
#endif
/** Abstracts persistently memory block identifier. */
typedef uint32_t pstorage_block_t;
@ -61,7 +74,7 @@ typedef struct
pstorage_block_t block_id; /**< Block ID.*/
} pstorage_handle_t;
typedef uint16_t pstorage_size_t; /** Size of length and offset fields. */
typedef uint32_t pstorage_size_t; /** Size of length and offset fields. */
/**@brief Handles Flash Access Result Events. To be called in the system event dispatcher of the application. */
void pstorage_sys_event_handler (uint32_t sys_evt);

View File

@ -1,72 +0,0 @@
/* Copyright (c) 2013 Nordic Semiconductor. All Rights Reserved.
*
* The information contained herein is property of Nordic Semiconductor ASA.
* Terms and conditions of usage are described in detail in NORDIC
* SEMICONDUCTOR STANDARD SOFTWARE LICENSE AGREEMENT.
*
* Licensees are granted free, non-transferable use of the information. NO
* WARRANTY of ANY KIND is provided. This heading must NOT be removed from
* the file.
*
*/
/** @cond To make doxygen skip this file */
/** @file
* This header contains defines with respect persistent storage that are specific to
* persistent storage implementation and application use case.
*/
#ifndef PSTORAGE_PL_H__
#define PSTORAGE_PL_H__
#include <stdint.h>
#include "nrf.h"
static __INLINE uint16_t pstorage_flash_page_size()
{
return (uint16_t)NRF_FICR->CODEPAGESIZE;
}
#define PSTORAGE_FLASH_PAGE_SIZE pstorage_flash_page_size() /**< Size of one flash page. */
#define PSTORAGE_FLASH_EMPTY_MASK 0xFFFFFFFF /**< Bit mask that defines an empty address in flash. */
static __INLINE uint32_t pstorage_flash_page_end()
{
uint32_t bootloader_addr = NRF_UICR->NRFFW[0];
return ((bootloader_addr != PSTORAGE_FLASH_EMPTY_MASK) ?
(bootloader_addr/ PSTORAGE_FLASH_PAGE_SIZE) : NRF_FICR->CODESIZE);
}
#define PSTORAGE_FLASH_PAGE_END pstorage_flash_page_end()
#define PSTORAGE_NUM_OF_PAGES 1 /**< Number of flash pages allocated for the pstorage module excluding the swap page, configurable based on system requirements. */
#define PSTORAGE_MIN_BLOCK_SIZE 0x0010 /**< Minimum size of block that can be registered with the module. Should be configured based on system requirements, recommendation is not have this value to be at least size of word. */
#define PSTORAGE_DATA_START_ADDR ((PSTORAGE_FLASH_PAGE_END - PSTORAGE_NUM_OF_PAGES - 1) \
* PSTORAGE_FLASH_PAGE_SIZE) /**< Start address for persistent data, configurable according to system requirements. */
#define PSTORAGE_DATA_END_ADDR ((PSTORAGE_FLASH_PAGE_END - 1) * PSTORAGE_FLASH_PAGE_SIZE) /**< End address for persistent data, configurable according to system requirements. */
#define PSTORAGE_SWAP_ADDR PSTORAGE_DATA_END_ADDR /**< Top-most page is used as swap area for clear and update. */
#define PSTORAGE_MAX_BLOCK_SIZE PSTORAGE_FLASH_PAGE_SIZE /**< Maximum size of block that can be registered with the module. Should be configured based on system requirements. And should be greater than or equal to the minimum size. */
#define PSTORAGE_CMD_QUEUE_SIZE 10 /**< Maximum number of flash access commands that can be maintained by the module for all applications. Configurable. */
/** Abstracts persistently memory block identifier. */
typedef uint32_t pstorage_block_t;
typedef struct
{
uint32_t module_id; /**< Module ID.*/
pstorage_block_t block_id; /**< Block ID.*/
} pstorage_handle_t;
typedef uint16_t pstorage_size_t; /** Size of length and offset fields. */
/**@brief Handles Flash Access Result Events. To be called in the system event dispatcher of the application. */
void pstorage_sys_event_handler (uint32_t sys_evt);
#endif // PSTORAGE_PL_H__
/** @} */
/** @endcond */

View File

@ -14,7 +14,6 @@
#include "dfu.h"
#include <dfu_types.h>
#include <stddef.h>
#include "boards.h"
#include "nrf.h"
#include "nrf_sdm.h"
#include "nrf_gpio.h"
@ -36,11 +35,17 @@
#include "nrf_delay.h"
#include "sdk_common.h"
#include "platform_config.h"
#define ADVERTISING_LED_PIN_NO LED1_PININDEX /**< Is on when device is advertising. */
#define ADVERTISING_LED_PIN_ON LED1_ONSTATE
#define CONNECTED_LED_PIN_NO LED2_PININDEX /**< Is on when device has connected. */
#define CONNECTED_LED_PIN_ON LED2_ONSTATE
#define DFU_REV_MAJOR 0x00 /** DFU Major revision number to be exposed. */
#define DFU_REV_MINOR 0x08 /** DFU Minor revision number to be exposed. */
#define DFU_REVISION ((DFU_REV_MAJOR << 8) | DFU_REV_MINOR) /** DFU Revision number to be exposed. Combined of major and minor versions. */
#define ADVERTISING_LED_PIN_NO BSP_LED_0 /**< Is on when device is advertising. */
#define CONNECTED_LED_PIN_NO BSP_LED_1 /**< Is on when device has connected. */
#define DFU_SERVICE_HANDLE 0x000C /**< Handle of DFU service when DFU service is first service initialized. */
#define BLE_HANDLE_MAX 0xFFFF /**< Max handle value is BLE. */
@ -734,7 +739,7 @@ static void advertising_start(void)
err_code = sd_ble_gap_adv_start(&m_adv_params);
APP_ERROR_CHECK(err_code);
nrf_gpio_pin_clear(ADVERTISING_LED_PIN_NO);
nrf_gpio_pin_write(ADVERTISING_LED_PIN_NO, ADVERTISING_LED_PIN_ON);
m_is_advertising = true;
}
@ -752,7 +757,7 @@ static void advertising_stop(void)
err_code = sd_ble_gap_adv_stop();
APP_ERROR_CHECK(err_code);
nrf_gpio_pin_set(ADVERTISING_LED_PIN_NO);
nrf_gpio_pin_write(ADVERTISING_LED_PIN_NO, !ADVERTISING_LED_PIN_ON);
m_is_advertising = false;
}
@ -771,8 +776,8 @@ static void on_ble_evt(ble_evt_t * p_ble_evt)
switch (p_ble_evt->header.evt_id)
{
case BLE_GAP_EVT_CONNECTED:
nrf_gpio_pin_clear(CONNECTED_LED_PIN_NO);
nrf_gpio_pin_set(ADVERTISING_LED_PIN_NO);
nrf_gpio_pin_write(CONNECTED_LED_PIN_NO, CONNECTED_LED_PIN_ON);
nrf_gpio_pin_write(ADVERTISING_LED_PIN_NO, !ADVERTISING_LED_PIN_ON);
m_conn_handle = p_ble_evt->evt.gap_evt.conn_handle;
m_is_advertising = false;
@ -784,7 +789,7 @@ static void on_ble_evt(ble_evt_t * p_ble_evt)
uint16_t sys_attr_len = 128;
m_direct_adv_cnt = APP_DIRECTED_ADV_TIMEOUT;
nrf_gpio_pin_set(CONNECTED_LED_PIN_NO);
nrf_gpio_pin_write(CONNECTED_LED_PIN_NO, !CONNECTED_LED_PIN_ON);
err_code = sd_ble_gatts_sys_attr_get(m_conn_handle,
sys_attr,
@ -946,8 +951,8 @@ static void leds_init(void)
{
nrf_gpio_cfg_output(ADVERTISING_LED_PIN_NO);
nrf_gpio_cfg_output(CONNECTED_LED_PIN_NO);
nrf_gpio_pin_set(ADVERTISING_LED_PIN_NO);
nrf_gpio_pin_set(CONNECTED_LED_PIN_NO);
nrf_gpio_pin_write(ADVERTISING_LED_PIN_NO, !ADVERTISING_LED_PIN_ON);
nrf_gpio_pin_write(CONNECTED_LED_PIN_NO, !CONNECTED_LED_PIN_ON);
}

View File

@ -57,8 +57,8 @@
#elif NRF52
#define BOOTLOADER_REGION_START 0x0007A000 /**< This field should correspond to start address of the bootloader, found in UICR.RESERVED, 0x10001014, register. This value is used for sanity check, so the bootloader will fail immediately if this value differs from runtime value. The value is used to determine max application size for updating. */
// see Makefile, dfu_gcc_nrf52.ld, linker_nrf52_ble_espruino_bootloader.ld and dfu_types.h
#define BOOTLOADER_REGION_START 0x00079000 /**< This field should correspond to start address of the bootloader, found in UICR.RESERVED, 0x10001014, register. This value is used for sanity check, so the bootloader will fail immediately if this value differs from runtime value. The value is used to determine max application size for updating. */
#define BOOTLOADER_SETTINGS_ADDRESS 0x0007F000 /**< The field specifies the page location of the bootloader settings address. */
#define BOOTLOADER_MBR_PARAMS_PAGE_ADDRESS 0x0007E000 /**< The field specifies the page location of the mbr params page address. */

View File

@ -155,19 +155,11 @@ static __INLINE void app_error_print(uint32_t id, uint32_t pc, uint32_t info)
*
* @param[in] ERR_CODE Error code supplied to the error handler.
*/
#ifdef DEBUG
#define APP_ERROR_HANDLER(ERR_CODE) \
do \
{ \
app_error_handler((ERR_CODE), __LINE__, (uint8_t*) __FILE__); \
} while (0)
#else
#define APP_ERROR_HANDLER(ERR_CODE) \
do \
{ \
app_error_handler_bare((ERR_CODE)); \
} while (0)
#endif
/**@brief Macro for calling error handler function if supplied error code any other than NRF_SUCCESS.
*
* @param[in] ERR_CODE Error code supplied to the error handler.

View File

@ -0,0 +1,59 @@
/* Linker script to configure memory regions. */
SEARCH_DIR(.)
GROUP(-lgcc -lc -lnosys)
MEMORY
{
/** Flash start address for the bootloader. This setting will also be stored in UICR to allow the
* MBR to init the bootloader when starting the system. This value must correspond to
* BOOTLOADER_REGION_START found in dfu_types.h. The system is prevented from starting up if
* those values do not match. The check is performed in main.c, see
* APP_ERROR_CHECK_BOOL(*((uint32_t *)NRF_UICR_BOOT_START_ADDRESS) == BOOTLOADER_REGION_START);
*/
FLASH (rx) : ORIGIN = 0x3C000, LENGTH = 0x3C00
/** RAM Region for bootloader. This setting is suitable when used with s110, s120, s130, s310. */
RAM (rwx) : ORIGIN = 0x20002C00, LENGTH = 0x5380
/** Location of non initialized RAM. Non initialized RAM is used for exchanging bond information
* from application to bootloader when using buttonluss DFU OTA.
*/
NOINIT (rwx) : ORIGIN = 0x20007F80, LENGTH = 0x80
/** Location of bootloader setting in at the last flash page. */
BOOTLOADER_SETTINGS (rw) : ORIGIN = 0x0003FC00, LENGTH = 0x0400
/** Location in UICR where bootloader start address is stored. */
UICR_BOOTLOADER (r) : ORIGIN = 0x10001014, LENGTH = 0x04
}
SECTIONS
{
.fs_data_out ALIGN(4):
{
PROVIDE( __start_fs_data = .);
KEEP(*(fs_data))
PROVIDE( __stop_fs_data = .);
} = 0
/* Ensures the bootloader settings are placed at the last flash page. */
.bootloaderSettings(NOLOAD) :
{
} > BOOTLOADER_SETTINGS
/* Ensures the Bootloader start address in flash is written to UICR when flashing the image. */
.uicrBootStartAddress :
{
KEEP(*(.uicrBootStartAddress))
} > UICR_BOOTLOADER
/* No init RAM section in bootloader. Used for bond information exchange. */
.noinit(NOLOAD) :
{
} > NOINIT
/* other placements follow here... */
}
INCLUDE "gcc_nrf5x_espruino_common.ld"

View File

@ -0,0 +1,80 @@
/* Linker script to configure memory regions. */
SEARCH_DIR(.)
GROUP(-lgcc -lc -lnosys)
MEMORY
{
/** Flash start address for the bootloader. This setting will also be stored in UICR to allow the
* MBR to init the bootloader when starting the system. This value must correspond to
* BOOTLOADER_REGION_START found in dfu_types.h. The system is prevented from starting up if
* those values do not match. The check is performed in main.c, see
* APP_ERROR_CHECK_BOOL(*((uint32_t *)NRF_UICR_BOOT_START_ADDRESS) == BOOTLOADER_REGION_START);
* see Makefile, dfu_gcc_nrf52.ld, linker_nrf52_ble_espruino_bootloader.ld and dfu_types.h
*/
FLASH (rx) : ORIGIN = 0x79000, LENGTH = 0x5000
/** RAM Region for bootloader. This setting is suitable when used with s132. */
RAM (rwx) : ORIGIN = 0x20002C00, LENGTH = 0x5380
/** Location of non initialized RAM. Non initialized RAM is used for exchanging bond information
* from application to bootloader when using buttonluss DFU OTA.
*/
NOINIT (rwx) : ORIGIN = 0x20007F80, LENGTH = 0x80
/** Location of bootloader setting in flash. */
BOOTLOADER_SETTINGS (rw) : ORIGIN = 0x0007F000, LENGTH = 0x1000
/** Location in UICR where bootloader start address is stored. */
UICR_BOOTLOADER (r) : ORIGIN = 0x10001014, LENGTH = 0x04
/** Location of mbr params page in flash. */
MBR_PARAMS_PAGE (rw) : ORIGIN = 0x0007E000, LENGTH = 0x1000
/** Location in UICR where mbr params page address is stored. */
UICR_MBR_PARAM_PAGE(r) : ORIGIN = 0x10001018, LENGTH = 0x04
}
SECTIONS
{
.fs_data_out ALIGN(4):
{
PROVIDE( __start_fs_data = .);
KEEP(*(fs_data))
PROVIDE( __stop_fs_data = .);
} = 0
/* Place the bootloader settings page in flash. */
.bootloaderSettings(NOLOAD) :
{
} > BOOTLOADER_SETTINGS
/* Write the bootloader address in UICR. */
.uicrBootStartAddress :
{
KEEP(*(.uicrBootStartAddress))
} > UICR_BOOTLOADER
/* Place the mbr params page in flash. */
.mbrParamsPage(NOLOAD) :
{
} > MBR_PARAMS_PAGE
/* Write the bootloader address in UICR. */
.uicrMbrParamsPageAddress :
{
KEEP(*(.uicrMbrParamsPageAddress))
} > UICR_MBR_PARAM_PAGE
/* No init RAM section in bootloader. Used for bond information exchange. */
.noinit(NOLOAD) :
{
} > NOINIT
/* other placements follow here... */
}
INCLUDE "gcc_nrf5x_espruino_common.ld"

View File

@ -6,7 +6,7 @@ GROUP(-lgcc -lc -lnosys)
MEMORY
{
FLASH (rx) : ORIGIN = 0x1b000, LENGTH = 0x25000
RAM (rwx) : ORIGIN = 0x20001fe8, LENGTH = 0x2018
RAM (rwx) : ORIGIN = 0x20002008, LENGTH = 0x1FF8
}
SECTIONS

View File

@ -6,7 +6,7 @@ GROUP(-lgcc -lc -lnosys)
MEMORY
{
FLASH (rx) : ORIGIN = 0x1b000, LENGTH = 0x25000
RAM (rwx) : ORIGIN = 0x20001fe8, LENGTH = 0x6018
RAM (rwx) : ORIGIN = 0x20002008, LENGTH = 0x5FF8
}
SECTIONS

View File

@ -5,8 +5,8 @@ GROUP(-lgcc -lc -lnosys)
MEMORY
{
FLASH (rx) : ORIGIN = 0x1c000, LENGTH = 0x5e000 /* 0x7a000 and above is reserved for the bootloader. */
RAM (rwx) : ORIGIN = 0x200025e0, LENGTH = 0xda20
FLASH (rx) : ORIGIN = 0x1c000, LENGTH = 0x64000
RAM (rwx) : ORIGIN = 0x20002600, LENGTH = 0xda00
/* FIXME - we seem to have to start with 256 bytes less RAM than the figures below */
/* length is just 65536 - origin */
/* PERIPH 1 CENTRAL 0 - RAM (rwx) : ORIGIN = 0x20001E00, LENGTH = 0xE200 */

View File

@ -0,0 +1,26 @@
/* Linker script to configure memory regions. */
SEARCH_DIR(.)
GROUP(-lgcc -lc -lnosys)
MEMORY
{
FLASH (rx) : ORIGIN = 0x1c000, LENGTH = 0x5d000 /* 0x79000 and above is reserved for the bootloader. see Makefile, dfu_gcc_nrf52.ld, linker_nrf52_ble_espruino_bootloader.ld and dfu_types.h */
RAM (rwx) : ORIGIN = 0x20002600, LENGTH = 0xda00
/* FIXME - we seem to have to start with 256 bytes less RAM than the figures below */
/* length is just 65536 - origin */
/* PERIPH 1 CENTRAL 0 - RAM (rwx) : ORIGIN = 0x20001E00, LENGTH = 0xE200 */
/* PERIPH 1 CENTRAL 1 - RAM (rwx) : ORIGIN = 0x200023C8, LENGTH = 0xDC38 */
}
SECTIONS
{
.fs_data_out ALIGN(4):
{
PROVIDE( __start_fs_data = .);
KEEP(*(fs_data))
PROVIDE( __stop_fs_data = .);
} = 0
}
INCLUDE "gcc_nrf5x_espruino_common.ld"

View File

@ -31,14 +31,9 @@
#include "nrf_gpio.h"
#include "nrf_gpiote.h"
#include "nrf_drv_twi.h"
#include "nrf_drv_gpiote.h"
#include "nrf_temp.h"
#include "nrf_timer.h"
#include "app_uart.h"
#include "nrf_drv_uart.h"
#include "nrf_delay.h"
#ifdef NRF52
#include "nrf_saadc.h"
#include "nrf_pwm.h"
@ -46,6 +41,13 @@
#include "nrf_adc.h"
#endif
#include "nrf_drv_uart.h"
#include "nrf_drv_twi.h"
#include "nrf_drv_gpiote.h"
#include "nrf_drv_ppi.h"
#include "app_uart.h"
#include "nrf5x_utils.h"
#include "softdevice_handler.h"
@ -70,6 +72,7 @@ volatile bool flashIsBusy = false;
volatile bool hadEvent = false; // set if we've had an event we need to deal with
bool uartIsSending = false;
bool uartInitialised = false;
unsigned int ticksSinceStart = 0;
JshPinFunction pinStates[JSH_PIN_COUNT];
@ -93,16 +96,48 @@ void sys_evt_handler(uint32_t sys_evt) {
}
}
#ifdef NRF52
/* SysTick interrupt Handler. */
void SysTick_Handler(void) {
/* Handle the delayed Ctrl-C -> interrupt behaviour (see description by EXEC_CTRL_C's definition) */
if (execInfo.execute & EXEC_CTRL_C_WAIT)
execInfo.execute = (execInfo.execute & ~EXEC_CTRL_C_WAIT) | EXEC_INTERRUPTED;
if (execInfo.execute & EXEC_CTRL_C)
execInfo.execute = (execInfo.execute & ~EXEC_CTRL_C) | EXEC_CTRL_C_WAIT;
ticksSinceStart++;
/* One second after start, call jsinteractive. This is used to swap
* to USB (if connected), or the Serial port. */
if (ticksSinceStart == 5) {
jsiOneSecondAfterStartup();
}
}
#endif
#ifdef NRF52
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;
else if ((func&JSH_MASK_TYPE) == JSH_TIMER3) return NRF_PWM2;
return 0;
}
#endif
static NO_INLINE void jshPinSetFunction_int(JshPinFunction func, uint32_t pin) {
JshPinFunction fType = func&JSH_MASK_TYPE;
JshPinFunction fInfo = func&JSH_MASK_INFO;
switch (fType) {
case JSH_NOTHING: break;
#ifdef NRF52
case JSH_TIMER1: NRF_PWM0->PSEL.OUT[fInfo>>JSH_SHIFT_INFO] = pin; break;
case JSH_TIMER2: NRF_PWM1->PSEL.OUT[fInfo>>JSH_SHIFT_INFO] = pin; break;
case JSH_TIMER3: NRF_PWM2->PSEL.OUT[fInfo>>JSH_SHIFT_INFO] = pin; break;
// FIXME: if no pins are active on the given PWM now, turn it off
case JSH_TIMER1:
case JSH_TIMER2:
case JSH_TIMER3: {
NRF_PWM_Type *pwm = nrf_get_pwm(fType);
pwm->PSEL.OUT[fInfo>>JSH_SHIFT_INFO] = pin;
// FIXME: Only disable if nothing else is using it!
if (pin==0xFFFFFFFF) nrf_pwm_disable(pwm);
break;
}
#endif
case JSH_USART1: if (fInfo==JSH_USART_RX) NRF_UART0->PSELRXD = pin;
else NRF_UART0->PSELTXD = pin; break;
@ -179,9 +214,16 @@ void jshInit() {
wakeup_handler);
if (err_code) jsiConsolePrintf("app_timer_create error %d\n", err_code);
#endif
// Softdevice is initialised now
softdevice_sys_evt_handler_set(sys_evt_handler);
// Enable PPI driver
err_code = nrf_drv_ppi_init();
APP_ERROR_CHECK(err_code);
#ifdef NRF52
// Turn on SYSTICK - used for handling Ctrl-C behaviour
SysTick_Config(0xFFFFFF);
#endif
}
// When 'reset' is called - we try and put peripherals back to their power-on state
@ -196,10 +238,12 @@ void jshKill() {
// stuff to do on idle
void jshIdle() {
#ifndef NRF52
if (init == 1) {
jsiOneSecondAfterStartup(); // Do this the first time we enter jshIdle() after we have called jshInit() and never again.
init = 0;
}
#endif
}
/// Get this IC's serial number. Passed max # of chars and a pointer to write to. Returns # of chars
@ -288,6 +332,7 @@ void jshPinSetState(Pin pin, JshPinState state) {
| (GPIO_PIN_CNF_DIR_Output << GPIO_PIN_CNF_DIR_Pos);
break;
case JSHPINSTATE_GPIO_IN :
case JSHPINSTATE_ADC_IN :
nrf_gpio_cfg_input(ipin, NRF_GPIO_PIN_NOPULL);
break;
case JSHPINSTATE_GPIO_IN_PULLUP :
@ -296,9 +341,7 @@ void jshPinSetState(Pin pin, JshPinState state) {
case JSHPINSTATE_GPIO_IN_PULLDOWN :
nrf_gpio_cfg_input(ipin, NRF_GPIO_PIN_PULLDOWN);
break;
/*case JSHPINSTATE_ADC_IN :
break;
case JSHPINSTATE_AF_OUT :
/*case JSHPINSTATE_AF_OUT :
break;
case JSHPINSTATE_AF_OUT_OPENDRAIN :
break;
@ -354,6 +397,7 @@ nrf_saadc_value_t nrf_analog_read() {
// Returns an analog value between 0 and 1
JsVarFloat jshPinAnalog(Pin pin) {
if (pinInfo[pin].analog == JSH_ANALOG_NONE) return NAN;
jshPinSetState(pin, JSHPINSTATE_ADC_IN);
#ifdef NRF52
// sanity checks for channel
assert(NRF_SAADC_INPUT_AIN0 == 1);
@ -376,7 +420,10 @@ JsVarFloat jshPinAnalog(Pin pin) {
nrf_saadc_resolution_set(NRF_SAADC_RESOLUTION_14BIT);
nrf_saadc_channel_init(0, &config);
return nrf_analog_read() / 16384.0;
JsVarFloat f = nrf_analog_read() / 16384.0;
nrf_saadc_channel_input_set(0, NRF_SAADC_INPUT_DISABLED, NRF_SAADC_INPUT_DISABLED); // give us back our pin!
nrf_saadc_disable();
return f;
#else
const nrf_adc_config_t nrf_adc_config = {
NRF_ADC_CONFIG_RES_10BIT,
@ -453,11 +500,8 @@ JshPinFunction jshPinAnalogOutput(Pin pin, JsVarFloat value, JsVarFloat freq, Js
JshPinFunction func = JSH_TIMER1 | JSH_TIMER_CH1;
// FIXME: Search for free timers to use (based on freq as well)
NRF_PWM_Type *pwm;
if ((func&JSH_MASK_TYPE) == JSH_TIMER1) pwm = NRF_PWM0;
else if ((func&JSH_MASK_TYPE) == JSH_TIMER2) pwm = NRF_PWM1;
else if ((func&JSH_MASK_TYPE) == JSH_TIMER3) pwm = NRF_PWM2;
else { assert(0); return 0; };
NRF_PWM_Type *pwm = nrf_get_pwm(func);
if (!pwm) { assert(0); return 0; };
jshPinSetState(pin, JSHPINSTATE_GPIO_OUT);
jshPinSetFunction(pin, func);
nrf_pwm_enable(pwm);
@ -562,6 +606,7 @@ static void jsvPinWatchHandler(nrf_drv_gpiote_pin_t pin, nrf_gpiote_polarity_t a
lastHandledPinState = (bool)nrf_gpio_pin_read(pin);
IOEventFlags evt = jshGetEventFlagsForWatchedPin(pin);
jshPushIOWatchEvent(evt);
jshHadEvent();
}
@ -574,7 +619,7 @@ IOEventFlags jshPinWatch(Pin pin, bool shouldWatch) {
if (!jshIsPinValid(pin)) return EV_NONE;
uint32_t p = (uint32_t)pinInfo[pin].pin;
if (shouldWatch) {
nrf_drv_gpiote_in_config_t cls_1_config = GPIOTE_CONFIG_IN_SENSE_TOGGLE(true);
nrf_drv_gpiote_in_config_t cls_1_config = GPIOTE_CONFIG_IN_SENSE_TOGGLE(true); // FIXME: Maybe we want low accuracy? Otherwise this will
nrf_drv_gpiote_in_init(p, &cls_1_config, jsvPinWatchHandler);
nrf_drv_gpiote_in_event_enable(p, true);
return jshGetEventFlagsForWatchedPin(p);
@ -643,6 +688,11 @@ void jshUSARTSetup(IOEventFlags device, JshUSARTInfo *inf) {
if (!jshIsPinValid(inf->pinRX) || !jshIsPinValid(inf->pinTX))
return jsError("Invalid RX or TX pins");
if (uartInitialised) {
uartInitialised = false;
app_uart_close();
}
uint32_t err_code;
const app_uart_comm_params_t comm_params = {
pinInfo[inf->pinRX].pin,
@ -661,21 +711,13 @@ void jshUSARTSetup(IOEventFlags device, JshUSARTInfo *inf) {
uart0_event_handle,
APP_IRQ_PRIORITY_HIGH,
err_code);
APP_ERROR_CHECK(err_code);
if (err_code)
jsExceptionHere(JSET_INTERNALERROR, "app_uart_init failed, error %d", err_code);
uartInitialised = true;
}
/** Kick a device into action (if required). For instance we may need to set up interrupts */
void jshUSARTKick(IOEventFlags device) {
if (device == EV_BLUETOOTH) {
/* For bluetooth, start transmit after one character.
The BLE_EVT_TX_COMPLETE event will get triggered and
will auto-reload whatever needs sending. */
bool jswrap_nrf_transmit_string();
jswrap_nrf_transmit_string();
}
if (device == EV_SERIAL1) {
if (uartInitialised) {
if (!uartIsSending) {

View File

@ -19,8 +19,13 @@
int main() {
jshInit();
bool buttonState = false;
#ifdef BTN1_PININDEX
buttonState = jshPinInput(BTN1_PININDEX) == BTN1_ONSTATE;
#endif
jsvInit();
jsiInit(true /* load from flash by default */);
jsiInit(!buttonState /* load from flash by default */); // pressing USER button skips autoload
while (1)
{

View File

@ -18,9 +18,16 @@
#include "nrf.h"
#include "nrf_gpio.h"
#include "nrf_gpiote.h"
#include "app_uart.h"
#include "nrf_error.h"
#include "nrf_nvmc.h"
#include "nrf_timer.h"
#include "nrf_drv_gpiote.h"
#include "nrf_drv_ppi.h"
#include "jsparse.h"
unsigned int nrf_utils_get_baud_enum(int baud) {
switch (baud) {
@ -56,8 +63,8 @@ void nrf_utils_lfclk_config_and_start()
NRF_CLOCK->TASKS_LFCLKSTART = 1;
while(NRF_CLOCK->EVENTS_LFCLKSTARTED == 0);
/*
// wait until the clock is running - Xtal only?
/*
// wait until the clock is running - Xtal only?
while (((NRF_CLOCK->LFCLKSTAT & CLOCK_LFCLKSTAT_STATE_Msk) != ((CLOCK_LFCLKSTAT_STATE_Running << CLOCK_LFCLKSTAT_STATE_Pos) & CLOCK_LFCLKSTAT_STATE_Msk)))
{
// Do nothing...
@ -86,7 +93,7 @@ int nrf_utils_get_device_id(uint8_t * device_id, int maxChars)
uint8_t nrf_utils_get_random_number()
{
NRF_RNG->CONFIG = 0x00000001; // Use the bias generator.
NRF_RNG->TASKS_START = 1;
@ -104,3 +111,119 @@ uint8_t nrf_utils_get_random_number()
return rand_num;
}
unsigned int nrf_utils_cap_sense(int capSenseTxPin, int capSenseRxPin) {
#ifdef NRF5DDD
uint32_t err_code;
nrf_drv_gpiote_in_config_t rxconfig = GPIOTE_CONFIG_IN_SENSE_LOTOHI(true);
nrf_drv_gpiote_in_init(capSenseRxPin, &rxconfig, 0);
nrf_drv_gpiote_in_event_enable(capSenseRxPin, false /* no interrupt */);
//
nrf_drv_gpiote_out_config_t txconfig = GPIOTE_CONFIG_OUT_TASK_TOGGLE(true);
nrf_drv_gpiote_out_init(capSenseTxPin, &txconfig);
nrf_drv_gpiote_out_task_enable(capSenseTxPin);
//;
nrf_timer_mode_set(NRF_TIMER2, TIMER_MODE_MODE_Timer);
nrf_timer_bit_width_set(NRF_TIMER2, NRF_TIMER_BIT_WIDTH_16);
nrf_timer_frequency_set(NRF_TIMER2, NRF_TIMER_FREQ_16MHz);
nrf_timer_cc_write(NRF_TIMER2, 0, 0);
nrf_timer_cc_write(NRF_TIMER2, 1, 2047);
nrf_timer_cc_write(NRF_TIMER2, 3, 4095);
nrf_timer_shorts_enable(NRF_TIMER2, NRF_TIMER_SHORT_COMPARE3_CLEAR_MASK);
nrf_ppi_channel_t ppi_channel1, ppi_channel2, ppi_channel3;
// 1: When RX pin goes low->high, capture it in the timer
err_code = nrf_drv_ppi_channel_alloc(&ppi_channel1);
APP_ERROR_CHECK(err_code);
err_code = nrf_drv_ppi_channel_assign(ppi_channel1,
nrf_drv_gpiote_in_event_addr_get(capSenseRxPin),
nrf_timer_task_address_get(NRF_TIMER2, NRF_TIMER_TASK_CAPTURE2));
APP_ERROR_CHECK(err_code);
// 2: When timer is at Compare0, toggle
err_code = nrf_drv_ppi_channel_alloc(&ppi_channel2);
APP_ERROR_CHECK(err_code);
err_code = nrf_drv_ppi_channel_assign(ppi_channel2,
nrf_timer_event_address_get(NRF_TIMER2, NRF_TIMER_EVENT_COMPARE0),
nrf_drv_gpiote_out_task_addr_get(capSenseTxPin));
APP_ERROR_CHECK(err_code);
// 3: When timer is at Compare1, toggle
err_code = nrf_drv_ppi_channel_alloc(&ppi_channel3);
APP_ERROR_CHECK(err_code);
err_code = nrf_drv_ppi_channel_assign(ppi_channel3,
nrf_timer_event_address_get(NRF_TIMER2, NRF_TIMER_EVENT_COMPARE1),
nrf_drv_gpiote_out_task_addr_get(capSenseTxPin));
APP_ERROR_CHECK(err_code);
// Enable both configured PPI channels
err_code = nrf_drv_ppi_channel_enable(ppi_channel1);
APP_ERROR_CHECK(err_code);
err_code = nrf_drv_ppi_channel_enable(ppi_channel2);
APP_ERROR_CHECK(err_code);
err_code = nrf_drv_ppi_channel_enable(ppi_channel3);
APP_ERROR_CHECK(err_code);
// start timer
NRF_TIMER2->CC[2] = 0;
nrf_timer_task_trigger(NRF_TIMER2, NRF_TIMER_TASK_START);
nrf_gpio_cfg_input(capSenseRxPin, NRF_GPIO_PIN_NOPULL);
nrf_gpio_cfg_output(capSenseTxPin);
//
unsigned int sum = 0;
NRF_TIMER2->EVENTS_COMPARE[1] = 0;
int i;
for (i=0;i<50;i++) {
unsigned int timeout = 100000;
while (!NRF_TIMER2->EVENTS_COMPARE[1] && --timeout);
NRF_TIMER2->EVENTS_COMPARE[1] = 0;
sum += NRF_TIMER2->CC[2];
if (jspIsInterrupted()) break;
}
nrf_gpio_cfg_input(capSenseTxPin, NRF_GPIO_PIN_NOPULL);
nrf_timer_task_trigger(NRF_TIMER2, NRF_TIMER_TASK_STOP);
nrf_timer_shorts_disable(NRF_TIMER2, NRF_TIMER_SHORT_COMPARE3_CLEAR_MASK);
nrf_drv_ppi_channel_disable(ppi_channel3);
nrf_drv_ppi_channel_disable(ppi_channel2);
nrf_drv_ppi_channel_disable(ppi_channel1);
nrf_drv_ppi_channel_free(ppi_channel3);
nrf_drv_ppi_channel_free(ppi_channel2);
nrf_drv_ppi_channel_free(ppi_channel1);
nrf_drv_gpiote_in_uninit(capSenseTxPin);
nrf_drv_gpiote_in_uninit(capSenseRxPin);
return sum;
#else
unsigned int sum = 0;
int i;
unsigned int mask = 1<<capSenseRxPin;
nrf_gpio_cfg_input(capSenseRxPin, NRF_GPIO_PIN_NOPULL);
nrf_gpio_pin_clear(capSenseTxPin);
nrf_gpio_cfg_output(capSenseTxPin);
for (i=0;i<100;i++) {
const unsigned int CTR_MAX = 100000;
unsigned int ctr = CTR_MAX;
nrf_gpio_pin_set(capSenseTxPin);
while (!(NRF_GPIO->IN & mask) && ctr--);
sum += CTR_MAX-ctr;
nrf_gpio_pin_clear(capSenseTxPin);
while (NRF_GPIO->IN & mask && ctr--);
sum += CTR_MAX-ctr;
if (jspIsInterrupted()) break;
}
nrf_gpio_cfg_input(capSenseTxPin, NRF_GPIO_PIN_NOPULL);
return sum;
#endif
}

View File

@ -28,6 +28,8 @@ void nrf_utils_lfclk_config_and_start(void);
int nrf_utils_get_device_id(uint8_t * device_id, int maxChars);
uint8_t nrf_utils_get_random_number(void);
unsigned int nrf_utils_cap_sense(int capSenseTxPin, int capSenseRxPin);
#endif // NRF5X_UTILS_H__
/** @} */

View File

@ -0,0 +1,205 @@
/* Copyright (c) 2014 Nordic Semiconductor. All Rights Reserved.
*
* The information contained herein is property of Nordic Semiconductor ASA.
* Terms and conditions of usage are described in detail in NORDIC
* SEMICONDUCTOR STANDARD SOFTWARE LICENSE AGREEMENT.
*
* Licensees are granted free, non-transferable use of the information. NO
* WARRANTY of ANY KIND is provided. This heading must NOT be removed from
* the file.
*
*/
#include "dfu_ble_svc.h"
#include <string.h>
#include "nrf_error.h"
#include "crc16.h"
#if defined ( __CC_ARM )
static dfu_ble_peer_data_t m_peer_data __attribute__((section("NoInit"), zero_init)); /**< This variable should be placed in a non initialized RAM section in order to be valid upon soft reset from application into bootloader. */
static uint16_t m_peer_data_crc __attribute__((section("NoInit"), zero_init)); /**< CRC variable to ensure the integrity of the peer data provided. */
#elif defined ( __GNUC__ )
__attribute__((section(".noinit"))) static dfu_ble_peer_data_t m_peer_data; /**< This variable should be placed in a non initialized RAM section in order to be valid upon soft reset from application into bootloader. */
__attribute__((section(".noinit"))) static uint16_t m_peer_data_crc; /**< CRC variable to ensure the integrity of the peer data provided. */
#elif defined ( __ICCARM__ )
__no_init static dfu_ble_peer_data_t m_peer_data @ 0x20003F80; /**< This variable should be placed in a non initialized RAM section in order to be valid upon soft reset from application into bootloader. */
__no_init static uint16_t m_peer_data_crc @ 0x20003F80 + sizeof(dfu_ble_peer_data_t); /**< CRC variable to ensure the integrity of the peer data provided. */
#endif
/**@brief Function for setting the peer data from application in bootloader before reset.
*
* @param[in] p_peer_data Pointer to the peer data containing keys for the connection.
*
* @retval NRF_SUCCES The data was set succesfully.
* @retval NRF_ERROR_NULL If a null pointer was passed as argument.
*/
static uint32_t dfu_ble_peer_data_set(dfu_ble_peer_data_t * p_peer_data)
{
if (p_peer_data == NULL)
{
return NRF_ERROR_NULL;
}
uint32_t src = (uint32_t)p_peer_data;
uint32_t dst = (uint32_t)&m_peer_data;
// Calculating length in order to check if destination is residing inside source.
// Source inside the the destination (calculation underflow) is safe a source is read before
// written to destination so that when destination grows into source, the source data is no
// longer needed.
uint32_t len = dst - src;
if (src == dst)
{
// Do nothing as source and destination are identical, just calculate crc below.
}
else if (len < sizeof(dfu_ble_peer_data_t))
{
uint32_t i = 0;
dst += sizeof(dfu_ble_peer_data_t);
src += sizeof(dfu_ble_peer_data_t);
// Copy byte wise backwards when facing overlapping structures.
while (i++ <= sizeof(dfu_ble_peer_data_t))
{
*((uint8_t *)dst--) = *((uint8_t *)src--);
}
}
else
{
memcpy((void *)dst, (void *)src, sizeof(dfu_ble_peer_data_t));
}
m_peer_data_crc = crc16_compute((uint8_t *)&m_peer_data, sizeof(m_peer_data), NULL);
return NRF_SUCCESS;
}
/**@brief Function for handling second stage of SuperVisor Calls (SVC).
*
* @details The function will use svc_num to call the corresponding SVC function.
*
* @param[in] svc_num SVC number for function to be executed
* @param[in] p_svc_args Argument list for the SVC.
*
* @return This function returns the error value of the SVC return. For further details, please
* refer to the details of the SVC implementation itself.
* @ref NRF_ERROR_SVC_HANDLER_MISSING is returned if no SVC handler is implemented for the
* provided svc_num.
*/
void C_SVC_Handler(uint8_t svc_num, uint32_t * p_svc_args)
{
switch (svc_num)
{
case DFU_BLE_SVC_PEER_DATA_SET:
p_svc_args[0] = dfu_ble_peer_data_set((dfu_ble_peer_data_t *)p_svc_args[0]);
break;
default:
p_svc_args[0] = NRF_ERROR_SVC_HANDLER_MISSING;
break;
}
}
/**@brief Function for handling the first stage of SuperVisor Calls (SVC) in assembly.
*
* @details The function will use the link register (LR) to determine the stack (PSP or MSP) to be
* used and then decode the SVC number afterwards. After decoding the SVC number then
* @ref C_SVC_Handler is called for further processing of the SVC.
*/
#if defined ( __CC_ARM )
__asm void SVC_Handler(void)
{
EXC_RETURN_CMD_PSP EQU 0xFFFFFFFD ; EXC_RETURN using PSP for ARM Cortex. If Link register contains this value it indicates the PSP was used before the SVC, otherwise the MSP was used.
IMPORT C_SVC_Handler
LDR R0, =EXC_RETURN_CMD_PSP ; Load the EXC_RETURN into R0 to be able to compare against LR to determine stack pointer used.
CMP R0, LR ; Compare the link register with R0. If equal then PSP was used, otherwise MSP was used before SVC.
BNE UseMSP ; Branch to code fetching SVC arguments using MSP.
MRS R1, PSP ; Move PSP into R1.
B Call_C_SVC_Handler ; Branch to Call_C_SVC_Handler below.
UseMSP
MRS R1, MSP ; MSP was used, therefore Move MSP into R1.
Call_C_SVC_Handler
LDR R0, [R1, #24] ; The arguments for the SVC was stacked. R1 contains Stack Pointer, the values stacked before SVC are R0, R1, R2, R3, R12, LR, PC (Return address), xPSR.
; R1 contains current SP so the PC of the stacked frame is at SP + 6 words (24 bytes). We load the PC into R0.
SUBS R0, #2 ; The PC before the SVC is in R0. We subtract 2 to get the address prior to the instruction executed where the SVC number is located.
LDRB R0, [R0] ; SVC instruction low octet: Load the byte at the address before the PC to fetch the SVC number.
LDR R2, =C_SVC_Handler ; Load address of C implementation of SVC handler.
BX R2 ; Branch to C implementation of SVC handler. R0 is now the SVC number, R1 is the StackPointer where the arguments (R0-R3) of the original SVC are located.
ALIGN
}
#elif defined ( __GNUC__ )
void __attribute__ (( naked )) SVC_Handler(void)
{
const uint32_t exc_return = 0xFFFFFFFD; // EXC_RETURN using PSP for ARM Cortex. If Link register contains this value it indicates the PSP was used before the SVC, otherwise the MSP was used.
__asm volatile(
"cmp lr, %0\t\n" // Compare the link register with argument 0 (%0), which is exc_return. If equal then PSP was used, otherwise MSP was used before SVC.
"bne UseMSP\t\n" // Branch to code fetching SVC arguments using MSP.
"mrs r1, psp\t\n" // Move PSP into R1.
"b Call_C_SVC_Handler\t\n" // Branch to Call_C_SVC_Handler below.
"UseMSP: \t\n" //
"mrs r1, msp\t\n" // MSP was used, therefore Move MSP into R1.
"Call_C_SVC_Handler: \t\n" //
"ldr r0, [r1, #24]\t\n" // The arguments for the SVC was stacked. R1 contains Stack Pointer, the values stacked before SVC are R0, R1, R2, R3, R12, LR, PC (Return address), xPSR.
// R1 contains current SP so the PC of the stacked frame is at SP + 6 words (24 bytes). We load the PC into R0.
"sub r0, r0, #2\t\n" // The PC before the SVC is in R0. We subtract 2 to get the address prior to the instruction executed where the SVC number is located.
"ldrb r0, [r0]\t\n" // SVC instruction low octet: Load the byte at the address before the PC to fetch the SVC number.
"bx %1\t\n" // Branch to C implementation of SVC handler, argument 1 (%1). R0 is now the SVC number, R1 is the StackPointer where the arguments (R0-R3) of the original SVC are located.
".align\t\n"
:: "r" (exc_return), "r" (C_SVC_Handler) // Argument list for the gcc assembly. exc_return is %0, C_SVC_Handler is %1.
: "r0", "r1" // List of register maintained manually.
);
}
#elif defined ( __ICCARM__ )
void SVC_Handler(void)
{
asm("movs r0, #0x02\n" // Load 0x02 into R6 to prepare for exec return test.
"mvns r0, r0\n" // Invert R0 to obtain exec return code using PSP for ARM Cortex.
"cmp lr, r0\n" // Compare the link register with argument 0 (%0), which is exc_return. If equal then PSP was used, otherwise MSP was used before SVC.
"bne.n UseMSP\n" // Branch to code fetching SVC arguments using MSP.
"mrs r1, psp\n" // Move PSP into R1.
"b.n Call_C_SVC_Handler\t\n" // Branch to Call_C_SVC_Handler below.
"UseMSP: \n" //
"mrs r1, msp\n" // MSP was used, therefore Move MSP into R1.
"Call_C_SVC_Handler: \n" //
"ldr r0, [r1, #24]\n" // The arguments for the SVC was stacked. R1 contains Stack Pointer, the values stacked before SVC are R0, R1, R2, R3, R12, LR, PC (Return address), xPSR.
// R1 contains current SP so the PC of the stacked frame is at SP + 6 words (24 bytes). We load the PC into R0.
"subs r0, #0x02\n" // The PC before the SVC is in R0. We subtract 2 to get the address prior to the instruction executed where the SVC number is located.
"ldrb r0, [r0]\n" // SVC instruction low octet: Load the byte at the address before the PC to fetch the SVC number.
"bx %0\n" // Branch to C implementation of SVC handler, argument 1 (%1). R0 is now the SVC number, R1 is the StackPointer where the arguments (R0-R3) of the original SVC are located.
:: "r" (C_SVC_Handler) // Argument list for the gcc assembly. C_SVC_Handler is %0.
: "r0", "r1" // List of register maintained manually.
);
}
#else
#error Compiler not supported.
#endif
uint32_t dfu_ble_peer_data_get(dfu_ble_peer_data_t * p_peer_data)
{
uint16_t crc;
if (p_peer_data == NULL)
{
return NRF_ERROR_NULL;
}
crc = crc16_compute((uint8_t *)&m_peer_data, sizeof(m_peer_data), NULL);
if (crc != m_peer_data_crc)
{
return NRF_ERROR_INVALID_DATA;
}
*p_peer_data = m_peer_data;
// corrupt CRC to invalidate shared information.
m_peer_data_crc++;
return NRF_SUCCESS;
}

279
targets/nrf5x_dfu/main.c Normal file
View File

@ -0,0 +1,279 @@
/* Copyright (c) 2013 Nordic Semiconductor. All Rights Reserved.
*
* The information contained herein is property of Nordic Semiconductor ASA.
* Terms and conditions of usage are described in detail in NORDIC
* SEMICONDUCTOR STANDARD SOFTWARE LICENSE AGREEMENT.
*
* Licensees are granted free, non-transferable use of the information. NO
* WARRANTY of ANY KIND is provided. This heading must NOT be removed from
* the file.
*
*/
/**@file
*
* @defgroup ble_sdk_app_bootloader_main main.c
* @{
* @ingroup dfu_bootloader_api
* @brief Bootloader project main file.
*
* -# Receive start data packet.
* -# Based on start packet, prepare NVM area to store received data.
* -# Receive data packet.
* -# Validate data packet.
* -# Write Data packet to NVM.
* -# If not finished - Wait for next packet.
* -# Receive stop data packet.
* -# Activate Image, boot application.
*
*/
#include "dfu_transport.h"
#include "bootloader.h"
#include "bootloader_util.h"
#include <stdint.h>
#include <string.h>
#include <stddef.h>
#include "nordic_common.h"
#include "nrf.h"
#include "nrf_soc.h"
#include "app_error.h"
#include "nrf_gpio.h"
#include "ble.h"
#include "nrf.h"
#include "ble_hci.h"
#include "app_scheduler.h"
#include "app_timer_appsh.h"
#include "nrf_error.h"
#include "softdevice_handler_appsh.h"
#include "pstorage_platform.h"
#include "nrf_mbr.h"
#include "nrf_log.h"
#include "nrf_delay.h"
#include "platform_config.h"
#define BOOTLOADER_BUTTON BTN1_PININDEX /**< Button used to enter SW update mode. */
#define BOOTLOADER_BUTTON_ONSTATE BTN1_ONSTATE /**< Button used to enter SW update mode. */
#define UPDATE_IN_PROGRESS_LED LED3_PININDEX /**< Led used to indicate that DFU is active. */
#define UPDATE_IN_PROGRESS_LED_ONSTATE LED3_ONSTATE /**< Led used to indicate that DFU is active. */
#define BOOTLOADER_BUTTON_PRESS_LED LED2_PININDEX /**< Led used to indicate that DFU is active. */
#define BOOTLOADER_BUTTON_PRESS_LED_ONSTATE LED2_ONSTATE /**< Led used to indicate that DFU is active. */
// Other LED is set in targetlibs/nrf5x/nrf5_sdk/components/libraries/bootloader_dfu/dfu_transport_ble.c (currently LED1)
#define IS_SRVC_CHANGED_CHARACT_PRESENT 1 /**< Include the service_changed characteristic. For DFU this should normally be the case. */
#define APP_TIMER_PRESCALER 0 /**< Value of the RTC1 PRESCALER register. */
#define APP_TIMER_OP_QUEUE_SIZE 4 /**< Size of timer operation queues. */
#define SCHED_MAX_EVENT_DATA_SIZE MAX(APP_TIMER_SCHED_EVT_SIZE, 0) /**< Maximum size of scheduler events. */
#define SCHED_QUEUE_SIZE 20 /**< Maximum number of events in the scheduler queue. */
/**@brief Callback function for asserts in the SoftDevice.
*
* @details This function will be called in case of an assert in the SoftDevice.
*
* @warning This handler is an example only and does not fit a final product. You need to analyze
* how your product is supposed to react in case of Assert.
* @warning On assert from the SoftDevice, the system can only recover on reset.
*
* @param[in] line_num Line number of the failing ASSERT call.
* @param[in] file_name File name of the failing ASSERT call.
*/
void assert_nrf_callback(uint16_t line_num, const uint8_t * p_file_name)
{
app_error_handler(0xDEADBEEF, line_num, p_file_name);
}
/**@brief Function for initialization of LEDs.
*/
static void leds_init(void)
{
nrf_gpio_cfg_output(UPDATE_IN_PROGRESS_LED);
nrf_gpio_pin_write(UPDATE_IN_PROGRESS_LED, !UPDATE_IN_PROGRESS_LED_ONSTATE);
nrf_gpio_cfg_output(BOOTLOADER_BUTTON_PRESS_LED);
nrf_gpio_pin_write(BOOTLOADER_BUTTON_PRESS_LED, !BOOTLOADER_BUTTON_PRESS_LED_ONSTATE);
}
/**@brief Function for initializing the timer handler module (app_timer).
*/
static void timers_init(void)
{
// Initialize timer module, making it use the scheduler.
APP_TIMER_APPSH_INIT(APP_TIMER_PRESCALER, APP_TIMER_OP_QUEUE_SIZE, true);
}
/**@brief Function for initializing the button module.
*/
static void buttons_init(void)
{
nrf_gpio_cfg_sense_input(BOOTLOADER_BUTTON,
BOOTLOADER_BUTTON_ONSTATE ? NRF_GPIO_PIN_PULLDOWN : NRF_GPIO_PIN_PULLUP,
BOOTLOADER_BUTTON_ONSTATE ? NRF_GPIO_PIN_SENSE_HIGH : NRF_GPIO_PIN_SENSE_LOW);
}
/**@brief Function for dispatching a BLE stack event to all modules with a BLE stack event handler.
*
* @details This function is called from the scheduler in the main loop after a BLE stack
* event has been received.
*
* @param[in] p_ble_evt Bluetooth stack event.
*/
static void sys_evt_dispatch(uint32_t event)
{
pstorage_sys_event_handler(event);
}
/**@brief Function for initializing the BLE stack.
*
* @details Initializes the SoftDevice and the BLE event interrupt.
*
* @param[in] init_softdevice true if SoftDeviceshould be initialized. The SoftDevice must only
* be initialized if a chip reset has occured. Soft reset from
* application must not reinitialize the SoftDevice.
*/
static void ble_stack_init(bool init_softdevice)
{
uint32_t err_code;
sd_mbr_command_t com = {SD_MBR_COMMAND_INIT_SD, };
if (init_softdevice)
{
err_code = sd_mbr_command(&com);
APP_ERROR_CHECK(err_code);
}
err_code = sd_softdevice_vector_table_base_set(BOOTLOADER_REGION_START);
APP_ERROR_CHECK(err_code);
// TODO: enable if we're on a device with 32kHz xtal
/*nrf_clock_lf_cfg_t clock_lf_cfg = {
.source = NRF_CLOCK_LF_SRC_XTAL,
.rc_ctiv = 0,
.rc_temp_ctiv = 0,
.xtal_accuracy = NRF_CLOCK_LF_XTAL_ACCURACY_20_PPM};*/
nrf_clock_lf_cfg_t clock_lf_cfg = {
.source = NRF_CLOCK_LF_SRC_RC,
.rc_ctiv = 16, // recommended for nRF52
.rc_temp_ctiv = 2, // recommended for nRF52
.xtal_accuracy = 0};
SOFTDEVICE_HANDLER_APPSH_INIT(&clock_lf_cfg, true);
// Enable BLE stack.
ble_enable_params_t ble_enable_params;
// Only one connection as a central is used when performing dfu.
err_code = softdevice_enable_get_default_config(1, 1, &ble_enable_params);
APP_ERROR_CHECK(err_code);
ble_enable_params.gatts_enable_params.service_changed = IS_SRVC_CHANGED_CHARACT_PRESENT;
err_code = softdevice_enable(&ble_enable_params);
APP_ERROR_CHECK(err_code);
err_code = softdevice_sys_evt_handler_set(sys_evt_dispatch);
APP_ERROR_CHECK(err_code);
}
/**@brief Function for event scheduler initialization.
*/
static void scheduler_init(void)
{
APP_SCHED_INIT(SCHED_MAX_EVENT_DATA_SIZE, SCHED_QUEUE_SIZE);
}
/**@brief Function for bootloader main entry.
*/
int main(void)
{
uint32_t err_code;
bool dfu_start = false;
bool app_reset = (NRF_POWER->GPREGRET == BOOTLOADER_DFU_START);
if (app_reset)
{
NRF_POWER->GPREGRET = 0;
}
leds_init();
// This check ensures that the defined fields in the bootloader corresponds with actual
// setting in the chip.
APP_ERROR_CHECK_BOOL(*((uint32_t *)NRF_UICR_BOOT_START_ADDRESS) == BOOTLOADER_REGION_START);
APP_ERROR_CHECK_BOOL(NRF_FICR->CODEPAGESIZE == CODE_PAGE_SIZE);
// Initialize.
timers_init();
buttons_init();
(void)bootloader_init();
if (bootloader_dfu_sd_in_progress())
{
nrf_gpio_pin_write(UPDATE_IN_PROGRESS_LED, UPDATE_IN_PROGRESS_LED_ONSTATE);
err_code = bootloader_dfu_sd_update_continue();
APP_ERROR_CHECK(err_code);
ble_stack_init(!app_reset);
scheduler_init();
err_code = bootloader_dfu_sd_update_finalize();
APP_ERROR_CHECK(err_code);
nrf_gpio_pin_write(UPDATE_IN_PROGRESS_LED, !UPDATE_IN_PROGRESS_LED_ONSTATE);
}
else
{
// If stack is present then continue initialization of bootloader.
ble_stack_init(!app_reset);
scheduler_init();
}
dfu_start = app_reset;
dfu_start |= ((nrf_gpio_pin_read(BOOTLOADER_BUTTON) == BOOTLOADER_BUTTON_ONSTATE) ? true: false);
// If button is held down for 3 seconds, don't start bootloader.
// This means that we go straight to Espruino, where the button is still
// pressed and can be used to stop execution of the sent code.
if (dfu_start) {
nrf_gpio_pin_write(BOOTLOADER_BUTTON_PRESS_LED, BOOTLOADER_BUTTON_PRESS_LED_ONSTATE);
int count = 3000;
while (nrf_gpio_pin_read(BOOTLOADER_BUTTON) == BOOTLOADER_BUTTON_ONSTATE && count) {
nrf_delay_us(999);
count--;
}
if (!count)
dfu_start = false;
nrf_gpio_pin_write(BOOTLOADER_BUTTON_PRESS_LED, !BOOTLOADER_BUTTON_PRESS_LED_ONSTATE);
}
if (dfu_start || (!bootloader_app_is_valid(DFU_BANK_0_REGION_START))) {
nrf_gpio_pin_write(UPDATE_IN_PROGRESS_LED, UPDATE_IN_PROGRESS_LED_ONSTATE);
// Initiate an update of the firmware.
err_code = bootloader_dfu_start();
APP_ERROR_CHECK(err_code);
nrf_gpio_pin_write(UPDATE_IN_PROGRESS_LED, !UPDATE_IN_PROGRESS_LED_ONSTATE);
}
if (bootloader_app_is_valid(DFU_BANK_0_REGION_START) && !bootloader_dfu_sd_in_progress())
{
// Select a bank region to use as application region.
// @note: Only applications running from DFU_BANK_0_REGION_START is supported.
bootloader_app_start(DFU_BANK_0_REGION_START);
}
NVIC_SystemReset();
}

View File

@ -707,6 +707,7 @@ void jshSetupRTC(bool isUsingLSI) {
RTC_InitStructure.RTC_HourFormat = RTC_HourFormat_24;
RTC_Init(&RTC_InitStructure);
#endif
RTC_WaitForSynchro();
}
void jshResetRTCTimer() {
@ -729,9 +730,10 @@ void jshDoSysTick() {
if (ticksSinceStart==RTC_INITIALISE_TICKS) {
// Use LSI if the LSE hasn't stabilised
bool isUsingLSI = RCC_GetFlagStatus(RCC_FLAG_LSERDY)==RESET;
bool wasUsingLSI = !jshIsRTCUsingLSE();
// If the RTC is already doing the right thing, do nothing
if (isUsingLSI == jshIsRTCUsingLSE()) {
if (isUsingLSI != wasUsingLSI) {
// We just set the RTC up, so we have to reset the
// backup domain again to change sources :(
#ifdef STM32F1
@ -744,14 +746,15 @@ void jshDoSysTick() {
#endif
RCC_BackupResetCmd(ENABLE);
RCC_BackupResetCmd(DISABLE);
RCC_LSEConfig(RCC_LSE_ON); // reset would have turned LSE off
if (!isUsingLSI) RCC_LSEConfig(RCC_LSE_ON); // reset would have turned LSE off
jshSetupRTC(isUsingLSI);
#ifdef STM32F1
RTC_SetCounter(time);
#else
RTC_SetDate(RTC_Format_BIN, &date);
RTC_SetTime(RTC_Format_BIN, &time);
RTC_WaitForSynchro();
#endif
jshSetupRTC(isUsingLSI);
}
// Disable RTC clocks depending on what we decided...
@ -760,7 +763,6 @@ void jshDoSysTick() {
RCC_LSEConfig(RCC_LSE_OFF); // disable low speed external oscillator
} else {
// LSE working! Yay! turn LSI off now
RCC_LSEConfig(RCC_LSE_ON);
RCC_LSICmd(DISABLE); // disable low speed internal oscillator
}
}
@ -1096,6 +1098,16 @@ void jshInit() {
jshPinOutput(LED1_PININDEX, 1);
#endif
#ifdef USE_RTC
/* RTC setup works like this:
* Turn LSI on (it always defaults to off)
* If RTC is set up already, awesome. Job done.
* If not, set up the RTC with the LSI, but turn the LSE on
* Around 1 sec later, in jshDoSysTick, check if the LSE is working
* If it isn't, turn it off
* If it is, switch over to it and disable LSI
*/
// allow access to backup domain
PWR_BackupAccessCmd(ENABLE);
// enable low speed internal oscillator (reset always kills this, and we might need it)

View File

@ -0,0 +1,5 @@
// http://forum.espruino.com/conversations/292461
a = "1234567890123456789012345678901234567890";
a+=a
result = a.length==80;