ESP32forth Update 🙘 October 8, 2022 IMPROVEMENTS SINCE AUGUST 🙘 • CASE • BTERM & RELINQUISH • Shell Words • Code Words & DUMP • More ESP-CAM Bindings • USER_VOCABULARIES CASE CASE 1 OF ." one" ENDOF 2 OF ." two" ENDOF ." other: " DUP . ENDCASE 1 OVER = IF s" one" type ELSE 2 OVER = IF s" two" type ELSE s" other:" type DUP . THEN THEN DROP CASE 🙘 • Terser branching on a value • Forth syntax doesn't quite allow jump tables - Worth exploring? Or un-Forthy? BTERM & RELINQUISH BTERM 🙘 • Bluetooth serial can be handy • Discovered that bterm wasn't working on regular ESP32! • The issue is that bluetooth needs about 120KB free • RELINQUISH ( n -- ) releases n bytes from the back of the heap • Built into bterm lazy loading Shell Words A Forth-y Shell 🙘 • Basic BASH-like words • But ESP32 doesn't build in directory support • A few extra words on Linux cp ( "src" "dst" -- ) Copy "src" file to "dst". mv ( "src" "dst" -- ) Rename "src" file to "dst". rm ( "path" -- ) Remove "path" file. touch ( "path" -- ) Create "path" file if it doesn't exist. cat ( "path" -- ) Print contents of "path" file. ls ( "path" -- ) List files or directories in "path". cd ( "path" -- ) Change director to "path". mkdir ( "path" -- ) Create directory "path". rmdir ( "path" -- ) Remove directory "path". pwd ( -- ) Print current directory. DEMO Shell & Editor Code Words & DUMP Code Words 🙘 • Added CODE words, but assembler not yet ready • Uses a C call signature for stable ABI • Not all memory can be used for ESP32 code • ESP32 and Linux support only at the moment • Assembler coming soon • Lazy loaded by ASM word CODE ( "name" ) -- Define a code word END-CODE -- End a code word CHERE ( -- a ) -- Get code pointer CALLOT ( n -- ) -- Allocate code memory CODE1, ( n -- ) -- Compile 1 byte CODE2, ( n -- ) -- Compile 2 byte CODE3, ( n -- ) -- Compile 3 byte CODE4, ( n -- ) -- Compile 4 byte Forth to C Entry SIGNATURE: cell_t *myfunc(cell_t *sp, float **fp); ------- On x64: %rdi - Data stack pointer in %rax - Data stack pointer out %rsi - Pointer to floating stack pointer ------- On Xtensa (ESP32): a2 - Data stack pointer in & out a3 - Pointer to floating stack pointer YV(internals, CALLCODE, float *t_fp = fp; DUP; \ sp = (cell_t *) (*(call_t*) (w + sizeof(cell_t)))(sp, &t_fp); \ fp = t_fp; DROP) \ ASM FORTH CODE my2* $48 CODE1, $89 CODE1, $f8 CODE1, ( mov %rdi, %rax ) $48 CODE1, $d1 CODE1, $27 CODE1, ( shlq [%rdi] ) $c3 CODE1, ( ret ) END-CODE ASM FORTH CODE my2* $004136 CODE3, ( entry a1, 32 ) $0288 CODE2, ( l32i.n a8, a2, 0 ) $1188f0 CODE3, ( slli a8, a8, 1 ) $0289 CODE2, ( s32i.n a8, a2, 0 ) $f01d CODE2, ( retw.n ) END-CODE ' - 20 hex dump 416208 34 2A 40 00 00 00 00 00 416210 B2 3E 41 00 00 00 00 00 08 03 00 00 00 00 00 00 416220 16 2A 40 00 00 00 00 00 ESP-CAM Bindings esp_camera_init ( config -- f ) esp_camera_deinit ( -- f ) esp_camera_fb_get ( -- fb ) esp_camera_fb_return ( fb -- ) esp_camera_sensor_get ( -- sensor ) esp_camera_save_to_nvs ( key -- n ) esp_camera_load_from_nvs ( key -- n ) ( formats ) PIXFORMAT_RGB565 PIXFORMAT_YUV422 PIXFORMAT_GRAYSCALE PIXFORMAT_JPEG PIXFORMAT_RGB888 PIXFORMAT_RAW PIXFORMAT_RGB444 PIXFORMAT_RGB555 ( frame sizes ) FRAMESIZE_96x96 ( 96x96) FRAMESIZE_QQVGA ( 160x120 ) FRAMESIZE_QCIF ( 176x144 ) FRAMESIZE_HQVGA ( 240x176 ) FRAMESIZE_240x240 ( 176x144 ) FRAMESIZE_QVGA ( 320x240 ) FRAMESIZE_CIF ( 400x296 ) FRAMESIZE_HVGA ( 480x320 ) FRAMESIZE_VGA ( 640x480 ) FRAMESIZE_SVGA ( 800x600 ) FRAMESIZE_XGA ( 1024x768 ) FRAMESIZE_HD ( 1280x720 ) FRAMESIZE_SXGA ( 1280x1024 ) FRAMESIZE_UXGA ( 1600x1200 ) ( access to config ) camera-fb-count ( -- a ) camera-jpeg-quality ( -- a ) camera-frame-size ( -- a ) camera-format ( -- a ) ( Access a frame returned by esp_camera_fb_get ) fb->buf ( -- a ) fb->len ( -- n ) fb->width ( -- n ) fb->height ( -- n ) fb->format ( -- n ) fb->sec ( -- n ) fb->usec ( -- n ) ( Access methods in struct returned by esp_camera_sensor_get ) s->xclk_freq_hz ( a ) s->init_status ( s ) s->reset ( s ) s->set_pixformat ( s pixformat ) s->set_framesize ( s framesize ) s->set_contrast ( s level ) s->set_brightness ( s level ) s->set_saturation ( s level ) s->set_sharpness ( s level ) s->set_denoise ( s level ) s->set_gainceiling ( s gainceil ) s->set_quality ( s quality ) s->set_colorbar ( s enable ) s->set_whitebal ( s enable ) s->set_gain_ctrl ( s enable ) s->set_exposure_ctrl ( s enable ) s->set_hmirror ( s enable ) s->set_vflip ( s enable ) ( --- ) s->set_aec2 ( s enable ) s->set_awb_gain ( s enable ) s->set_agc_gain ( s gain ) s->set_aec_value ( s gain ) ( --- ) s->set_special_effect ( s effect ) s->set_wb_mode ( s mode ) s->set_ae_level ( s level ) ( --- ) s->set_raw_gma ( s enable ) s->set_lenc ( s enable ) ( --- ) s->get_reg ( s reg mask ) s->set_reg ( s reg mask value ) s->set_res_raw ( s startX startY endX endY offsetX offsetY totalX totalY outputX outputY scale binning ) s->set_pll ( s bypass mul sys root pre seld5 pclken pclk ) s->set_xclk ( s time xclk ) USER_VOCABULARIES Y(myword, n0 = myfunc(a1, n0); DROP) \ X("myword!", MYWORDBANG, n0 = myfunc(n0)) \ YV(myvocab, myword, n0 = myfunc(a1, n0); DROP) \ XV(myvocab, "myword!", MYWORDBANG, n0 = myfunc(n0)) \ Builtins add an extra chain of builtin words e.g. internals-builtins Wire-builtins userwords.h ----------- #define USER_VOCABULARIES V(myvocab) V(myvocab2) #define USER_WORDS \ XV(myvocab, "my+", MYPLUS, n1 = n1 + n0; DROP) \ YV(myvocab2, myword, n0 = n0 + 10) \ VOCABULARY myvocab myvocab DEFINITIONS transfer myvocab-builtins FORTH VOCABULARY myvocab2 myvocab2 DEFINITIONS transfer myvocab2-builtins FORTH QUESTIONS? 🏵 Thank you!