mirror of
https://github.com/espruino/Espruino.git
synced 2025-12-08 19:06:15 +00:00
re-add f5 variant
This commit is contained in:
parent
5fa9c7d770
commit
75bc0132c0
72
.gitignore
vendored
72
.gitignore
vendored
@ -10,51 +10,51 @@
|
||||
*.bin
|
||||
*.pyc
|
||||
/*.zip
|
||||
gen/*
|
||||
.vagrant/*
|
||||
boards/*.html
|
||||
boards/*.json
|
||||
zipcontents
|
||||
tmp
|
||||
benchmark/*.txt
|
||||
benchmark/*.result.json
|
||||
/gen/*
|
||||
/.vagrant/*
|
||||
/boards/*.html
|
||||
/boards/*.json
|
||||
/zipcontents
|
||||
/tmp
|
||||
/benchmark/*.txt
|
||||
/benchmark/*.result.json
|
||||
/espruino
|
||||
archives/*
|
||||
diffs/*
|
||||
.cproject
|
||||
.project
|
||||
.settings
|
||||
MDN_URLS.txt
|
||||
/archives/*
|
||||
/diffs/*
|
||||
/.cproject
|
||||
/.project
|
||||
/.settings
|
||||
/MDN_URLS.txt
|
||||
node_modules
|
||||
/build/
|
||||
esp_iot_sdk_v1.5.0
|
||||
esp_iot_sdk_v2.0.0.p1
|
||||
ESP8266_NONOS_SDK-2.2.1
|
||||
xtensa-lx106-elf
|
||||
app
|
||||
esp-idf
|
||||
/esp_iot_sdk_v1.5.0
|
||||
/esp_iot_sdk_v2.0.0.p1
|
||||
/ESP8266_NONOS_SDK-2.2.1
|
||||
/xtensa-lx106-elf
|
||||
/app
|
||||
/esp-idf
|
||||
xtensa-esp32-elf
|
||||
gcc-arm-none-eabi*
|
||||
*.c#
|
||||
/function_keywords.js
|
||||
/functions.html
|
||||
targetlibs/nrf5x_11
|
||||
targetlibs/nrf5x_12/examples
|
||||
targetlibs/nrf5x_12/documentation/
|
||||
targetlibs/nrf5x_14
|
||||
targetlibs/nrf5x_15/components
|
||||
targetlibs/nrf5x_15/example_config
|
||||
targetlibs/nrf5x_15/examples
|
||||
targetlibs/nrf5x_15/external
|
||||
targetlibs/nrf5x_15/external_tools
|
||||
targetlibs/nrf5x_15/integration
|
||||
targetlibs/nrf5x_15/modules
|
||||
targetlibs/nrf5x_15_*
|
||||
targetlibs/nrf5x_15x
|
||||
targetlibs/nrf5x_mesh
|
||||
targetlibs/raspberrypi
|
||||
/targetlibs/nrf5x_11
|
||||
/targetlibs/nrf5x_12/examples
|
||||
/targetlibs/nrf5x_12/documentation/
|
||||
/targetlibs/nrf5x_14
|
||||
/targetlibs/nrf5x_15/components
|
||||
/targetlibs/nrf5x_15/example_config
|
||||
/targetlibs/nrf5x_15/examples
|
||||
/targetlibs/nrf5x_15/external
|
||||
/targetlibs/nrf5x_15/external_tools
|
||||
/targetlibs/nrf5x_15/integration
|
||||
/targetlibs/nrf5x_15/modules
|
||||
/targetlibs/nrf5x_15_*
|
||||
/targetlibs/nrf5x_15x
|
||||
/targetlibs/nrf5x_mesh
|
||||
/targetlibs/raspberrypi
|
||||
/.vscode
|
||||
/CURRENT_BOARD.make
|
||||
/topreadonly
|
||||
/topstrings
|
||||
misc
|
||||
/misc
|
||||
|
||||
184
boards/BANGLEF5.py
Normal file
184
boards/BANGLEF5.py
Normal file
@ -0,0 +1,184 @@
|
||||
#!/bin/false
|
||||
# This file is part of Espruino, a JavaScript interpreter for Microcontrollers
|
||||
#
|
||||
# Copyright (C) 2013 Gordon Williams <gw@pur3.co.uk>
|
||||
#
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
#
|
||||
# ----------------------------------------------------------------------------------------
|
||||
# This file contains information for a specific board - the available pins, and where LEDs,
|
||||
# Buttons, and other in-built peripherals are. It is used to build documentation as well
|
||||
# as various source and header files for Espruino.
|
||||
# ----------------------------------------------------------------------------------------
|
||||
|
||||
import pinutils;
|
||||
|
||||
info = {
|
||||
'name' : "Espruino Bangle.js",
|
||||
'link' : [ "http://www.espruino.com/Bangle.js" ],
|
||||
'espruino_page_link' : 'Bangle.js',
|
||||
'default_console' : "EV_BLUETOOTH",
|
||||
'variables' : 2100, # 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_banglef5.hex',
|
||||
'build' : {
|
||||
'optimizeflags' : '-Os',
|
||||
'libraries' : [
|
||||
'BLUETOOTH',
|
||||
'TERMINAL',
|
||||
'GRAPHICS',
|
||||
'LCD_SPI',
|
||||
# 'TENSORFLOW'
|
||||
],
|
||||
'makefile' : [
|
||||
'DEFINES += -DCONFIG_NFCT_PINS_AS_GPIOS', # Allow the reset pin to work
|
||||
'DEFINES += -DBUTTONPRESS_TO_REBOOT_BOOTLOADER',
|
||||
'DEFINES+=-DBLUETOOTH_NAME_PREFIX=\'"Bangle.js"\'',
|
||||
'DEFINES+=-DDUMP_IGNORE_VARIABLES=\'"g\\0"\'',
|
||||
'DEFINES+=-DUSE_FONT_6X8 -DGRAPHICS_PALETTED_IMAGES',
|
||||
'DFU_PRIVATE_KEY=targets/nrf5x_dfu/dfu_private_key.pem',
|
||||
'DFU_SETTINGS=--application-version 0xff --hw-version 52 --sd-req 0x8C',
|
||||
'INCLUDE += -I$(ROOT)/libs/banglejs -I$(ROOT)/libs/misc',
|
||||
'WRAPPERSOURCES += libs/banglejs/jswrap_banglef5.c',
|
||||
'SOURCES += libs/misc/nmea.c',
|
||||
'JSMODULESOURCES += libs/js/graphical_menu.min.js',
|
||||
'NRF_BL_DFU_INSECURE=1',
|
||||
'LINKER_BOOTLOADER=targetlibs/nrf5x_12/nrf5x_linkers/banglejs_dfu.ld',
|
||||
'LINKER_ESPRUINO=targetlibs/nrf5x_12/nrf5x_linkers/banglejs_espruino.ld'
|
||||
]
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
chip = {
|
||||
'part' : "NRF52832",
|
||||
'family' : "NRF52",
|
||||
'package' : "QFN48",
|
||||
'ram' : 64,
|
||||
'flash' : 512,
|
||||
'speed' : 64,
|
||||
'usart' : 1,
|
||||
'spi' : 1,
|
||||
'i2c' : 1,
|
||||
'adc' : 1,
|
||||
'dac' : 0,
|
||||
'saved_code' : {
|
||||
'address' : 0x40000000, # put this in external flash
|
||||
'page_size' : 4096,
|
||||
'pages' : 64, # 256kb - still loads left
|
||||
'flash_available' : 512 - ((31 + 8 + 2)*4) # Softdevice uses 31 pages of flash, bootloader 8, FS 2. Each page is 4 kb.
|
||||
},
|
||||
};
|
||||
|
||||
devices = {
|
||||
|
||||
'BTN1' : { 'pin' : 'D12', 'pinstate' : 'IN_PULLDOWN' }, # Top right - Pin negated in software
|
||||
'BTN2' : { 'pin' : 'D13', 'pinstate' : 'IN_PULLDOWN' }, # Bottom right - Pin negated in software
|
||||
'BTN3' : { 'pin' : 'D16' }, # Touch
|
||||
# 'BTN4' : { 'pin' : 'D16', 'pinstate' : 'IN_PULLDOWN' }, # Pin negated in software
|
||||
'LED1' : { 'pin' : 'D14' }, # Pin negated in software
|
||||
# 'LED2' : { 'pin' : 'D18' }, # Pin negated in software
|
||||
# 'LED3' : { 'pin' : 'D19' }, # Pin negated in software
|
||||
# 'LED4' : { 'pin' : 'D20' }, # Pin negated in software
|
||||
'VIBRATE' : { 'pin' : 'D11' }, # Pin negated in software
|
||||
'LCD' : {
|
||||
'width' : 128, 'height' : 96, 'bpp' : 4,
|
||||
'controller' : 'st7735',
|
||||
'pin_dc' : 'D22',
|
||||
'pin_cs' : 'D10',
|
||||
'pin_rst' : 'D23',
|
||||
'pin_sck' : 'D9',
|
||||
'pin_mosi' : 'D8',
|
||||
'pin_bl' : 'D21',
|
||||
},
|
||||
'GPS' : {
|
||||
'device' : 'M8130-KT',
|
||||
'pin_en' : 'D0', # inverted
|
||||
'pin_rx' : 'D5',
|
||||
'pin_tx' : 'D6'
|
||||
},
|
||||
'BAT' : {
|
||||
'pin_charging' : 'D7', # inverted
|
||||
'pin_voltage' : 'D4'
|
||||
},
|
||||
'HEARTRATE' : {
|
||||
'pin_led' : 'D14',
|
||||
'pin_analog' : 'D3'
|
||||
},
|
||||
'ACCEL' : {
|
||||
'device' : 'KX023', 'addr' : 0x1e,
|
||||
'pin_sda' : 'D1',
|
||||
'pin_scl' : 'D2'
|
||||
},
|
||||
'SPIFLASH' : {
|
||||
'pin_cs' : 'D18',
|
||||
'pin_sck' : 'D19',
|
||||
'pin_mosi' : 'D20',
|
||||
'pin_miso' : 'D17',
|
||||
'size' : 2097152
|
||||
},
|
||||
'PRESSURE' : {
|
||||
'device' : 'HP203', 'addr' : 0x76,
|
||||
'pin_sda' : 'D1',
|
||||
'pin_scl' : 'D2'
|
||||
},
|
||||
};
|
||||
|
||||
# left-right, or top-bottom order
|
||||
board = {
|
||||
'left' : [],
|
||||
'right' : [],
|
||||
'_notes' : {
|
||||
}
|
||||
};
|
||||
board["_css"] = """
|
||||
#board {
|
||||
width: 528px;
|
||||
height: 800px;
|
||||
top: 0px;
|
||||
left : 200px;
|
||||
background-image: url(img/BANGLEF5.jpg);
|
||||
}
|
||||
#boardcontainer {
|
||||
height: 900px;
|
||||
}
|
||||
|
||||
#left {
|
||||
top: 219px;
|
||||
right: 466px;
|
||||
}
|
||||
#right {
|
||||
top: 150px;
|
||||
left: 466px;
|
||||
}
|
||||
|
||||
.leftpin { height: 17px; }
|
||||
.rightpin { height: 17px; }
|
||||
""";
|
||||
|
||||
def get_pins():
|
||||
pins = pinutils.generate_pins(0,31) # 32 General Purpose I/O Pins.
|
||||
pinutils.findpin(pins, "PD0", True)["functions"]["XL1"]=0;
|
||||
pinutils.findpin(pins, "PD1", True)["functions"]["XL2"]=0;
|
||||
pinutils.findpin(pins, "PD2", True)["functions"]["ADC1_IN0"]=0;
|
||||
pinutils.findpin(pins, "PD3", True)["functions"]["ADC1_IN1"]=0;
|
||||
pinutils.findpin(pins, "PD4", True)["functions"]["ADC1_IN2"]=0;
|
||||
pinutils.findpin(pins, "PD5", True)["functions"]["ADC1_IN3"]=0;
|
||||
pinutils.findpin(pins, "PD28", True)["functions"]["ADC1_IN4"]=0;
|
||||
pinutils.findpin(pins, "PD29", True)["functions"]["ADC1_IN5"]=0;
|
||||
pinutils.findpin(pins, "PD30", True)["functions"]["ADC1_IN6"]=0;
|
||||
pinutils.findpin(pins, "PD31", True)["functions"]["ADC1_IN7"]=0;
|
||||
# negate buttons
|
||||
pinutils.findpin(pins, "PD12", True)["functions"]["NEGATED"]=0; # btn1
|
||||
pinutils.findpin(pins, "PD13", True)["functions"]["NEGATED"]=0; # btn2
|
||||
pinutils.findpin(pins, "PD11", True)["functions"]["NEGATED"]=0; # vibrate
|
||||
pinutils.findpin(pins, "PD14", True)["functions"]["NEGATED"]=0; # HRM LED
|
||||
|
||||
|
||||
# everything is non-5v tolerant
|
||||
for pin in pins:
|
||||
pin["functions"]["3.3"]=0;
|
||||
#The boot/reset button will function as a reset button in normal operation. Pin reset on PD21 needs to be enabled on the nRF52832 device for this to work.
|
||||
return pins
|
||||
@ -30,7 +30,7 @@ info = {
|
||||
'TERMINAL',
|
||||
'GRAPHICS',
|
||||
'LCD_ST7789_8BIT',
|
||||
#'TENSORFLOW'
|
||||
'TENSORFLOW'
|
||||
],
|
||||
'makefile' : [
|
||||
'DEFINES += -DCONFIG_NFCT_PINS_AS_GPIOS', # Allow the reset pin to work
|
||||
@ -40,8 +40,9 @@ info = {
|
||||
'DEFINES+=-DUSE_FONT_6X8 -DGRAPHICS_PALETTED_IMAGES',
|
||||
'DFU_PRIVATE_KEY=targets/nrf5x_dfu/dfu_private_key.pem',
|
||||
'DFU_SETTINGS=--application-version 0xff --hw-version 52 --sd-req 0x8C',
|
||||
'INCLUDE += -I$(ROOT)/libs/banglejs',
|
||||
'INCLUDE += -I$(ROOT)/libs/banglejs -I$(ROOT)/libs/misc',
|
||||
'WRAPPERSOURCES += libs/banglejs/jswrap_bangle.c',
|
||||
'SOURCES += libs/misc/nmea.c',
|
||||
'JSMODULESOURCES += libs/js/graphical_menu.min.js',
|
||||
'NRF_BL_DFU_INSECURE=1',
|
||||
'LINKER_BOOTLOADER=targetlibs/nrf5x_12/nrf5x_linkers/banglejs_dfu.ld',
|
||||
|
||||
@ -36,6 +36,7 @@
|
||||
|
||||
#include "jswrap_graphics.h"
|
||||
#include "lcd_st7789_8bit.h"
|
||||
#include "nmea.h"
|
||||
|
||||
/*JSON{
|
||||
"type": "class",
|
||||
@ -161,18 +162,8 @@ If the watch is tapped, this event contains information on the way it was tapped
|
||||
#define IOEXP_LCD_RESET 0x40
|
||||
#define IOEXP_HRM 0x80
|
||||
|
||||
typedef struct {
|
||||
double lat,lon,alt;
|
||||
double speed, course;
|
||||
int hour,min,sec,ms;
|
||||
uint8_t day,month,year;
|
||||
uint8_t quality; // from GGA packet, 0 = no fix
|
||||
uint8_t satellites; // how many satellites
|
||||
} NMEAFixInfo;
|
||||
|
||||
#define NMEA_MAX_SIZE 82 // 82 is the max for NMEA
|
||||
uint8_t nmeaCount = 0; // how many characters of NMEA data do we have?
|
||||
char nmeaIn[NMEA_MAX_SIZE]; // NMEA line being received right now
|
||||
char nmeaIn[NMEA_MAX_SIZE]; // 82 is the max for NMEA
|
||||
char nmeaLine[NMEA_MAX_SIZE]; // A line of received NMEA data
|
||||
NMEAFixInfo gpsFix;
|
||||
|
||||
@ -783,27 +774,8 @@ bool jswrap_banglejs_idle() {
|
||||
}
|
||||
}
|
||||
if (bangle && (bangleTasks & JSBT_GPS_DATA)) {
|
||||
JsVar *o = jsvNewObject();
|
||||
JsVar *o = nmea_to_jsVar(&gpsFix);
|
||||
if (o) {
|
||||
jsvObjectSetChildAndUnLock(o, "lat", jsvNewFromFloat(gpsFix.lat));
|
||||
jsvObjectSetChildAndUnLock(o, "lon", jsvNewFromFloat(gpsFix.lon));
|
||||
jsvObjectSetChildAndUnLock(o, "alt", jsvNewFromFloat(gpsFix.alt));
|
||||
jsvObjectSetChildAndUnLock(o, "speed", jsvNewFromFloat(gpsFix.speed));
|
||||
jsvObjectSetChildAndUnLock(o, "course", jsvNewFromFloat(gpsFix.course));
|
||||
CalendarDate date;
|
||||
date.day = gpsFix.day;
|
||||
date.month = gpsFix.month;
|
||||
date.year = 2000+gpsFix.year;
|
||||
TimeInDay td;
|
||||
td.daysSinceEpoch = fromCalenderDate(&date);
|
||||
td.hour = gpsFix.hour;
|
||||
td.min = gpsFix.min;
|
||||
td.sec = gpsFix.sec;
|
||||
td.ms = gpsFix.ms;
|
||||
td.zone = 0; // jsdGetTimeZone(); - no! GPS time is always in UTC :)
|
||||
jsvObjectSetChildAndUnLock(o, "time", jswrap_date_from_milliseconds(fromTimeInDay(&td)));
|
||||
jsvObjectSetChildAndUnLock(o, "satellites", jsvNewFromInteger(gpsFix.satellites));
|
||||
jsvObjectSetChildAndUnLock(o, "fix", jsvNewFromInteger(gpsFix.quality));
|
||||
jsiQueueObjectCallbacks(bangle, JS_EVENT_PREFIX"GPS", &o, 1);
|
||||
jsvUnLock(o);
|
||||
}
|
||||
@ -812,7 +784,6 @@ bool jswrap_banglejs_idle() {
|
||||
JsVar *line = jsvNewFromString(nmeaLine);
|
||||
if (line) {
|
||||
jsiQueueObjectCallbacks(bangle, JS_EVENT_PREFIX"GPS-raw", &line, 1);
|
||||
|
||||
}
|
||||
jsvUnLock(line);
|
||||
}
|
||||
@ -852,109 +823,6 @@ bool jswrap_banglejs_idle() {
|
||||
}
|
||||
|
||||
|
||||
char *nmea_next_comma(char *nmea) {
|
||||
while (*nmea && *nmea!=',') nmea++; // find the comma
|
||||
return nmea;
|
||||
}
|
||||
double nmea_decode_latlon(char *nmea, char *comma) {
|
||||
if (*nmea==',') return NAN; // no reading
|
||||
char *dp = nmea;
|
||||
while (*dp && *dp!='.' && *dp!=',') dp++; // find decimal pt
|
||||
*comma = 0;
|
||||
double minutes = stringToFloat(&dp[-2]);
|
||||
*comma = ',';
|
||||
dp[-2] = 0;
|
||||
int x = stringToInt(nmea);
|
||||
return x+(minutes/60);
|
||||
}
|
||||
double nmea_decode_float(char *nmea, char *comma) {
|
||||
*comma = 0;
|
||||
double r = stringToFloat(nmea);
|
||||
*comma = ',';
|
||||
return r;
|
||||
}
|
||||
uint8_t nmea_decode_1(char *nmea) {
|
||||
return chtod(nmea[0]);
|
||||
}
|
||||
uint8_t nmea_decode_2(char *nmea) {
|
||||
return chtod(nmea[0])*10 + chtod(nmea[1]);
|
||||
}
|
||||
bool nmea_decode(const char *nmeaLine) {
|
||||
char buf[NMEA_MAX_SIZE];
|
||||
strcpy(buf, nmeaLine);
|
||||
char *nmea = buf, *nextComma;
|
||||
|
||||
|
||||
if (nmea[0]!='$' || nmea[1]!='G') return false; // not valid
|
||||
if (nmea[3]=='R' && nmea[4]=='M' && nmea[5]=='C') {
|
||||
// $GNRMC,161945.00,A,5139.11397,N,00116.07202,W,1.530,,190919,,,A*7E
|
||||
nmea = nmea_next_comma(nmea)+1;
|
||||
nextComma = nmea_next_comma(nmea);
|
||||
// time
|
||||
gpsFix.hour = nmea_decode_2(&nmea[0]);
|
||||
gpsFix.min = nmea_decode_2(&nmea[2]);
|
||||
gpsFix.sec = nmea_decode_2(&nmea[4]);
|
||||
gpsFix.ms = nmea_decode_2(&nmea[7]);
|
||||
// status
|
||||
nmea = nextComma+1; nextComma = nmea_next_comma(nmea);
|
||||
nmea = nextComma+1; nextComma = nmea_next_comma(nmea);//?
|
||||
// lat + NS
|
||||
nmea = nextComma+1; nextComma = nmea_next_comma(nmea);
|
||||
nmea = nextComma+1; nextComma = nmea_next_comma(nmea);
|
||||
// lon + EW
|
||||
nmea = nextComma+1; nextComma = nmea_next_comma(nmea);
|
||||
nmea = nextComma+1; nextComma = nmea_next_comma(nmea);
|
||||
// speed
|
||||
gpsFix.speed = nmea_decode_float(nmea, nextComma);
|
||||
nmea = nextComma+1; nextComma = nmea_next_comma(nmea);
|
||||
// course
|
||||
gpsFix.course = nmea_decode_float(nmea, nextComma);
|
||||
nmea = nextComma+1; nextComma = nmea_next_comma(nmea);
|
||||
// date
|
||||
gpsFix.day = nmea_decode_2(&nmea[0]);
|
||||
gpsFix.month = nmea_decode_2(&nmea[2]);
|
||||
gpsFix.year = nmea_decode_2(&nmea[4]);
|
||||
// ....
|
||||
}
|
||||
if (nmea[3]=='G' && nmea[4]=='G' && nmea[5]=='A') {
|
||||
// $GNGGA,161945.00,5139.11397,N,00116.07202,W,1,06,1.29,71.1,M,47.0,M,,*64
|
||||
nmea = nmea_next_comma(nmea)+1;
|
||||
nextComma = nmea_next_comma(nmea);
|
||||
// time
|
||||
nmea = nextComma+1; nextComma = nmea_next_comma(nmea);
|
||||
// LAT
|
||||
gpsFix.lat = nmea_decode_latlon(nmea, nextComma);
|
||||
nmea = nextComma+1; nextComma = nmea_next_comma(nmea);
|
||||
if (*nmea=='S') gpsFix.lat=-gpsFix.lat;
|
||||
nmea = nextComma+1; nextComma = nmea_next_comma(nmea);
|
||||
// LON
|
||||
gpsFix.lon = nmea_decode_latlon(nmea, nextComma);
|
||||
nmea = nextComma+1; nextComma = nmea_next_comma(nmea);
|
||||
if (*nmea=='W') gpsFix.lon=-gpsFix.lon;
|
||||
nmea = nextComma+1; nextComma = nmea_next_comma(nmea);
|
||||
// quality
|
||||
gpsFix.quality = nmea_decode_1(nmea);
|
||||
nmea = nextComma+1; nextComma = nmea_next_comma(nmea);
|
||||
// num satellites
|
||||
gpsFix.satellites = nmea_decode_2(nmea);
|
||||
nmea = nextComma+1; nextComma = nmea_next_comma(nmea);
|
||||
// dilution of precision
|
||||
nmea = nextComma+1; nextComma = nmea_next_comma(nmea);
|
||||
// altitude
|
||||
gpsFix.alt = nmea_decode_float(nmea, nextComma);
|
||||
nmea = nextComma+1; nextComma = nmea_next_comma(nmea);
|
||||
// ....
|
||||
}
|
||||
if (nmea[3]=='G' && nmea[4]=='S' && nmea[5]=='V') {
|
||||
// loads of cool data about what satellites we have
|
||||
}
|
||||
if (nmea[3]=='G' && nmea[4]=='L' && nmea[5]=='L') {
|
||||
// Complete set of data received
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/*JSON{
|
||||
"type" : "EV_SERIAL1",
|
||||
"generate" : "jswrap_banglejs_gps_character"
|
||||
@ -979,7 +847,7 @@ bool jswrap_banglejs_gps_character(char ch) {
|
||||
memcpy(nmeaLine, nmeaIn, nmeaCount);
|
||||
nmeaLine[nmeaCount-1]=0; // just overwriting \n
|
||||
bangleTasks |= JSBT_GPS_DATA_LINE;
|
||||
if (nmea_decode(nmeaLine))
|
||||
if (nmea_decode(&gpsFix, nmeaLine))
|
||||
bangleTasks |= JSBT_GPS_DATA;
|
||||
}
|
||||
nmeaCount = 0;
|
||||
|
||||
748
libs/banglejs/jswrap_banglef5.c
Normal file
748
libs/banglejs/jswrap_banglef5.c
Normal file
@ -0,0 +1,748 @@
|
||||
/*
|
||||
* 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 Pixl.js (http://www.espruino.com/Pixl.js)
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#include <jswrap_banglef5.h>
|
||||
#include "jsinteractive.h"
|
||||
#include "jsdevices.h"
|
||||
#include "jsnative.h"
|
||||
#include "jshardware.h"
|
||||
#include "jsdevices.h"
|
||||
#include "jspin.h"
|
||||
#include "jstimer.h"
|
||||
#include "jswrap_promise.h"
|
||||
#include "jswrap_bluetooth.h"
|
||||
#include "nrf_gpio.h"
|
||||
#include "nrf_delay.h"
|
||||
#include "nrf_soc.h"
|
||||
#include "nrf5x_utils.h"
|
||||
#include "jsflash.h" // for jsfRemoveCodeFromFlash
|
||||
#include "bluetooth.h" // for self-test
|
||||
#include "jsi2c.h" // accelerometer/etc
|
||||
|
||||
#include "jswrap_graphics.h"
|
||||
#include "lcd_spilcd.h"
|
||||
#include "nmea.h"
|
||||
|
||||
#define GPS_UART EV_SERIAL1
|
||||
|
||||
uint8_t nmeaCount = 0; // how many characters of NMEA data do we have?
|
||||
char nmeaIn[NMEA_MAX_SIZE]; // 82 is the max for NMEA
|
||||
char nmeaLine[NMEA_MAX_SIZE]; // A line of received NMEA data
|
||||
NMEAFixInfo gpsFix;
|
||||
|
||||
/*JSON{
|
||||
"type": "class",
|
||||
"class" : "Bangle",
|
||||
"ifdef" : "BANGLEJS"
|
||||
}
|
||||
Class containing utility functions for the [Bangle.js Smart Watch](http://www.espruino.com/Bangle.js)
|
||||
*/
|
||||
|
||||
|
||||
/*JSON{
|
||||
"type" : "variable",
|
||||
"name" : "VIBRATE",
|
||||
"generate_full" : "VIBRATE_PIN",
|
||||
"ifdef" : "BANGLEJS",
|
||||
"return" : ["pin",""]
|
||||
}
|
||||
The Bangle.js's vibration motor.
|
||||
*/
|
||||
|
||||
#define ACCEL_POLL_INTERVAL 100 // in msec
|
||||
/// Internal I2C used for Accelerometer/Pressure
|
||||
JshI2CInfo internalI2C;
|
||||
/// Is I2C busy? if so we'll skip one reading in our interrupt so we don't overlap
|
||||
bool i2cBusy;
|
||||
/// Promise when pressure is requested
|
||||
JsVar *promisePressure;
|
||||
/// counter that counts up if watch has stayed face up or down
|
||||
unsigned char faceUpCounter;
|
||||
/// Was the watch face-up? we use this when firing events
|
||||
bool wasFaceUp;
|
||||
/// time since LCD contents were last modified
|
||||
volatile unsigned char flipCounter;
|
||||
/// Is LCD power automatic? If true this is the number of ms for the timeout, if false it's 0
|
||||
int lcdPowerTimeout = 100;
|
||||
/// Is the LCD on?
|
||||
bool lcdPowerOn;
|
||||
/// accelerometer data
|
||||
int accx,accy,accz,accdiff;
|
||||
/// data on how watch was tapped
|
||||
unsigned char tapInfo;
|
||||
|
||||
typedef enum {
|
||||
JSBT_NONE,
|
||||
JSBT_LCD_ON = 1,
|
||||
JSBT_LCD_OFF = 2,
|
||||
JSBT_ACCEL_DATA = 4, // need to push xyz data to JS
|
||||
JSBT_ACCEL_TAPPED = 8, // tap event detected
|
||||
JSBT_GPS_DATA = 16, ///< we got a complete set of GPS data in 'gpsFix'
|
||||
JSBT_GPS_DATA_LINE = 32, ///< we got a line of GPS data
|
||||
} JsBangleTasks;
|
||||
JsBangleTasks bangleTasks;
|
||||
|
||||
|
||||
|
||||
/// Send buffer contents to the screen. Usually only the modified data will be output, but if all=true then the whole screen contents is sent
|
||||
void lcd_flip(JsVar *parent, bool all) {
|
||||
JsGraphics gfx;
|
||||
if (!graphicsGetFromVar(&gfx, parent)) return;
|
||||
if (all) {
|
||||
gfx.data.modMinX = 0;
|
||||
gfx.data.modMinY = 0;
|
||||
gfx.data.modMaxX = LCD_WIDTH-1;
|
||||
gfx.data.modMaxY = LCD_HEIGHT-1;
|
||||
}
|
||||
if (lcdPowerTimeout && !lcdPowerOn) {
|
||||
// LCD was turned off, turn it back on
|
||||
jswrap_banglejs_setLCDPower(1);
|
||||
}
|
||||
flipCounter = 0;
|
||||
lcdFlip_SPILCD(&gfx);
|
||||
graphicsSetVar(&gfx);
|
||||
}
|
||||
|
||||
/*JSON{
|
||||
"type" : "staticmethod",
|
||||
"class" : "Bangle",
|
||||
"name" : "setLCDPower",
|
||||
"generate" : "jswrap_banglejs_setLCDPower",
|
||||
"params" : [
|
||||
["isOn","bool","True if the LCD should be on, false if not"]
|
||||
]
|
||||
}
|
||||
This function can be used to turn Bangle.js's LCD off or on.
|
||||
*/
|
||||
void jswrap_banglejs_setLCDPower(bool isOn) {
|
||||
if (isOn) {
|
||||
lcdCmd_SPILCD(0x11, 0, NULL); // SLPOUT
|
||||
jshPinOutput(LCD_BL,0); // backlight
|
||||
} else {
|
||||
lcdCmd_SPILCD(0x10, 0, NULL); // SLPIN
|
||||
jshPinOutput(LCD_BL,1); // backlight
|
||||
}
|
||||
if (lcdPowerOn != isOn) {
|
||||
JsVar *bangle =jsvObjectGetChild(execInfo.root, "Bangle", 0);
|
||||
if (bangle) {
|
||||
JsVar *v = jsvNewFromBool(isOn);
|
||||
jsiQueueObjectCallbacks(bangle, JS_EVENT_PREFIX"lcdPower", &v, 1);
|
||||
jsvUnLock(v);
|
||||
}
|
||||
jsvUnLock(bangle);
|
||||
}
|
||||
lcdPowerOn = isOn;
|
||||
}
|
||||
|
||||
/*JSON{
|
||||
"type" : "staticmethod",
|
||||
"class" : "Bangle",
|
||||
"name" : "setLCDTimeout",
|
||||
"generate" : "jswrap_banglejs_setLCDTimeout",
|
||||
"params" : [
|
||||
["isOn","float","The timeout of the display in seconds, or `0`/`undefined` to turn power saving off. Default is 10 seconds."]
|
||||
]
|
||||
}
|
||||
This function can be used to turn Bangle.js's LCD power saving on or off.
|
||||
|
||||
With power saving off, the display will remain in the state you set it with `Bangle.setLCDPower`.
|
||||
|
||||
With power saving on, the display will turn on if a button is pressed, the watch is turned face up, or the screen is updated. It'll turn off automatically after the given timeout.
|
||||
*/
|
||||
void jswrap_banglejs_setLCDTimeout(JsVarFloat timeout) {
|
||||
if (!isfinite(timeout)) lcdPowerTimeout=0;
|
||||
else lcdPowerTimeout = timeout*(1000.0/ACCEL_POLL_INTERVAL);
|
||||
if (lcdPowerTimeout<0) lcdPowerTimeout=0;
|
||||
}
|
||||
|
||||
/*JSON{
|
||||
"type" : "staticmethod",
|
||||
"class" : "Bangle",
|
||||
"name" : "setLCDPalette",
|
||||
"generate" : "jswrap_banglejs_setLCDPalette",
|
||||
"params" : [
|
||||
["palette","JsVar","An array of 24 bit 0xRRGGBB values"]
|
||||
]
|
||||
}
|
||||
Bangle.js's LCD can display colours in 12 bit, but to keep the offscreen
|
||||
buffer to a reasonable size it uses a 4 bit paletted buffer.
|
||||
|
||||
With this, you can change the colour palette that is used.
|
||||
*/
|
||||
void jswrap_banglejs_setLCDPalette(JsVar *palette) {
|
||||
if (jsvIsIterable(palette)) {
|
||||
uint16_t pal[16];
|
||||
JsvIterator it;
|
||||
jsvIteratorNew(&it, palette, JSIF_EVERY_ARRAY_ELEMENT);
|
||||
int idx = 0;
|
||||
while (idx<16 && jsvIteratorHasElement(&it)) {
|
||||
unsigned int rgb = jsvIteratorGetIntegerValue(&it);
|
||||
unsigned int r = rgb>>16;
|
||||
unsigned int g = (rgb>>8)&0xFF;
|
||||
unsigned int b = rgb&0xFF;
|
||||
pal[idx++] = ((r&0xF0)<<4) | (g&0xF0) | (b>>4);
|
||||
jsvIteratorNext(&it);
|
||||
}
|
||||
jsvIteratorFree(&it);
|
||||
lcdSetPalette_SPILCD(pal);
|
||||
} else
|
||||
lcdSetPalette_SPILCD(0);
|
||||
}
|
||||
|
||||
/*JSON{
|
||||
"type" : "staticmethod",
|
||||
"class" : "Bangle",
|
||||
"name" : "isLCDOn",
|
||||
"generate" : "jswrap_banglejs_isLCDOn",
|
||||
"return" : ["bool","Is the display on or not?"]
|
||||
}
|
||||
*/
|
||||
bool jswrap_banglejs_isLCDOn() {
|
||||
return lcdPowerOn;
|
||||
}
|
||||
|
||||
/*JSON{
|
||||
"type" : "staticmethod",
|
||||
"class" : "Bangle",
|
||||
"name" : "lcdWr",
|
||||
"generate" : "jswrap_banglejs_lcdWr",
|
||||
"params" : [
|
||||
["cmd","int",""],
|
||||
["data","JsVar",""]
|
||||
]
|
||||
}
|
||||
Writes a command directly to the ST7735 LCD controller
|
||||
*/
|
||||
void jswrap_banglejs_lcdWr(JsVarInt cmd, JsVar *data) {
|
||||
JSV_GET_AS_CHAR_ARRAY(dPtr, dLen, data);
|
||||
lcdCmd_SPILCD(cmd, dLen, dPtr);
|
||||
}
|
||||
|
||||
/*JSON{
|
||||
"type" : "staticmethod",
|
||||
"class" : "Bangle",
|
||||
"name" : "setGPSPower",
|
||||
"generate" : "jswrap_banglejs_setGPSPower",
|
||||
"params" : [
|
||||
["isOn","bool","True if the GPS should be on, false if not"]
|
||||
]
|
||||
}
|
||||
Set the power to the GPS.
|
||||
*/
|
||||
void jswrap_banglejs_setGPSPower(bool isOn) {
|
||||
if (isOn) {
|
||||
JshUSARTInfo inf;
|
||||
jshUSARTInitInfo(&inf);
|
||||
inf.baudRate = 9600;
|
||||
inf.pinRX = GPS_PIN_RX;
|
||||
inf.pinTX = GPS_PIN_TX;
|
||||
jshUSARTSetup(GPS_UART, &inf);
|
||||
jshPinOutput(GPS_PIN_EN,1); // GPS on
|
||||
nmeaCount = 0;
|
||||
} else {
|
||||
jshPinOutput(GPS_PIN_EN,0); // GPS off
|
||||
// setting pins to pullup will cause jshardware.c to disable the UART, saving power
|
||||
jshPinSetState(GPS_PIN_RX, JSHPINSTATE_GPIO_IN_PULLUP);
|
||||
jshPinSetState(GPS_PIN_TX, JSHPINSTATE_GPIO_IN_PULLUP);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Holding down both buttons will reboot
|
||||
void watchdogHandler() {
|
||||
//jshPinOutput(LED1_PININDEX, 1);
|
||||
// Handle watchdog
|
||||
if (!(jshPinGetValue(BTN1_PININDEX) && jshPinGetValue(BTN2_PININDEX)))
|
||||
jshKickWatchDog();
|
||||
// power on display if a button is pressed
|
||||
if (lcdPowerTimeout &&
|
||||
(jshPinGetValue(BTN1_PININDEX) || jshPinGetValue(BTN2_PININDEX) ||
|
||||
jshPinGetValue(BTN3_PININDEX))) {
|
||||
flipCounter = 0;
|
||||
if (!lcdPowerOn)
|
||||
bangleTasks |= JSBT_LCD_ON;
|
||||
}
|
||||
if (flipCounter<255) flipCounter++;
|
||||
|
||||
if (lcdPowerTimeout && lcdPowerOn && flipCounter>=lcdPowerTimeout) {
|
||||
// 10 seconds of inactivity, turn off display
|
||||
bangleTasks |= JSBT_LCD_OFF;
|
||||
}
|
||||
|
||||
|
||||
if (i2cBusy) return;
|
||||
// poll KX023 accelerometer (no other way as IRQ line seems disconnected!)
|
||||
unsigned char buf[6];
|
||||
buf[0]=6;
|
||||
jsi2cWrite(&internalI2C, ACCEL_ADDR, 1, buf, true);
|
||||
jsi2cRead(&internalI2C, ACCEL_ADDR, 6, buf, true);
|
||||
int newx = (buf[1]<<8)|buf[0];
|
||||
int newy = (buf[3]<<8)|buf[2];
|
||||
int newz = (buf[5]<<8)|buf[4];
|
||||
if (newx&0x8000) newx-=0x10000;
|
||||
if (newy&0x8000) newy-=0x10000;
|
||||
if (newz&0x8000) newz-=0x10000;
|
||||
int dx = newx-accx;
|
||||
int dy = newy-accy;
|
||||
int dz = newz-accz;
|
||||
accx = newx;
|
||||
accy = newy;
|
||||
accz = newz;
|
||||
accdiff = dx*dx + dy*dy + dz*dz;
|
||||
bangleTasks |= JSBT_ACCEL_DATA;
|
||||
// read interrupt source data
|
||||
buf[0]=0x12;
|
||||
jsi2cWrite(&internalI2C, ACCEL_ADDR, 1, buf, true);
|
||||
jsi2cRead(&internalI2C, ACCEL_ADDR, 2, buf, true);
|
||||
// 0 -> 0x12 INS1 - tap event
|
||||
// 1 -> 0x13 INS2 - what kind of event
|
||||
int tapType = (buf[1]>>2)&3;
|
||||
if (tapType) {
|
||||
// report tap
|
||||
tapInfo = buf[0] | (tapType<<6);
|
||||
bangleTasks |= JSBT_ACCEL_TAPPED;
|
||||
// clear the IRQ flags
|
||||
buf[0]=0x17;
|
||||
jsi2cWrite(&internalI2C, ACCEL_ADDR, 1, buf, true);
|
||||
jsi2cRead(&internalI2C, ACCEL_ADDR, 1, buf, true);
|
||||
}
|
||||
|
||||
//jshPinOutput(LED1_PININDEX, 0);
|
||||
}
|
||||
|
||||
/*JSON{
|
||||
"type" : "init",
|
||||
"generate" : "jswrap_banglejs_init"
|
||||
}*/
|
||||
void jswrap_banglejs_init() {
|
||||
jshPinOutput(GPS_PIN_EN,0); // GPS off
|
||||
jshPinOutput(VIBRATE_PIN,0); // vibrate off
|
||||
jshPinOutput(LED1_PININDEX,0); // LED off
|
||||
lcdPowerOn = true;
|
||||
|
||||
// Create backing graphics for LCD
|
||||
JsVar *graphics = jspNewObject(0, "Graphics");
|
||||
if (!graphics) return; // low memory
|
||||
JsGraphics gfx;
|
||||
graphicsStructInit(&gfx);
|
||||
gfx.data.type = JSGRAPHICSTYPE_SPILCD;
|
||||
gfx.data.flags = JSGRAPHICSFLAGS_INVERT_X | JSGRAPHICSFLAGS_INVERT_Y;
|
||||
gfx.graphicsVar = graphics;
|
||||
gfx.data.width = LCD_WIDTH;
|
||||
gfx.data.height = LCD_HEIGHT;
|
||||
gfx.data.bpp = LCD_BPP;
|
||||
|
||||
//gfx.data.fontSize = JSGRAPHICS_FONTSIZE_6X8;
|
||||
lcdInit_SPILCD(&gfx);
|
||||
graphicsSetVar(&gfx);
|
||||
jsvObjectSetChild(execInfo.root, "g", graphics);
|
||||
jsvObjectSetChild(execInfo.hiddenRoot, JS_GRAPHICS_VAR, graphics);
|
||||
graphicsGetFromVar(&gfx, graphics);
|
||||
|
||||
// Create 'flip' fn
|
||||
JsVar *fn;
|
||||
fn = jsvNewNativeFunction((void (*)(void))lcd_flip, JSWAT_VOID|JSWAT_THIS_ARG|(JSWAT_BOOL << (JSWAT_BITS*1)));
|
||||
jsvObjectSetChildAndUnLock(graphics,"flip",fn);
|
||||
|
||||
/* If the button is pressed during reset, perform a self test.
|
||||
* With bootloader this means apply power while holding button for >3 secs */
|
||||
static bool firstStart = true;
|
||||
|
||||
graphicsClear(&gfx);
|
||||
int h=6;
|
||||
jswrap_graphics_drawCString(&gfx,0,h*1," ____ _ ");
|
||||
jswrap_graphics_drawCString(&gfx,0,h*2,"| __|___ ___ ___ _ _|_|___ ___ ");
|
||||
jswrap_graphics_drawCString(&gfx,0,h*3,"| __|_ -| . | _| | | | | . |");
|
||||
jswrap_graphics_drawCString(&gfx,0,h*4,"|____|___| _|_| |___|_|_|_|___|");
|
||||
jswrap_graphics_drawCString(&gfx,0,h*5," |_| espruino.com");
|
||||
jswrap_graphics_drawCString(&gfx,0,h*6," "JS_VERSION" (c) 2019 G.Williams");
|
||||
// Write MAC address in bottom right
|
||||
JsVar *addr = jswrap_ble_getAddress();
|
||||
char buf[20];
|
||||
jsvGetString(addr, buf, sizeof(buf));
|
||||
jsvUnLock(addr);
|
||||
jswrap_graphics_drawCString(&gfx,(LCD_WIDTH-1)-strlen(buf)*6,h*8,buf);
|
||||
lcdFlip_SPILCD(&gfx);
|
||||
|
||||
/*
|
||||
if (firstStart && (jshPinGetValue(BTN1_PININDEX) == BTN1_ONSTATE || jshPinGetValue(BTN4_PININDEX) == BTN4_ONSTATE)) {
|
||||
// don't do it during a software reset - only first hardware reset
|
||||
jsiConsolePrintf("SELF TEST\n");
|
||||
if (pixl_selfTest()) jsiConsolePrintf("Test passed!\n");
|
||||
}*/
|
||||
|
||||
// If the button is *still* pressed, remove all code from flash memory too!
|
||||
/*if (firstStart && jshPinGetValue(BTN1_PININDEX) == BTN1_ONSTATE) {
|
||||
jsfRemoveCodeFromFlash();
|
||||
jsiConsolePrintf("Removed saved code from Flash\n");
|
||||
}*/
|
||||
graphicsSetVar(&gfx);
|
||||
|
||||
firstStart = false;
|
||||
jsvUnLock(graphics);
|
||||
|
||||
// Setup touchscreen I2C
|
||||
i2cBusy = true;
|
||||
jshI2CInitInfo(&internalI2C);
|
||||
internalI2C.bitrate = 0x7FFFFFFF;
|
||||
internalI2C.pinSDA = ACCEL_PIN_SDA;
|
||||
internalI2C.pinSCL = ACCEL_PIN_SCL;
|
||||
jshPinSetValue(internalI2C.pinSCL, 1);
|
||||
jshPinSetState(internalI2C.pinSCL, JSHPINSTATE_GPIO_OUT_OPENDRAIN_PULLUP);
|
||||
jshPinSetValue(internalI2C.pinSDA, 1);
|
||||
jshPinSetState(internalI2C.pinSDA, JSHPINSTATE_GPIO_OUT_OPENDRAIN_PULLUP);
|
||||
// accelerometer init
|
||||
jswrap_banglejs_accelWr(0x18,0x0a); // CNTL1 Off, 4g range, Wakeup
|
||||
jswrap_banglejs_accelWr(0x19,0x80); // CNTL2 Software reset
|
||||
jshDelayMicroseconds(2000);
|
||||
/*jswrap_banglejs_accelWr(0x1b,0x02); // ODCNTL - 50Hz acceleration output data rate, filteringlow-pass ODR/9
|
||||
jswrap_banglejs_accelWr(0x1a,0xb11011110); // CNTL3
|
||||
// 50Hz tilt
|
||||
// 50Hz directional tap
|
||||
// 50Hz general motion detection and the high-pass filtered outputs
|
||||
jswrap_banglejs_accelWr(0x1c,0); // INC1 disabled
|
||||
jswrap_banglejs_accelWr(0x1d,0); // INC2 disabled
|
||||
jswrap_banglejs_accelWr(0x1e,0); // INC3 disabled
|
||||
jswrap_banglejs_accelWr(0x1f,0); // INC4 disabled
|
||||
jswrap_banglejs_accelWr(0x20,0); // INC5 disabled
|
||||
jswrap_banglejs_accelWr(0x21,0); // INC6 disabled
|
||||
jswrap_banglejs_accelWr(0x23,3); // WUFC wakeupi detect counter
|
||||
//jswrap_banglejs_accelWr(0x24,3); // TDTRC Tap detect enable
|
||||
//jswrap_banglejs_accelWr(0x25, 0x78); // TDTC Tap detect double tap
|
||||
//jswrap_banglejs_accelWr(0x26, 0x20); // TTH Tap detect threshold high (0xCB recommended)
|
||||
//jswrap_banglejs_accelWr(0x27, 0x10); // TTH Tap detect threshold low (0x1A recommended)
|
||||
jswrap_banglejs_accelWr(0x30,1); // ATH low wakeup detect threshold
|
||||
jswrap_banglejs_accelWr(0x35,0); // LP_CNTL no averaging of samples
|
||||
jswrap_banglejs_accelWr(0x3e,0); // clear the buffer*/
|
||||
jswrap_banglejs_accelWr(0x18,0b10001100); // CNTL1 On, ODR/2(high res), 4g range, Wakeup, tap
|
||||
// pressure init
|
||||
buf[0]=0x06; jsi2cWrite(&internalI2C, PRESSURE_ADDR, 1, (uint8_t)*buf, true); // SOFT_RST
|
||||
i2cBusy = false;
|
||||
|
||||
// Add watchdog timer to ensure watch always stays usable (hopefully!)
|
||||
// This gets killed when _kill / _init happens
|
||||
// - the bootloader probably already set this up so the
|
||||
// enable will do nothing - but good to try anyway
|
||||
jshEnableWatchDog(5); // 5 second watchdog
|
||||
// This timer kicks the watchdog, and does some other stuff as well
|
||||
JsSysTime t = jshGetTimeFromMilliseconds(ACCEL_POLL_INTERVAL);
|
||||
jstExecuteFn(watchdogHandler, NULL, jshGetSystemTime()+t, t);
|
||||
}
|
||||
|
||||
/*JSON{
|
||||
"type" : "kill",
|
||||
"generate" : "jswrap_banglejs_kill"
|
||||
}*/
|
||||
void jswrap_banglejs_kill() {
|
||||
jstStopExecuteFn(watchdogHandler, 0);
|
||||
jsvUnLock(promisePressure);
|
||||
promisePressure = 0;
|
||||
}
|
||||
|
||||
/*JSON{
|
||||
"type" : "idle",
|
||||
"generate" : "jswrap_banglejs_idle"
|
||||
}*/
|
||||
bool jswrap_banglejs_idle() {
|
||||
if (bangleTasks == JSBT_NONE) return false;
|
||||
JsVar *bangle =jsvObjectGetChild(execInfo.root, "Bangle", 0);
|
||||
if (bangleTasks & JSBT_LCD_OFF) jswrap_banglejs_setLCDPower(0);
|
||||
if (bangleTasks & JSBT_LCD_ON) jswrap_banglejs_setLCDPower(1);
|
||||
if (bangleTasks & JSBT_ACCEL_DATA) {
|
||||
if (bangle && jsiObjectHasCallbacks(bangle, JS_EVENT_PREFIX"accel")) {
|
||||
JsVar *o = jsvNewObject();
|
||||
if (o) {
|
||||
jsvObjectSetChildAndUnLock(o, "x", jsvNewFromFloat(accx/8192.0));
|
||||
jsvObjectSetChildAndUnLock(o, "y", jsvNewFromFloat(accy/8192.0));
|
||||
jsvObjectSetChildAndUnLock(o, "z", jsvNewFromFloat(accz/8192.0));
|
||||
jsvObjectSetChildAndUnLock(o, "mag", jsvNewFromFloat(sqrt(accx*accx + accy*accy + accz*accz)/8192.0));
|
||||
jsvObjectSetChildAndUnLock(o, "diff", jsvNewFromFloat(sqrt(accdiff)/8192.0));
|
||||
jsiQueueObjectCallbacks(bangle, JS_EVENT_PREFIX"accel", &o, 1);
|
||||
jsvUnLock(o);
|
||||
}
|
||||
}
|
||||
bool faceUp = (accz<7000) && abs(accx)<4096 && abs(accy)<4096;
|
||||
if (faceUp!=wasFaceUp) {
|
||||
faceUpCounter=0;
|
||||
wasFaceUp = faceUp;
|
||||
}
|
||||
if (faceUpCounter<255) faceUpCounter++;
|
||||
if (faceUpCounter==2) {
|
||||
if (bangle) {
|
||||
JsVar *v = jsvNewFromBool(faceUp);
|
||||
jsiQueueObjectCallbacks(bangle, JS_EVENT_PREFIX"faceUp", &v, 1);
|
||||
jsvUnLock(v);
|
||||
}
|
||||
if (lcdPowerTimeout && !lcdPowerOn) {
|
||||
// LCD was turned off, turn it back on
|
||||
jswrap_banglejs_setLCDPower(1);
|
||||
flipCounter = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (bangle && (bangleTasks & JSBT_ACCEL_TAPPED)) {
|
||||
JsVar *o = jsvNewObject();
|
||||
if (o) {
|
||||
const char *string="";
|
||||
if (tapInfo&1) string="front";
|
||||
if (tapInfo&2) string="back";
|
||||
if (tapInfo&4) string="bottom";
|
||||
if (tapInfo&8) string="top";
|
||||
if (tapInfo&16) string="right";
|
||||
if (tapInfo&32) string="left";
|
||||
int n = (tapInfo&0x80)?2:1;
|
||||
jsvObjectSetChildAndUnLock(o, "dir", jsvNewFromString(string));
|
||||
jsvObjectSetChildAndUnLock(o, "double", jsvNewFromBool(tapInfo&0x80));
|
||||
jsvObjectSetChildAndUnLock(o, "x", jsvNewFromInteger((tapInfo&16)?-n:(tapInfo&32)?n:0));
|
||||
jsvObjectSetChildAndUnLock(o, "y", jsvNewFromInteger((tapInfo&4)?-n:(tapInfo&8)?n:0));
|
||||
jsvObjectSetChildAndUnLock(o, "z", jsvNewFromInteger((tapInfo&1)?-n:(tapInfo&2)?n:0));
|
||||
jsiQueueObjectCallbacks(bangle, JS_EVENT_PREFIX"tap", &o, 1);
|
||||
jsvUnLock(o);
|
||||
}
|
||||
}
|
||||
if (bangle && (bangleTasks & JSBT_GPS_DATA)) {
|
||||
JsVar *o = nmea_to_jsVar(&gpsFix);
|
||||
if (o) {
|
||||
jsiQueueObjectCallbacks(bangle, JS_EVENT_PREFIX"GPS", &o, 1);
|
||||
jsvUnLock(o);
|
||||
}
|
||||
}
|
||||
if (bangle && (bangleTasks & JSBT_GPS_DATA_LINE)) {
|
||||
JsVar *line = jsvNewFromString(nmeaLine);
|
||||
if (line) {
|
||||
jsiQueueObjectCallbacks(bangle, JS_EVENT_PREFIX"GPS-raw", &line, 1);
|
||||
}
|
||||
jsvUnLock(line);
|
||||
}
|
||||
jsvUnLock(bangle);
|
||||
bangleTasks = JSBT_NONE;
|
||||
return false;
|
||||
}
|
||||
|
||||
/*JSON{
|
||||
"type" : "EV_SERIAL1",
|
||||
"generate" : "jswrap_banglejs_gps_character"
|
||||
}*/
|
||||
bool jswrap_banglejs_gps_character(char ch) {
|
||||
if (ch=='\r') return true; // we don't care
|
||||
// if too many chars, roll over since it's probably because we skipped a newline
|
||||
if (nmeaCount>=sizeof(nmeaIn)) nmeaCount=0;
|
||||
nmeaIn[nmeaCount++]=ch;
|
||||
if (ch!='\n') return true; // now handled
|
||||
// Now we have a line of GPS data...
|
||||
/* $GNRMC,161945.00,A,5139.11397,N,00116.07202,W,1.530,,190919,,,A*7E
|
||||
$GNVTG,,T,,M,1.530,N,2.834,K,A*37
|
||||
$GNGGA,161945.00,5139.11397,N,00116.07202,W,1,06,1.29,71.1,M,47.0,M,,*64
|
||||
$GNGSA,A,3,09,06,23,07,03,29,,,,,,,1.96,1.29,1.48*14
|
||||
$GPGSV,3,1,12,02,45,293,13,03,10,109,16,05,13,291,,06,56,213,25*73
|
||||
$GPGSV,3,2,12,07,39,155,18,09,76,074,33,16,08,059,,19,02,218,18*7E
|
||||
$GPGSV,3,3,12,23,40,066,23,26,08,033,18,29,07,342,20,30,14,180,*7F
|
||||
$GNGLL,5139.11397,N,00116.07202,W,161945.00,A,A*69 */
|
||||
// Let's just chuck it over into JS-land for now
|
||||
if (nmeaCount>1) {
|
||||
memcpy(nmeaLine, nmeaIn, nmeaCount);
|
||||
nmeaLine[nmeaCount-1]=0; // just overwriting \n
|
||||
bangleTasks |= JSBT_GPS_DATA_LINE;
|
||||
if (nmea_decode(&gpsFix, nmeaLine))
|
||||
bangleTasks |= JSBT_GPS_DATA;
|
||||
}
|
||||
nmeaCount = 0;
|
||||
return true; // handled
|
||||
}
|
||||
|
||||
/*JSON{
|
||||
"type" : "staticmethod",
|
||||
"class" : "Bangle",
|
||||
"name" : "accelWr",
|
||||
"generate" : "jswrap_banglejs_accelWr",
|
||||
"params" : [
|
||||
["reg","int",""],
|
||||
["data","int",""]
|
||||
]
|
||||
}
|
||||
Writes a register on the KX023 Accelerometer
|
||||
*/
|
||||
void jswrap_banglejs_accelWr(JsVarInt reg, JsVarInt data) {
|
||||
unsigned char buf[2];
|
||||
buf[0] = (unsigned char)reg;
|
||||
buf[1] = (unsigned char)data;
|
||||
i2cBusy = true;
|
||||
jsi2cWrite(&internalI2C, ACCEL_ADDR, 2, buf, true);
|
||||
i2cBusy = false;
|
||||
}
|
||||
|
||||
/*JSON{
|
||||
"type" : "staticmethod",
|
||||
"class" : "Bangle",
|
||||
"name" : "accelRd",
|
||||
"generate" : "jswrap_banglejs_accelRd",
|
||||
"params" : [
|
||||
["reg","int",""]
|
||||
],
|
||||
"return" : ["int",""]
|
||||
}
|
||||
Reads a register from the KX023 Accelerometer
|
||||
*/
|
||||
int jswrap_banglejs_accelRd(JsVarInt reg) {
|
||||
unsigned char buf[1];
|
||||
buf[0] = (unsigned char)reg;
|
||||
i2cBusy = true;
|
||||
jsi2cWrite(&internalI2C, ACCEL_ADDR, 1, buf, true);
|
||||
jsi2cRead(&internalI2C, ACCEL_ADDR, 1, buf, true);
|
||||
i2cBusy = false;
|
||||
return buf[0];
|
||||
}
|
||||
|
||||
/*JSON{
|
||||
"type" : "staticmethod",
|
||||
"class" : "Bangle",
|
||||
"name" : "getPressure",
|
||||
"generate" : "jswrap_banglejs_getPressure",
|
||||
"return" : ["JsVar","A promise that will be resolved with `{temperature, pressure, altitude}`"]
|
||||
}
|
||||
Read temperature, pressure and altitude data. A promise is returned
|
||||
which will be resolved with `{temperature, pressure, altitude}`.
|
||||
|
||||
Conversions take roughly 100ms.
|
||||
|
||||
```
|
||||
Bangle.getPressure().then(d=>{
|
||||
console.log(d);
|
||||
// {temperature, pressure, altitude}
|
||||
});
|
||||
```
|
||||
*/
|
||||
void jswrap_banglejs_getPressure_callback() {
|
||||
JsVar *o = jsvNewObject();
|
||||
if (o) {
|
||||
i2cBusy = true;
|
||||
unsigned char buf[6];
|
||||
// ADC_CVT - 0b010 01 000 - pressure and temperature channel, OSR = 4096
|
||||
buf[0] = 0x48; jsi2cWrite(&internalI2C, PRESSURE_ADDR, 1, buf, true);
|
||||
// wait 100ms
|
||||
jshDelayMicroseconds(100*1000); // we should really have a callback
|
||||
// READ_PT
|
||||
buf[0] = 0x10; jsi2cWrite(&internalI2C, PRESSURE_ADDR, 1, buf, true);
|
||||
jsi2cRead(&internalI2C, PRESSURE_ADDR, 6, buf, true);
|
||||
int temperature = (buf[0]<<16)|(buf[1]<<8)|buf[2];
|
||||
if (temperature&0x800000) temperature-=0x1000000;
|
||||
int pressure = (buf[3]<<16)|(buf[4]<<8)|buf[5];
|
||||
jsvObjectSetChildAndUnLock(o,"temperature", jsvNewFromFloat(temperature/100.0));
|
||||
jsvObjectSetChildAndUnLock(o,"pressure", jsvNewFromFloat(pressure/100.0));
|
||||
|
||||
buf[0] = 0x31; jsi2cWrite(&internalI2C, PRESSURE_ADDR, 1, buf, true); // READ_A
|
||||
jsi2cRead(&internalI2C, PRESSURE_ADDR, 3, buf, true);
|
||||
int altitude = (buf[0]<<16)|(buf[1]<<8)|buf[2];
|
||||
if (altitude&0x800000) altitude-=0x1000000;
|
||||
jsvObjectSetChildAndUnLock(o,"altitude", jsvNewFromFloat(altitude/100.0));
|
||||
i2cBusy = false;
|
||||
|
||||
jspromise_resolve(promisePressure, o);
|
||||
}
|
||||
jsvUnLock2(promisePressure,o);
|
||||
promisePressure = 0;
|
||||
}
|
||||
|
||||
JsVar *jswrap_banglejs_getPressure() {
|
||||
if (promisePressure) {
|
||||
jsExceptionHere(JSET_ERROR, "Conversion in progress");
|
||||
return 0;
|
||||
}
|
||||
promisePressure = jspromise_create();
|
||||
if (!promisePressure) return 0;
|
||||
|
||||
jsiSetTimeout(jswrap_banglejs_getPressure_callback, 100);
|
||||
return jsvLockAgain(promisePressure);
|
||||
}
|
||||
/*JSON{
|
||||
"type" : "staticmethod",
|
||||
"class" : "Bangle",
|
||||
"name" : "off",
|
||||
"generate" : "jswrap_banglejs_off"
|
||||
}
|
||||
Turn Bangle.js off. It can only be woken by pressing BTN1.
|
||||
*/
|
||||
void jswrap_banglejs_off() {
|
||||
jsiKill();
|
||||
jsvKill();
|
||||
jshKill();
|
||||
jshPinOutput(GPS_PIN_EN,0); // GPS off
|
||||
jshPinOutput(VIBRATE_PIN,0); // vibrate off
|
||||
jshPinOutput(LCD_BL,1); // backlight off
|
||||
jshPinOutput(LED1_PININDEX,0); // LED off
|
||||
lcdCmd_SPILCD(0x28, 0, NULL); // display off
|
||||
|
||||
|
||||
nrf_gpio_cfg_sense_set(BTN2_PININDEX, NRF_GPIO_PIN_NOSENSE);
|
||||
nrf_gpio_cfg_sense_set(BTN3_PININDEX, NRF_GPIO_PIN_NOSENSE);
|
||||
nrf_gpio_cfg_sense_set(BTN1_PININDEX, NRF_GPIO_PIN_SENSE_LOW);
|
||||
sd_power_system_off();
|
||||
}
|
||||
|
||||
/*JSON{
|
||||
"type" : "event",
|
||||
"class" : "Bangle",
|
||||
"name" : "accel",
|
||||
"params" : [["xyz","JsVar",""]],
|
||||
"ifdef" : "BANGLEJS"
|
||||
}
|
||||
Accelerometer data available with `{x,y,z,diff,mag}` object as a parameter
|
||||
|
||||
* `x` is X axis (left-right) in `g`
|
||||
* `y` is Y axis (up-down) in `g`
|
||||
* `z` is Z axis (in-out) in `g`
|
||||
* `diff` is difference between this and the last reading in `g`
|
||||
* `mag` is the magnitude of the acceleration in `g`
|
||||
*/
|
||||
/*JSON{
|
||||
"type" : "event",
|
||||
"class" : "Bangle",
|
||||
"name" : "faceUp",
|
||||
"params" : [["up","bool","`true` if face-up"]],
|
||||
"ifdef" : "BANGLEJS"
|
||||
}
|
||||
Has the watch been moved so that it is face-up, or not face up?
|
||||
*/
|
||||
/*JSON{
|
||||
"type" : "event",
|
||||
"class" : "Bangle",
|
||||
"name" : "lcdPower",
|
||||
"params" : [["on","bool","`true` if screen is on"]],
|
||||
"ifdef" : "BANGLEJS"
|
||||
}
|
||||
Has the screen been turned on or off? Can be used to stop tasks that are no longer useful if nothing is displayed.
|
||||
*/
|
||||
/*JSON{
|
||||
"type" : "event",
|
||||
"class" : "Bangle",
|
||||
"name" : "faceUp",
|
||||
"params" : [["data","JsVar","`{dir, double, x, y, z}`"]],
|
||||
"ifdef" : "BANGLEJS"
|
||||
}
|
||||
If the watch is tapped, this event contains information on the way it was tapped.
|
||||
|
||||
`dir` reports the side of the watch that was tapped (not the direction it was tapped in).
|
||||
|
||||
```
|
||||
{
|
||||
dir : "left/right/top/bottom/front/back",
|
||||
double : true/false // was this a double-tap?
|
||||
x : -2 .. 2, // the axis of the tap
|
||||
y : -2 .. 2, // the axis of the tap
|
||||
z : -2 .. 2 // the axis of the tap
|
||||
```
|
||||
*/
|
||||
|
||||
32
libs/banglejs/jswrap_banglef5.h
Normal file
32
libs/banglejs/jswrap_banglef5.h
Normal file
@ -0,0 +1,32 @@
|
||||
/*
|
||||
* 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 Bangle.js (http://www.espruino.com/Bangle.js)
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
#include "jspin.h"
|
||||
|
||||
void jswrap_banglejs_lcdWr(JsVarInt cmd, JsVar *data);
|
||||
void jswrap_banglejs_setLCDPower(bool isOn);
|
||||
void jswrap_banglejs_setLCDTimeout(JsVarFloat timeout);
|
||||
void jswrap_banglejs_setLCDPalette(JsVar *palette);
|
||||
bool jswrap_banglejs_isLCDOn();
|
||||
|
||||
void jswrap_banglejs_setGPSPower(bool isOn);
|
||||
|
||||
void jswrap_banglejs_accelWr(JsVarInt reg, JsVarInt data);
|
||||
int jswrap_banglejs_accelRd(JsVarInt reg);
|
||||
JsVar *jswrap_banglejs_getPressure();
|
||||
void jswrap_banglejs_off();
|
||||
|
||||
void jswrap_banglejs_init();
|
||||
void jswrap_banglejs_kill();
|
||||
bool jswrap_banglejs_idle();
|
||||
bool jswrap_banglejs_gps_character(char ch);
|
||||
146
libs/misc/nmea.c
Normal file
146
libs/misc/nmea.c
Normal file
@ -0,0 +1,146 @@
|
||||
/*
|
||||
* This file is part of Espruino, a JavaScript interpreter for Microcontrollers
|
||||
*
|
||||
* Copyright (C) 2019 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/.
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
* NMEA decoder
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#include "nmea.h"
|
||||
#include "jswrap_date.h"
|
||||
|
||||
char *nmea_next_comma(char *nmea) {
|
||||
while (*nmea && *nmea!=',') nmea++; // find the comma
|
||||
return nmea;
|
||||
}
|
||||
double nmea_decode_latlon(char *nmea, char *comma) {
|
||||
if (*nmea==',') return NAN; // no reading
|
||||
char *dp = nmea;
|
||||
while (*dp && *dp!='.' && *dp!=',') dp++; // find decimal pt
|
||||
*comma = 0;
|
||||
double minutes = stringToFloat(&dp[-2]);
|
||||
*comma = ',';
|
||||
dp[-2] = 0;
|
||||
int x = stringToInt(nmea);
|
||||
return x+(minutes/60);
|
||||
}
|
||||
double nmea_decode_float(char *nmea, char *comma) {
|
||||
*comma = 0;
|
||||
double r = stringToFloat(nmea);
|
||||
*comma = ',';
|
||||
return r;
|
||||
}
|
||||
uint8_t nmea_decode_1(char *nmea) {
|
||||
return chtod(nmea[0]);
|
||||
}
|
||||
uint8_t nmea_decode_2(char *nmea) {
|
||||
return chtod(nmea[0])*10 + chtod(nmea[1]);
|
||||
}
|
||||
bool nmea_decode(NMEAFixInfo *gpsFix, const char *nmeaLine) {
|
||||
char buf[NMEA_MAX_SIZE];
|
||||
strcpy(buf, nmeaLine);
|
||||
char *nmea = buf, *nextComma;
|
||||
|
||||
|
||||
if (nmea[0]!='$' || nmea[1]!='G') return false; // not valid
|
||||
if (nmea[3]=='R' && nmea[4]=='M' && nmea[5]=='C') {
|
||||
// $GNRMC,161945.00,A,5139.11397,N,00116.07202,W,1.530,,190919,,,A*7E
|
||||
nmea = nmea_next_comma(nmea)+1;
|
||||
nextComma = nmea_next_comma(nmea);
|
||||
// time
|
||||
gpsFix->hour = nmea_decode_2(&nmea[0]);
|
||||
gpsFix->min = nmea_decode_2(&nmea[2]);
|
||||
gpsFix->sec = nmea_decode_2(&nmea[4]);
|
||||
gpsFix->ms = nmea_decode_2(&nmea[7]);
|
||||
// status
|
||||
nmea = nextComma+1; nextComma = nmea_next_comma(nmea);
|
||||
nmea = nextComma+1; nextComma = nmea_next_comma(nmea);//?
|
||||
// lat + NS
|
||||
nmea = nextComma+1; nextComma = nmea_next_comma(nmea);
|
||||
nmea = nextComma+1; nextComma = nmea_next_comma(nmea);
|
||||
// lon + EW
|
||||
nmea = nextComma+1; nextComma = nmea_next_comma(nmea);
|
||||
nmea = nextComma+1; nextComma = nmea_next_comma(nmea);
|
||||
// speed
|
||||
gpsFix->speed = nmea_decode_float(nmea, nextComma);
|
||||
nmea = nextComma+1; nextComma = nmea_next_comma(nmea);
|
||||
// course
|
||||
gpsFix->course = nmea_decode_float(nmea, nextComma);
|
||||
nmea = nextComma+1; nextComma = nmea_next_comma(nmea);
|
||||
// date
|
||||
gpsFix->day = nmea_decode_2(&nmea[0]);
|
||||
gpsFix->month = nmea_decode_2(&nmea[2]);
|
||||
gpsFix->year = nmea_decode_2(&nmea[4]);
|
||||
// ....
|
||||
}
|
||||
if (nmea[3]=='G' && nmea[4]=='G' && nmea[5]=='A') {
|
||||
// $GNGGA,161945.00,5139.11397,N,00116.07202,W,1,06,1.29,71.1,M,47.0,M,,*64
|
||||
nmea = nmea_next_comma(nmea)+1;
|
||||
nextComma = nmea_next_comma(nmea);
|
||||
// time
|
||||
nmea = nextComma+1; nextComma = nmea_next_comma(nmea);
|
||||
// LAT
|
||||
gpsFix->lat = nmea_decode_latlon(nmea, nextComma);
|
||||
nmea = nextComma+1; nextComma = nmea_next_comma(nmea);
|
||||
if (*nmea=='S') gpsFix->lat=-gpsFix->lat;
|
||||
nmea = nextComma+1; nextComma = nmea_next_comma(nmea);
|
||||
// LON
|
||||
gpsFix->lon = nmea_decode_latlon(nmea, nextComma);
|
||||
nmea = nextComma+1; nextComma = nmea_next_comma(nmea);
|
||||
if (*nmea=='W') gpsFix->lon=-gpsFix->lon;
|
||||
nmea = nextComma+1; nextComma = nmea_next_comma(nmea);
|
||||
// quality
|
||||
gpsFix->quality = nmea_decode_1(nmea);
|
||||
nmea = nextComma+1; nextComma = nmea_next_comma(nmea);
|
||||
// num satellites
|
||||
gpsFix->satellites = nmea_decode_2(nmea);
|
||||
nmea = nextComma+1; nextComma = nmea_next_comma(nmea);
|
||||
// dilution of precision
|
||||
nmea = nextComma+1; nextComma = nmea_next_comma(nmea);
|
||||
// altitude
|
||||
gpsFix->alt = nmea_decode_float(nmea, nextComma);
|
||||
nmea = nextComma+1; nextComma = nmea_next_comma(nmea);
|
||||
// ....
|
||||
}
|
||||
if (nmea[3]=='G' && nmea[4]=='S' && nmea[5]=='V') {
|
||||
// loads of cool data about what satellites we have
|
||||
}
|
||||
if (nmea[3]=='G' && nmea[4]=='L' && nmea[5]=='L') {
|
||||
// Complete set of data received
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
JsVar *nmea_to_jsVar(NMEAFixInfo *gpsFix) {
|
||||
JsVar *o = jsvNewObject();
|
||||
if (o) {
|
||||
jsvObjectSetChildAndUnLock(o, "lat", jsvNewFromFloat(gpsFix->lat));
|
||||
jsvObjectSetChildAndUnLock(o, "lon", jsvNewFromFloat(gpsFix->lon));
|
||||
jsvObjectSetChildAndUnLock(o, "alt", jsvNewFromFloat(gpsFix->alt));
|
||||
jsvObjectSetChildAndUnLock(o, "speed", jsvNewFromFloat(gpsFix->speed));
|
||||
jsvObjectSetChildAndUnLock(o, "course", jsvNewFromFloat(gpsFix->course));
|
||||
CalendarDate date;
|
||||
date.day = gpsFix->day;
|
||||
date.month = gpsFix->month;
|
||||
date.year = 2000+gpsFix->year;
|
||||
TimeInDay td;
|
||||
td.daysSinceEpoch = fromCalenderDate(&date);
|
||||
td.hour = gpsFix->hour;
|
||||
td.min = gpsFix->min;
|
||||
td.sec = gpsFix->sec;
|
||||
td.ms = gpsFix->ms;
|
||||
td.zone = 0; // jsdGetTimeZone(); - no! GPS time is always in UTC :)
|
||||
jsvObjectSetChildAndUnLock(o, "time", jswrap_date_from_milliseconds(fromTimeInDay(&td)));
|
||||
jsvObjectSetChildAndUnLock(o, "satellites", jsvNewFromInteger(gpsFix->satellites));
|
||||
jsvObjectSetChildAndUnLock(o, "fix", jsvNewFromInteger(gpsFix->quality));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
30
libs/misc/nmea.h
Normal file
30
libs/misc/nmea.h
Normal file
@ -0,0 +1,30 @@
|
||||
/*
|
||||
* This file is part of Espruino, a JavaScript interpreter for Microcontrollers
|
||||
*
|
||||
* Copyright (C) 2019 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/.
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
* NMEA decoder
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#include "jsvar.h"
|
||||
|
||||
typedef struct {
|
||||
double lat,lon,alt;
|
||||
double speed, course;
|
||||
int hour,min,sec,ms;
|
||||
uint8_t day,month,year;
|
||||
uint8_t quality; // from GGA packet, 0 = no fix
|
||||
uint8_t satellites; // how many satellites
|
||||
} NMEAFixInfo;
|
||||
|
||||
#define NMEA_MAX_SIZE 82 // 82 is the max for NMEA
|
||||
|
||||
|
||||
bool nmea_decode(NMEAFixInfo *gpsFix, const char *nmeaLine);
|
||||
JsVar *nmea_to_jsVar(NMEAFixInfo *gpsFix);
|
||||
Loading…
x
Reference in New Issue
Block a user