This apps lets you run a JavaScript script on your NumWorks calculator!
Installing is rather easy:
- (not yet, see 2) Download the latest
javascript.nwa
file from the Releases page ; - This Release page is not-yet ready, on this project, use this folder instead, and this direct link ;
- Head to my.numworks.com/apps to send the
nwa
file on your calculator (on Google Chrome browser). On this page you will be able to also send a default example of a JavaScript file (a tiny test script), and you can edit it yourself later on, on your calculator!
Just launch the app, and it will read and execute your script javascript.py
!
This script should be located in the javascript.py
file, that you can create, edit and save from within your NumWorks!.
If you want a demo, use this javascript.py
script, that you can install on your NumWorks calculator, directly from their website (from my user space).
This programs uses the code generated by the Espruino project (espruino_embedded.c
, espruino_embedded.h
etc), a portable JavaScript interpreter for microcontrolers.
I've started to work on my fork of Espruino, in order to solve this issue: I wanted to give access to NumWorks's EADK library (see eadk.h
) to the JavaScript files that are executed in this Espruino JS interpreter.
It's a work in progress!
To rebuild the two espruino_embedded.c
and espruino_embedded.h
files from Espruino's source code, you must run this in its main directory (of my fork, not the main project):
BOARD=EMBED RELEASE=1 V=1 make
Then remove these lines from the espruino_embedded.c
file:
typedef unsigned char __u_char;
typedef unsigned short int __u_short;
...
typedef __intmax_t intmax_t;
typedef __uintmax_t uintmax_t;
Copy the files you obtained to the ./src/javascript/
folder on this project (they are included, you shouldn't have to do this, unless you want to help me developping this!).
Here is a short documentation for each function that I've ported from their interface in eadk.h
to a working version in JavaScript.
I've exposed an Eadk
module (see example in JavaScript below, or here), which comes ready with these functions and constants:
Legend:
- ✅ = code written, function tested!
- ✅? = code written, function not yet working!
- ❌ = code written, function unavailable / or code not yet written!!
Eadk.color_black
, Eadk.color_white
, Eadk.color_red
, Eadk.color_green
, Eadk.color_blue
are the five predefined colors.
Eadk.SCREEN_WIDTH
and Eadk.SCREEN_HEIGHT
are the screen's width and height, respectively.
Returns the screen's brightness, it's a 8 bits integer (uint8_t
in C), ranging between 0 (min brightness, screen almost shut down) to 240 (for max brightness).
Sets the screen's brightness to this value.
brightness
must be an integer value which fits inside a uint8_t
, between 0 and 256.
Indicates whether the battery is charging.
Returns a 8 bits integer giving the battery level.
Returns a floating value of the battery voltage (in Volt, I guess?).
These functions are missing from the hardware! See this issue on NumWorks/epsilon's repository DONE: I just implemented them myself, by SVC calls
❌✅ void Eadk.display_draw_string(const char* text, uint16_t x, uint16_t y, bool large_font, uint16_t text_color, uint16_t background_color)
Displays a given text
string, at a {x,y}
position, in large/small font (large_font
?), with the text in text_color
and the background in background_color
.
Eadk.display_draw_string(text, x, y, large, text_color, background_color);
TODO: it's still a bit buggy! See this issue
✅ void Eadk.display_push_rect_uniform(uint16_t x, uint16_t y, uint16_t width, uint16_t height, uint16_t color)
Fills a rectangle on the display with a uniform color. This can also be used to draw a single pixel by setting width and height to 1.
x
: X coordinate of the top-left corner,y
: Y coordinate of the top-left corner,width
: Width of the rectangle,height
: Height of the rectangle,color
: Color of the rectangle (e.g.,0xFFFF
for white,0xF800
for red).
For instance:
Eadk.display_push_rect_uniform(0, 0, 10, 20, 0xF800); // Fills a 10x20 red rectangle at (0,0)
Eadk.display_push_rect_uniform(50, 50, 1, 1, 0x07E0); // Draws a single green pixel at (50,50)
Display: wait for vblank? It is not documented in eadk.h so not documented here (we don't really know what it does)
Eadk.display_push_rect
: is missing.Eadk.display_pull_rect
: is missing.
Sleep for us
micro-seconds
Sleep for ms
micro-seconds
Time since boot of the machine? Not clear. FIXME:
Indicates whether the USB is plugged.
This function is missing from the hardware! See this issue on NumWorks/epsilon's repository DONE: I just implemented it myself, by SVC calls
Returns an almost truly random number, generated from the hardware RNG (a uint32_t, unsigned 32 bits integer).
To add new functions, edit in my fork of Espruino the files: libs/eadk/jswrap_eadk.c
and libs/eadk/jswrap_eadk.h
.
The functions already present should give a good direction to follow!
The example below runs now correctly and showcases a few iterations of decrease then increase in brightness, with small pauses between every change:
For a more complete and length example, see src/test.js
.
// Save this to `javascript.py` on your NumWorks, and run it with
// the "JS interpreter" NumWorks application!
console.log("Hello world from JavaScript!\n");
console.log("Testing some Eadk functions:\n");
Eadk.timing_msleep(5000);
const brightness = Eadk.backlight_brightness();
console.log("Eadk.backlight_brightness() =", Eadk.backlight_brightness());
Eadk.timing_msleep(2000);
for (let a = 1; a <= 10; a++) {
for (let b = brightness; b >= 0; b=b-16) {
Eadk.set_backlight_brightness(b);
console.log("Eadk.backlight_brightness() =", Eadk.backlight_brightness());
Eadk.timing_msleep(50);
}
for (let b = 0; b <= brightness; b=b+16) {
Eadk.set_backlight_brightness(b);
console.log("Eadk.backlight_brightness() =", Eadk.backlight_brightness());
Eadk.timing_msleep(50);
}
}
To build this sample app, you will need to install the embedded ARM toolchain and nwlink.
brew install numworks/tap/arm-none-eabi-gcc node # Or equivalent on your OS
npm install -g nwlink
make clean && make build
MIT Licensed (file LICENSE). © Lilian Besson, 2025.