├── .gitignore ├── .vscode └── extensions.json ├── cpwords.md ├── data └── autoexec.fs ├── forth ├── M5StampS3-gpio.fs ├── autoexec.fs ├── fastLed.fs └── lgfx.fs ├── include └── README ├── lib └── README ├── media ├── M5CardForth.png └── sdusage.png ├── platformio.ini ├── readme.md ├── readmeJa.md ├── reference └── hal │ ├── hal.h │ ├── hal_cardputer.cpp │ └── hal_cardputer.h ├── src ├── hal_display.hpp ├── main.cpp └── theme_define.h └── tests └── README /.gitignore: -------------------------------------------------------------------------------- 1 | .pio 2 | .vscode/.browse.c_cpp.db* 3 | .vscode/c_cpp_properties.json 4 | .vscode/launch.json 5 | .vscode/ipch 6 | .DS_Store -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | // See http://go.microsoft.com/fwlink/?LinkId=827846 3 | // for the documentation about the extensions.json format 4 | "recommendations": [ 5 | "platformio.platformio-ide" 6 | ], 7 | "unwantedRecommendations": [ 8 | "ms-vscode.cpptools-extension-pack" 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /cpwords.md: -------------------------------------------------------------------------------- 1 | # Additional words for M5Cardputer 2 | 3 | ``` 4 | ( Cardputer console ) 5 | m5type-on ( -- ) ( use Cardputer display ) 6 | m5type-off ( -- ) ( use Serial output ) 7 | m5key-on ( -- ) ( use Cardputer keyboard ) 8 | m5key-off ( -- ) ( use Serial input ) 9 | m5-key ( -- n ) 10 | m5-key? ( -- n ) 11 | m5-type ( a n -- ) 12 | 13 | ( RGB Led : FastLED library ) 14 | showLeds ( n n n -- ) ( r g b led ) 15 | 16 | ( Display : LovyanGFX ) 17 | : home ( -- ) m5Home ; 18 | : locate ( n n -- ) m5SetCursor ; 19 | : palette ( n n n n -- ) m5gfxSetPaletteColor ; 20 | : fillscreen ( n -- ) m5gfxFillScreen ; 21 | : screenUpdate ( -- ) lcdUpdate ; 22 | : gcls ( -- ) 0 m5gfxFillScreen screenUpdate ; 23 | : pset ( n n n -- ) m5gfxPset ; 24 | : vline ( n n n n -- ) m5gfxDrawFastVLine ; 25 | : hline ( n n n n -- ) m5gfxDrawFastHLine ; 26 | : rect ( n n n n n -- ) m5gfxDrawRect ; 27 | : frect ( n n n n n -- ) m5gfxFillRect ; 28 | : rrect ( n n n n n n -- ) m5gfxDrawRoundRect ; 29 | : frrect ( n n n n n n -- ) m5gfxFillRoundRect ; 30 | : circle ( n n n n -- ) m5gfxDrawCircle ; 31 | : fcircle ( n n n n -- ) m5gfxFillCircle ; 32 | : ellipsis ( n n n n n -- ) m5gfxDrawEllipse ; 33 | : fellipsis ( n n n n n -- ) m5gfxFillEllipse ; 34 | : line ( n n n n n -- ) m5gfxDrawLine ; 35 | : triangle ( n n n n n n n -- ) m5gfxDrawTriangle ; 36 | : ftriangle ( n n n n n n n -- ) m5gfxFillTriangle ; 37 | : bezier ( n n n n n n n -- ) m5gfxDrawBezier ; 38 | : bezier4 ( n n n n n n n n n -- ) m5gfxDrawBezier4 ; 39 | : arc ( n n n n n n n -- ) m5gfxDrawArc ; 40 | : farc ( n n n n n n n -- ) m5gfxFillArc ; 41 | 42 | ( Arduino enhancement ) 43 | delay ( n -- ) ( ms delay ) 44 | ``` 45 | 46 | -------------------------------------------------------------------------------- /data/autoexec.fs: -------------------------------------------------------------------------------- 1 | vocabulary m5demo m5demo definitions 2 | 3 | ( fastLed ) 4 | ( addLeds is done during sytem startup ) 5 | : offLED ( -- ) 0 0 0 showLeds ; 6 | : redLED ( -- ) 200 0 0 showLeds ; 7 | : greenLED ( -- ) 0 200 0 showLeds ; 8 | : blueLED ( -- ) 0 0 200 showLeds ; 9 | : whiteLED ( -- ) 200 200 200 showLeds ; 10 | 11 | : 3dup dup >r rot rot dup >r rot rot dup >r rot rot r> r> r> ; 12 | : flashLED ( n n n -- ) 64 0 do 3dup i 64 */ rot i 64 */ rot i 64 */ rot showLeds 10 delay loop 64 0 do 3dup 64 i - 64 */ rot 64 i - 64 */ rot 64 i - 64 */ rot showLeds 10 delay loop drop drop ; 13 | : flashLEDgo ( -- ) 2 0 do 2 0 do 2 0 do i 255 * j 255 * k 255 * flashLED loop loop loop ; 14 | 15 | ( gfx ) 16 | : vgrad 231 0 do i 0 127 i 255 16 - 232 */ 16 + vline loop screenUpdate ; 17 | : hgrad 127 0 do 0 i 231 i 255 16 - 128 */ 16 + hline loop screenUpdate ; 18 | : go home gcls m5gfx-on screenUpdate 500 delay vgrad 500 delay hgrad 500 delay ; 19 | 0 0 0 0 palette 20 | 1 127 0 0 palette 21 | 2 0 127 0 palette 22 | 3 127 127 0 palette 23 | 4 0 0 127 palette 24 | 5 127 0 127 palette 25 | 6 0 127 127 palette 26 | 7 127 127 127 palette 27 | 28 | 9 255 0 0 palette 29 | 10 0 255 0 palette 30 | 11 255 255 0 palette 31 | 12 0 0 255 palette 32 | 13 255 0 255 palette 33 | 14 0 255 255 palette 34 | 15 255 255 255 palette 35 | 36 | : mbox 7 0 do 0 0 100 i 12 * - dup i frect loop screenUpdate ; 37 | : bullseye 7 0 do 134 64 60 i 8 * - i 8 + fcircle loop screenUpdate ; 38 | : moire 50 0 do 231 0 131 i 2 * 80 line screenUpdate loop 51 0 do 231 0 131 i 2 * + 100 80 line screenUpdate loop ; 39 | 40 | : go2 m5gfx-on gcls go bullseye 500 delay mbox 500 delay moire 500 delay 3 0 do ." Hello " i . cr loop ; 41 | 42 | ( gpio ) 43 | 0 constant G0 ( Cardputer Button B0 ) 44 | 1 constant G1 ( Grove PortA G1 ) 45 | 2 constant G2 ( Grove PortA G2 ) 46 | G0 INPUT pinMode 47 | G1 OUTPUT pinMode 48 | G2 OUTPUT pinMode 49 | 50 | : led-off G1 0 digitalWrite ; ( G1 goes 0 V ) 51 | : led-on G1 1 digitalWrite ; ( G1 goes 3.3 V ) 52 | : button? ( -- n ) G0 digitalRead 0 = if 1 else 0 then ; 53 | 54 | hex 55 | : gogpio 0 0 do 2 60004008 L! 2 6000400C L! 0 +loop ; 56 | decimal 57 | 58 | forth definitions -------------------------------------------------------------------------------- /forth/M5StampS3-gpio.fs: -------------------------------------------------------------------------------- 1 | 0 constant G0 ( Cardputer Button B0 ) 2 | 1 constant G1 ( Grove PortA G1 ) 3 | 2 constant G2 ( Grove PortA G2 ) 4 | G0 INPUT pinMode 5 | G1 OUTPUT pinMode 6 | G2 OUTPUT pinMode 7 | 8 | : led-off G1 0 digitalWrite ; ( G1 goes 0 V ) 9 | : led-on G1 1 digitalWrite ; ( G1 goes 3.3 V ) 10 | : button? ( -- n ) G0 digitalRead 0 = if 1 else 0 then ; 11 | 12 | ( Caution: the following words go into infinite loops ) 13 | 14 | : go 0 0 do button? . cr 0 +loop ; 15 | 16 | : go1 0 0 do led-off led-on 0 +loop ; 17 | 18 | ( ESP32-S3 HW ACCESS ) 19 | ( GPIO BASE ADDRESS = 0x60004000 ) 20 | ( GPIO_OUT_W1TS_REG = 0x0008 ; bit set, GPIO0 = 1 ) 21 | ( GPIO_OUT_W1TC_REG = 0x000C ; bit clear, GPIO0 = 1 ) 22 | ( GPIO_OUT_DATA_ORIG = 0x0004 ; to read the value ) 23 | hex 24 | : go2 0 0 do 2 60004008 L! 2 6000400C L! 0 +loop ; 25 | decimal 26 | -------------------------------------------------------------------------------- /forth/autoexec.fs: -------------------------------------------------------------------------------- 1 | vocabulary m5demo m5demo definitions 2 | 3 | ( fastLed ) 4 | ( addLeds is done during sytem startup ) 5 | : offLED ( -- ) 0 0 0 showLeds ; 6 | : redLED ( -- ) 200 0 0 showLeds ; 7 | : greenLED ( -- ) 0 200 0 showLeds ; 8 | : blueLED ( -- ) 0 0 200 showLeds ; 9 | : whiteLED ( -- ) 200 200 200 showLeds ; 10 | 11 | : 3dup dup >r rot rot dup >r rot rot dup >r rot rot r> r> r> ; 12 | : flashLED ( n n n -- ) 64 0 do 3dup i 64 */ rot i 64 */ rot i 64 */ rot showLeds 10 delay loop 64 0 do 3dup 64 i - 64 */ rot 64 i - 64 */ rot 64 i - 64 */ rot showLeds 10 delay loop drop drop ; 13 | : flashLEDgo ( -- ) 2 0 do 2 0 do 2 0 do i 255 * j 255 * k 255 * flashLED loop loop loop ; 14 | 15 | ( gfx ) 16 | : vgrad 231 0 do i 0 127 i 255 16 - 232 */ 16 + vline loop screenUpdate ; 17 | : hgrad 127 0 do 0 i 231 i 255 16 - 128 */ 16 + hline loop screenUpdate ; 18 | : go home gcls m5gfx-on screenUpdate 500 delay vgrad 500 delay hgrad 500 delay ; 19 | 0 0 0 0 palette 20 | 1 127 0 0 palette 21 | 2 0 127 0 palette 22 | 3 127 127 0 palette 23 | 4 0 0 127 palette 24 | 5 127 0 127 palette 25 | 6 0 127 127 palette 26 | 7 127 127 127 palette 27 | 28 | 9 255 0 0 palette 29 | 10 0 255 0 palette 30 | 11 255 255 0 palette 31 | 12 0 0 255 palette 32 | 13 255 0 255 palette 33 | 14 0 255 255 palette 34 | 15 255 255 255 palette 35 | 36 | : mbox 7 0 do 0 0 100 i 12 * - dup i frect loop screenUpdate ; 37 | : bullseye 7 0 do 134 64 60 i 8 * - i 8 + fcircle loop screenUpdate ; 38 | : moire 50 0 do 231 0 131 i 2 * 80 line screenUpdate loop 51 0 do 231 0 131 i 2 * + 100 80 line screenUpdate loop ; 39 | 40 | : go2 m5gfx-on gcls go bullseye 500 delay mbox 500 delay moire 500 delay 3 0 do ." Hello " i . cr loop ; 41 | 42 | ( gpio ) 43 | 0 constant G0 ( Cardputer Button B0 ) 44 | 1 constant G1 ( Grove PortA G1 ) 45 | 2 constant G2 ( Grove PortA G2 ) 46 | G0 INPUT pinMode 47 | G1 OUTPUT pinMode 48 | G2 OUTPUT pinMode 49 | 50 | : led-off G1 0 digitalWrite ; ( G1 goes 0 V ) 51 | : led-on G1 1 digitalWrite ; ( G1 goes 3.3 V ) 52 | : button? ( -- n ) G0 digitalRead 0 = if 1 else 0 then ; 53 | 54 | hex 55 | : gogpio 0 0 do 2 60004008 L! 2 6000400C L! 0 +loop ; 56 | decimal 57 | 58 | forth definitions -------------------------------------------------------------------------------- /forth/fastLed.fs: -------------------------------------------------------------------------------- 1 | ( addLeds is done during sytem startup ) 2 | : offLED ( -- ) 0 0 0 showLeds ; 3 | : redLED ( -- ) 200 0 0 showLeds ; 4 | : greenLED ( -- ) 0 200 0 showLeds ; 5 | : blueLED ( -- ) 0 0 200 showLeds ; 6 | : whiteLED ( -- ) 200 200 200 showLeds ; 7 | 8 | : 3dup dup >r rot rot dup >r rot rot dup >r rot rot r> r> r> ; 9 | : flashLED ( n n n -- ) 64 0 do 3dup i 64 */ rot i 64 */ rot i 64 */ rot showLeds 10 delay loop 64 0 do 3dup 64 i - 64 */ rot 64 i - 64 */ rot 64 i - 64 */ rot showLeds 10 delay loop drop drop drop ; 10 | : flashLEDgo ( -- ) 2 0 do 2 0 do 2 0 do i 255 * j 255 * k 255 * flashLED loop loop loop ; 11 | -------------------------------------------------------------------------------- /forth/lgfx.fs: -------------------------------------------------------------------------------- 1 | : vgrad 231 0 do i 0 127 i 255 16 - 232 */ 16 + vline loop screenUpdate ; 2 | : hgrad 127 0 do 0 i 231 i 255 16 - 128 */ 16 + hline loop screenUpdate ; 3 | : go home gcls m5gfx-on screenUpdate 500 delay vgrad 500 delay hgrad 500 delay ; 4 | 0 0 0 0 palette \ 5 | 1 127 0 0 palette \ 6 | 2 0 127 0 palette \ 7 | 3 127 127 0 palette \ 8 | 4 0 0 127 palette \ 9 | 5 127 0 127 palette \ 10 | 6 0 127 127 palette \ 11 | 7 127 127 127 palette 12 | 13 | 9 255 0 0 palette \ 14 | 10 0 255 0 palette \ 15 | 11 255 255 0 palette \ 16 | 12 0 0 255 palette \ 17 | 13 255 0 255 palette \ 18 | 14 0 255 255 palette \ 19 | 15 255 255 255 palette 20 | : mbox 7 0 do 0 0 100 i 12 * - dup i frect loop screenUpdate ; 21 | : bullseye 7 0 do 134 64 60 i 8 * - i 8 + fcircle loop screenUpdate ; 22 | : moire 50 0 do 231 0 131 i 2 * 80 line screenUpdate loop 51 0 do 231 0 131 i 2 * + 100 80 line screenUpdate loop ; 23 | 24 | : go2 m5gfx-on gcls go bullseye 500 delay mbox 500 delay moire 500 delay 3 0 do ." Hello " i . cr loop ; 25 | 26 | go2 27 | 28 | ." 日本語と簡体字の共通部分だけ表示されるの? ひらがなは? カタカナは? 繁体字は?" cr 29 | 30 | -------------------------------------------------------------------------------- /include/README: -------------------------------------------------------------------------------- 1 | 2 | This directory is intended for project header files. 3 | 4 | A header file is a file containing C declarations and macro definitions 5 | to be shared between several project source files. You request the use of a 6 | header file in your project source file (C, C++, etc) located in `src` folder 7 | by including it, with the C preprocessing directive `#include'. 8 | 9 | ```src/main.c 10 | 11 | #include "header.h" 12 | 13 | int main (void) 14 | { 15 | ... 16 | } 17 | ``` 18 | 19 | Including a header file produces the same results as copying the header file 20 | into each source file that needs it. Such copying would be time-consuming 21 | and error-prone. With a header file, the related declarations appear 22 | in only one place. If they need to be changed, they can be changed in one 23 | place, and programs that include the header file will automatically use the 24 | new version when next recompiled. The header file eliminates the labor of 25 | finding and changing all the copies as well as the risk that a failure to 26 | find one copy will result in inconsistencies within a program. 27 | 28 | In C, the usual convention is to give header files names that end with `.h'. 29 | It is most portable to use only letters, digits, dashes, and underscores in 30 | header file names, and at most one dot. 31 | 32 | Read more about using header files in official GCC documentation: 33 | 34 | * Include Syntax 35 | * Include Operation 36 | * Once-Only Headers 37 | * Computed Includes 38 | 39 | https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html 40 | -------------------------------------------------------------------------------- /lib/README: -------------------------------------------------------------------------------- 1 | 2 | This directory is intended for project specific (private) libraries. 3 | PlatformIO will compile them to static libraries and link into executable file. 4 | 5 | The source code of each library should be placed in a an own separate directory 6 | ("lib/your_library_name/[here are source files]"). 7 | 8 | For example, see a structure of the following two libraries `Foo` and `Bar`: 9 | 10 | |--lib 11 | | | 12 | | |--Bar 13 | | | |--docs 14 | | | |--examples 15 | | | |--src 16 | | | |- Bar.c 17 | | | |- Bar.h 18 | | | |- library.json (optional, custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html 19 | | | 20 | | |--Foo 21 | | | |- Foo.c 22 | | | |- Foo.h 23 | | | 24 | | |- README --> THIS FILE 25 | | 26 | |- platformio.ini 27 | |--src 28 | |- main.c 29 | 30 | and a contents of `src/main.c`: 31 | ``` 32 | #include 33 | #include 34 | 35 | int main (void) 36 | { 37 | ... 38 | } 39 | 40 | ``` 41 | 42 | PlatformIO Library Dependency Finder will find automatically dependent 43 | libraries scanning project source files. 44 | 45 | More information about PlatformIO Library Dependency Finder 46 | - https://docs.platformio.org/page/librarymanager/ldf.html 47 | -------------------------------------------------------------------------------- /media/M5CardForth.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ryu10/M5CardForth/c25a8e3b6cfb942212303899133d82cde0e920b4/media/M5CardForth.png -------------------------------------------------------------------------------- /media/sdusage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ryu10/M5CardForth/c25a8e3b6cfb942212303899133d82cde0e920b4/media/sdusage.png -------------------------------------------------------------------------------- /platformio.ini: -------------------------------------------------------------------------------- 1 | ; PlatformIO Project Configuration File 2 | ; 3 | ; Build options: build flags, source filter 4 | ; Upload options: custom upload port, speed and extra flags 5 | ; Library options: dependencies, extra library storages 6 | ; Advanced options: extra scripting 7 | ; 8 | ; Please visit documentation for the other options and examples 9 | ; https://docs.platformio.org/page/projectconf.html 10 | 11 | [env:esp32-s3-devkitc-1] 12 | platform = espressif32 13 | board = esp32-s3-devkitc-1 14 | framework = arduino 15 | monitor_speed = 115200 16 | lib_deps = 17 | fastled/FastLED@^3.6.0 18 | lovyan03/LovyanGFX@^1.1.9 19 | m5stack/M5Cardputer@^1.0.2 20 | m5stack/M5Unified@^0.1.11 21 | m5stack/M5GFX@^0.1.11 22 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # M5CardForth (alpha) 2 | 3 | [EN|[日本語](readmeJa.md)] 4 | 5 | ![M5CardForth](media/M5CardForth.png) 6 | 7 | ## Summary 8 | 9 | A simple console for M5Cardputer + ESP32forth. 10 | 11 | The current release is alpha. 12 | 13 | The following components are roughly combined: 14 | 15 | * [ueforth](https://github.com/flagxor/ueforth) 16 | * [M5Cardputer](https://github.com/m5stack/M5Cardputer) 17 | * [LovyanGFX](https://github.com/lovyan03/LovyanGFX) 18 | * [FastLED](https://github.com/FastLED/FastLED) 19 | 20 | Build / flash the project with [Platformio](https://platformio.org/). 21 | 22 | ## Console 23 | 24 | At startup, the console reads from the USBSerial input. Open `PlatformIO : Serial Console` and type on your computer. To use the M5Cardputer keyboard, type `m5key-on`. 25 | 26 | The following words can be used to switch the console I/O : `m5key-on m5key-off m5type-on m5type-off` 27 | 28 | ### Using M5Cardputer standalone 29 | 30 | To use the M5CardForth standalone, without serial, follow the steps: 31 | 32 | 1. Do either: 33 | * Turn M5Cardputer power switch on, or, 34 | * press and relase the button `BtnRst` (at the top-left of M5Cardputer). 35 | 2. Immediately after you complete Step 1, press `BtnG0` (top-right). 36 | 3. After prompt `ok` is displayed, you may release `BtnG0`. 37 | 38 | Both the M5Cardputer keyboard and console output will be enabled. 39 | 40 | ## Cardputer keyboard 41 | 42 | Supported keys: 43 | 44 | * Alphanumeric and symbols 45 | * `Shift` 46 | * `Enter` and `BS` 47 | 48 | The `ctrl`/`opt`/`alt`/`fn`/`esc` keys do not work. 49 | 50 | ## Sample programs 51 | 52 | [forth/fastLed.fs](forth/fastLed.fs) 53 | 54 | [forth/lgfx.fs](forth/lgfx.fs) 55 | 56 | [forth/M5StampS3-gpio.fs](forth/M5StampS3-gpio.fs) 57 | 58 | ## Additional words 59 | 60 | In addition to ESP32Forth standard words, several new words are defined to access the M5cardputer features. Currently under development, the specs will be changed in the future. 61 | 62 | -> ([See this page](cpwords.md)) 63 | 64 | ## SD Card support 65 | 66 | Use the ESP32Forth `SD` vocabulary. 67 | 68 | ![SDUsage](media/sdusage.png) 69 | 70 | ### Example: block editor 71 | 72 | ``` 73 | sd 74 | sd.begin 75 | use /sd/myblk 76 | s" /sd/myblk" open-blocks 77 | editor 78 | 0 a : hi ." Howdy!" ; 79 | update 80 | save-buffers 81 | 0 load hi 82 | ``` 83 | 84 | Note ```visual editor``` does not work with SD. 85 | 86 | ### Using `/spiffs/autoexec.fs` 87 | 88 | You may copy [forth/autoexec.fs](forth/autoexec.fs) to `/spiffs/autoexec.fs` (via an SD card), then the contents of the file will be automatically executed at startup. Type the following to run a demo. 89 | 90 | ``` 91 | m5demo 92 | go2 93 | ``` 94 | 95 | ## Todo 96 | 97 | * switch between Cardputer console and serial ✅ 98 | * rgb led ✅ 99 | * backspace ✅ 100 | * graphics ✅ 101 | * sd card ✅ 102 | * sound 103 | * mic 104 | * (ir) 105 | * (clock) 106 | * (wifi) 107 | 108 | Have fun. -------------------------------------------------------------------------------- /readmeJa.md: -------------------------------------------------------------------------------- 1 | # M5CardForth (alpha) 2 | 3 | [[EN](readme.md)|JA] 4 | 5 | ![M5CardForth](media/M5CardForth.png) 6 | 7 | ## 概要 8 | 9 | M5Cardputer を使って ESP32forth コンソールを作っています。 10 | まだ作業中なので仕様は頻繁に変更されます。 11 | 12 | 以下のコンポーネントを使用しています。 13 | 14 | * [ueforth](https://github.com/flagxor/ueforth) 15 | * [M5Cardputer](https://github.com/m5stack/M5Cardputer) 16 | * [LovyanGFX](https://github.com/lovyan03/LovyanGFX) 17 | * [FastLED](https://github.com/FastLED/FastLED) 18 | 19 | プロジェクトは [Platformio](https://platformio.org/) でビルド、書き込みできます。 20 | 21 | ## コンソール 22 | 23 | 初期状態で入力は Platformio Serial Monitor コンソール、出力は M5Cardputer ディスプレイです。Platformio の Serial Monitor コンソールウィンドウ内をクリックしてからコンピュータのキーボードを使って入力します。 24 | 25 | `m5key-on` と入力すると M5Cardputer キーボードに切り替わります。 26 | 27 | `m5key-on m5key-off m5type-on m5type-off` の各ワードで、コンソールの入出力を切り替えられます。 28 | 29 | ### M5Cardputer を単体で使用する 30 | 31 | USB ケーブルを接続せず M5Cardputer 単体で使用するには以下の手順で起動します。 32 | 33 | 1. 以下のいずれかの操作を行います。 34 | 1. M5Cardupter の電源を入れる 35 | 2. リセットボタン(本体左上)を押して放す 36 | 2. 直後に M5Cardputer の `BtnG0` ボタン(本体右上)を押します。 37 | 3. 画面に `ok` プロンプトが表示されたら `BtnG0` ボタンを放します。 38 | 39 | この方法で起動すると M5Cardputer のキーボードとコンソール出力が使用可能になります。 40 | 41 | ## Cardputer キーボード 42 | 43 | 以下のキーが使えます。 44 | 45 | * 英数文字および記号入力キー 46 | * `Shift` キー ('`Aa`') 47 | * `Enter` キーと `BS` キー 48 | 49 | `ctrl`/`opt`/`alt`/`fn`/`esc` キーは機能しません。 50 | 51 | ## サンプルコード 52 | 53 | [forth/fastLed.fs](forth/fastLed.fs) : RGB LED の操作 54 | 55 | [forth/lgfx.fs](forth/lgfx.fs) : LovyanGFX でグラフィックス表示 56 | 57 | [forth/M5StampS3-gpio.fs](forth/M5StampS3-gpio.fs) : Grove PortA の G1 と G2 を制御 58 | 59 | Serial Monitor コンソールにコピペして使います。入力バッファに上限があるためコンソールには大量のテキストを一度に貼り付けられません。複数回に分けてコピペしてください。 60 | 61 | ## 追加 Forth ワード 62 | 63 | 各コンポーネントの機能を呼び出します。作者が Forth 初学者のためワード定義の記述や配置はあまりまとまっていません。今後整理します。 64 | 65 | -> ([See this page](cpwords.md)) 66 | 67 | ## SD カードサポート 68 | 69 | ESP32Forth の ```SD``` ボキャブラリを使用します。 70 | 71 | ![SDUsage](media/sdusage.png) 72 | 73 | ### ブロックエディタ使用例 74 | 75 | ``` 76 | sd 77 | sd.begin 78 | use /sd/myblk 79 | s" /sd/myblk" open-blocks 80 | editor 81 | 0 a : hi ." Howdy!" ; 82 | update 83 | save-buffers 84 | 0 load hi 85 | ``` 86 | 87 | ```visual editor /sd``` は動きません。 88 | 89 | ### /spiffs/autoexec.fs の使用 90 | 91 | [forth/autoexec.fs](forth/autoexec.fs) を SD カード経由で `/spiffs/autoexec.fs`にコピーするとファイルの内容が ESP32Forth 起動時に自動実行されます。`src/autoexec.fs` にはサンプルコードの内容が `m5demo` ボキャブラリとして記述されています。下記をコンソールに入力するとデモプログラムが実行されます。 92 | 93 | ``` 94 | m5demo 95 | go2 96 | ``` 97 | 98 | ## Todo 99 | 100 | * switch between Cardputer console and serial ✅ 101 | * rgb led ✅ 102 | * backspace ✅ 103 | * graphics ✅ 104 | * sd card ✅ 105 | * sound 106 | * mic 107 | * (ir) 108 | * (clock) 109 | * (wifi) 110 | -------------------------------------------------------------------------------- /reference/hal/hal.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file hal.h 3 | * @author Forairaaaaa 4 | * @brief 5 | * @version 0.1 6 | * @date 2023-09-18 7 | * 8 | * @copyright Copyright (c) 2023 9 | * 10 | */ 11 | #pragma once 12 | #include "../../components/LovyanGFX/src/LovyanGFX.hpp" 13 | #include "keyboard/keyboard.h" 14 | #include "mic/Mic_Class.hpp" 15 | #include "speaker/Speaker_Class.hpp" 16 | #include "button/Button.h" 17 | #include 18 | #include 19 | 20 | namespace HAL 21 | { 22 | /** 23 | * @brief Hal base for DI 24 | * 25 | */ 26 | class Hal 27 | { 28 | protected: 29 | LGFX_Device* _display; 30 | LGFX_Sprite* _canvas; 31 | LGFX_Sprite* _canvas_system_bar; 32 | LGFX_Sprite* _canvas_keyboard_bar; 33 | 34 | KEYBOARD::Keyboard* _keyboard; 35 | m5::Mic_Class* _mic; 36 | m5::Speaker_Class* _speaker; 37 | Button* _homeButton; 38 | 39 | bool _sntp_adjusted; 40 | 41 | public: 42 | Hal() : 43 | _display(nullptr), 44 | _canvas(nullptr), 45 | _canvas_system_bar(nullptr), 46 | _canvas_keyboard_bar(nullptr), 47 | _keyboard(nullptr), 48 | _mic(nullptr), 49 | _speaker(nullptr), 50 | _homeButton(nullptr), 51 | _sntp_adjusted(false) 52 | {} 53 | 54 | // Getter 55 | inline LGFX_Device* display() { return _display; } 56 | inline LGFX_Sprite* canvas() { return _canvas; } 57 | inline LGFX_Sprite* canvas_system_bar() { return _canvas_system_bar; } 58 | inline LGFX_Sprite* canvas_keyboard_bar() { return _canvas_keyboard_bar; } 59 | inline KEYBOARD::Keyboard* keyboard() { return _keyboard; } 60 | inline m5::Mic_Class* mic() { return _mic; } 61 | inline m5::Speaker_Class* Speaker() { return _speaker; } 62 | inline Button* homeButton() { return _homeButton; } 63 | 64 | inline void setSntpAdjusted(bool isAdjusted) { _sntp_adjusted = isAdjusted; } 65 | inline bool isSntpAdjusted(void) { return _sntp_adjusted; } 66 | 67 | 68 | 69 | // Canvas 70 | inline void canvas_system_bar_update() { _canvas_system_bar->pushSprite(_canvas_keyboard_bar->width(), 0); } 71 | inline void canvas_keyboard_bar_update() { _canvas_keyboard_bar->pushSprite(0, 0); } 72 | inline void canvas_update() { _canvas->pushSprite(_canvas_keyboard_bar->width(), _canvas_system_bar->height()); } 73 | 74 | // Override 75 | virtual std::string type() { return "null"; } 76 | virtual void init() {} 77 | 78 | virtual void playLastSound() {} 79 | virtual void playNextSound() {} 80 | virtual void playKeyboardSound() {} 81 | 82 | virtual uint8_t getBatLevel() { return 100; } 83 | }; 84 | } 85 | -------------------------------------------------------------------------------- /reference/hal/hal_cardputer.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * @file hal_cardputer.cpp 3 | * @author Forairaaaaa 4 | * @brief 5 | * @version 0.1 6 | * @date 2023-09-22 7 | * 8 | * @copyright Copyright (c) 2023 9 | * 10 | */ 11 | // #include "hal_cardputer.h" 12 | // #include "display/hal_display.hpp" 13 | // #include 14 | // #include "../apps/utils/common_define.h" 15 | // #include "bat/adc_read.h" 16 | #include "theme_define.h" 17 | 18 | using namespace HAL; 19 | 20 | 21 | void HalCardputer::_display_init() 22 | { 23 | spdlog::info("init display"); 24 | 25 | // Display 26 | _display = new LGFX_Cardputer; 27 | _display->init(); 28 | _display->setRotation(1); 29 | 30 | // Canvas 31 | _canvas = new LGFX_Sprite(_display); 32 | _canvas->createSprite(204, 109); 33 | 34 | _canvas_keyboard_bar = new LGFX_Sprite(_display); 35 | _canvas_keyboard_bar->createSprite(_display->width() - _canvas->width(), display()->height()); 36 | 37 | _canvas_system_bar = new LGFX_Sprite(_display); 38 | _canvas_system_bar->createSprite(_canvas->width(), _display->height() - _canvas->height()); 39 | 40 | _canvas_clear(); 41 | _canvas->setTextScroll(true); 42 | _canvas->setBaseColor(THEME_COLOR_BG); 43 | _canvas->setTextColor(THEME_COLOR_REPL_TEXT, THEME_COLOR_BG); 44 | _canvas->setFont(FONT_REPL); 45 | _canvas->setTextSize(FONT_SIZE_REPL); 46 | 47 | // Avoid input panel 48 | _canvas->setCursor(0, 0); 49 | _canvas->print("\n\nHELLO"); 50 | } 51 | 52 | 53 | void HalCardputer::_keyboard_init() 54 | { 55 | _keyboard = new KEYBOARD::Keyboard; 56 | _keyboard->init(); 57 | } 58 | 59 | 60 | void HalCardputer::_mic_init() 61 | { 62 | spdlog::info("init mic"); 63 | 64 | _mic = new m5::Mic_Class; 65 | 66 | // Configs 67 | auto cfg = _mic->config(); 68 | cfg.pin_data_in = 46; 69 | cfg.pin_ws = 43; 70 | cfg.magnification = 4; 71 | 72 | cfg.task_priority = 15; 73 | 74 | // cfg.dma_buf_count = 8; 75 | // cfg.dma_buf_len = 512; 76 | // cfg.stereo = true; 77 | // cfg.sample_rate = 16000; 78 | 79 | cfg.i2s_port = i2s_port_t::I2S_NUM_0; 80 | _mic->config(cfg); 81 | } 82 | 83 | 84 | void HalCardputer::_speaker_init() 85 | { 86 | spdlog::info("init speaker"); 87 | 88 | _speaker = new m5::Speaker_Class; 89 | 90 | auto cfg = _speaker->config(); 91 | cfg.pin_data_out = 42; 92 | cfg.pin_bck = 41; 93 | cfg.pin_ws = 43; 94 | cfg.i2s_port = i2s_port_t::I2S_NUM_1; 95 | // cfg.magnification = 1; 96 | _speaker->config(cfg); 97 | } 98 | 99 | 100 | void HalCardputer::_button_init() 101 | { 102 | _homeButton = new Button(0); 103 | _homeButton->begin(); 104 | } 105 | 106 | 107 | void HalCardputer::_bat_init() 108 | { 109 | adc_read_init(); 110 | } 111 | 112 | 113 | void HalCardputer::init() 114 | { 115 | spdlog::info("hal init"); 116 | 117 | _display_init(); 118 | _keyboard_init(); 119 | _speaker_init(); 120 | _mic_init(); 121 | _button_init(); 122 | _bat_init(); 123 | } 124 | 125 | 126 | double getBatVolBfb(double batVcc) //获取电压的百分比,经过换算并非线性关系 127 | { 128 | double bfb = 0.0; 129 | 130 | //y = 497.50976 x4 - 7,442.07254 x3 + 41,515.70648 x2 - 102,249.34377 x + 93,770.99821 131 | bfb = 497.50976 * batVcc * batVcc * batVcc * batVcc 132 | - 7442.07254 * batVcc * batVcc * batVcc 133 | + 41515.70648 * batVcc * batVcc 134 | - 102249.34377 * batVcc 135 | + 93770.99821; 136 | if (bfb > 100) 137 | bfb = 100.0; 138 | else if (bfb < 0) 139 | bfb = 3.0; 140 | 141 | return bfb; 142 | } 143 | 144 | 145 | uint8_t HalCardputer::getBatLevel() 146 | { 147 | // spdlog::info("get bat: {}", adc_read_get_value()); 148 | // spdlog::info("bat level: {}", getBatVolBfb((double)(adc_read_get_value() * 2 / 1000))); 149 | 150 | // return 100; 151 | // return (uint8_t)getBatVolBfb(4.2); 152 | return (uint8_t)getBatVolBfb((double)((adc_read_get_value() * 2 + 100) / 1000)); 153 | } 154 | 155 | 156 | void HalCardputer::MicTest(HalCardputer* hal) 157 | { 158 | // hal->mic()->begin(); 159 | 160 | int16_t mic_buffer[256]; 161 | 162 | while (1) 163 | { 164 | hal->mic()->record(mic_buffer, 256); 165 | while (hal->mic()->isRecording()) { vTaskDelay(5); } 166 | 167 | for (int i = 0; i < 256; i++) 168 | printf("m:%d\n", mic_buffer[i]); 169 | } 170 | } 171 | 172 | 173 | #include "../apps/utils/boot_sound/boot_sound_1.h" 174 | #include "../apps/utils/boot_sound/boot_sound_2.h" 175 | 176 | void HalCardputer::SpeakerTest(HalCardputer* hal) 177 | { 178 | spdlog::info("speaker test"); 179 | 180 | // hal->Speaker()->setVolume(32); 181 | hal->Speaker()->setVolume(128); 182 | 183 | while (1) 184 | { 185 | // hal->Speaker()->tone(4000, 200); 186 | // delay(500); 187 | // hal->Speaker()->tone(3000, 200); 188 | // delay(500); 189 | // hal->Speaker()->tone(6000, 200); 190 | // delay(500); 191 | // hal->Speaker()->tone(5000, 200); 192 | // delay(500); 193 | 194 | 195 | 196 | spdlog::info("boot 1"); 197 | hal->Speaker()->playWav(boot_sound_1, sizeof(boot_sound_1)); 198 | while (hal->Speaker()->isPlaying()) 199 | delay(5); 200 | spdlog::info("boot 1"); 201 | delay(1000); 202 | 203 | spdlog::info("boot 2"); 204 | hal->Speaker()->playWav(boot_sound_2, sizeof(boot_sound_2)); 205 | while (hal->Speaker()->isPlaying()) 206 | delay(5); 207 | spdlog::info("boot 2"); 208 | delay(1000); 209 | 210 | } 211 | } 212 | -------------------------------------------------------------------------------- /reference/hal/hal_cardputer.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file hal_cardputer.h 3 | * @author Forairaaaaa 4 | * @brief 5 | * @version 0.1 6 | * @date 2023-09-22 7 | * 8 | * @copyright Copyright (c) 2023 9 | * 10 | */ 11 | #include "hal.h" 12 | 13 | namespace HAL 14 | { 15 | class HalCardputer : public Hal 16 | { 17 | private: 18 | void _display_init(); 19 | void _keyboard_init(); 20 | void _mic_init(); 21 | void _speaker_init(); 22 | void _button_init(); 23 | void _bat_init(); 24 | 25 | public: 26 | std::string type() override { return "cardputer"; } 27 | void init() override; 28 | void playKeyboardSound() override { _speaker->setVolume(72); _speaker->tone(5000, 20); } 29 | void playLastSound() override { _speaker->setVolume(32); _speaker->tone(6000, 20); } 30 | void playNextSound() override { _speaker->setVolume(64); _speaker->tone(7000, 20); } 31 | uint8_t getBatLevel() override; 32 | 33 | public: 34 | static void MicTest(HalCardputer* hal); 35 | static void SpeakerTest(HalCardputer* hal); 36 | }; 37 | } 38 | -------------------------------------------------------------------------------- /src/hal_display.hpp: -------------------------------------------------------------------------------- 1 | /** 2 | * @file hal_display.hpp 3 | * @author Forairaaaaa 4 | * @brief 5 | * @version 0.1 6 | * @date 2023-06-28 7 | * 8 | * @copyright Copyright (c) 2023 9 | * 10 | */ 11 | #pragma once 12 | // #include 13 | // #include 14 | 15 | #define LGFX_USE_V1 16 | #include 17 | 18 | #include "theme_define.h" 19 | 20 | 21 | 22 | #define LCD_MOSI_PIN 35 23 | #define LCD_MISO_PIN -1 24 | #define LCD_SCLK_PIN 36 25 | #define LCD_DC_PIN 34 26 | #define LCD_CS_PIN 37 27 | #define LCD_RST_PIN 33 28 | #define LCD_BUSY_PIN -1 29 | #define LCD_BL_PIN 38 30 | 31 | 32 | class LGFX_Cardputer : public lgfx::LGFX_Device { 33 | lgfx::Panel_ST7789 _panel_instance; 34 | lgfx::Bus_SPI _bus_instance; 35 | lgfx::Light_PWM _light_instance; 36 | 37 | public: 38 | LGFX_Cardputer(void) { 39 | { 40 | auto cfg = _bus_instance.config(); 41 | 42 | cfg.pin_mosi = LCD_MOSI_PIN; 43 | cfg.pin_miso = LCD_MISO_PIN; 44 | cfg.pin_sclk = LCD_SCLK_PIN; 45 | cfg.pin_dc = LCD_DC_PIN; 46 | cfg.freq_write = 40000000; 47 | 48 | _bus_instance.config(cfg); 49 | _panel_instance.setBus(&_bus_instance); 50 | } 51 | { 52 | auto cfg = _panel_instance.config(); 53 | 54 | cfg.invert = true; 55 | cfg.pin_cs = LCD_CS_PIN; 56 | cfg.pin_rst = LCD_RST_PIN; 57 | cfg.pin_busy = LCD_BUSY_PIN; 58 | // cfg.panel_width = 240; 59 | // cfg.panel_height = 240; 60 | // cfg.offset_x = 52; 61 | // cfg.offset_y = 40; 62 | cfg.panel_width = 135; 63 | cfg.panel_height = 240; 64 | cfg.offset_x = 52; 65 | cfg.offset_y = 40; 66 | 67 | _panel_instance.config(cfg); 68 | } 69 | { // バックライト制御の設定を行います。(必要なければ削除) 70 | auto cfg = _light_instance.config(); // バックライト設定用の構造体を取得します。 71 | 72 | cfg.pin_bl = LCD_BL_PIN; // バックライトが接続されているピン番号 73 | cfg.invert = false; // バックライトの輝度を反転させる場合 true 74 | // cfg.freq = 44100; // バックライトのPWM周波数 75 | cfg.freq = 200; // バックライトのPWM周波数 76 | cfg.pwm_channel = 7; // 使用するPWMのチャンネル番号 77 | 78 | _light_instance.config(cfg); 79 | _panel_instance.setLight(&_light_instance); // バックライトをパネルにセットします。 80 | } 81 | 82 | setPanel(&_panel_instance); 83 | } 84 | }; 85 | 86 | -------------------------------------------------------------------------------- /src/main.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 Bradley D. Nelson 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | /* Espressif ESP32-S3 is the MCU of M5CardPuter */ 18 | #define CONFIG_IDF_TARGET_ESP32S3 19 | 20 | /* FastLED */ 21 | #include 22 | #define PIN_LED 21 // G21 23 | #define NUM_LEDS 1 24 | CRGB leds[1]; 25 | 26 | void addLeds(void){ 27 | FastLED.addLeds(leds, NUM_LEDS); 28 | } 29 | 30 | /* LGFX Display */ 31 | #include "hal_display.hpp" 32 | 33 | LGFX_Device* _display; 34 | LGFX_Sprite* _canvas_text; 35 | LGFX_Sprite* _canvas_char; 36 | LGFX_Sprite* _canvas_gfx; 37 | 38 | void lcdInit(void){ 39 | // Cardputer Display resolution - 240 x 135 40 | // set the display area (canvas) to 232 x 128, origin at (4, 4) 41 | _display = new LGFX_Cardputer; 42 | _display->init(); 43 | _display->setRotation(1); 44 | 45 | _display->fillScreen(TFT_BLACK); // clear 46 | 47 | _canvas_text = new LGFX_Sprite(_display); 48 | _canvas_text->setColorDepth(4); // 16color palette 49 | #define CANVAS_TEXT_X 232 50 | #define CANVAS_TEXT_Y 128 51 | if(_canvas_text->createSprite(CANVAS_TEXT_X, CANVAS_TEXT_Y) == nullptr){ 52 | USBSerial.write("INIT TEXT SPRITE FAILED!\n"); 53 | while(true){;} 54 | } 55 | // _canvas_text->setPaletteColor(15, 0xffffff); 56 | _canvas_text->setPaletteColor(12, TFT_ORANGE); 57 | _canvas_text->setPaletteColor(14, 0x00ff00U); 58 | _canvas_text->setTextScroll(true); 59 | _canvas_text->setBaseColor(0); 60 | _canvas_text->fillScreen(0); 61 | _canvas_text->setFont(FONT_REPL); // efontCN_16 (8x16px font) 62 | #define CN16_width 8 63 | #define CN16_height 16 64 | _canvas_text->setTextSize(1); 65 | _canvas_text->setCursor(6*CN16_width, 0); 66 | _canvas_text->setTextColor(12,0); 67 | _canvas_text->printf("M5Cardputer Forth\n"); 68 | _canvas_text->setTextColor(14,0); 69 | _canvas_text->pushSprite(4,4,0); 70 | 71 | _canvas_char = new LGFX_Sprite(_display); 72 | _canvas_char->setColorDepth(4); // 16color palette 73 | if(_canvas_char->createSprite(CN16_width, CN16_height) == nullptr){ 74 | USBSerial.write("INIT CHAR SPRITE FAILED!\n"); 75 | while(true){;} 76 | } 77 | _canvas_char->setPaletteColor(14, 0x00ff00U); 78 | _canvas_char->setTextScroll(false); 79 | _canvas_char->setBaseColor(0); 80 | _canvas_char->fillScreen(0); 81 | _canvas_char->setFont(FONT_REPL); // efontCN_16 (8x16px font) 82 | _canvas_char->setTextSize(1); 83 | _canvas_char->setCursor(0, 0); 84 | _canvas_char->setTextColor(14,0); 85 | } 86 | 87 | void lcdSetcursor(int x, int y){ 88 | _canvas_text->setCursor(x * CN16_width, y * CN16_height); 89 | } 90 | 91 | bool _canvas_gfx_visible = false; 92 | 93 | void lcdGfxInit(void){ 94 | _canvas_gfx = new LGFX_Sprite(_display); 95 | _canvas_gfx->setColorDepth(8); // 256color 96 | _canvas_gfx->createPalette(); // Palette 97 | #define CANVAS_GFX_X 232 98 | #define CANVAS_GFX_Y 128 99 | if(_canvas_gfx->createSprite(CANVAS_GFX_X, CANVAS_GFX_Y) == nullptr){ 100 | USBSerial.write("INIT GRAPHICS SPRITE FAILED!\n"); 101 | while(true){;} 102 | }; 103 | _canvas_gfx->fillScreen(TFT_BLACK); 104 | _canvas_text->setPaletteColor(200, TFT_WHITE); 105 | 106 | } 107 | 108 | // fillScreen ( color); // 画面全体の塗り潰し 109 | void lcdGfxFillScreen(int color){ 110 | _canvas_gfx->fillScreen ( color); // 画面全体の塗り潰し 111 | } 112 | // drawPixel ( x, y , color); // 点 113 | void lcdGfxPset(int x, int y, int col){ 114 | _canvas_gfx->drawPixel(x, y, col); 115 | } 116 | // drawFastVLine ( x, y , h , color); // 垂直線 117 | void lcdGfxDrawFastVLine(int x, int y, int h, int color){ 118 | _canvas_gfx->drawFastVLine( x, y , h , color); // 垂直線 119 | } 120 | // drawFastHLine ( x, int y, w , color); // 水平線 121 | void lcdGfxDrawFastHLine (int x, int y, int w, int color){ 122 | _canvas_gfx->drawFastHLine ( x, y, w , color); // 水平線 123 | } 124 | // drawRect ( x, y, w, h , color); // 矩形の外周 125 | void lcdGfxDrawRect (int x, int y, int w, int h, int color){ 126 | _canvas_gfx->drawRect ( x, y, w, h , color); // 矩形の外周 127 | } 128 | // fillRect ( x, y, w, h , color); // 矩形の塗り 129 | void lcdGfxFillRect (int x, int y, int w, int h , int color){ 130 | _canvas_gfx->fillRect ( x, y, w, h , color); // 矩形の塗り 131 | } 132 | // drawRoundRect ( x, y, w, h, r, color); // 角丸の矩形の外周 133 | void lcdGfxDrawRoundRect(int x, int y, int w, int h, int r, int color){ 134 | _canvas_gfx->drawRoundRect ( x, y, w, h, r, color); // 角丸の矩形の外周 135 | } 136 | // fillRoundRect ( x, y, w, h, r, color); // 角丸の矩形の塗り 137 | void lcdGfxFillRoundRect (int x, int y, int w, int h, int r, int color){ 138 | _canvas_gfx->fillRoundRect ( x, y, w, h, r, color); // 角丸の矩形の塗り 139 | } 140 | // drawCircle ( x, y , r, color); // 円の外周 141 | void lcdGfxDrawCircle (int x, int y , int r, int color){ 142 | _canvas_gfx->drawCircle ( x, y , r, color); // 円の外周 143 | } 144 | // fillCircle ( x, y , r, color); // 円の塗り 145 | void lcdGfxFillCircle (int x, int y , int r, int color){ 146 | _canvas_gfx->fillCircle ( x, y , r, color); // 円の塗り 147 | } 148 | // drawEllipse ( x, y, rx, ry , color); // 楕円の外周 149 | void lcdGfxDrawEllipse (int x, int y, int rx, int ry , int color){ 150 | _canvas_gfx->drawEllipse ( x, y, rx, ry , color); // 楕円の外周 151 | } 152 | // fillEllipse ( x, y, rx, ry , color); // 楕円の塗り 153 | void lcdGfxFillEllipse (int x, int y, int rx, int ry , int color){ 154 | _canvas_gfx->fillEllipse ( x, y, rx, ry , color); // 楕円の塗り 155 | } 156 | // drawLine ( x0, y0, x1, y1 , color); // 2点間の直線 157 | void lcdGfxDrawLine (int x0, int y0, int x1, int y1 , int color){ 158 | _canvas_gfx->drawLine ( x0, y0, x1, y1 , color); // 2点間の直線 159 | } 160 | // drawTriangle ( x0, y0, x1, y1, x2, y2, color); // 3点間の三角形の外周 161 | void lcdGfxDrawTriangle (int x0, int y0, int x1, int y1, int x2, int y2, int color){ 162 | _canvas_gfx->drawTriangle ( x0, y0, x1, y1, x2, y2, color); // 3点間の三角形の外周 163 | } 164 | // fillTriangle ( x0, y0, x1, y1, x2, y2, color); // 3点間の三角形の塗り 165 | void lcdGfxFillTriangle (int x0, int y0, int x1, int y1, int x2, int y2, int color){ 166 | _canvas_gfx->fillTriangle ( x0, y0, x1, y1, x2, y2, color); // 3点間の三角形の塗り 167 | } 168 | // drawBezier ( x0, y0, x1, y1, x2, y2, color); // 3点間のベジエ曲線 169 | void lcdGfxDrawBezier (int x0, int y0, int x1, int y1, int x2, int y2, int color){ 170 | _canvas_gfx->drawBezier ( x0, y0, x1, y1, x2, y2, color); // 3点間のベジエ曲線 171 | } 172 | // drawBezier ( x0, y0, x1, y1, x2, y2, x3, y3, color); // 4点間のベジエ曲線 173 | void lcdGfxDrawBezier4 (int x0, int y0, int x1, int y1, int x2, int y2, int x3, int y3, int color){ 174 | _canvas_gfx->drawBezier ( x0, y0, x1, y1, x2, y2, x3, y3, color); // 4点間のベジエ曲線 175 | } 176 | // drawArc ( x, y, r0, r1, angle0, angle1, color); // 円弧の外周 177 | void lcdGfxDrawArc (int x, int y, int r0, int r1, int angle0, int angle1, int color){ 178 | _canvas_gfx->drawArc ( x, y, r0, r1, angle0, angle1, color); // 円弧の外周 179 | } 180 | // fillArc ( x, y, r0, r1, angle0, angle1, color); // 円弧の塗り 181 | void lcdGfxFillArc (int x, int y, int r0, int r1, int angle0, int angle1, int color){ 182 | _canvas_gfx->fillArc ( x, y, r0, r1, angle0, angle1, color); // 円弧の塗り 183 | } 184 | 185 | void gfxSetPaletteColor(int no, int r, int g, int b){ 186 | _canvas_gfx->setPaletteColor(no, _display->color888(r, g, b)); 187 | } 188 | 189 | void gfxVisible(int mode){ 190 | if(mode == 0){ 191 | _canvas_gfx_visible = false; 192 | }else{ 193 | _canvas_gfx_visible = true; 194 | } 195 | } 196 | 197 | void lcdUpdate(void){ 198 | // _display->fillScreen(TFT_BLACK); // clear 199 | if(_canvas_gfx_visible){ 200 | _canvas_gfx->pushSprite(4,4); 201 | _canvas_text->pushSprite(4,4,0); 202 | }else{ 203 | _canvas_text->pushSprite(4,4); 204 | } 205 | } 206 | 207 | void lcdHome(void){ 208 | _canvas_text->fillScreen(TFT_BLACK); 209 | _canvas_text->setCursor(0, 0); 210 | lcdUpdate(); 211 | } 212 | 213 | void lcdBackspace(void){ 214 | // note Forth repl treats BS as 'one char back', without rubout 215 | int x, y; 216 | x = _canvas_text->getCursorX(); 217 | y = _canvas_text->getCursorY(); 218 | x -= CN16_width; 219 | if(x<0){ 220 | x = CANVAS_TEXT_X - CN16_width; 221 | y -= CN16_height; 222 | if(y<0){ 223 | x = 0; 224 | y = 0; 225 | } 226 | } 227 | _canvas_text->setCursor(x,y); 228 | } 229 | 230 | int lcdPrint(uint8_t *s, int size){ 231 | uint8_t str[16]; 232 | int x, y; 233 | for(int t = 0; tgetCursorX(); 237 | y = _canvas_text->getCursorY(); 238 | if( x > CANVAS_TEXT_X - CN16_width){ 239 | x = 0; 240 | y += CN16_height; 241 | } 242 | if( y > CANVAS_TEXT_Y - CN16_height){ 243 | y -= CN16_height; 244 | } 245 | if(str[0] == 0x08){ 246 | lcdBackspace(); 247 | lcdUpdate(); 248 | }else if((y < CANVAS_TEXT_Y - CN16_height * 2) or (x > CN16_width)){ 249 | _canvas_char->fillScreen(0); 250 | _canvas_char->setCursor(0, 0); 251 | _canvas_char->print((const char *)str); 252 | _canvas_char->pushSprite(x+4, y+4, 0); 253 | _canvas_text->print((const char *)str); 254 | }else{ 255 | _canvas_text->print((const char *)str); 256 | lcdUpdate(); 257 | } 258 | } 259 | return size; 260 | } 261 | 262 | /* M5Cardputer Keyboard */ 263 | /* #include "M5Cardputer.h" // Incompatible! */ 264 | #include "utility/Keyboard.h" 265 | 266 | Keyboard_Class Keyboard = Keyboard_Class(); 267 | String _keyboard_buf = ""; 268 | 269 | void kbdInit(void){ 270 | Keyboard.begin(); 271 | } 272 | 273 | size_t kbdGet(char *buf, int count){ 274 | if(_keyboard_buf.length() > 0){ 275 | *buf = (char)_keyboard_buf[_keyboard_buf.length() -1]; 276 | _keyboard_buf.clear(); 277 | return 1; 278 | } 279 | return 0; 280 | } 281 | 282 | int kbdAvailable(void){ 283 | // M5Cardputer.update(); 284 | Keyboard.updateKeyList(); 285 | Keyboard.updateKeysState(); 286 | if (Keyboard.isChange()) { 287 | if (Keyboard.isPressed()) { 288 | Keyboard_Class::KeysState status = Keyboard.keysState(); 289 | for (auto i : status.word) { 290 | _keyboard_buf += i; 291 | return 1; 292 | } 293 | if (status.del) { 294 | _keyboard_buf += (char)0x08; // ASCII BS 295 | return 1; 296 | } 297 | if (status.enter) { 298 | _keyboard_buf += "\n"; // ASCII LF 299 | return 1; 300 | } 301 | else{ 302 | _keyboard_buf = ""; // clear anyway 303 | return -1; 304 | } 305 | } 306 | } 307 | return -1; 308 | } 309 | 310 | /* ESP32-S3 GPIO Reg op. */ 311 | void setGpio(uint32_t reg){ 312 | GPIO.out_w1ts = reg; 313 | } 314 | 315 | void setGpio1(uint32_t reg){ 316 | GPIO.out1_w1ts.val = reg; 317 | } 318 | 319 | void resetGpio(uint32_t reg){ 320 | GPIO.out_w1tc = reg; 321 | } 322 | 323 | void resetGpio1(uint32_t reg){ 324 | GPIO.out1_w1tc.val = reg; 325 | } 326 | 327 | uint32_t getGpio(void){ 328 | return GPIO.in; 329 | } 330 | 331 | uint32_t getGpio1(void){ 332 | return GPIO.in1.val; 333 | } 334 | 335 | // M5Cardputer SD 336 | #include 337 | #include 338 | 339 | SPIClass SPI2; 340 | 341 | bool mySDbegin(void){ 342 | SPI2.begin(40, 39, 14, 12); 343 | SPI2.setDataMode(SPI_MODE0); 344 | return SD.begin(12, SPI2); 345 | } 346 | 347 | /* 348 | * ESP32forth v7.0.7.15 349 | * Revision: 564a8fc68b545ebeb3ab 350 | */ 351 | 352 | #if defined(CONFIG_IDF_TARGET_ESP32) 353 | # define UEFORTH_PLATFORM_IS_ESP32 (-1) 354 | #else 355 | # define UEFORTH_PLATFORM_IS_ESP32 0 356 | #endif 357 | 358 | #if defined(CONFIG_IDF_TARGET_ESP32S2) 359 | # define UEFORTH_PLATFORM_IS_ESP32S2 (-1) 360 | #else 361 | # define UEFORTH_PLATFORM_IS_ESP32S2 0 362 | #endif 363 | 364 | #if defined(CONFIG_IDF_TARGET_ESP32S3) 365 | # define UEFORTH_PLATFORM_IS_ESP32S3 (-1) 366 | #else 367 | # define UEFORTH_PLATFORM_IS_ESP32S3 0 368 | #endif 369 | 370 | #if defined(CONFIG_IDF_TARGET_ESP32C3) 371 | # define UEFORTH_PLATFORM_IS_ESP32C3 (-1) 372 | #else 373 | # define UEFORTH_PLATFORM_IS_ESP32C3 0 374 | #endif 375 | 376 | #if defined(BOARD_HAS_PSRAM) 377 | # define UEFORTH_PLATFORM_HAS_PSRAM (-1) 378 | #else 379 | # define UEFORTH_PLATFORM_HAS_PSRAM 0 380 | #endif 381 | 382 | #if defined(__XTENSA__) 383 | # define UEFORTH_PLATFORM_IS_XTENSA (-1) 384 | #else 385 | # define UEFORTH_PLATFORM_IS_XTENSA 0 386 | #endif 387 | 388 | #if defined(__riscv) 389 | # define UEFORTH_PLATFORM_IS_RISCV (-1) 390 | #else 391 | # define UEFORTH_PLATFORM_IS_RISCV 0 392 | #endif 393 | #define STACK_CELLS 512 394 | #define MINIMUM_FREE_SYSTEM_HEAP (64 * 1024) 395 | 396 | // Default on several options. 397 | #define ENABLE_SPIFFS_SUPPORT 398 | #define ENABLE_WIFI_SUPPORT 399 | #define ENABLE_MDNS_SUPPORT 400 | #define ENABLE_I2C_SUPPORT 401 | #define ENABLE_SOCKETS_SUPPORT 402 | #define ENABLE_FREERTOS_SUPPORT 403 | #define ENABLE_LEDC_SUPPORT 404 | #define ENABLE_SD_SUPPORT 405 | #define ENABLE_ESP32_FORTH_FAULT_HANDLING 406 | 407 | // SD_MMC does not work on ESP32-S2 / ESP32-C3 408 | #if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) 409 | # define ENABLE_SD_MMC_SUPPORT 410 | #endif 411 | 412 | // Serial2 does not work on ESP32-S2 / ESP32-C3 413 | #if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) 414 | # define ENABLE_SERIAL2_SUPPORT 415 | #endif 416 | 417 | // No DACS on ESP32-S3 and ESP32-C3. 418 | #if !defined(CONFIG_IDF_TARGET_ESP32S3) && !defined(CONFIG_IDF_TARGET_ESP32C3) 419 | # define ENABLE_DAC_SUPPORT 420 | #endif 421 | 422 | // ESP32-C3 doesn't support fault handling yet. 423 | #if !defined(CONFIG_IDF_TARGET_ESP32C3) 424 | #endif 425 | 426 | #if !defined(USER_VOCABULARIES) 427 | # define USER_VOCABULARIES 428 | #endif 429 | 430 | #if defined(CONFIG_IDF_TARGET_ESP32) 431 | # define UEFORTH_PLATFORM_IS_ESP32 -1 432 | #else 433 | # define UEFORTH_PLATFORM_IS_ESP32 0 434 | #endif 435 | 436 | #if defined(CONFIG_IDF_TARGET_ESP32S2) 437 | # define UEFORTH_PLATFORM_IS_ESP32S2 -1 438 | #else 439 | # define UEFORTH_PLATFORM_IS_ESP32S2 0 440 | #endif 441 | 442 | #if defined(CONFIG_IDF_TARGET_ESP32S3) 443 | # define UEFORTH_PLATFORM_IS_ESP32S3 -1 444 | #else 445 | # define UEFORTH_PLATFORM_IS_ESP32S3 0 446 | #endif 447 | 448 | #if defined(CONFIG_IDF_TARGET_ESP32C3) 449 | # define UEFORTH_PLATFORM_IS_ESP32C3 -1 450 | #else 451 | # define UEFORTH_PLATFORM_IS_ESP32C3 0 452 | #endif 453 | 454 | #if defined(BOARD_HAS_PSRAM) 455 | # define UEFORTH_PLATFORM_HAS_PSRAM -1 456 | #else 457 | # define UEFORTH_PLATFORM_HAS_PSRAM 0 458 | #endif 459 | 460 | #if defined(BOARD_HAS_PSRAM) 461 | # define UEFORTH_PLATFORM_HAS_PSRAM -1 462 | #else 463 | # define UEFORTH_PLATFORM_HAS_PSRAM 0 464 | #endif 465 | 466 | #define VOCABULARY_LIST \ 467 | V(forth) V(internals) \ 468 | V(rtos) V(SPIFFS) V(serial) V(SD) V(SD_MMC) V(ESP) \ 469 | V(ledc) V(Wire) V(WiFi) V(sockets) \ 470 | OPTIONAL_CAMERA_VOCABULARY \ 471 | OPTIONAL_BLUETOOTH_VOCABULARY \ 472 | OPTIONAL_INTERRUPTS_VOCABULARIES \ 473 | OPTIONAL_OLED_VOCABULARY \ 474 | OPTIONAL_RMT_VOCABULARY \ 475 | OPTIONAL_SPI_FLASH_VOCABULARY \ 476 | USER_VOCABULARIES 477 | #include 478 | #include 479 | #include 480 | #include 481 | 482 | typedef intptr_t cell_t; 483 | typedef uintptr_t ucell_t; 484 | 485 | #define XV(flags, name, op, code) Z(flags, name, op, code) 486 | #define YV(flags, op, code) Z(flags, #op, op, code) 487 | #define X(name, op, code) Z(forth, name, op, code) 488 | #define Y(op, code) Z(forth, #op, op, code) 489 | 490 | #define NIP (--sp) 491 | #define NIPn(n) (sp -= (n)) 492 | #define DROP (tos = *sp--) 493 | #define DROPn(n) (NIPn(n-1), DROP) 494 | #define DUP (*++sp = tos) 495 | #define PUSH DUP; tos = (cell_t) 496 | 497 | #define PARK *++rp = (cell_t) ip; *++rp = (cell_t) fp; DUP; *++rp = (cell_t) sp; 498 | #define UNPARK sp = (cell_t *) *rp--; DROP; fp = (float *) *rp--; ip = (cell_t *) *rp--; 499 | 500 | #define THROWIT(n) \ 501 | rp = *g_sys->throw_handler; *g_sys->throw_handler = (cell_t *) *rp--; UNPARK; tos = (n); 502 | 503 | #define TOFLAGS(xt) ((uint8_t *) (((cell_t *) (xt)) - 1)) 504 | #define TONAMELEN(xt) (TOFLAGS(xt) + 1) 505 | #define TOPARAMS(xt) ((uint16_t *) (TOFLAGS(xt) + 2)) 506 | #define TOSIZE(xt) (CELL_ALIGNED(*TONAMELEN(xt)) + sizeof(cell_t) * (3 + *TOPARAMS(xt))) 507 | #define TOLINK(xt) (((cell_t *) (xt)) - 2) 508 | #define TONAME(xt) ((*TOFLAGS(xt) & BUILTIN_MARK) ? (*(char **) TOLINK(xt)) \ 509 | : (((char *) TOLINK(xt)) - CELL_ALIGNED(*TONAMELEN(xt)))) 510 | #define TOBODY(xt) (((cell_t *) xt) + ((void *) *((cell_t *) xt) == ADDROF(DOCREATE) || \ 511 | (void *) *((cell_t *) xt) == ADDROF(DODOES) ? 2 : 1)) 512 | 513 | #ifndef COMMA 514 | # define COMMA(n) *g_sys->heap++ = (cell_t) (n) 515 | # define CCOMMA(n) *(uint8_t *) g_sys->heap = (n); \ 516 | g_sys->heap = (cell_t *) (1 + ((cell_t) g_sys->heap)); 517 | # define DOES(ip) **g_sys->current = (cell_t) ADDROF(DODOES); (*g_sys->current)[1] = (cell_t) ip 518 | # define DOIMMEDIATE() *TOFLAGS(*g_sys->current) |= IMMEDIATE 519 | # define UNSMUDGE() *TOFLAGS(*g_sys->current) &= ~SMUDGE; finish() 520 | #endif 521 | 522 | #ifndef SSMOD_FUNC 523 | # if __SIZEOF_POINTER__ == 8 524 | typedef __int128_t dcell_t; 525 | # elif __SIZEOF_POINTER__ == 4 || defined(_M_IX86) 526 | typedef int64_t dcell_t; 527 | # else 528 | # error "unsupported cell size" 529 | # endif 530 | # define SSMOD_FUNC dcell_t d = (dcell_t) *sp * (dcell_t) sp[-1]; \ 531 | --sp; cell_t a = (cell_t) (d / tos); \ 532 | a = a * tos == d ? a : a - ((d < 0) ^ (tos < 0)); \ 533 | *sp = (cell_t) (d - ((dcell_t) a) * tos); tos = a 534 | #endif 535 | 536 | #ifdef WEB_DUMP 537 | // Use */mod as the base for the web version. 538 | # define SLASHMOD_FUNC DUP; *sp = 1; SSMOD_FUNC 539 | # define SLASH_FUNC SLASHMOD_FUNC; NIP 540 | # define MOD_FUNC SLASHMOD_FUNC; DROP 541 | # define CELLSLASH_FUNC DUP; tos = sizeof(cell_t); SLASH_FUNC 542 | #else 543 | // Use separate versions for non-web so throw has the right depth. 544 | # define SLASHMOD_FUNC cell_t d = *sp; cell_t a = d / tos; \ 545 | cell_t b = a * tos == d ? a : a - ((d < 0) ^ (tos < 0)); \ 546 | *sp = d - b * tos; tos = b 547 | # define SLASH_FUNC cell_t d = *sp; cell_t a = d / tos; NIP; \ 548 | tos = a * tos == d ? a : a - ((d < 0) ^ (tos < 0)) 549 | # define MOD_FUNC cell_t d = *sp; cell_t a = d / tos; \ 550 | cell_t b = a * tos == d ? a : a - ((d < 0) ^ (tos < 0)); \ 551 | NIP; tos = d - b * tos 552 | # define CELLSLASH_FUNC tos = tos < 0 ? ~(~tos / sizeof(cell_t)) : tos / sizeof(cell_t) 553 | #endif 554 | 555 | typedef struct { 556 | const char *name; 557 | union { 558 | struct { 559 | uint8_t flags, name_length; 560 | uint16_t vocabulary; 561 | }; 562 | cell_t multi; // Forces cell alignment throughout. 563 | }; 564 | const void *code; 565 | } BUILTIN_WORD; 566 | 567 | #define TIER0_OPCODE_LIST \ 568 | YV(internals, NOP, ) \ 569 | X("0=", ZEQUAL, tos = !tos ? -1 : 0) \ 570 | X("0<", ZLESS, tos = (tos|0) < 0 ? -1 : 0) \ 571 | X("+", PLUS, tos += *sp--) \ 572 | X("U/MOD", USMOD, w = *sp; *sp = (ucell_t) w % (ucell_t) tos; \ 573 | tos = (ucell_t) w / (ucell_t) tos) \ 574 | X("*/MOD", SSMOD, SSMOD_FUNC) \ 575 | Y(LSHIFT, tos = (*sp << tos); --sp) \ 576 | Y(RSHIFT, tos = (((ucell_t) *sp) >> tos); --sp) \ 577 | Y(ARSHIFT, tos = (*sp >> tos); --sp) \ 578 | Y(AND, tos &= *sp--) \ 579 | Y(OR, tos |= *sp--) \ 580 | Y(XOR, tos ^= *sp--) \ 581 | X("DUP", ALTDUP, DUP) \ 582 | Y(SWAP, w = tos; tos = *sp; *sp = w) \ 583 | Y(OVER, DUP; tos = sp[-1]) \ 584 | X("DROP", ALTDROP, DROP) \ 585 | X("@", AT, tos = *(cell_t *) tos) \ 586 | X("SL@", SLAT, tos = *(int32_t *) tos) \ 587 | X("UL@", ULAT, tos = *(uint32_t *) tos) \ 588 | X("SW@", SWAT, tos = *(int16_t *) tos) \ 589 | X("UW@", UWAT, tos = *(uint16_t *) tos) \ 590 | X("C@", CAT, tos = *(uint8_t *) tos) \ 591 | X("!", STORE, *(cell_t *) tos = *sp--; DROP) \ 592 | X("L!", LSTORE, *(int32_t *) tos = *sp--; DROP) \ 593 | X("W!", WSTORE, *(int16_t *) tos = *sp--; DROP) \ 594 | X("C!", CSTORE, *(uint8_t *) tos = *sp--; DROP) \ 595 | X("SP@", SPAT, DUP; tos = (cell_t) sp) \ 596 | X("SP!", SPSTORE, sp = (cell_t *) tos; DROP) \ 597 | X("RP@", RPAT, DUP; tos = (cell_t) rp) \ 598 | X("RP!", RPSTORE, rp = (cell_t *) tos; DROP) \ 599 | X(">R", TOR, *++rp = tos; DROP) \ 600 | X("R>", FROMR, DUP; tos = *rp; --rp) \ 601 | X("R@", RAT, DUP; tos = *rp) \ 602 | Y(EXECUTE, w = tos; DROP; JMPW) \ 603 | YV(internals, BRANCH, ip = (cell_t *) *ip) \ 604 | YV(internals, 0BRANCH, if (!tos) ip = (cell_t *) *ip; else ++ip; DROP) \ 605 | YV(internals, DONEXT, *rp = *rp - 1; if (~*rp) ip = (cell_t *) *ip; else (--rp, ++ip)) \ 606 | YV(internals, DOLIT, DUP; tos = *ip++) \ 607 | YV(internals, DOSET, *((cell_t *) *ip) = tos; ++ip; DROP) \ 608 | YV(internals, DOCOL, ++rp; *rp = (cell_t) ip; ip = (cell_t *) (w + sizeof(cell_t))) \ 609 | YV(internals, DOCON, DUP; tos = *(cell_t *) (w + sizeof(cell_t))) \ 610 | YV(internals, DOVAR, DUP; tos = w + sizeof(cell_t)) \ 611 | YV(internals, DOCREATE, DUP; tos = w + sizeof(cell_t) * 2) \ 612 | YV(internals, DODOES, DUP; tos = w + sizeof(cell_t) * 2; \ 613 | ++rp; *rp = (cell_t) ip; \ 614 | ip = (cell_t *) *(cell_t *) (w + sizeof(cell_t))) \ 615 | YV(internals, ALITERAL, COMMA(g_sys->DOLIT_XT); COMMA(tos); DROP) \ 616 | Y(CELL, DUP; tos = sizeof(cell_t)) \ 617 | XV(internals, "LONG-SIZE", LONG_SIZE, DUP; tos = sizeof(long)) \ 618 | Y(FIND, tos = find((const char *) *sp, tos); --sp) \ 619 | Y(PARSE, DUP; tos = parse(tos, sp)) \ 620 | XV(internals, "S>NUMBER?", \ 621 | CONVERT, tos = convert((const char *) *sp, tos, g_sys->base, sp); \ 622 | if (!tos) --sp) \ 623 | Y(CREATE, DUP; DUP; tos = parse(32, sp); \ 624 | create((const char *) *sp, tos, 0, ADDROF(DOCREATE)); \ 625 | COMMA(0); DROPn(2)) \ 626 | Y(VARIABLE, DUP; DUP; tos = parse(32, sp); \ 627 | create((const char *) *sp, tos, 0, ADDROF(DOVAR)); \ 628 | COMMA(0); DROPn(2)) \ 629 | Y(CONSTANT, DUP; DUP; tos = parse(32, sp); \ 630 | create((const char *) *sp, tos, 0, ADDROF(DOCON)); \ 631 | DROPn(2); COMMA(tos); DROP) \ 632 | X("DOES>", DOES, DOES(ip); ip = (cell_t *) *rp; --rp) \ 633 | Y(IMMEDIATE, DOIMMEDIATE()) \ 634 | X(">BODY", TOBODY, tos = (cell_t) TOBODY(tos)) \ 635 | XV(internals, "'SYS", SYS, DUP; tos = (cell_t) g_sys) \ 636 | YV(internals, YIELD, PARK; return rp) \ 637 | X(":", COLON, DUP; DUP; tos = parse(32, sp); \ 638 | create((const char *) *sp, tos, SMUDGE, ADDROF(DOCOL)); \ 639 | g_sys->state = -1; --sp; DROP) \ 640 | YV(internals, EVALUATE1, PARK; rp = evaluate1(rp); UNPARK; w = tos; DROP; if (w) JMPW) \ 641 | Y(EXIT, ip = (cell_t *) *rp--) \ 642 | XV(internals, "'builtins", TBUILTINS, DUP; tos = (cell_t) &g_sys->builtins->code) \ 643 | XV(forth_immediate, ";", SEMICOLON, COMMA(g_sys->DOEXIT_XT); UNSMUDGE(); g_sys->state = 0) 644 | #define TIER1_OPCODE_LIST \ 645 | Y(nip, NIP) \ 646 | Y(rdrop, --rp) \ 647 | XV(forth, "*/", STARSLASH, SSMOD_FUNC; NIP) \ 648 | X("*", STAR, tos *= *sp--) \ 649 | X("/mod", SLASHMOD, SLASHMOD_FUNC) \ 650 | X("/", SLASH, SLASH_FUNC) \ 651 | X("mod", MOD, MOD_FUNC) \ 652 | Y(invert, tos = ~tos) \ 653 | Y(negate, tos = -tos) \ 654 | X("-", MINUS, tos = (*sp--) - tos) \ 655 | Y(rot, w = sp[-1]; sp[-1] = *sp; *sp = tos; tos = w) \ 656 | X("-rot", MROT, w = tos; tos = *sp; *sp = sp[-1]; sp[-1] = w) \ 657 | X("?dup", QDUP, if (tos) DUP) \ 658 | X("<", LESS, tos = *sp < tos ? -1 : 0; --sp) \ 659 | X(">", GREATER, tos = *sp > tos ? -1 : 0; --sp) \ 660 | X("<=", LESSEQ, tos = *sp <= tos ? -1 : 0; --sp) \ 661 | X(">=", GREATEREQ, tos = *sp >= tos ? -1 : 0; --sp) \ 662 | X("=", EQUAL, tos = *sp == tos ? -1 : 0; --sp) \ 663 | X("<>", NOTEQUAL, tos = *sp != tos ? -1 : 0; --sp) \ 664 | X("0<>", ZNOTEQUAL, tos = tos ? -1 : 0) \ 665 | Y(bl, DUP; tos = ' ') \ 666 | Y(nl, DUP; tos = '\n') \ 667 | X("1+", ONEPLUS, ++tos) \ 668 | X("1-", ONEMINUS, --tos) \ 669 | X("2*", TWOSTAR, tos = tos << 1) \ 670 | X("2/", TWOSLASH, tos = tos >> 1) \ 671 | X("4*", FOURSTAR, tos = tos << 2) \ 672 | X("4/", FOURSLASH, tos = tos >> 2) \ 673 | X("+!", PLUSSTORE, *((cell_t *) tos) += *sp--; DROP) \ 674 | X("cell+", CELLPLUS, tos += sizeof(cell_t)) \ 675 | Y(cells, tos *= sizeof(cell_t)) \ 676 | X("cell/", CELLSLASH, CELLSLASH_FUNC) \ 677 | X("2drop", TWODROP, NIP; DROP) \ 678 | X("2dup", TWODUP, DUP; tos = sp[-1]; DUP; tos = sp[-1]) \ 679 | X("2@", TWOAT, DUP; *sp = *(cell_t *) tos; tos = ((cell_t *) tos)[1]) \ 680 | X("2!", TWOSTORE, *(cell_t *) tos = sp[-1]; \ 681 | ((cell_t *) tos)[1] = *sp; sp -= 2; DROP) \ 682 | Y(cmove, memmove((void *) *sp, (void *) sp[-1], tos); sp -= 2; DROP) \ 683 | X("cmove>", cmove2, memmove((void *) *sp, (void *) sp[-1], tos); sp -= 2; DROP) \ 684 | Y(fill, memset((void *) sp[-1], tos, *sp); sp -= 2; DROP) \ 685 | Y(erase, memset((void *) *sp, 0, tos); NIP; DROP) \ 686 | Y(blank, memset((void *) *sp, ' ', tos); NIP; DROP) \ 687 | Y(min, tos = tos < *sp ? tos : *sp; NIP) \ 688 | Y(max, tos = tos > *sp ? tos : *sp; NIP) \ 689 | Y(abs, tos = tos < 0 ? -tos : tos) \ 690 | Y(here, DUP; tos = (cell_t) g_sys->heap) \ 691 | Y(allot, g_sys->heap = (cell_t *) (tos + (cell_t) g_sys->heap); DROP) \ 692 | X(",", COMMA, COMMA(tos); DROP) \ 693 | X("c,", CCOMMA, CCOMMA(tos); DROP) \ 694 | XV(internals, "'heap", THEAP, DUP; tos = (cell_t) &g_sys->heap) \ 695 | Y(current, DUP; tos = (cell_t) &g_sys->current) \ 696 | XV(internals, "'context", TCONTEXT, DUP; tos = (cell_t) &g_sys->context) \ 697 | XV(internals, "'latestxt", TLATESTXT, DUP; tos = (cell_t) &g_sys->latestxt) \ 698 | XV(internals, "'notfound", TNOTFOUND, DUP; tos = (cell_t) &g_sys->notfound) \ 699 | XV(internals, "'heap-start", THEAP_START, DUP; tos = (cell_t) &g_sys->heap_start) \ 700 | XV(internals, "'heap-size", THEAP_SIZE, DUP; tos = (cell_t) &g_sys->heap_size) \ 701 | XV(internals, "'stack-cells", TSTACK_CELLS, DUP; tos = (cell_t) &g_sys->stack_cells) \ 702 | XV(internals, "'boot", TBOOT, DUP; tos = (cell_t) &g_sys->boot) \ 703 | XV(internals, "'boot-size", TBOOT_SIZE, DUP; tos = (cell_t) &g_sys->boot_size) \ 704 | XV(internals, "'tib", TTIB, DUP; tos = (cell_t) &g_sys->tib) \ 705 | X("#tib", NTIB, DUP; tos = (cell_t) &g_sys->ntib) \ 706 | X(">in", TIN, DUP; tos = (cell_t) &g_sys->tin) \ 707 | Y(state, DUP; tos = (cell_t) &g_sys->state) \ 708 | Y(base, DUP; tos = (cell_t) &g_sys->base) \ 709 | XV(internals, "'argc", ARGC, DUP; tos = (cell_t) &g_sys->argc) \ 710 | XV(internals, "'argv", ARGV, DUP; tos = (cell_t) &g_sys->argv) \ 711 | XV(internals, "'runner", RUNNER, DUP; tos = (cell_t) &g_sys->runner) \ 712 | XV(internals, "'throw-handler", TTHROW_HANDLER, DUP; tos = (cell_t) &g_sys->throw_handler) \ 713 | Y(context, DUP; tos = (cell_t) (g_sys->context + 1)) \ 714 | Y(latestxt, DUP; tos = (cell_t) g_sys->latestxt) \ 715 | XV(forth_immediate, "[", LBRACKET, g_sys->state = 0) \ 716 | XV(forth_immediate, "]", RBRACKET, g_sys->state = -1) \ 717 | YV(forth_immediate, literal, COMMA(g_sys->DOLIT_XT); COMMA(tos); DROP) 718 | #define TIER2_OPCODE_LIST \ 719 | X(">flags", TOFLAGS, tos = *TOFLAGS(tos)) \ 720 | X(">flags&", TOFLAGSAT, tos = (cell_t) TOFLAGS(tos)) \ 721 | X(">params", TOPARAMS, tos = *TOPARAMS(tos)) \ 722 | X(">size", TOSIZE, tos = TOSIZE(tos)) \ 723 | X(">link&", TOLINKAT, tos = (cell_t) TOLINK(tos)) \ 724 | X(">link", TOLINK, tos = *TOLINK(tos)) \ 725 | X(">name", TONAME, DUP; *sp = (cell_t) TONAME(tos); tos = *TONAMELEN(tos)) \ 726 | Y(aligned, tos = CELL_ALIGNED(tos)) \ 727 | Y(align, g_sys->heap = (cell_t *) CELL_ALIGNED(g_sys->heap)) \ 728 | YV(internals, fill32, cell_t c = tos; DROP; cell_t n = tos; DROP; \ 729 | uint32_t *a = (uint32_t *) tos; DROP; \ 730 | for (;n;--n) *a++ = c) 731 | #include 732 | 733 | #define FLOATING_POINT_LIST \ 734 | YV(internals, DOFLIT, *++fp = *(float *) ip; ++ip) \ 735 | X("FP@", FPAT, DUP; tos = (cell_t) fp) \ 736 | X("FP!", FPSTORE, fp = (float *) tos; DROP) \ 737 | X("SF@", FAT, *++fp = *(float *) tos; DROP) \ 738 | X("SF!", FSTORE, *(float *) tos = *fp--; DROP) \ 739 | Y(FDUP, fp[1] = *fp; ++fp) \ 740 | Y(FNIP, fp[-1] = *fp; --fp) \ 741 | Y(FDROP, --fp) \ 742 | Y(FOVER, fp[1] = fp[-1]; ++fp) \ 743 | Y(FSWAP, ft = fp[-1]; fp[-1] = *fp; *fp = ft) \ 744 | Y(FROT, ft = fp[-2]; fp[-2] = fp[-1]; fp[-1] = *fp; *fp = ft) \ 745 | Y(FNEGATE, *fp = -*fp) \ 746 | X("F0<", FZLESS, DUP; tos = *fp < 0.0f ? -1 : 0; --fp) \ 747 | X("F0=", FZEQUAL, DUP; tos = *fp == 0.0f ? -1 : 0; --fp) \ 748 | X("F=", FEQUAL, DUP; tos = fp[-1] == fp[0] ? -1 : 0; fp -= 2) \ 749 | X("F<", FLESS, DUP; tos = fp[-1] < fp[0] ? -1 : 0; fp -= 2) \ 750 | X("F>", FGREATER, DUP; tos = fp[-1] > fp[0] ? -1 : 0; fp -= 2) \ 751 | X("F<>", FNEQUAL, DUP; tos = fp[-1] != fp[0] ? -1 : 0; fp -= 2) \ 752 | X("F<=", FLESSEQ, DUP; tos = fp[-1] <= fp[0] ? -1 : 0; fp -= 2) \ 753 | X("F>=", FGREATEREQ, DUP; tos = fp[-1] >= fp[0] ? -1 : 0; fp -= 2) \ 754 | X("F+", FPLUS, fp[-1] = fp[-1] + *fp; --fp) \ 755 | X("F-", FMINUS, fp[-1] = fp[-1] - *fp; --fp) \ 756 | X("F*", FSTAR, fp[-1] = fp[-1] * *fp; --fp) \ 757 | X("F/", FSLASH, fp[-1] = fp[-1] / *fp; --fp) \ 758 | X("1/F", FINVERSE, *fp = 1.0f / *fp) \ 759 | X("S>F", STOF, *++fp = (float) tos; DROP) \ 760 | X("F>S", FTOS, DUP; tos = (cell_t) *fp--) \ 761 | XV(internals, "S>FLOAT?", FCONVERT, tos = fconvert((const char *) *sp, tos, fp)|0; --sp) \ 762 | Y(SFLOAT, DUP; tos = sizeof(float)) \ 763 | Y(SFLOATS, tos *= sizeof(float)) \ 764 | X("SFLOAT+", SFLOATPLUS, tos += sizeof(float)) \ 765 | X("PI", PI_CONST, *++fp = (float) 3.14159265359) \ 766 | Y(FSIN, *fp = sin(+*fp)) \ 767 | Y(FCOS, *fp = cos(+*fp)) \ 768 | Y(FSINCOS, fp[1] = cos(+*fp); *fp = sin(+*fp); ++fp) \ 769 | Y(FATAN2, fp[-1] = atan2(+fp[-1], +*fp); --fp) \ 770 | X("F**", FSTARSTAR, fp[-1] = pow(+fp[-1], +*fp); --fp) \ 771 | Y(FLOOR, *fp = floor(+*fp)) \ 772 | Y(FEXP, *fp = exp(+*fp)) \ 773 | Y(FLN, *fp = log(+*fp)) \ 774 | Y(FABS, *fp = fabs(+*fp)) \ 775 | Y(FMIN, fp[-1] = fmin(+fp[-1], +*fp); --fp) \ 776 | Y(FMAX, fp[-1] = fmax(+fp[-1], +*fp); --fp) \ 777 | Y(FSQRT, *fp = sqrt(+*fp)) 778 | #ifndef CALLTYPE 779 | # define CALLTYPE 780 | #endif 781 | 782 | #ifdef __cplusplus 783 | typedef cell_t (CALLTYPE *call_t)(...); 784 | #else 785 | typedef cell_t (CALLTYPE *call_t)(); 786 | #endif 787 | 788 | #define ct0 ((call_t) n0) 789 | 790 | #define CALLING_OPCODE_LIST \ 791 | YV(internals, CALLCODE, float *t_fp = fp; DUP; \ 792 | sp = (cell_t *) (*(call_t*) (w + sizeof(cell_t)))(sp, &t_fp); \ 793 | fp = t_fp; DROP) \ 794 | YV(internals, CALL0, n0 = ct0()) \ 795 | YV(internals, CALL1, n0 = ct0(n1); --sp) \ 796 | YV(internals, CALL2, n0 = ct0(n2, n1); sp -= 2) \ 797 | YV(internals, CALL3, n0 = ct0(n3, n2, n1); sp -= 3) \ 798 | YV(internals, CALL4, n0 = ct0(n4, n3, n2, n1); sp -= 4) \ 799 | YV(internals, CALL5, n0 = ct0(n5, n4, n3, n2, n1); sp -= 5) \ 800 | YV(internals, CALL6, n0 = ct0(n6, n5, n4, n3, n2, n1); sp -= 6) \ 801 | YV(internals, CALL7, n0 = ct0(n7, n6, n5, n4, n3, n2, n1); sp -= 7) \ 802 | YV(internals, CALL8, n0 = ct0(n8, n7, n6, n5, n4, n3, n2, n1); sp -= 8) \ 803 | YV(internals, CALL9, n0 = ct0(n9, n8, n7, n6, n5, n4, n3, n2, n1); sp -= 9) \ 804 | YV(internals, CALL10, n0 = ct0(n10, n9, n8, n7, n6, n5, n4, n3, n2, n1); sp -= 10) \ 805 | YV(internals, CALL11, n0 = ct0(n11, n10, n9, n8, n7, n6, n5, n4, n3, n2, n1); sp -= 11) \ 806 | YV(internals, CALL12, n0 = ct0(n12, n11, n10, n9, n8, n7, n6, n5, n4, n3, n2, n1); sp -= 12) \ 807 | YV(internals, CALL13, n0 = ct0(n13, n12, n11, n10, n9, n8, n7, n6, n5, n4, n3, n2, n1); sp -= 13) \ 808 | YV(internals, CALL14, n0 = ct0(n14, n13, n12, n11, n10, n9, n8, n7, n6, n5, n4, n3, n2, n1); sp -= 14) \ 809 | YV(internals, CALL15, n0 = ct0(n15, n14, n13, n12, n11, n10, n9, n8, n7, n6, n5, n4, n3, n2, n1); sp -= 15) 810 | #define IMMEDIATE 1 811 | #define SMUDGE 2 812 | #define BUILTIN_FORK 4 813 | #define BUILTIN_MARK 8 814 | 815 | typedef struct { 816 | cell_t *heap, **current, ***context; 817 | cell_t *latestxt, notfound; 818 | cell_t *heap_start; 819 | cell_t heap_size, stack_cells; 820 | const char *boot; 821 | cell_t boot_size; 822 | const char *tib; 823 | cell_t ntib, tin, state, base; 824 | int argc; 825 | char **argv; 826 | cell_t *(*runner)(cell_t *rp); // pointer to forth_run 827 | cell_t **throw_handler; 828 | 829 | // Layout not used by Forth. 830 | cell_t *rp; // spot to park main thread 831 | cell_t DOLIT_XT, DOFLIT_XT, DOEXIT_XT, YIELD_XT; 832 | void *DOCREATE_OP; 833 | const BUILTIN_WORD *builtins; 834 | } G_SYS; 835 | 836 | static G_SYS *g_sys = 0; 837 | static cell_t *forth_run(cell_t *init_rp); 838 | #ifndef SIM_PRINT_ONLY 839 | 840 | # include 841 | # include 842 | # include 843 | # include 844 | # include 845 | # include 846 | # include 847 | 848 | // Hook to pull in words from optional userwords.h 849 | # if __has_include("userwords.h") 850 | # include "userwords.h" 851 | # else 852 | # define USER_WORDS 853 | # endif 854 | 855 | // Hook to pull in words from optional assemblers. 856 | # if __has_include("assemblers.h") 857 | # include "assemblers.h" 858 | # else 859 | # define OPTIONAL_ASSEMBLERS_SUPPORT 860 | # endif 861 | 862 | // Hook to pull in optional interrupts and timers support. 863 | # if __has_include("interrupts.h") 864 | # include "interrupts.h" 865 | # else 866 | # define OPTIONAL_INTERRUPTS_VOCABULARIES 867 | # define OPTIONAL_INTERRUPTS_SUPPORT 868 | # endif 869 | 870 | // Hook to pull in optional Oled support. 871 | # if __has_include("oled.h") 872 | # include "oled.h" 873 | # else 874 | # define OPTIONAL_OLED_VOCABULARY 875 | # define OPTIONAL_OLED_SUPPORT 876 | # endif 877 | 878 | // Hook to pull in optional ESP32-CAM camera support. 879 | # if __has_include("camera.h") 880 | # include "camera.h" 881 | # else 882 | # define OPTIONAL_CAMERA_VOCABULARY 883 | # define OPTIONAL_CAMERA_SUPPORT 884 | # endif 885 | 886 | // Hook to pull in optional RMT (Remote Control) support. 887 | # if __has_include("rmt.h") 888 | # include "rmt.h" 889 | # else 890 | # define OPTIONAL_RMT_VOCABULARY 891 | # define OPTIONAL_RMT_SUPPORT 892 | # endif 893 | 894 | // Hook to pull in optional serial bluetooth support. 895 | # if __has_include("serial-bluetooth.h") 896 | # include "serial-bluetooth.h" 897 | # else 898 | # define OPTIONAL_BLUETOOTH_VOCABULARY 899 | # define OPTIONAL_SERIAL_BLUETOOTH_SUPPORT 900 | # endif 901 | 902 | // Hook to pull in optional SPI flash support. 903 | # if __has_include("spi-flash.h") 904 | # include "spi-flash.h" 905 | # else 906 | # define OPTIONAL_SPI_FLASH_VOCABULARY 907 | # define OPTIONAL_SPI_FLASH_SUPPORT 908 | # endif 909 | 910 | static cell_t ResizeFile(cell_t fd, cell_t size); 911 | 912 | #endif 913 | 914 | #define PLATFORM_OPCODE_LIST \ 915 | USER_WORDS \ 916 | EXTERNAL_OPTIONAL_MODULE_SUPPORT \ 917 | REQUIRED_PLATFORM_SUPPORT \ 918 | REQUIRED_ESP_SUPPORT \ 919 | REQUIRED_MEMORY_SUPPORT \ 920 | REQUIRED_SERIAL_SUPPORT \ 921 | OPTIONAL_M5KEYBOARD_SUPPORT \ 922 | OPTIONAL_M5DISPLAY_SUPPORT \ 923 | OPTIONAL_M5GPIO_SUPPORT \ 924 | OPTIONAL_SERIAL2_SUPPORT \ 925 | REQUIRED_ARDUINO_GPIO_SUPPORT \ 926 | OPTIONAL_FAST_LED \ 927 | REQUIRED_SYSTEM_SUPPORT \ 928 | REQUIRED_FILES_SUPPORT \ 929 | OPTIONAL_LEDC_SUPPORT \ 930 | OPTIONAL_DAC_SUPPORT \ 931 | OPTIONAL_SPIFFS_SUPPORT \ 932 | OPTIONAL_WIFI_SUPPORT \ 933 | OPTIONAL_MDNS_SUPPORT \ 934 | OPTIONAL_SD_SUPPORT \ 935 | OPTIONAL_SD_MMC_SUPPORT \ 936 | OPTIONAL_I2C_SUPPORT \ 937 | OPTIONAL_SOCKETS_SUPPORT \ 938 | OPTIONAL_FREERTOS_SUPPORT \ 939 | CALLING_OPCODE_LIST \ 940 | FLOATING_POINT_LIST 941 | 942 | #define EXTERNAL_OPTIONAL_MODULE_SUPPORT \ 943 | OPTIONAL_ASSEMBLERS_SUPPORT \ 944 | OPTIONAL_CAMERA_SUPPORT \ 945 | OPTIONAL_INTERRUPTS_SUPPORT \ 946 | OPTIONAL_OLED_SUPPORT \ 947 | OPTIONAL_RMT_SUPPORT \ 948 | OPTIONAL_SERIAL_BLUETOOTH_SUPPORT \ 949 | OPTIONAL_SPI_FLASH_SUPPORT 950 | 951 | #define REQUIRED_MEMORY_SUPPORT \ 952 | YV(internals, MALLOC, SET malloc(n0)) \ 953 | YV(internals, SYSFREE, free(a0); DROP) \ 954 | YV(internals, REALLOC, SET realloc(a1, n0); NIP) \ 955 | YV(internals, heap_caps_malloc, SET heap_caps_malloc(n1, n0); NIP) \ 956 | YV(internals, heap_caps_free, heap_caps_free(a0); DROP) \ 957 | YV(internals, heap_caps_realloc, \ 958 | tos = (cell_t) heap_caps_realloc(a2, n1, n0); NIPn(2)) \ 959 | YV(internals, heap_caps_get_total_size, n0 = heap_caps_get_total_size(n0)) \ 960 | YV(internals, heap_caps_get_free_size, n0 = heap_caps_get_free_size(n0)) \ 961 | YV(internals, heap_caps_get_minimum_free_size, \ 962 | n0 = heap_caps_get_minimum_free_size(n0)) \ 963 | YV(internals, heap_caps_get_largest_free_block, \ 964 | n0 = heap_caps_get_largest_free_block(n0)) 965 | 966 | #define REQUIRED_PLATFORM_SUPPORT \ 967 | X("ESP32?", IS_ESP32, PUSH UEFORTH_PLATFORM_IS_ESP32) \ 968 | X("ESP32-S2?", IS_ESP32S2, PUSH UEFORTH_PLATFORM_IS_ESP32S2) \ 969 | X("ESP32-S3?", IS_ESP32S3, PUSH UEFORTH_PLATFORM_IS_ESP32S3) \ 970 | X("ESP32-C3?", IS_ESP32C3, PUSH UEFORTH_PLATFORM_IS_ESP32C3) \ 971 | X("PSRAM?", HAS_PSRAM, PUSH UEFORTH_PLATFORM_HAS_PSRAM) \ 972 | X("Xtensa?", IS_XTENSA, PUSH UEFORTH_PLATFORM_IS_XTENSA) \ 973 | X("RISC-V?", IS_RISCV, PUSH UEFORTH_PLATFORM_IS_RISCV) 974 | 975 | #define REQUIRED_ESP_SUPPORT \ 976 | YV(ESP, getHeapSize, PUSH ESP.getHeapSize()) \ 977 | YV(ESP, getFreeHeap, PUSH ESP.getFreeHeap()) \ 978 | YV(ESP, getMaxAllocHeap, PUSH ESP.getMaxAllocHeap()) \ 979 | YV(ESP, getChipModel, PUSH ESP.getChipModel()) \ 980 | YV(ESP, getChipCores, PUSH ESP.getChipCores()) \ 981 | YV(ESP, getFlashChipSize, PUSH ESP.getFlashChipSize()) \ 982 | YV(ESP, getCpuFreqMHz, PUSH ESP.getCpuFreqMHz()) \ 983 | YV(ESP, getSketchSize, PUSH ESP.getSketchSize()) \ 984 | YV(ESP, deepSleep, ESP.deepSleep(tos); DROP) \ 985 | YV(ESP, getEfuseMac, PUSH (cell_t) ESP.getEfuseMac(); PUSH (cell_t) (ESP.getEfuseMac() >> 32)) \ 986 | YV(ESP, esp_log_level_set, esp_log_level_set(c1, (esp_log_level_t) n0); DROPn(2)) 987 | 988 | #define REQUIRED_SYSTEM_SUPPORT \ 989 | X("MS-TICKS", MS_TICKS, PUSH millis()) \ 990 | XV(internals, "RAW-YIELD", RAW_YIELD, yield()) \ 991 | XV(internals, "RAW-TERMINATE", RAW_TERMINATE, ESP.restart()) 992 | 993 | #define REQUIRED_SERIAL_SUPPORT \ 994 | XV(serial, "Serial.begin", SERIAL_BEGIN, USBSerial.begin(tos); DROP) \ 995 | XV(serial, "Serial.end", SERIAL_END, USBSerial.end()) \ 996 | XV(serial, "Serial.available", SERIAL_AVAILABLE, PUSH USBSerial.available()) \ 997 | XV(serial, "Serial.readBytes", SERIAL_READ_BYTES, n0 = USBSerial.readBytes(b1, n0); NIP) \ 998 | XV(serial, "Serial.write", SERIAL_WRITE, n0 = USBSerial.write(b1, n0); NIP) \ 999 | XV(serial, "Serial.flush", SERIAL_FLUSH, USBSerial.flush()) \ 1000 | XV(serial, "Serial.setDebugOutput", SERIAL_DEBUG_OUTPUT, USBSerial.setDebugOutput(n0); DROP) 1001 | 1002 | // XV(serial, "Serial.available", SERIAL_AVAILABLE, PUSH USBSerial.available()) \ 1003 | // XV(serial, "Serial.readBytes", SERIAL_READ_BYTES, n0 = USBSerial.readBytes(b1, n0); NIP) \ 1004 | // XV(serial, "Serial.available", SERIAL_AVAILABLE, PUSH kbdAvailable()) \ 1005 | // XV(serial, "Serial.readBytes", SERIAL_READ_BYTES, n0 = kbdGet((char *)b1,n0); NIP) \ 1006 | // XV(serial, "Serial.write", SERIAL_WRITE, n0 = lcdPrint(b1, n0); NIP) \ 1007 | 1008 | #define OPTIONAL_M5KEYBOARD_SUPPORT \ 1009 | XV(serial, "M5Keyboard.available", M5KEYBOARD_AVAILABLE, PUSH kbdAvailable()) \ 1010 | XV(serial, "M5Keyboard.readBytes", M5KEYBOARD_READ_BYTES, n0 = kbdGet((char *)b1,n0); NIP) 1011 | 1012 | #define OPTIONAL_M5DISPLAY_SUPPORT \ 1013 | XV(serial, "M5Display.write", M5DISPLAY_WRITE, n0 = lcdPrint(b1, n0); NIP) \ 1014 | Y(m5SetCursor, lcdSetcursor(n1, n0); DROPn(2))\ 1015 | Y(m5Home, lcdHome())\ 1016 | Y(lcdUpdate, lcdUpdate())\ 1017 | Y(m5gfxSetPaletteColor, gfxSetPaletteColor(n3, n2, n1, n0); DROPn(4))\ 1018 | Y(m5gfxFillScreen, lcdGfxFillScreen(n0); DROP)\ 1019 | Y(m5gfxPset, lcdGfxPset(n2, n1, n0); DROPn(3))\ 1020 | Y(m5gfxDrawFastVLine, lcdGfxDrawFastVLine(n3, n2, n1, n0); DROPn(4))\ 1021 | Y(m5gfxDrawFastHLine, lcdGfxDrawFastHLine(n3, n2, n1, n0); DROPn(4))\ 1022 | Y(m5gfxDrawRect, lcdGfxDrawRect(n4, n3, n2, n1, n0); DROPn(5))\ 1023 | Y(m5gfxFillRect, lcdGfxFillRect(n4, n3, n2, n1, n0); DROPn(5))\ 1024 | Y(m5gfxDrawRoundRect, lcdGfxDrawRoundRect(n5, n4, n3, n2, n1, n0); DROPn(6))\ 1025 | Y(m5gfxFillRoundRect, lcdGfxFillRoundRect(n5, n4, n3, n2, n1, n0); DROPn(6))\ 1026 | Y(m5gfxDrawCircle, lcdGfxDrawCircle(n3, n2, n1, n0); DROPn(4))\ 1027 | Y(m5gfxFillCircle, lcdGfxFillCircle(n3, n2, n1, n0); DROPn(4))\ 1028 | Y(m5gfxDrawEllipse, lcdGfxDrawEllipse(n4, n3, n2, n1, n0); DROPn(5))\ 1029 | Y(m5gfxFillEllipse, lcdGfxFillEllipse(n4, n3, n2, n1, n0); DROPn(5))\ 1030 | Y(m5gfxDrawLine, lcdGfxDrawLine(n4, n3, n2, n1, n0); DROPn(5))\ 1031 | Y(m5gfxDrawTriangle, lcdGfxDrawTriangle(n6, n5, n4, n3, n2, n1, n0); DROPn(7))\ 1032 | Y(m5gfxFillTriangle, lcdGfxFillTriangle(n6, n5, n4, n3, n2, n1, n0); DROPn(7))\ 1033 | Y(m5gfxDrawBezier, lcdGfxDrawBezier(n6, n5, n4, n3, n2, n1, n0); DROPn(7))\ 1034 | Y(m5gfxDrawBezier4, lcdGfxDrawBezier4(n8, n7, n6, n5, n4, n3, n2, n1, n0); DROPn(9))\ 1035 | Y(m5gfxDrawArc, lcdGfxDrawArc(n6, n5, n4, n3, n2, n1, n0); DROPn(7))\ 1036 | Y(m5gfxFillArc, lcdGfxFillArc(n6, n5, n4, n3, n2, n1, n0); DROPn(7))\ 1037 | Y(delay, delay(n0); DROP) \ 1038 | Y(m5gfxVisible, gfxVisible(n0); DROP)\ 1039 | // Y(lcdInit, lcdInit()) \ 1040 | // Y(lcdPrint, lcdPrint(n0); DROP) \ 1041 | 1042 | #define OPTIONAL_M5GPIO_SUPPORT \ 1043 | XV(serial, "M5Gpio.setGpio", M5GPIO_SETGPIO, setGpio(n0); DROP)\ 1044 | XV(serial, "M5Gpio.resetGpio", M5GPIO_RESETGPIO, resetGpio(n0); DROP)\ 1045 | XV(serial, "M5Gpio.getGpio", M5GPIO_GETGPIO, n0 = getGpio())\ 1046 | 1047 | #ifndef ENABLE_SERIAL2_SUPPORT 1048 | # define OPTIONAL_SERIAL2_SUPPORT 1049 | #else 1050 | # define OPTIONAL_SERIAL2_SUPPORT \ 1051 | XV(serial, "Serial2.begin", SERIAL2_BEGIN, Serial2.begin(tos); DROP) \ 1052 | XV(serial, "Serial2.end", SERIAL2_END, Serial2.end()) \ 1053 | XV(serial, "Serial2.available", SERIAL2_AVAILABLE, PUSH Serial2.available()) \ 1054 | XV(serial, "Serial2.readBytes", SERIAL2_READ_BYTES, n0 = Serial2.readBytes(b1, n0); NIP) \ 1055 | XV(serial, "Serial2.write", SERIAL2_WRITE, n0 = Serial2.write(b1, n0); NIP) \ 1056 | XV(serial, "Serial2.flush", SERIAL2_FLUSH, Serial2.flush()) \ 1057 | XV(serial, "Serial2.setDebugOutput", SERIAL2_DEBUG_OUTPUT, Serial2.setDebugOutput(n0); DROP) 1058 | #endif 1059 | 1060 | #define REQUIRED_ARDUINO_GPIO_SUPPORT \ 1061 | Y(pinMode, pinMode(n1, n0); DROPn(2)) \ 1062 | Y(digitalWrite, digitalWrite(n1, n0); DROPn(2)) \ 1063 | Y(digitalRead, n0 = digitalRead(n0)) \ 1064 | Y(analogRead, n0 = analogRead(n0)) \ 1065 | Y(pulseIn, n0 = pulseIn(n2, n1, n0); NIPn(2)) 1066 | 1067 | #define OPTIONAL_FAST_LED \ 1068 | Y(addLeds, addLeds()) \ 1069 | Y(showLeds, leds[0] = CRGB(n2, n1, n0); FastLED.show(); DROPn(3)) 1070 | 1071 | #define REQUIRED_FILES_SUPPORT \ 1072 | X("R/O", R_O, PUSH O_RDONLY) \ 1073 | X("W/O", W_O, PUSH O_WRONLY) \ 1074 | X("R/W", R_W, PUSH O_RDWR) \ 1075 | Y(BIN, ) \ 1076 | X("CLOSE-FILE", CLOSE_FILE, tos = close(tos); tos = tos ? errno : 0) \ 1077 | X("FLUSH-FILE", FLUSH_FILE, fsync(tos); /* fsync has no impl and returns ENOSYS :-( */ tos = 0) \ 1078 | X("OPEN-FILE", OPEN_FILE, cell_t mode = n0; DROP; cell_t len = n0; DROP; \ 1079 | memcpy(filename, a0, len); filename[len] = 0; \ 1080 | n0 = open(filename, mode, 0777); PUSH n0 < 0 ? errno : 0) \ 1081 | X("CREATE-FILE", CREATE_FILE, cell_t mode = n0; DROP; cell_t len = n0; DROP; \ 1082 | memcpy(filename, a0, len); filename[len] = 0; \ 1083 | n0 = open(filename, mode | O_CREAT | O_TRUNC); PUSH n0 < 0 ? errno : 0) \ 1084 | X("DELETE-FILE", DELETE_FILE, cell_t len = n0; DROP; \ 1085 | memcpy(filename, a0, len); filename[len] = 0; \ 1086 | n0 = unlink(filename); n0 = n0 ? errno : 0) \ 1087 | X("RENAME-FILE", RENAME_FILE, \ 1088 | cell_t len = n0; DROP; memcpy(filename, a0, len); filename[len] = 0; DROP; \ 1089 | cell_t len2 = n0; DROP; memcpy(filename2, a0, len2); filename2[len2] = 0; \ 1090 | n0 = rename(filename2, filename); n0 = n0 ? errno : 0) \ 1091 | X("WRITE-FILE", WRITE_FILE, cell_t fd = n0; DROP; cell_t len = n0; DROP; \ 1092 | n0 = write(fd, a0, len); n0 = n0 != len ? errno : 0) \ 1093 | X("READ-FILE", READ_FILE, cell_t fd = n0; DROP; cell_t len = n0; DROP; \ 1094 | n0 = read(fd, a0, len); PUSH n0 < 0 ? errno : 0) \ 1095 | X("FILE-POSITION", FILE_POSITION, \ 1096 | n0 = (cell_t) lseek(n0, 0, SEEK_CUR); PUSH n0 < 0 ? errno : 0) \ 1097 | X("REPOSITION-FILE", REPOSITION_FILE, cell_t fd = n0; DROP; \ 1098 | n0 = (cell_t) lseek(fd, tos, SEEK_SET); n0 = n0 < 0 ? errno : 0) \ 1099 | X("RESIZE-FILE", RESIZE_FILE, cell_t fd = n0; DROP; n0 = ResizeFile(fd, tos)) \ 1100 | X("FILE-SIZE", FILE_SIZE, struct stat st; w = fstat(n0, &st); \ 1101 | n0 = (cell_t) st.st_size; PUSH w < 0 ? errno : 0) \ 1102 | X("NON-BLOCK", NON_BLOCK, n0 = fcntl(n0, F_SETFL, O_NONBLOCK); \ 1103 | n0 = n0 < 0 ? errno : 0) \ 1104 | X("OPEN-DIR", OPEN_DIR, memcpy(filename, a1, n0); filename[n0] = 0; \ 1105 | n1 = (cell_t) opendir(filename); n0 = n1 ? 0 : errno) \ 1106 | X("CLOSE-DIR", CLOSE_DIR, n0 = closedir((DIR *) n0); n0 = n0 ? errno : 0) \ 1107 | YV(internals, READDIR, \ 1108 | struct dirent *ent = readdir((DIR *) n0); SET (ent ? ent->d_name: 0)) 1109 | 1110 | #ifndef ENABLE_LEDC_SUPPORT 1111 | # define OPTIONAL_LEDC_SUPPORT 1112 | #else 1113 | # define OPTIONAL_LEDC_SUPPORT \ 1114 | YV(ledc, ledcSetup, \ 1115 | n0 = (cell_t) (1000000 * ledcSetup(n2, n1 / 1000.0, n0)); NIPn(2)) \ 1116 | YV(ledc, ledcAttachPin, ledcAttachPin(n1, n0); DROPn(2)) \ 1117 | YV(ledc, ledcDetachPin, ledcDetachPin(n0); DROP) \ 1118 | YV(ledc, ledcRead, n0 = ledcRead(n0)) \ 1119 | YV(ledc, ledcReadFreq, n0 = (cell_t) (1000000 * ledcReadFreq(n0))) \ 1120 | YV(ledc, ledcWrite, ledcWrite(n1, n0); DROPn(2)) \ 1121 | YV(ledc, ledcWriteTone, \ 1122 | n0 = (cell_t) (1000000 * ledcWriteTone(n1, n0 / 1000.0)); NIP) \ 1123 | YV(ledc, ledcWriteNote, \ 1124 | tos = (cell_t) (1000000 * ledcWriteNote(n2, (note_t) n1, n0)); NIPn(2)) 1125 | #endif 1126 | 1127 | #ifndef ENABLE_DAC_SUPPORT 1128 | # define OPTIONAL_DAC_SUPPORT 1129 | # else 1130 | # define OPTIONAL_DAC_SUPPORT \ 1131 | Y(dacWrite, dacWrite(n1, n0); DROPn(2)) 1132 | #endif 1133 | 1134 | #ifndef ENABLE_SPIFFS_SUPPORT 1135 | // Provide a default failing SPIFFS.begin 1136 | # define OPTIONAL_SPIFFS_SUPPORT \ 1137 | X("SPIFFS.begin", SPIFFS_BEGIN, NIPn(2); n0 = 0) 1138 | #else 1139 | # ifndef SIM_PRINT_ONLY 1140 | # include "SPIFFS.h" 1141 | # endif 1142 | # define OPTIONAL_SPIFFS_SUPPORT \ 1143 | XV(SPIFFS, "SPIFFS.begin", SPIFFS_BEGIN, \ 1144 | tos = SPIFFS.begin(n2, c1, n0); NIPn(2)) \ 1145 | XV(SPIFFS, "SPIFFS.end", SPIFFS_END, SPIFFS.end()) \ 1146 | XV(SPIFFS, "SPIFFS.format", SPIFFS_FORMAT, PUSH SPIFFS.format()) \ 1147 | XV(SPIFFS, "SPIFFS.totalBytes", SPIFFS_TOTAL_BYTES, PUSH SPIFFS.totalBytes()) \ 1148 | XV(SPIFFS, "SPIFFS.usedBytes", SPIFFS_USED_BYTES, PUSH SPIFFS.usedBytes()) 1149 | #endif 1150 | 1151 | #ifndef ENABLE_FREERTOS_SUPPORT 1152 | # define OPTIONAL_FREERTOS_SUPPORT 1153 | #else 1154 | # ifndef SIM_PRINT_ONLY 1155 | # include "freertos/FreeRTOS.h" 1156 | # include "freertos/task.h" 1157 | # endif 1158 | # define OPTIONAL_FREERTOS_SUPPORT \ 1159 | YV(rtos, vTaskDelete, vTaskDelete((TaskHandle_t) n0); DROP) \ 1160 | YV(rtos, xTaskCreatePinnedToCore, n0 = xTaskCreatePinnedToCore((TaskFunction_t) a6, \ 1161 | c5, n4, a3, (UBaseType_t) n2, (TaskHandle_t *) a1, (BaseType_t) n0); NIPn(6)) \ 1162 | YV(rtos, xPortGetCoreID, PUSH xPortGetCoreID()) 1163 | #endif 1164 | 1165 | #ifndef ENABLE_SOCKETS_SUPPORT 1166 | # define OPTIONAL_SOCKETS_SUPPORT 1167 | #else 1168 | # ifndef SIM_PRINT_ONLY 1169 | # include 1170 | # include 1171 | # include 1172 | # include 1173 | # include 1174 | # include 1175 | # include 1176 | # include 1177 | # endif 1178 | # define OPTIONAL_SOCKETS_SUPPORT \ 1179 | YV(sockets, socket, n0 = socket(n2, n1, n0); NIPn(2)) \ 1180 | YV(sockets, setsockopt, n0 = setsockopt(n4, n3, n2, a1, n0); NIPn(4)) \ 1181 | YV(sockets, bind, n0 = bind(n2, (struct sockaddr *) a1, n0); NIPn(2)) \ 1182 | YV(sockets, listen, n0 = listen(n1, n0); NIP) \ 1183 | YV(sockets, connect, n0 = connect(n2, (struct sockaddr *) a1, n0); NIPn(2)) \ 1184 | YV(sockets, sockaccept, n0 = accept(n2, (struct sockaddr *) a1, (socklen_t *) a0); NIPn(2)) \ 1185 | YV(sockets, select, n0 = select(n4, (fd_set *) a3, (fd_set *) a2, (fd_set *) a1, (struct timeval *) a0); NIPn(4)) \ 1186 | YV(sockets, poll, n0 = poll((struct pollfd *) a2, (nfds_t) n1, n0); NIPn(2)) \ 1187 | YV(sockets, send, n0 = send(n3, a2, n1, n0); NIPn(3)) \ 1188 | YV(sockets, sendto, n0 = sendto(n5, a4, n3, n2, (const struct sockaddr *) a1, n0); NIPn(5)) \ 1189 | YV(sockets, sendmsg, n0 = sendmsg(n2, (const struct msghdr *) a1, n0); NIPn(2)) \ 1190 | YV(sockets, recv, n0 = recv(n3, a2, n1, n0); NIPn(3)) \ 1191 | YV(sockets, recvfrom, n0 = recvfrom(n5, a4, n3, n2, (struct sockaddr *) a1, (socklen_t *) a0); NIPn(5)) \ 1192 | YV(sockets, recvmsg, n0 = recvmsg(n2, (struct msghdr *) a1, n0); NIPn(2)) \ 1193 | YV(sockets, gethostbyname, n0 = (cell_t) gethostbyname(c0)) \ 1194 | XV(sockets, "errno", ERRNO, PUSH errno) 1195 | #endif 1196 | 1197 | #ifndef ENABLE_SD_SUPPORT 1198 | # define OPTIONAL_SD_SUPPORT 1199 | #else 1200 | # ifndef SIM_PRINT_ONLY 1201 | # include "SD.h" 1202 | # endif 1203 | # define OPTIONAL_SD_SUPPORT \ 1204 | XV(SD, "SD.begin", SD_BEGIN, PUSH mySDbegin()) \ 1205 | XV(SD, "SD.beginFull", SD_BEGIN_FULL, \ 1206 | tos = SD.begin(n5, *(SPIClass*)a4, n3, c2, n1, n0); NIPn(5)) \ 1207 | XV(SD, "SD.beginDefaults", SD_BEGIN_DEFAULTS, \ 1208 | PUSH SS; PUSH &SPI; PUSH 4000000; PUSH "/sd"; PUSH 5; PUSH false) \ 1209 | XV(SD, "SD.end", SD_END, SD.end()) \ 1210 | XV(SD, "SD.cardType", SD_CARD_TYPE, PUSH SD.cardType()) \ 1211 | XV(SD, "SD.totalBytes", SD_TOTAL_BYTES, PUSH SD.totalBytes()) \ 1212 | XV(SD, "SD.usedBytes", SD_USED_BYTES, PUSH SD.usedBytes()) 1213 | #endif 1214 | 1215 | // XV(SD, "SD.begin", SD_BEGIN, PUSH SD.begin()) \ 1216 | 1217 | #ifndef ENABLE_SD_MMC_SUPPORT 1218 | # define OPTIONAL_SD_MMC_SUPPORT 1219 | #else 1220 | # ifndef SIM_PRINT_ONLY 1221 | # include "SD_MMC.h" 1222 | # endif 1223 | # define OPTIONAL_SD_MMC_SUPPORT \ 1224 | XV(SD_MMC, "SD_MMC.begin", SD_MMC_BEGIN, PUSH SD_MMC.begin()) \ 1225 | XV(SD_MMC, "SD_MMC.beginFull", SD_MMC_BEGIN_FULL, tos = SD_MMC.begin(c2, n1, n0); NIPn(2)) \ 1226 | XV(SD_MMC, "SD_MMC.beginDefaults", SD_MMC_BEGIN_DEFAULTS, \ 1227 | PUSH "/sdcard"; PUSH false; PUSH false) \ 1228 | XV(SD_MMC, "SD_MMC.end", SD_MMC_END, SD_MMC.end()) \ 1229 | XV(SD_MMC, "SD_MMC.cardType", SD_MMC_CARD_TYPE, PUSH SD_MMC.cardType()) \ 1230 | XV(SD_MMC, "SD_MMC.totalBytes", SD_MMC_TOTAL_BYTES, PUSH SD_MMC.totalBytes()) \ 1231 | XV(SD_MMC, "SD_MMC.usedBytes", SD_MMC_USED_BYTES, PUSH SD_MMC.usedBytes()) 1232 | #endif 1233 | 1234 | #ifndef ENABLE_I2C_SUPPORT 1235 | # define OPTIONAL_I2C_SUPPORT 1236 | #else 1237 | # ifndef SIM_PRINT_ONLY 1238 | # include 1239 | # endif 1240 | # define OPTIONAL_I2C_SUPPORT \ 1241 | XV(Wire, "Wire.begin", WIRE_BEGIN, n0 = Wire.begin(n1, n0); NIP) \ 1242 | XV(Wire, "Wire.setClock", WIRE_SET_CLOCK, Wire.setClock(n0); DROP) \ 1243 | XV(Wire, "Wire.getClock", WIRE_GET_CLOCK, PUSH Wire.getClock()) \ 1244 | XV(Wire, "Wire.setTimeout", WIRE_SET_TIMEOUT, Wire.setTimeout(n0); DROP) \ 1245 | XV(Wire, "Wire.getTimeout", WIRE_GET_TIMEOUT, PUSH Wire.getTimeout()) \ 1246 | XV(Wire, "Wire.beginTransmission", WIRE_BEGIN_TRANSMISSION, Wire.beginTransmission(n0); DROP) \ 1247 | XV(Wire, "Wire.endTransmission", WIRE_END_TRANSMISSION, SET Wire.endTransmission(n0)) \ 1248 | XV(Wire, "Wire.requestFrom", WIRE_REQUEST_FROM, n0 = Wire.requestFrom(n2, n1, n0); NIPn(2)) \ 1249 | XV(Wire, "Wire.write", WIRE_WRITE, n0 = Wire.write(b1, n0); NIP) \ 1250 | XV(Wire, "Wire.available", WIRE_AVAILABLE, PUSH Wire.available()) \ 1251 | XV(Wire, "Wire.read", WIRE_READ, PUSH Wire.read()) \ 1252 | XV(Wire, "Wire.peek", WIRE_PEEK, PUSH Wire.peek()) \ 1253 | XV(Wire, "Wire.flush", WIRE_FLUSH, Wire.flush()) 1254 | #endif 1255 | 1256 | #ifndef ENABLE_WIFI_SUPPORT 1257 | # define OPTIONAL_WIFI_SUPPORT 1258 | #else 1259 | # ifndef SIM_PRINT_ONLY 1260 | # include 1261 | # include 1262 | 1263 | static IPAddress ToIP(cell_t ip) { 1264 | return IPAddress(ip & 0xff, ((ip >> 8) & 0xff), ((ip >> 16) & 0xff), ((ip >> 24) & 0xff)); 1265 | } 1266 | 1267 | static cell_t FromIP(IPAddress ip) { 1268 | cell_t ret = 0; 1269 | ret = (ret << 8) | ip[3]; 1270 | ret = (ret << 8) | ip[2]; 1271 | ret = (ret << 8) | ip[1]; 1272 | ret = (ret << 8) | ip[0]; 1273 | return ret; 1274 | } 1275 | # endif 1276 | 1277 | # define OPTIONAL_WIFI_SUPPORT \ 1278 | /* WiFi */ \ 1279 | XV(WiFi, "WiFi.config", WIFI_CONFIG, \ 1280 | WiFi.config(ToIP(n3), ToIP(n2), ToIP(n1), ToIP(n0)); DROPn(4)) \ 1281 | XV(WiFi, "WiFi.begin", WIFI_BEGIN, WiFi.begin(c1, c0); DROPn(2)) \ 1282 | XV(WiFi, "WiFi.disconnect", WIFI_DISCONNECT, WiFi.disconnect()) \ 1283 | XV(WiFi, "WiFi.status", WIFI_STATUS, PUSH WiFi.status()) \ 1284 | XV(WiFi, "WiFi.macAddress", WIFI_MAC_ADDRESS, WiFi.macAddress(b0); DROP) \ 1285 | XV(WiFi, "WiFi.localIP", WIFI_LOCAL_IPS, PUSH FromIP(WiFi.localIP())) \ 1286 | XV(WiFi, "WiFi.mode", WIFI_MODE, WiFi.mode((wifi_mode_t) n0); DROP) \ 1287 | XV(WiFi, "WiFi.setTxPower", WIFI_SET_TX_POWER, WiFi.setTxPower((wifi_power_t) n0); DROP) \ 1288 | XV(WiFi, "WiFi.getTxPower", WIFI_GET_TX_POWER, PUSH WiFi.getTxPower()) \ 1289 | XV(WiFi, "WiFi.softAP", WIFI_SOFTAP, n0 = WiFi.softAP(c1, c0); NIP) \ 1290 | XV(WiFi, "WiFi.softAPIP", WIFI_SOFTAP_IP, PUSH FromIP(WiFi.softAPIP())) \ 1291 | XV(WiFi, "WiFi.softAPBroadcastIP", WIFI_SOFTAP_BROADCASTIP, PUSH FromIP(WiFi.softAPBroadcastIP())) \ 1292 | XV(WiFi, "WiFi.softAPNetworkID", WIFI_SOFTAP_NETWORKID, PUSH FromIP(WiFi.softAPNetworkID())) \ 1293 | XV(WiFi, "WiFi.softAPConfig", WIFI_SOFTAP_CONFIG, n0 = WiFi.softAPConfig(ToIP(n2), ToIP(n1), ToIP(n0))) \ 1294 | XV(WiFi, "WiFi.softAPdisconnect", WIFI_SOFTAP_DISCONNECT, n0 = WiFi.softAPdisconnect(n0)) \ 1295 | XV(WiFi, "WiFi.softAPgetStationNum", WIFI_SOFTAP_GET_STATION_NUM, PUSH WiFi.softAPgetStationNum()) 1296 | #endif 1297 | 1298 | #ifndef ENABLE_MDNS_SUPPORT 1299 | # define OPTIONAL_MDNS_SUPPORT 1300 | #else 1301 | # ifndef SIM_PRINT_ONLY 1302 | # include 1303 | # endif 1304 | # define OPTIONAL_MDNS_SUPPORT \ 1305 | /* mDNS */ \ 1306 | X("MDNS.begin", MDNS_BEGIN, n0 = MDNS.begin(c0)) 1307 | #endif 1308 | static char filename[PATH_MAX]; 1309 | static char filename2[PATH_MAX]; 1310 | 1311 | #define PRINT_ERRORS 0 1312 | 1313 | #define CELL_MASK (sizeof(cell_t) - 1) 1314 | #define CELL_LEN(n) (((n) + CELL_MASK) / sizeof(cell_t)) 1315 | #define FIND(name) find((name), sizeof(name) - 1) 1316 | #define UPPER(ch) (((ch) >= 'a' && (ch) <= 'z') ? ((ch) & 0x5F) : (ch)) 1317 | #define CELL_ALIGNED(a) ((((cell_t) (a)) + CELL_MASK) & ~CELL_MASK) 1318 | #define IMMEDIATE 1 1319 | #define SMUDGE 2 1320 | #define BUILTIN_FORK 4 1321 | #define BUILTIN_MARK 8 1322 | 1323 | // Maximum ALSO layers. 1324 | #define VOCABULARY_DEPTH 16 1325 | 1326 | #if PRINT_ERRORS 1327 | #include 1328 | #endif 1329 | 1330 | enum { 1331 | #define V(name) VOC_ ## name, 1332 | VOCABULARY_LIST 1333 | #undef V 1334 | }; 1335 | 1336 | enum { 1337 | #define V(name) VOC_ ## name ## _immediate = VOC_ ## name + (IMMEDIATE << 8), 1338 | VOCABULARY_LIST 1339 | #undef V 1340 | }; 1341 | 1342 | static cell_t convert(const char *pos, cell_t n, cell_t base, cell_t *ret) { 1343 | *ret = 0; 1344 | cell_t negate = 0; 1345 | if (!n) { return 0; } 1346 | if (*pos == '-') { negate = -1; ++pos; --n; } 1347 | if (*pos == '$') { base = 16; ++pos; --n; } 1348 | for (; n; --n) { 1349 | uintptr_t d = UPPER(*pos) - '0'; 1350 | if (d > 9) { 1351 | d -= 7; 1352 | if (d < 10) { return 0; } 1353 | } 1354 | if (d >= (uintptr_t) base) { return 0; } 1355 | *ret = *ret * base + d; 1356 | ++pos; 1357 | } 1358 | if (negate) { *ret = -*ret; } 1359 | return -1; 1360 | } 1361 | 1362 | static cell_t fconvert(const char *pos, cell_t n, float *ret) { 1363 | *ret = 0; 1364 | cell_t negate = 0; 1365 | cell_t has_dot = 0; 1366 | cell_t exp = 0; 1367 | float shift = 1.0; 1368 | if (!n) { return 0; } 1369 | if (*pos == '-') { negate = -1; ++pos; --n; } 1370 | for (; n; --n) { 1371 | if (*pos >= '0' && *pos <= '9') { 1372 | if (has_dot) { 1373 | shift = shift * 0.1f; 1374 | *ret = *ret + (*pos - '0') * shift; 1375 | } else { 1376 | *ret = *ret * 10 + (*pos - '0'); 1377 | } 1378 | } else if (*pos == 'e' || *pos == 'E') { 1379 | break; 1380 | } else if (*pos == '.') { 1381 | if (has_dot) { return 0; } 1382 | has_dot = -1; 1383 | } else { 1384 | return 0; 1385 | } 1386 | ++pos; 1387 | } 1388 | if (!n) { return 0; } // must have E 1389 | ++pos; --n; 1390 | if (n) { 1391 | if (!convert(pos, n, 10, &exp)) { return 0; } 1392 | } 1393 | if (exp < -128 || exp > 128) { return 0; } 1394 | for (; exp < 0; ++exp) { *ret *= 0.1f; } 1395 | for (; exp > 0; --exp) { *ret *= 10.0f; } 1396 | if (negate) { *ret = -*ret; } 1397 | return -1; 1398 | } 1399 | 1400 | static cell_t same(const char *a, const char *b, cell_t len) { 1401 | for (;len && UPPER(*a) == UPPER(*b); --len, ++a, ++b); 1402 | return len == 0; 1403 | } 1404 | 1405 | static cell_t find(const char *name, cell_t len) { 1406 | if (len == 0) { 1407 | return 0; 1408 | } 1409 | for (cell_t ***voc = g_sys->context; *voc; ++voc) { 1410 | cell_t xt = (cell_t) **voc; 1411 | while (xt) { 1412 | if ((*TOFLAGS(xt) & BUILTIN_FORK)) { 1413 | cell_t vocab = TOLINK(xt)[3]; 1414 | for (int i = 0; g_sys->builtins[i].name; ++i) { 1415 | if (g_sys->builtins[i].vocabulary == vocab && 1416 | len == g_sys->builtins[i].name_length && 1417 | same(name, g_sys->builtins[i].name, len)) { 1418 | return (cell_t) &g_sys->builtins[i].code; 1419 | } 1420 | } 1421 | } 1422 | if (!(*TOFLAGS(xt) & SMUDGE) && 1423 | len == *TONAMELEN(xt) && 1424 | same(name, TONAME(xt), len)) { 1425 | return xt; 1426 | } 1427 | xt = *TOLINK(xt); 1428 | } 1429 | } 1430 | return 0; 1431 | } 1432 | 1433 | static void finish(void) { 1434 | if (g_sys->latestxt && !*TOPARAMS(g_sys->latestxt)) { 1435 | cell_t sz = g_sys->heap - &g_sys->latestxt[1]; 1436 | if (sz < 0 || sz > 0xffff) { sz = 0xffff; } 1437 | *TOPARAMS(g_sys->latestxt) = sz; 1438 | } 1439 | } 1440 | 1441 | static void create(const char *name, cell_t nlength, cell_t flags, void *op) { 1442 | finish(); 1443 | g_sys->heap = (cell_t *) CELL_ALIGNED(g_sys->heap); 1444 | for (cell_t n = nlength; n; --n) { CCOMMA(*name++); } // name 1445 | g_sys->heap = (cell_t *) CELL_ALIGNED(g_sys->heap); 1446 | COMMA(*g_sys->current); // link 1447 | COMMA((nlength << 8) | flags); // flags & length 1448 | *g_sys->current = g_sys->heap; 1449 | g_sys->latestxt = g_sys->heap; 1450 | COMMA(op); // code 1451 | } 1452 | 1453 | static int match(char sep, char ch) { 1454 | return sep == ch || (sep == ' ' && (ch == '\t' || ch == '\n' || ch == '\r')); 1455 | } 1456 | 1457 | static cell_t parse(cell_t sep, cell_t *ret) { 1458 | if (sep == ' ') { 1459 | while (g_sys->tin < g_sys->ntib && 1460 | match(sep, g_sys->tib[g_sys->tin])) { ++g_sys->tin; } 1461 | } 1462 | cell_t start = g_sys->tin; 1463 | while (g_sys->tin < g_sys->ntib && 1464 | !match(sep, g_sys->tib[g_sys->tin])) { ++g_sys->tin; } 1465 | cell_t len = g_sys->tin - start; 1466 | if (g_sys->tin < g_sys->ntib) { ++g_sys->tin; } 1467 | *ret = (cell_t) (g_sys->tib + start); 1468 | return len; 1469 | } 1470 | 1471 | static cell_t *evaluate1(cell_t *rp) { 1472 | cell_t call = 0; 1473 | cell_t tos, *sp, *ip; 1474 | float *fp; 1475 | UNPARK; 1476 | cell_t name; 1477 | cell_t len = parse(' ', &name); 1478 | if (len == 0) { DUP; tos = 0; PARK; return rp; } // ignore empty 1479 | cell_t xt = find((const char *) name, len); 1480 | if (xt) { 1481 | if (g_sys->state && !(*TOFLAGS(xt) & IMMEDIATE)) { 1482 | COMMA(xt); 1483 | } else { 1484 | call = xt; 1485 | } 1486 | } else { 1487 | cell_t n; 1488 | if (convert((const char *) name, len, g_sys->base, &n)) { 1489 | if (g_sys->state) { 1490 | COMMA(g_sys->DOLIT_XT); 1491 | COMMA(n); 1492 | } else { 1493 | PUSH n; 1494 | } 1495 | } else { 1496 | float f; 1497 | if (fconvert((const char *) name, len, &f)) { 1498 | if (g_sys->state) { 1499 | COMMA(g_sys->DOFLIT_XT); 1500 | *(float *) g_sys->heap++ = f; 1501 | } else { 1502 | *++fp = f; 1503 | } 1504 | } else { 1505 | #if PRINT_ERRORS 1506 | fprintf(stderr, "CANT FIND: "); 1507 | fwrite((void *) name, 1, len, stderr); 1508 | fprintf(stderr, "\n"); 1509 | #endif 1510 | PUSH name; 1511 | PUSH len; 1512 | PUSH -1; 1513 | call = g_sys->notfound; 1514 | } 1515 | } 1516 | } 1517 | PUSH call; 1518 | PARK; 1519 | return rp; 1520 | } 1521 | 1522 | static cell_t *forth_run(cell_t *initrp); 1523 | 1524 | static void forth_init(int argc, char *argv[], 1525 | void *heap, cell_t heap_size, 1526 | const char *src, cell_t src_len) { 1527 | g_sys = (G_SYS *) heap; 1528 | memset(g_sys, 0, sizeof(G_SYS)); 1529 | g_sys->heap_start = (cell_t *) heap; 1530 | g_sys->heap_size = heap_size; 1531 | g_sys->stack_cells = STACK_CELLS; 1532 | 1533 | // Start heap after G_SYS area. 1534 | g_sys->heap = g_sys->heap_start + sizeof(G_SYS) / sizeof(cell_t); 1535 | g_sys->heap += 4; // Leave a little room. 1536 | 1537 | // Allocate stacks. 1538 | float *fp = (float *) (g_sys->heap + 1); g_sys->heap += STACK_CELLS; 1539 | cell_t *rp = g_sys->heap + 1; g_sys->heap += STACK_CELLS; 1540 | cell_t *sp = g_sys->heap + 1; g_sys->heap += STACK_CELLS; 1541 | 1542 | // FORTH worldlist (relocated when vocabularies added). 1543 | cell_t *forth_wordlist = g_sys->heap; 1544 | COMMA(0); 1545 | // Vocabulary stack. 1546 | g_sys->current = (cell_t **) forth_wordlist; 1547 | g_sys->context = (cell_t ***) g_sys->heap; 1548 | g_sys->latestxt = 0; 1549 | COMMA(forth_wordlist); 1550 | for (int i = 0; i < VOCABULARY_DEPTH; ++i) { COMMA(0); } 1551 | 1552 | // Setup boot text. 1553 | g_sys->boot = src; 1554 | g_sys->boot_size = src_len; 1555 | 1556 | forth_run(0); 1557 | #define V(name) \ 1558 | create(#name "-builtins", sizeof(#name "-builtins") - 1, \ 1559 | BUILTIN_FORK, g_sys->DOCREATE_OP); \ 1560 | COMMA(VOC_ ## name); 1561 | VOCABULARY_LIST 1562 | #undef V 1563 | g_sys->latestxt = 0; // So last builtin doesn't get wrong size. 1564 | g_sys->DOLIT_XT = FIND("DOLIT"); 1565 | g_sys->DOFLIT_XT = FIND("DOFLIT"); 1566 | g_sys->DOEXIT_XT = FIND("EXIT"); 1567 | g_sys->YIELD_XT = FIND("YIELD"); 1568 | g_sys->notfound = FIND("DROP"); 1569 | 1570 | // Init code. 1571 | cell_t *start = g_sys->heap; 1572 | COMMA(FIND("EVALUATE1")); 1573 | COMMA(FIND("BRANCH")); 1574 | COMMA(start); 1575 | 1576 | g_sys->argc = argc; 1577 | g_sys->argv = argv; 1578 | g_sys->base = 10; 1579 | g_sys->tib = src; 1580 | g_sys->ntib = src_len; 1581 | 1582 | *++rp = (cell_t) start; 1583 | *++rp = (cell_t) fp; 1584 | *++rp = (cell_t) sp; 1585 | g_sys->rp = rp; 1586 | g_sys->runner = forth_run; 1587 | } 1588 | #if defined(ENABLE_ESP32_FORTH_FAULT_HANDLING) 1589 | 1590 | # if defined(CONFIG_IDF_TARGET_ESP32C3) 1591 | 1592 | #include 1593 | #include "riscv/csr.h" 1594 | #include "esp_heap_caps.h" 1595 | 1596 | #define FORTH_VECTOR_TABLE_SIZE 32 1597 | 1598 | static __thread jmp_buf g_forth_fault; 1599 | static __thread int g_forth_signal; 1600 | static void **g_forth_vector_table; 1601 | extern void *_vector_table; 1602 | 1603 | #define FAULT_ENTRY \ 1604 | if (setjmp(g_forth_fault)) { THROWIT(g_forth_signal); } 1605 | 1606 | static void forth_faults_setup(void) { 1607 | g_forth_vector_table = (void **) malloc(sizeof(void *) * FORTH_VECTOR_TABLE_SIZE); 1608 | //g_forth_vector_table = (void **) heap_caps_malloc(sizeof(void *) * FORTH_VECTOR_TABLE_SIZE, 1609 | // MALLOC_CAP_EXEC); 1610 | void **vector_table = (void **) &_vector_table; 1611 | for (int i = 0; i < FORTH_VECTOR_TABLE_SIZE; ++i) { 1612 | g_forth_vector_table[i] = vector_table[i]; 1613 | } 1614 | // TODO: Actually apply it. 1615 | /* 1616 | uint32_t mtvec_val = (uint32_t) g_forth_vector_table; 1617 | mtvec_val |= 1; 1618 | RV_WRITE_CSR(mtvec, mtvec_val); 1619 | */ 1620 | //rv_utils_set_mtvec((uint32_t) g_forth_vector_table); 1621 | } 1622 | 1623 | # else 1624 | 1625 | #include 1626 | #include "soc/soc.h" 1627 | #include 1628 | 1629 | static __thread jmp_buf g_forth_fault; 1630 | static __thread int g_forth_signal; 1631 | static __thread uint32_t g_forth_setlevel; 1632 | 1633 | #define FAULT_ENTRY \ 1634 | if (setjmp(g_forth_fault)) { THROWIT(g_forth_signal); } 1635 | 1636 | static void IRAM_ATTR forth_exception_handler(XtExcFrame *frame) { 1637 | switch (frame->exccause) { 1638 | case EXCCAUSE_LOAD_STORE_ERROR: 1639 | case EXCCAUSE_LOAD_PROHIBITED: 1640 | case EXCCAUSE_STORE_PROHIBITED: 1641 | case EXCCAUSE_LOAD_STORE_DATA_ERROR: 1642 | case EXCCAUSE_LOAD_STORE_RING: 1643 | case EXCCAUSE_LOAD_STORE_ADDR_ERROR: 1644 | g_forth_signal = -9; 1645 | break; 1646 | case EXCCAUSE_DIVIDE_BY_ZERO: g_forth_signal = -10; break; 1647 | case EXCCAUSE_UNALIGNED: g_forth_signal = -23; break; 1648 | default: g_forth_signal = -256 - frame->exccause; break; 1649 | } 1650 | XTOS_RESTORE_INTLEVEL(g_forth_setlevel); 1651 | longjmp(g_forth_fault, 1); 1652 | } 1653 | 1654 | static void forth_faults_setup(void) { 1655 | // Install exception handler for everything, as window + alloca handlers 1656 | // don't actually get dispatched. 1657 | for (int i = 0; i < 64; ++i) { 1658 | xt_set_exception_handler(i, forth_exception_handler); 1659 | } 1660 | uint32_t default_setlevel = XTOS_SET_INTLEVEL(XCHAL_EXCM_LEVEL); 1661 | XTOS_RESTORE_INTLEVEL(default_setlevel); 1662 | g_forth_setlevel = default_setlevel; 1663 | } 1664 | 1665 | # endif 1666 | 1667 | #else 1668 | 1669 | #define forth_faults_setup() 1670 | #define FAULT_ENTRY 1671 | 1672 | #endif 1673 | #define SET tos = (cell_t) 1674 | 1675 | #define n0 tos 1676 | #define n1 (*sp) 1677 | #define n2 sp[-1] 1678 | #define n3 sp[-2] 1679 | #define n4 sp[-3] 1680 | #define n5 sp[-4] 1681 | #define n6 sp[-5] 1682 | #define n7 sp[-6] 1683 | #define n8 sp[-7] 1684 | #define n9 sp[-8] 1685 | #define n10 sp[-9] 1686 | #define n11 sp[-10] 1687 | #define n12 sp[-11] 1688 | #define n13 sp[-12] 1689 | #define n14 sp[-13] 1690 | #define n15 sp[-14] 1691 | 1692 | #define a0 ((void *) tos) 1693 | #define a1 (*(void **) &n1) 1694 | #define a2 (*(void **) &n2) 1695 | #define a3 (*(void **) &n3) 1696 | #define a4 (*(void **) &n4) 1697 | #define a5 (*(void **) &n5) 1698 | #define a6 (*(void **) &n6) 1699 | 1700 | #define b0 ((uint8_t *) tos) 1701 | #define b1 (*(uint8_t **) &n1) 1702 | #define b2 (*(uint8_t **) &n2) 1703 | #define b3 (*(uint8_t **) &n3) 1704 | #define b4 (*(uint8_t **) &n4) 1705 | #define b5 (*(uint8_t **) &n5) 1706 | #define b6 (*(uint8_t **) &n6) 1707 | 1708 | #define c0 ((char *) tos) 1709 | #define c1 (*(char **) &n1) 1710 | #define c2 (*(char **) &n2) 1711 | #define c3 (*(char **) &n3) 1712 | #define c4 (*(char **) &n4) 1713 | #define c5 (*(char **) &n5) 1714 | #define c6 (*(char **) &n6) 1715 | #define JMPW goto **(void **) w 1716 | #define NEXT w = *ip++; JMPW 1717 | #define ADDROF(x) (&& OP_ ## x) 1718 | 1719 | static cell_t *forth_run(cell_t *init_rp) { 1720 | static const BUILTIN_WORD builtins[] = { 1721 | #define Z(flags, name, op, code) \ 1722 | name, ((VOC_ ## flags >> 8) & 0xff) | BUILTIN_MARK, \ 1723 | sizeof(name) - 1, (VOC_ ## flags & 0xff), && OP_ ## op, 1724 | PLATFORM_OPCODE_LIST 1725 | TIER2_OPCODE_LIST 1726 | TIER1_OPCODE_LIST 1727 | TIER0_OPCODE_LIST 1728 | #undef Z 1729 | 0, 0, 0, 0, 0, 1730 | }; 1731 | 1732 | if (!init_rp) { 1733 | g_sys->DOCREATE_OP = ADDROF(DOCREATE); 1734 | g_sys->builtins = builtins; 1735 | forth_faults_setup(); 1736 | return 0; 1737 | } 1738 | register cell_t *ip, *rp, *sp, tos, w; 1739 | register float *fp, ft; 1740 | rp = init_rp; UNPARK; FAULT_ENTRY; NEXT; 1741 | #define Z(flags, name, op, code) OP_ ## op: { code; } NEXT; 1742 | PLATFORM_OPCODE_LIST 1743 | TIER2_OPCODE_LIST 1744 | TIER1_OPCODE_LIST 1745 | TIER0_OPCODE_LIST 1746 | #undef Z 1747 | } 1748 | const char boot[] = R"""( 1749 | : ( 41 parse drop drop ; immediate 1750 | : \ 10 parse drop drop ; immediate 1751 | : #! 10 parse drop drop ; immediate ( shebang for scripts ) 1752 | ( Now can do comments! ) 1753 | ( Stack Baseline ) 1754 | sp@ constant sp0 1755 | rp@ constant rp0 1756 | fp@ constant fp0 1757 | : depth ( -- n ) sp@ sp0 - cell/ ; 1758 | : fdepth ( -- n ) fp@ fp0 - 4 / ; 1759 | 1760 | ( Useful heap size words ) 1761 | : remaining ( -- n ) 'heap-start @ 'heap-size @ + 'heap @ - ; 1762 | : used ( -- n ) 'heap @ sp@ 'stack-cells @ cells + - 28 + ; 1763 | 1764 | ( Quoting Words ) 1765 | : ' bl parse 2dup find dup >r -rot r> 0= 'notfound @ execute 2drop ; 1766 | : ['] ' aliteral ; immediate 1767 | : char bl parse drop c@ ; 1768 | : [char] char aliteral ; immediate 1769 | 1770 | ( Core Control Flow ) 1771 | create BEGIN ' nop @ ' begin ! : begin ['] begin , here ; immediate 1772 | create AGAIN ' branch @ ' again ! : again ['] again , , ; immediate 1773 | create UNTIL ' 0branch @ ' until ! : until ['] until , , ; immediate 1774 | create AHEAD ' branch @ ' ahead ! : ahead ['] ahead , here 0 , ; immediate 1775 | create THEN ' nop @ ' then ! : then ['] then , here swap ! ; immediate 1776 | create IF ' 0branch @ ' if ! : if ['] if , here 0 , ; immediate 1777 | create ELSE ' branch @ ' else ! : else ['] else , here 0 , swap here swap ! ; immediate 1778 | create WHILE ' 0branch @ ' while ! : while ['] while , here 0 , swap ; immediate 1779 | create REPEAT ' branch @ ' repeat ! : repeat ['] repeat , , here swap ! ; immediate 1780 | create AFT ' branch @ ' aft ! : aft drop ['] aft , here 0 , here swap ; immediate 1781 | 1782 | ( Recursion ) 1783 | : recurse current @ @ aliteral ['] execute , ; immediate 1784 | 1785 | ( Postpone - done here so we have ['] and IF ) 1786 | : immediate? ( xt -- f ) >flags 1 and 0= 0= ; 1787 | : postpone ' dup immediate? if , else aliteral ['] , , then ; immediate 1788 | 1789 | ( Rstack nest depth ) 1790 | variable nest-depth 1791 | 1792 | ( FOR..NEXT ) 1793 | create FOR ' >r @ ' for ! : for 1 nest-depth +! ['] for , here ; immediate 1794 | create NEXT ' donext @ ' next ! : next -1 nest-depth +! ['] next , , ; immediate 1795 | 1796 | ( DO..LOOP ) 1797 | variable leaving 1798 | : leaving, here leaving @ , leaving ! ; 1799 | : leaving( leaving @ 0 leaving ! 2 nest-depth +! ; 1800 | : )leaving leaving @ swap leaving ! -2 nest-depth +! 1801 | begin dup while dup @ swap here swap ! repeat drop ; 1802 | : DO ( n n -- .. ) swap r> -rot >r >r >r ; 1803 | : do ( lim s -- ) leaving( postpone DO here ; immediate 1804 | : ?DO ( n n -- n n f .. ) 1805 | 2dup = if 2drop r> @ >r else swap r> cell+ -rot >r >r >r then ; 1806 | : ?do ( lim s -- ) leaving( postpone ?DO leaving, here ; immediate 1807 | : UNLOOP r> rdrop rdrop >r ; 1808 | : LEAVE r> rdrop rdrop @ >r ; 1809 | : leave postpone LEAVE leaving, ; immediate 1810 | : +LOOP ( n -- ) r> r> dup r@ - >r rot + r> -rot 1811 | dup r@ - -rot >r >r xor 0< 1812 | if r> cell+ rdrop rdrop >r else r> @ >r then ; 1813 | : +loop ( n -- ) postpone +LOOP , )leaving ; immediate 1814 | : LOOP r> r> dup r@ - >r 1+ r> -rot 1815 | dup r@ - -rot >r >r xor 0< 1816 | if r> cell+ rdrop rdrop >r else r> @ >r then ; 1817 | : loop postpone LOOP , )leaving ; immediate 1818 | create I ' r@ @ ' i ! ( i is same as r@ ) 1819 | : J ( -- n ) rp@ 3 cells - @ ; 1820 | : K ( -- n ) rp@ 5 cells - @ ; 1821 | 1822 | ( Exceptions ) 1823 | variable handler 1824 | handler 'throw-handler ! 1825 | : catch ( xt -- n ) 1826 | fp@ >r sp@ >r handler @ >r rp@ handler ! execute 1827 | r> handler ! rdrop rdrop 0 ; 1828 | : throw ( n -- ) 1829 | dup if handler @ rp! r> handler ! 1830 | r> swap >r sp! drop r> r> fp! else drop then ; 1831 | ' throw 'notfound ! 1832 | 1833 | ( Values ) 1834 | : value ( n -- ) constant ; 1835 | : value-bind ( xt-val xt ) 1836 | >r >body state @ if 1837 | r@ ['] ! = if rdrop ['] doset , , else aliteral r> , then 1838 | else r> execute then ; 1839 | : to ( n -- ) ' ['] ! value-bind ; immediate 1840 | : +to ( n -- ) ' ['] +! value-bind ; immediate 1841 | 1842 | ( Deferred Words ) 1843 | : defer ( "name" -- ) create 0 , does> @ dup 0= throw execute ; 1844 | : is ( xt "name -- ) postpone to ; immediate 1845 | ( Defer I/O to platform specific ) 1846 | defer type 1847 | defer key 1848 | defer key? 1849 | defer terminate 1850 | : bye 0 terminate ; 1851 | : emit ( n -- ) >r rp@ 1 type rdrop ; 1852 | : space bl emit ; : cr 13 emit nl emit ; 1853 | 1854 | ( Numeric Output ) 1855 | variable hld 1856 | : pad ( -- a ) here 80 + ; 1857 | : digit ( u -- c ) 9 over < 7 and + 48 + ; 1858 | : extract ( n base -- n c ) u/mod swap digit ; 1859 | : <# ( -- ) pad hld ! ; 1860 | : hold ( c -- ) hld @ 1 - dup hld ! c! ; 1861 | : # ( u -- u ) base @ extract hold ; 1862 | : #s ( u -- 0 ) begin # dup while repeat ; 1863 | : sign ( n -- ) 0< if 45 hold then ; 1864 | : #> ( w -- b u ) drop hld @ pad over - ; 1865 | : str ( n -- b u ) dup >r abs <# #s r> sign #> ; 1866 | : hex ( -- ) 16 base ! ; : octal ( -- ) 8 base ! ; 1867 | : decimal ( -- ) 10 base ! ; : binary ( -- ) 2 base ! ; 1868 | : u. ( u -- ) <# #s #> type space ; 1869 | : . ( w -- ) base @ 10 xor if u. exit then str type space ; 1870 | : ? ( a -- ) @ . ; 1871 | : n. ( n -- ) base @ swap decimal <# #s #> type base ! ; 1872 | 1873 | ( Strings ) 1874 | : parse-quote ( -- a n ) [char] " parse ; 1875 | : $place ( a n -- ) for aft dup c@ c, 1+ then next drop ; 1876 | : zplace ( a n -- ) $place 0 c, align ; 1877 | : $@ r@ dup cell+ swap @ r> dup @ 1+ aligned + cell+ >r ; 1878 | : s" parse-quote state @ if postpone $@ dup , zplace 1879 | else dup here swap >r >r zplace r> r> then ; immediate 1880 | : ." postpone s" state @ if postpone type else type then ; immediate 1881 | : z" postpone s" state @ if postpone drop else drop then ; immediate 1882 | : r" parse-quote state @ if swap aliteral aliteral then ; immediate 1883 | : r| [char] | parse state @ if swap aliteral aliteral then ; immediate 1884 | : r~ [char] ~ parse state @ if swap aliteral aliteral then ; immediate 1885 | : s>z ( a n -- z ) here >r zplace r> ; 1886 | : z>s ( z -- a n ) 0 over begin dup c@ while 1+ swap 1+ swap repeat drop ; 1887 | 1888 | ( Better Errors ) 1889 | : notfound ( a n n -- ) 1890 | if cr ." ERROR: " type ." NOT FOUND!" cr -1 throw then ; 1891 | ' notfound 'notfound ! 1892 | 1893 | ( Abort ) 1894 | : abort -1 throw ; 1895 | : abort" postpone ." postpone cr -2 aliteral postpone throw ; immediate 1896 | 1897 | ( Input ) 1898 | : raw.s depth 0 max for aft sp@ r@ cells - @ . then next ; 1899 | variable echo -1 echo ! variable arrow -1 arrow ! 0 value wascr 1900 | : *emit ( n -- ) dup 13 = if drop cr else emit then ; 1901 | : ?echo ( n -- ) echo @ if *emit else drop then ; 1902 | : ?arrow. arrow @ if >r >r raw.s r> r> ." --> " then ; 1903 | : *key ( -- n ) 1904 | begin 1905 | key 1906 | dup nl = if 1907 | drop wascr if 0 else 13 exit then 1908 | then 1909 | dup 13 = to wascr 1910 | dup if exit else drop then 1911 | again ; 1912 | : eat-till-cr begin *key dup 13 = if ?echo exit else drop then again ; 1913 | : accept ( a n -- n ) ?arrow. 0 swap begin 2dup < while 1914 | *key 1915 | dup 13 = if ?echo drop nip exit then 1916 | dup 8 = over 127 = or if 1917 | drop over if rot 1- rot 1- rot 8 ?echo bl ?echo 8 ?echo then 1918 | else 1919 | dup ?echo 1920 | >r rot r> over c! 1+ -rot swap 1+ swap 1921 | then 1922 | repeat drop nip 1923 | eat-till-cr 1924 | ; 1925 | 200 constant input-limit 1926 | : tib ( -- a ) 'tib @ ; 1927 | create input-buffer input-limit allot 1928 | : tib-setup input-buffer 'tib ! ; 1929 | : refill tib-setup tib input-limit accept #tib ! 0 >in ! -1 ; 1930 | 1931 | ( Stack Guards ) 1932 | sp0 'stack-cells @ 2 3 */ cells + constant sp-limit 1933 | : ?stack sp@ sp0 < if ." STACK UNDERFLOW " -4 throw then 1934 | sp-limit sp@ < if ." STACK OVERFLOW " -3 throw then ; 1935 | 1936 | ( REPL ) 1937 | : prompt ." ok" cr ; 1938 | : evaluate-buffer begin >in @ #tib @ < while evaluate1 ?stack repeat ; 1939 | : evaluate ( a n -- ) 'tib @ >r #tib @ >r >in @ >r 1940 | #tib ! 'tib ! 0 >in ! evaluate-buffer 1941 | r> >in ! r> #tib ! r> 'tib ! ; 1942 | : evaluate&fill 1943 | begin >in @ #tib @ >= if prompt refill drop then evaluate-buffer again ; 1944 | : quit 1945 | #tib @ >in ! 1946 | begin ['] evaluate&fill catch 1947 | if 0 state ! sp0 sp! fp0 fp! rp0 rp! ." ERROR " cr then 1948 | again ; 1949 | variable boot-prompt 1950 | : free. ( nf nu -- ) 2dup swap . ." free + " . ." used = " 2dup + . ." total (" 1951 | over + 100 -rot */ n. ." % free)" ; 1952 | : raw-ok ." v7.0.7.15 - rev 564a8fc68b545ebeb3ab" cr 1953 | boot-prompt @ if boot-prompt @ execute then 1954 | ." Forth dictionary: " remaining used free. cr 1955 | ." 3 x Forth stacks: " 'stack-cells @ cells . ." bytes each" cr 1956 | quit ; 1957 | ( Interpret time conditionals ) 1958 | 1959 | : DEFINED? ( "name" -- xt|0 ) 1960 | begin bl parse dup 0= while 2drop refill 0= throw repeat 1961 | find state @ if aliteral then ; immediate 1962 | defer [SKIP] 1963 | : [THEN] ; immediate 1964 | : [ELSE] [SKIP] ; immediate 1965 | : [IF] 0= if [SKIP] then ; immediate 1966 | : [SKIP]' 0 begin postpone defined? dup if 1967 | dup ['] [IF] = if swap 1+ swap then 1968 | dup ['] [ELSE] = if swap dup 0 <= if 2drop exit then swap then 1969 | dup ['] [THEN] = if swap 1- dup 0< if 2drop exit then swap then 1970 | then drop again ; 1971 | ' [SKIP]' is [SKIP] 1972 | ( Implement Vocabularies ) 1973 | ( normal: link, flags&len, code ) 1974 | ( vocab: link, flags&len, code | link , len=0, voclink ) 1975 | variable last-vocabulary 1976 | : vocabulary ( "name" ) 1977 | create current @ 2 cells + , 0 , last-vocabulary @ , 1978 | current @ @ last-vocabulary ! 1979 | does> context ! ; 1980 | : definitions context @ current ! ; 1981 | vocabulary FORTH 1982 | ' forth >body @ >link ' forth >body ! 1983 | forth definitions 1984 | 1985 | ( Make it easy to transfer words between vocabularies ) 1986 | : xt-find& ( xt -- xt& ) context @ begin 2dup @ <> while @ >link& repeat nip ; 1987 | : xt-hide ( xt -- ) xt-find& dup @ >link swap ! ; 1988 | 8 constant BUILTIN_MARK 1989 | : xt-transfer ( xt -- ) dup >flags BUILTIN_MARK and if drop exit then 1990 | dup xt-hide current @ @ over >link& ! current @ ! ; 1991 | : transfer ( "name" ) ' xt-transfer ; 1992 | : }transfer ; 1993 | : transfer{ begin ' dup ['] }transfer = if drop exit then xt-transfer again ; 1994 | 1995 | ( Watered down versions of these ) 1996 | : only forth 0 context cell+ ! ; 1997 | : voc-stack-end ( -- a ) context begin dup @ while cell+ repeat ; 1998 | : also context context cell+ voc-stack-end over - 2 cells + cmove> ; 1999 | : previous 2000 | voc-stack-end context cell+ = throw 2001 | context cell+ context voc-stack-end over - cell+ cmove ; 2002 | : sealed 0 last-vocabulary @ >body ! ; 2003 | 2004 | ( Hide some words in an internals vocabulary ) 2005 | vocabulary internals internals definitions 2006 | 2007 | ( Vocabulary chain for current scope, place at the -1 position ) 2008 | variable scope scope context cell - ! 2009 | 2010 | transfer{ 2011 | xt-find& xt-hide xt-transfer 2012 | voc-stack-end last-vocabulary notfound 2013 | *key *emit wascr eat-till-cr 2014 | immediate? input-buffer ?echo ?arrow. arrow 2015 | evaluate-buffer evaluate&fill aliteral value-bind 2016 | leaving( )leaving leaving leaving, 2017 | parse-quote digit $@ raw.s 2018 | tib-setup input-limit sp-limit ?stack 2019 | [SKIP] [SKIP]' raw-ok boot-prompt free. 2020 | $place zplace BUILTIN_MARK 2021 | }transfer 2022 | 2023 | ( Move branching opcodes to separate vocabulary ) 2024 | vocabulary internalized internalized definitions 2025 | : cleave ' >link xt-transfer ; 2026 | cleave begin cleave again cleave until 2027 | cleave ahead cleave then cleave if 2028 | cleave else cleave while cleave repeat 2029 | cleave aft cleave for cleave next 2030 | cleave do cleave ?do cleave +loop 2031 | cleave loop cleave leave 2032 | 2033 | forth definitions 2034 | 2035 | ( Make DOES> switch to compile mode when interpreted ) 2036 | ( 2037 | forth definitions internals 2038 | ' does> 2039 | : does> state @ if postpone does> exit then 2040 | ['] constant @ current @ @ dup >r ! 2041 | here r> cell+ ! postpone ] ; immediate 2042 | xt-hide 2043 | forth definitions 2044 | ) 2045 | : sf, ( r -- ) here sf! sfloat allot ; 2046 | 2047 | : afliteral ( r -- ) ['] DOFLIT , sf, align ; 2048 | : fliteral afliteral ; immediate 2049 | 2050 | : fconstant ( r "name" ) create sf, align does> sf@ ; 2051 | : fvariable ( "name" ) create sfloat allot align ; 2052 | 2053 | 6 value precision 2054 | : set-precision ( n -- ) to precision ; 2055 | 2056 | internals definitions 2057 | : #f+s ( r -- ) fdup precision for aft 10e f* then next 2058 | precision for aft fdup f>s 10 mod [char] 0 + hold 0.1e f* then next 2059 | [char] . hold fdrop f>s #s ; 2060 | forth definitions internals 2061 | 2062 | : #fs ( r -- ) fdup f0< if fnegate #f+s [char] - hold else #f+s then ; 2063 | : f. ( r -- ) <# #fs #> type space ; 2064 | : f.s ." <" fdepth n. ." > " 2065 | fdepth 0 max for aft fp@ r@ sfloats - sf@ f. then next ; 2066 | 2067 | forth definitions 2068 | ( Vocabulary for building C-style structures ) 2069 | 2070 | vocabulary structures structures definitions 2071 | 2072 | variable last-align 2073 | : typer ( align sz "name" ) create , , 2074 | does> dup cell+ @ last-align ! @ ; 2075 | 1 1 typer i8 2076 | 2 2 typer i16 2077 | 4 4 typer i32 2078 | cell 8 typer i64 2079 | cell cell typer ptr 2080 | long-size long-size typer long 2081 | 2082 | variable last-struct 2083 | 2084 | : struct ( "name" ) 1 0 typer latestxt >body last-struct ! 2085 | 1 last-align ! ; 2086 | : align-by ( a n -- a ) 1- dup >r + r> invert and ; 2087 | : struct-align ( n -- ) 2088 | dup last-struct @ cell+ @ max last-struct @ cell+ ! 2089 | last-struct @ @ swap align-by last-struct @ ! ; 2090 | : field ( n "name" ) 2091 | last-align @ struct-align 2092 | create last-struct @ @ , last-struct @ +! 2093 | does> @ + ; 2094 | 2095 | forth definitions 2096 | ( Words with OS assist ) 2097 | : allocate ( n -- a ior ) malloc dup 0= ; 2098 | : free ( a -- ior ) sysfree 0 ; 2099 | : resize ( a n -- a ior ) realloc dup 0= ; 2100 | 2101 | ( Migrate various words to separate vocabularies, and constants ) 2102 | 2103 | forth definitions internals 2104 | : read-dir ( dh -- a n ) readdir dup if z>s else 0 then ; 2105 | forth definitions 2106 | 2107 | vocabulary ESP ESP definitions 2108 | transfer ESP-builtins 2109 | only forth definitions 2110 | 2111 | vocabulary Wire Wire definitions 2112 | transfer wire-builtins 2113 | forth definitions 2114 | 2115 | vocabulary WiFi WiFi definitions 2116 | transfer WiFi-builtins 2117 | ( WiFi Modes ) 2118 | 0 constant WIFI_MODE_NULL 2119 | 1 constant WIFI_MODE_STA 2120 | 2 constant WIFI_MODE_AP 2121 | 3 constant WIFI_MODE_APSTA 2122 | forth definitions 2123 | 2124 | vocabulary SD SD definitions 2125 | transfer SD-builtins 2126 | forth definitions 2127 | 2128 | vocabulary SD_MMC SD_MMC definitions 2129 | transfer SD_MMC-builtins 2130 | forth definitions 2131 | 2132 | vocabulary SPIFFS SPIFFS definitions 2133 | transfer SPIFFS-builtins 2134 | forth definitions 2135 | 2136 | vocabulary ledc ledc definitions 2137 | transfer ledc-builtins 2138 | forth definitions 2139 | 2140 | vocabulary Serial Serial definitions 2141 | transfer Serial-builtins 2142 | forth definitions 2143 | 2144 | vocabulary sockets sockets definitions 2145 | transfer sockets-builtins 2146 | 1 constant SOCK_STREAM 2147 | 2 constant SOCK_DGRAM 2148 | 3 constant SOCK_RAW 2149 | 2150 | 2 constant AF_INET 2151 | 16 constant sizeof(sockaddr_in) 2152 | 1 constant SOL_SOCKET 2153 | 2 constant SO_REUSEADDR 2154 | 2155 | : bs, ( n -- ) dup 8 rshift c, c, ; 2156 | : s, ( n -- ) dup c, 8 rshift c, ; 2157 | : l, ( n -- ) dup s, 16 rshift s, ; 2158 | : sockaddr create 16 c, AF_INET c, 0 bs, 0 l, 0 l, 0 l, ; 2159 | : ->port@ ( a -- n ) 2 + >r r@ c@ 8 lshift r> 1+ c@ + ; 2160 | : ->port! ( n a -- ) 2 + >r dup 8 rshift r@ c! r> 1+ c! ; 2161 | : ->addr@ ( a -- n ) 4 + ul@ ; 2162 | : ->addr! ( n a -- ) 4 + l! ; 2163 | : ->h_addr ( hostent -- n ) 2 cells + 8 + @ @ ul@ ; 2164 | : ip# ( n -- n ) dup 255 and n. [char] . emit 8 rshift ; 2165 | : ip. ( n -- ) ip# ip# ip# 255 and n. ; 2166 | forth definitions 2167 | 2168 | vocabulary rtos rtos definitions 2169 | transfer rtos-builtins 2170 | forth definitions 2171 | 2172 | internals definitions 2173 | ( Heap Capabilities ) 2174 | 1 0 lshift constant MALLOC_CAP_EXEC 2175 | 1 1 lshift constant MALLOC_CAP_32BIT 2176 | 1 2 lshift constant MALLOC_CAP_8BIT 2177 | 1 3 lshift constant MALLOC_CAP_DMA 2178 | 1 10 lshift constant MALLOC_CAP_SPIRAM 2179 | 1 11 lshift constant MALLOC_CAP_INTERNAL 2180 | 1 12 lshift constant MALLOC_CAP_DEFAULT 2181 | 1 13 lshift constant MALLOC_CAP_IRAM_8BIT 2182 | 1 14 lshift constant MALLOC_CAP_RETENTION 2183 | 1 15 lshift constant MALLOC_CAP_RTCRAM 2184 | forth definitions 2185 | ( Words built after boot ) 2186 | 2187 | ( For tests and asserts ) 2188 | : assert ( f -- ) 0= throw ; 2189 | 2190 | ( Print spaces ) 2191 | : spaces ( n -- ) for aft space then next ; 2192 | 2193 | internals definitions 2194 | 2195 | ( Temporary for platforms without CALLCODE ) 2196 | DEFINED? CALLCODE 0= [IF] 2197 | create CALLCODE 2198 | [THEN] 2199 | 2200 | ( Safe memory access, i.e. aligned ) 2201 | cell 1- constant cell-mask 2202 | : cell-base ( a -- a ) cell-mask invert and ; 2203 | : cell-shift ( a -- a ) cell-mask and 8 * ; 2204 | : ca@ ( a -- n ) dup cell-base @ swap cell-shift rshift 255 and ; 2205 | 2206 | ( Print address line leaving room ) 2207 | : dump-line ( a -- a ) cr <# #s #> 20 over - >r type r> spaces ; 2208 | 2209 | ( Semi-dangerous word to trim down the system heap ) 2210 | DEFINED? realloc [IF] 2211 | : relinquish ( n -- ) negate 'heap-size +! 'heap-start @ 'heap-size @ realloc drop ; 2212 | [THEN] 2213 | 2214 | forth definitions internals 2215 | 2216 | ( Examine Memory ) 2217 | : dump ( a n -- ) 2218 | over 15 and if over dump-line over 15 and 3 * spaces then 2219 | for aft 2220 | dup 15 and 0= if dup dump-line then 2221 | dup ca@ <# # #s #> type space 1+ 2222 | then next drop cr ; 2223 | 2224 | ( Remove from Dictionary ) 2225 | : forget ( "name" ) ' dup >link current @ ! >name drop here - allot ; 2226 | 2227 | internals definitions 2228 | 1 constant IMMEDIATE_MARK 2229 | 2 constant SMUDGE 2230 | 4 constant BUILTIN_FORK 2231 | 16 constant NONAMED 2232 | 32 constant +TAB 2233 | 64 constant -TAB 2234 | 128 constant ARGS_MARK 2235 | : mem= ( a a n -- f) 2236 | for aft 2dup c@ swap c@ <> if 2drop rdrop 0 exit then 1+ swap 1+ then next 2drop -1 ; 2237 | forth definitions also internals 2238 | : :noname ( -- xt ) 0 , current @ @ , NONAMED SMUDGE or , 2239 | here dup current @ ! ['] mem= @ , postpone ] ; 2240 | : str= ( a n a n -- f) >r swap r@ <> if rdrop 2drop 0 exit then r> mem= ; 2241 | : startswith? ( a n a n -- f ) >r swap r@ < if rdrop 2drop 0 exit then r> mem= ; 2242 | : .s ." <" depth n. ." > " raw.s cr ; 2243 | only forth definitions 2244 | 2245 | ( Tweak indent on branches ) 2246 | internals internalized definitions 2247 | 2248 | : flags'or! ( n -- ) ' >flags& dup >r c@ or r> c! ; 2249 | +TAB flags'or! BEGIN 2250 | -TAB flags'or! AGAIN 2251 | -TAB flags'or! UNTIL 2252 | +TAB flags'or! AHEAD 2253 | -TAB flags'or! THEN 2254 | +TAB flags'or! IF 2255 | +TAB -TAB or flags'or! ELSE 2256 | +TAB -TAB or flags'or! WHILE 2257 | -TAB flags'or! REPEAT 2258 | +TAB flags'or! AFT 2259 | +TAB flags'or! FOR 2260 | -TAB flags'or! NEXT 2261 | +TAB flags'or! DO 2262 | ARGS_MARK +TAB or flags'or! ?DO 2263 | ARGS_MARK -TAB or flags'or! +LOOP 2264 | ARGS_MARK -TAB or flags'or! LOOP 2265 | ARGS_MARK flags'or! LEAVE 2266 | 2267 | forth definitions 2268 | 2269 | ( Definitions building to SEE and ORDER ) 2270 | internals definitions 2271 | variable indent 2272 | : see. ( xt -- ) >name type space ; 2273 | : icr cr indent @ 0 max 4* spaces ; 2274 | : indent+! ( n -- ) indent +! icr ; 2275 | : see-one ( xt -- xt+1 ) 2276 | dup cell+ swap @ 2277 | dup ['] DOLIT = if drop dup @ . cell+ exit then 2278 | dup ['] DOSET = if drop ." TO " dup @ cell - see. cell+ icr exit then 2279 | dup ['] DOFLIT = if drop dup sf@ <# [char] e hold #fs #> type space cell+ exit then 2280 | dup ['] $@ = if drop ['] s" see. 2281 | dup @ dup >r >r dup cell+ r> type cell+ r> 1+ aligned + 2282 | [char] " emit space exit then 2283 | dup ['] DOES> = if icr then 2284 | dup >flags -TAB AND if -1 indent+! then 2285 | dup see. 2286 | dup >flags +TAB AND if 2287 | 1 indent+! 2288 | else 2289 | dup >flags -TAB AND if icr then 2290 | then 2291 | dup ['] ! = if icr then 2292 | dup ['] +! = if icr then 2293 | dup @ ['] BRANCH @ = 2294 | over @ ['] 0BRANCH @ = or 2295 | over @ ['] DONEXT @ = or 2296 | over >flags ARGS_MARK and or 2297 | if swap cell+ swap then 2298 | drop 2299 | ; 2300 | : see-loop dup >body swap >params 1- cells over + 2301 | begin 2dup < while swap see-one swap repeat 2drop ; 2302 | : ?see-flags >flags IMMEDIATE_MARK and if ." IMMEDIATE " then ; 2303 | : see-xt ( xt -- ) 2304 | dup @ ['] see-loop @ = if 2305 | ['] : see. dup see. 2306 | 1 indent ! icr 2307 | dup see-loop 2308 | -1 indent+! ['] ; see. 2309 | ?see-flags cr 2310 | exit 2311 | then 2312 | dup >flags BUILTIN_FORK and if ." Built-in-fork: " see. exit then 2313 | dup @ ['] input-buffer @ = if ." CREATE/VARIABLE: " see. cr exit then 2314 | dup @ ['] SMUDGE @ = if ." DOES>/CONSTANT: " see. cr exit then 2315 | dup @ ['] callcode @ = if ." Code: " see. cr exit then 2316 | dup >params 0= if ." Built-in: " see. cr exit then 2317 | ." Unsupported: " see. cr ; 2318 | 2319 | : nonvoc? ( xt -- f ) 2320 | dup 0= if exit then dup >name nip swap >flags NONAMED BUILTIN_FORK or and or ; 2321 | : see-vocabulary ( voc ) 2322 | @ begin dup nonvoc? while dup see-xt >link repeat drop cr ; 2323 | : >vocnext ( xt -- xt ) >body 2 cells + @ ; 2324 | : see-all 2325 | last-vocabulary @ begin dup while 2326 | ." VOCABULARY " dup see. cr ." ------------------------" cr 2327 | dup >body see-vocabulary 2328 | >vocnext 2329 | repeat drop cr ; 2330 | : voclist-from ( voc -- ) begin dup while dup see. cr >vocnext repeat drop ; 2331 | : voclist last-vocabulary @ voclist-from ; 2332 | : voc. ( voc -- ) 2 cells - see. ; 2333 | : vocs. ( voc -- ) dup voc. @ begin dup while 2334 | dup nonvoc? 0= if ." >> " dup 2 cells - voc. then 2335 | >link 2336 | repeat drop cr ; 2337 | 2338 | ( Words to measure size of things ) 2339 | : size-vocabulary ( voc ) 2340 | @ begin dup nonvoc? while 2341 | dup >params . dup >size . dup . dup see. cr >link 2342 | repeat drop ; 2343 | : size-all 2344 | last-vocabulary @ begin dup while 2345 | 0 . 0 . 0 . dup see. cr 2346 | dup >body size-vocabulary 2347 | >vocnext 2348 | repeat drop cr ; 2349 | 2350 | forth definitions also internals 2351 | : see ' see-xt ; 2352 | : order context begin dup @ while dup @ vocs. cell+ repeat drop ; 2353 | only forth definitions 2354 | 2355 | ( List words in Dictionary / Vocabulary ) 2356 | internals definitions 2357 | 70 value line-width 2358 | 0 value line-pos 2359 | : onlines ( xt -- xt ) 2360 | line-pos line-width > if cr 0 to line-pos then 2361 | dup >name nip 1+ line-pos + to line-pos ; 2362 | : vins. ( voc -- ) 2363 | >r 'builtins begin dup >link while 2364 | dup >params r@ = if dup onlines see. then 2365 | 3 cells + 2366 | repeat drop rdrop ; 2367 | : ins. ( n xt -- n ) cell+ @ vins. ; 2368 | : ?ins. ( xt -- xt ) dup >flags BUILTIN_FORK and if dup ins. then ; 2369 | forth definitions also internals 2370 | : vlist 0 to line-pos context @ @ 2371 | begin dup nonvoc? while ?ins. dup onlines see. >link repeat drop cr ; 2372 | : words 0 to line-pos context @ @ 2373 | begin dup while ?ins. dup onlines see. >link repeat drop cr ; 2374 | only forth definitions 2375 | ( Lazy loaded code words ) 2376 | : asm r| 2377 | 2378 | also forth definitions 2379 | vocabulary asm 2380 | internals definitions 2381 | 2382 | : ca! ( n a -- ) dup cell-base >r cell-shift swap over lshift 2383 | swap 255 swap lshift invert r@ @ and or r> ! ; 2384 | 2385 | also asm definitions 2386 | 2387 | variable code-start 2388 | variable code-at 2389 | 2390 | DEFINED? posix [IF] 2391 | also posix 2392 | : reserve ( n -- ) 2393 | 0 swap PROT_READ PROT_WRITE PROT_EXEC or or 2394 | MAP_ANONYMOUS MAP_PRIVATE or -1 0 mmap code-start ! ; 2395 | previous 2396 | 4096 reserve 2397 | [THEN] 2398 | 2399 | DEFINED? esp [IF] 2400 | also esp 2401 | : reserve ( n -- ) MALLOC_CAP_EXEC heap_caps_malloc code-start ! ; 2402 | previous 2403 | 1024 reserve 2404 | [THEN] 2405 | 2406 | code-start @ code-at ! 2407 | 2408 | : chere ( -- a ) code-at @ ; 2409 | : callot ( n -- ) code-at +! ; 2410 | : code1, ( n -- ) chere ca! 1 callot ; 2411 | : code2, ( n -- ) dup code1, 8 rshift code1, ; 2412 | : code3, ( n -- ) dup code2, 16 rshift code1, ; 2413 | : code4, ( n -- ) dup code2, 16 rshift code2, ; 2414 | cell 8 = [IF] 2415 | : code, dup code4, 32 rshift code4, ; 2416 | [ELSE] 2417 | : code, code4, ; 2418 | [THEN] 2419 | : end-code previous ; 2420 | 2421 | also forth definitions 2422 | 2423 | : code ( "name" ) create ['] callcode @ latestxt ! 2424 | code-at @ latestxt cell+ ! also asm ; 2425 | 2426 | previous previous previous 2427 | asm 2428 | 2429 | | evaluate ; 2430 | ( Local Variables ) 2431 | 2432 | ( NOTE: These are not yet gforth compatible ) 2433 | 2434 | internals definitions 2435 | 2436 | ( Leave a region for locals definitions ) 2437 | 1024 constant locals-capacity 128 constant locals-gap 2438 | create locals-area locals-capacity allot 2439 | variable locals-here locals-area locals-here ! 2440 | : <>locals locals-here @ here locals-here ! here - allot ; 2441 | 2442 | : local@ ( n -- ) rp@ + @ ; 2443 | : local! ( n -- ) rp@ + ! ; 2444 | : local+! ( n -- ) rp@ + +! ; 2445 | 2446 | variable scope-depth 2447 | variable local-op ' local@ local-op ! 2448 | : scope-exit scope-depth @ for aft postpone rdrop then next ; 2449 | : scope-clear 2450 | scope-exit 2451 | scope-depth @ negate nest-depth +! 2452 | 0 scope-depth ! 0 scope ! locals-area locals-here ! ; 2453 | : do-local ( n -- ) nest-depth @ + cells negate aliteral 2454 | local-op @ , ['] local@ local-op ! ; 2455 | : scope-create ( a n -- ) 2456 | dup >r $place align ( name ) 2457 | scope @ , r> 8 lshift 1 or , ( IMMEDIATE ) here scope ! ( link, flags&length ) 2458 | ['] scope-clear @ ( docol) , 2459 | nest-depth @ negate aliteral postpone do-local ['] exit , 2460 | 1 scope-depth +! 1 nest-depth +! 2461 | ; 2462 | 2463 | : ?room locals-here @ locals-area - locals-capacity locals-gap - > 2464 | if scope-clear -1 throw then ; 2465 | 2466 | : }? ( a n -- ) 1 <> if drop 0 exit then c@ [char] } = ; 2467 | : --? ( a n -- ) s" --" str= ; 2468 | : (to) ( xt -- ) ['] local! local-op ! execute ; 2469 | : (+to) ( xt -- ) ['] local+! local-op ! execute ; 2470 | 2471 | also forth definitions 2472 | 2473 | : (local) ( a n -- ) 2474 | dup 0= if 2drop exit then 2475 | ?room <>locals scope-create <>locals postpone >r ; 2476 | : { bl parse 2477 | dup 0= if scope-clear -1 throw then 2478 | 2dup --? if 2drop [char] } parse 2drop exit then 2479 | 2dup }? if 2drop exit then 2480 | recurse (local) ; immediate 2481 | ( TODO: Hide the words overriden here. ) 2482 | : ; scope-clear postpone ; ; immediate 2483 | : exit scope-exit postpone exit ; immediate 2484 | : to ( n -- ) ' dup >flags if (to) else ['] ! value-bind then ; immediate 2485 | : +to ( n -- ) ' dup >flags if (+to) else ['] +! value-bind then ; immediate 2486 | 2487 | only forth definitions 2488 | internals definitions 2489 | variable cases 2490 | forth definitions internals 2491 | 2492 | : CASE ( n -- ) cases @ 0 cases ! ; immediate 2493 | : ENDCASE postpone drop cases @ for aft postpone then then next 2494 | cases ! ; immediate 2495 | : OF ( n -- ) postpone over postpone = postpone if postpone drop ; immediate 2496 | : ENDOF 1 cases +! postpone else ; immediate 2497 | 2498 | forth definitions 2499 | ( Cooperative Tasks ) 2500 | 2501 | vocabulary tasks tasks definitions also internals 2502 | 2503 | variable task-list 2504 | 2505 | : .tasks task-list @ begin dup 2 cells - see. @ dup task-list @ = until drop ; 2506 | 2507 | forth definitions tasks also internals 2508 | 2509 | : pause 2510 | rp@ sp@ task-list @ cell+ ! 2511 | task-list @ @ task-list ! 2512 | task-list @ cell+ @ sp! rp! 2513 | ; 2514 | 2515 | : task ( xt dsz rsz "name" ) 2516 | create here >r 0 , 0 , ( link, sp ) 2517 | swap here cell+ r@ cell+ ! cells allot 2518 | here r@ cell+ @ ! cells allot 2519 | dup 0= if drop else 2520 | here r@ cell+ @ @ ! ( set rp to point here ) 2521 | , postpone pause ['] branch , here 3 cells - , 2522 | then rdrop ; 2523 | 2524 | : start-task ( t -- ) 2525 | task-list @ if 2526 | task-list @ @ over ! 2527 | task-list @ ! 2528 | else 2529 | dup task-list ! 2530 | dup ! 2531 | then 2532 | ; 2533 | 2534 | DEFINED? ms-ticks [IF] 2535 | : ms ( n -- ) ms-ticks >r begin pause ms-ticks r@ - over >= until rdrop drop ; 2536 | [THEN] 2537 | 2538 | tasks definitions 2539 | 0 0 0 task main-task main-task start-task 2540 | only forth definitions 2541 | ( Byte Stream / Ring Buffer ) 2542 | 2543 | vocabulary streams streams definitions 2544 | 2545 | : stream ( n "name" ) create 1+ dup , 0 , 0 , allot align ; 2546 | : >write ( st -- wr ) cell+ ; : >read ( st -- rd ) 2 cells + ; 2547 | : >offset ( n st -- a ) 3 cells + + ; 2548 | : stream# ( sz -- n ) >r r@ >write @ r@ >read @ - r> @ mod ; 2549 | : full? ( st -- f ) dup stream# swap @ 1- = ; 2550 | : empty? ( st -- f ) stream# 0= ; 2551 | : wait-write ( st -- ) begin dup full? while pause repeat drop ; 2552 | : wait-read ( st -- ) begin dup empty? while pause repeat drop ; 2553 | : ch>stream ( ch st -- ) 2554 | dup wait-write 2555 | >r r@ >write @ r@ >offset c! 2556 | r@ >write @ 1+ r@ @ mod r> >write ! ; 2557 | : stream>ch ( st -- ch ) 2558 | dup wait-read 2559 | >r r@ >read @ r@ >offset c@ 2560 | r@ >read @ 1+ r@ @ mod r> >read ! ; 2561 | : >stream ( a n st -- ) 2562 | swap for aft over c@ over ch>stream swap 1+ swap then next 2drop ; 2563 | : stream> ( a n st -- ) 2564 | begin over 1 > over empty? 0= and while 2565 | dup stream>ch >r rot dup r> swap c! 1+ rot 1- rot repeat 2drop 0 swap c! ; 2566 | 2567 | forth definitions 2568 | : dump-file ( a n a n -- ) 2569 | w/o create-file throw 2570 | >r r@ write-file throw 2571 | r> close-file drop 2572 | ; 2573 | 2574 | : cp ( "src" "dst" -- ) 2575 | bl parse r/o bin open-file throw { inf } 2576 | bl parse w/o bin create-file throw { outf } 2577 | begin 2578 | here 80 inf read-file throw 2579 | dup 0= if drop outf close-file throw inf close-file throw exit then 2580 | here swap outf write-file throw 2581 | again 2582 | ; 2583 | 2584 | : mv ( "src" "dst" -- ) bl parse bl parse rename-file throw ; 2585 | : rm ( "path" -- ) bl parse delete-file throw ; 2586 | 2587 | : touch ( "path" -- ) 2588 | bl parse 2dup w/o open-file 2589 | if drop w/o create-file throw then 2590 | close-file throw 2591 | ; 2592 | 2593 | internals definitions 2594 | 2595 | : cremit ( ch -- ) dup nl = if drop cr else emit then ; 2596 | : crtype ( a n -- ) for aft dup c@ cremit 1+ then next drop ; 2597 | 2598 | forth definitions internals 2599 | 2600 | : cat ( "path" -- ) 2601 | bl parse r/o bin open-file throw { fh } 2602 | begin 2603 | here 80 fh read-file throw 2604 | dup 0= if drop fh close-file throw exit then 2605 | here swap crtype 2606 | again 2607 | ; 2608 | 2609 | DEFINED? read-dir [IF] 2610 | : ls ( "path" -- ) 2611 | bl parse dup 0= if 2drop s" ." then 2612 | open-dir throw { dh } begin 2613 | dh read-dir dup 0= if 2614 | 2drop dh close-dir throw exit 2615 | then type cr 2616 | again 2617 | ; 2618 | [THEN] 2619 | 2620 | internals definitions 2621 | ( Leave some room for growth of starting system. ) 2622 | 0 value saving-base 2623 | : park-heap ( -- a ) saving-base ; 2624 | : park-forth ( -- a ) saving-base cell+ ; 2625 | : 'cold ( -- a ) saving-base 2 cells + ; 2626 | : setup-saving-base 2627 | here to saving-base 16 cells allot 0 'cold ! ; 2628 | 2629 | ' forth >body constant forth-wordlist 2630 | 2631 | : save-name 2632 | 'heap @ park-heap ! 2633 | forth-wordlist @ park-forth ! 2634 | w/o create-file throw >r 2635 | saving-base here over - r@ write-file throw 2636 | r> close-file throw ; 2637 | 2638 | : restore-name ( "name" -- ) 2639 | r/o open-file throw >r 2640 | saving-base r@ file-size throw r@ read-file throw drop 2641 | r> close-file throw 2642 | park-heap @ 'heap ! 2643 | park-forth @ forth-wordlist ! 2644 | 'cold @ dup if execute else drop then ; 2645 | 2646 | defer remember-filename 2647 | : default-remember-filename s" myforth" ; 2648 | ' default-remember-filename is remember-filename 2649 | 2650 | forth definitions also internals 2651 | 2652 | : save ( "name" -- ) bl parse save-name ; 2653 | : restore ( "name" -- ) bl parse restore-name ; 2654 | : remember remember-filename save-name ; 2655 | : startup: ( "name" ) ' 'cold ! remember ; 2656 | : revive remember-filename restore-name ; 2657 | : reset remember-filename delete-file throw ; 2658 | 2659 | only forth definitions 2660 | ( Including Files ) 2661 | 2662 | internals definitions 2663 | 2664 | : ends/ ( a n -- f ) 1- + c@ [char] / = ; 2665 | : dirname ( a n -- ) 2666 | dup if 2667 | 2dup ends/ if 1- then 2668 | then 2669 | begin dup while 2670 | 2dup ends/ if exit then 1- 2671 | repeat ; 2672 | 2673 | : starts./ ( a n -- f ) 2674 | 2 < if drop 0 exit then 2675 | 2 s" ./" str= ; 2676 | 2677 | : starts../ ( a n -- f ) 2678 | 3 < if drop 0 exit then 2679 | 3 s" ../" str= ; 2680 | 2681 | 0 value sourcefilename& 2682 | 0 value sourcefilename# 2683 | : sourcefilename ( -- a n ) sourcefilename& sourcefilename# ; 2684 | : sourcefilename! ( a n -- ) to sourcefilename# to sourcefilename& ; 2685 | : sourcedirname ( -- a n ) sourcefilename dirname ; 2686 | 2687 | : include-file ( fh -- ) 2688 | dup file-size throw 2689 | dup allocate throw 2690 | swap over >r 2691 | rot read-file throw 2692 | r@ swap evaluate 2693 | r> free throw ; 2694 | 2695 | : raw-included ( a n -- ) 2696 | r/o open-file throw 2697 | dup >r include-file 2698 | r> close-file throw ; 2699 | 2700 | 0 value included-files 2701 | 2702 | : path-join { a a# b b# -- a n } 2703 | b if 2704 | b c@ [char] / = if 0 to a# then 2705 | then 2706 | a# b# + { r# } r# cell+ cell+ allocate throw { r } 2707 | 2 cells +to r 2708 | begin b b# starts./ while 2709 | 2 +to b -2 +to b# 2710 | a# b# + to r# 2711 | repeat 2712 | begin b b# starts../ a# 0<> and while 2713 | 3 +to b -3 +to b# 2714 | a a# dirname to a# to a 2715 | a# b# + to r# 2716 | repeat 2717 | a r a# cmove b r a# + b# cmove 2718 | r# r cell - ! 2719 | r r# ; 2720 | : include+ 2 cells - { a } 2721 | included-files a ! a to included-files ; 2722 | 2723 | forth definitions internals 2724 | 2725 | : included ( a n -- ) 2726 | sourcefilename >r >r 2727 | >r >r sourcedirname r> r> path-join 2dup sourcefilename! 2728 | ['] raw-included catch if 2729 | ." Error including: " sourcefilename type cr 2730 | -38 throw 2731 | then 2732 | sourcefilename& include+ 2733 | r> r> sourcefilename! ; 2734 | 2735 | : include ( "name" -- ) bl parse included ; 2736 | 2737 | : included? { a n -- f } 2738 | sourcedirname a n path-join to n to a 2739 | included-files begin dup while 2740 | dup cell+ cell+ over cell+ @ a n str= if 2741 | a 2 cells - free throw drop -1 exit 2742 | then @ 2743 | repeat 2744 | a 2 cells - free throw ; 2745 | 2746 | : required ( a n -- ) 2dup included? if 2drop else included then ; 2747 | : needs ( "name" -- ) bl parse required ; 2748 | 2749 | : file-exists? ( "name" -- f ) r/o open-file if drop 0 else close-file throw -1 then ; 2750 | 2751 | forth 2752 | ( Block Files ) 2753 | internals definitions 2754 | : clobber-line ( a -- a' ) dup 63 blank 63 + nl over c! 1+ ; 2755 | : clobber ( a -- ) 15 for clobber-line next drop ; 2756 | 0 value block-dirty 2757 | create block-data 1024 allot 2758 | forth definitions internals 2759 | 2760 | -1 value block-fid variable scr -1 value block-id 2761 | : open-blocks ( a n -- ) 2762 | block-fid 0< 0= if block-fid close-file throw -1 to block-fid then 2763 | 2dup r/w open-file if drop r/w create-file throw else nip nip then to block-fid ; 2764 | : use ( "name" -- ) bl parse open-blocks ; 2765 | defer default-use 2766 | internals definitions 2767 | : common-default-use s" blocks.fb" open-blocks ; 2768 | ' common-default-use is default-use 2769 | : use?! block-fid 0< if default-use then ; 2770 | : grow-blocks ( n -- ) 1024 * block-fid file-size throw max block-fid resize-file throw ; 2771 | forth definitions internals 2772 | : save-buffers 2773 | block-dirty if 2774 | block-id grow-blocks block-id 1024 * block-fid reposition-file throw 2775 | block-data 1024 block-fid write-file throw 2776 | block-fid flush-file throw 2777 | 0 to block-dirty 2778 | then ; 2779 | : block ( n -- a ) use?! dup block-id = if drop block-data exit then 2780 | save-buffers dup grow-blocks 2781 | dup 1024 * block-fid reposition-file throw 2782 | block-data clobber 2783 | block-data 1024 block-fid read-file throw drop 2784 | to block-id block-data ; 2785 | : buffer ( n -- a ) use?! dup block-id = if drop block-data exit then 2786 | save-buffers to block-id block-data ; 2787 | : empty-buffers -1 to block-id ; 2788 | : update -1 to block-dirty ; 2789 | : flush save-buffers empty-buffers ; 2790 | 2791 | ( Loading ) 2792 | : load ( n -- ) block 1024 evaluate ; 2793 | : thru ( a b -- ) over - 1+ for aft dup >r load r> 1+ then next drop ; 2794 | 2795 | ( Utility ) 2796 | : copy ( from to -- ) 2797 | swap block pad 1024 cmove pad swap block 1024 cmove update ; 2798 | 2799 | ( Editing ) 2800 | : list ( n -- ) scr ! ." Block " scr @ . cr scr @ block 2801 | 15 for dup 63 type [char] | emit space 15 r@ - . cr 64 + next drop ; 2802 | internals definitions 2803 | : @line ( n -- ) 64 * scr @ block + ; 2804 | : e' ( n -- ) @line clobber-line drop update ; 2805 | forth definitions internals 2806 | vocabulary editor also editor definitions 2807 | : l scr @ list ; : n 1 scr +! l ; : p -1 scr +! l ; 2808 | : wipe 15 for r@ e' next l ; : e e' l ; 2809 | : d ( n -- ) dup 1+ @line swap @line 15 @line over - cmove 15 e ; 2810 | : r ( n "line" -- ) 0 parse 64 min rot dup e @line swap cmove l ; 2811 | : a ( n "line" -- ) dup @line over 1+ @line 16 @line over - cmove> r ; 2812 | only forth definitions 2813 | ( ANSI Codes ) 2814 | vocabulary ansi ansi definitions 2815 | : esc 27 emit ; : bel 7 emit ; 2816 | : clear-to-eol esc ." [0K" ; 2817 | : scroll-down esc ." D" ; 2818 | : scroll-up esc ." M" ; 2819 | : hide esc ." [?25l" ; 2820 | : show esc ." [?25h" ; 2821 | : terminal-save esc ." [?1049h" ; 2822 | : terminal-restore esc ." [?1049l" ; 2823 | 2824 | forth definitions ansi 2825 | : fg ( n -- ) esc ." [38;5;" n. ." m" ; 2826 | : bg ( n -- ) esc ." [48;5;" n. ." m" ; 2827 | : normal esc ." [0m" ; 2828 | : at-xy ( x y -- ) esc ." [" 1+ n. ." ;" 1+ n. ." H" ; 2829 | : page esc ." [2J" esc ." [H" ; 2830 | : set-title ( a n -- ) esc ." ]0;" type bel ; 2831 | forth 2832 | ( Lazy loaded visual editor. ) 2833 | 2834 | : visual r| 2835 | 2836 | also DEFINED? termios [IF] termios [THEN] 2837 | also internals 2838 | also ansi 2839 | also forth 2840 | current @ 2841 | vocabulary visual visual definitions 2842 | vocabulary insides insides definitions 2843 | 2844 | 256 constant max-path 2845 | create filename max-path allot 0 value filename# 2846 | 0 value fileh 2847 | 2848 | 10 constant start-size 2849 | start-size allocate throw value text 2850 | start-size value capacity 2851 | 0 value length 2852 | 0 value caret 2853 | 2854 | : up ( n -- n ) begin dup 0 > over text + c@ nl <> and while 1- repeat 1- 0 max ; 2855 | : nup ( n -- n ) 10 for up next ; 2856 | : down ( n -- n ) begin dup length < over text + c@ nl <> and while 1+ repeat 1+ length min ; 2857 | : ndown ( n -- n ) 10 for down next ; 2858 | 2859 | : update 2860 | caret nup dup 0<> if 1+ 1+ then { before } 2861 | before ndown ndown { after } 2862 | page 2863 | text before + caret before - crtype 2864 | caret length < text caret + c@ nl <> and if 2865 | 1 bg text caret + c@ emit normal 2866 | text caret + 1+ after caret - 1- 0 max crtype 2867 | else 2868 | 1 bg space normal 2869 | text caret + after caret - crtype 2870 | then normal 2871 | ; 2872 | 2873 | : insert ( ch -- ) 2874 | length capacity = if text capacity 1+ 2* >r r@ 1+ resize throw to text r> to capacity then 2875 | text caret + dup 1+ length caret - cmove> 2876 | text caret + c! 2877 | 1 +to caret 2878 | 1 +to length 2879 | update 2880 | ; 2881 | 2882 | : handle-esc 2883 | key 2884 | dup [char] [ = if drop 2885 | key 2886 | dup [char] A = if drop caret up to caret update exit then 2887 | dup [char] B = if drop caret down to caret update exit then 2888 | dup [char] C = if drop caret 1+ length min to caret update exit then 2889 | dup [char] D = if drop caret 1- 0 max to caret update exit then 2890 | dup [char] 5 = if drop key drop caret 8 for up next to caret update exit then 2891 | dup [char] 6 = if drop key drop caret 8 for down next to caret update exit then 2892 | drop 2893 | exit 2894 | then 2895 | drop 2896 | ; 2897 | 2898 | : delete 2899 | length caret > if 2900 | text caret + dup 1+ swap length caret - 1- 0 max cmove 2901 | -1 +to length 2902 | update 2903 | then 2904 | ; 2905 | 2906 | : backspace 2907 | caret 0 > if 2908 | -1 +to caret 2909 | delete 2910 | then 2911 | ; 2912 | 2913 | : load ( a n -- ) 2914 | 0 to caret 2915 | dup to filename# 2916 | filename swap cmove 2917 | filename filename# r/o open-file 0= if 2918 | to fileh 2919 | fileh file-size throw to capacity 2920 | text capacity 1+ resize throw to text 2921 | capacity to length 2922 | text length fileh read-file throw drop 2923 | fileh close-file throw 2924 | else 2925 | drop 2926 | 0 to capacity 2927 | 0 to length 2928 | then 2929 | ; 2930 | 2931 | : save 2932 | filename filename# w/o create-file throw to fileh 2933 | text length fileh write-file throw 2934 | fileh close-file throw 2935 | ; 2936 | 2937 | : quit-edit 2938 | page filename filename# type cr ." SAVE? " 2939 | begin 2940 | key 95 and 2941 | dup [char] Y = if drop save 123 throw then 2942 | dup [char] N = if drop 123 throw then 2943 | drop 2944 | again 2945 | ; 2946 | 2947 | : handle-key ( ch -- ) 2948 | dup 27 = if drop handle-esc exit then 2949 | dup [char] D [char] @ - = if delete exit then 2950 | dup [char] H [char] @ - = over 127 = or if drop backspace exit then 2951 | dup [char] L [char] @ - = if drop update exit then 2952 | dup [char] S [char] @ - = if drop save update exit then 2953 | dup [char] X [char] @ - = if drop quit-edit then 2954 | dup [char] Q [char] @ - = if drop quit-edit then 2955 | dup 13 = if drop nl insert exit then 2956 | dup bl >= if insert else drop then 2957 | ; 2958 | 2959 | : ground depth 0<> throw ; 2960 | : step *key handle-key ground ; 2961 | 2962 | DEFINED? raw-mode 0= [IF] 2963 | : raw-mode ; 2964 | : normal-mode ; 2965 | [THEN] 2966 | 2967 | : run 2968 | raw-mode update 2969 | begin 2970 | ['] step catch 2971 | dup 123 = if drop normal-mode page exit then 2972 | if ." FAILURE!" then 2973 | again 2974 | ; 2975 | 2976 | visual definitions insides 2977 | 2978 | : edit ( ) bl parse load run ; 2979 | 2980 | previous previous previous previous current ! visual 2981 | | evaluate ; 2982 | ( Add a yielding task so pause yields ) 2983 | internals definitions 2984 | : yield-step raw-yield yield ; 2985 | ' yield-step 100 100 task yield-task 2986 | yield-task start-task 2987 | forth definitions 2988 | 2989 | ( Set up Basic I/O ) 2990 | internals definitions also serial 2991 | : serial-type ( a n -- ) Serial.write drop ; 2992 | : serial-key ( -- n ) 2993 | begin pause Serial.available until 0 >r rp@ 1 Serial.readBytes drop r> ; 2994 | : serial-key? ( -- n ) Serial.available ; 2995 | 2996 | ( Set up M5Cardputer I/O ) 2997 | : m5-type ( a n -- ) M5Display.write drop ; 2998 | : m5-key ( -- n ) 2999 | begin pause M5Keyboard.available until 0 >r rp@ 1 M5Keyboard.readBytes drop r> ; 3000 | : m5-key? ( -- n ) M5Keyboard.available ; 3001 | variable m5write 1 m5write ! 3002 | variable m5read 1 m5read ! 3003 | also forth definitions 3004 | : default-type ( a n -- ) m5write @ 0 = if serial-type else m5-type then ; 3005 | : default-key ( -- n ) m5read @ 0 = if serial-key else m5-key then ; 3006 | : default-key? ( -- n ) m5read @ 0 = if serial-key? else m5-key? then ; 3007 | : m5type-on ( -- ) 1 m5write ! ; 3008 | : m5type-off ( -- ) 0 m5write ! ; 3009 | : m5key-on ( -- ) 1 m5read ! ; 3010 | : m5key-off ( -- ) 0 m5read ! ; 3011 | : m5gfx-on ( -- ) 1 m5gfxVisible ; 3012 | : m5gfx-off ( -- ) 0 m5gfxVisible ; 3013 | : home ( -- ) m5Home ; 3014 | : locate ( n n -- ) m5SetCursor ; 3015 | : palette ( n n n n -- ) m5gfxSetPaletteColor ; 3016 | : fillscreen ( n -- ) m5gfxFillScreen ; 3017 | : screenUpdate ( -- ) lcdUpdate ; 3018 | : gcls ( -- ) 0 m5gfxFillScreen screenUpdate ; 3019 | : pset ( n n n -- ) m5gfxPset ; 3020 | : vline ( n n n n -- ) m5gfxDrawFastVLine ; 3021 | : hline ( n n n n -- ) m5gfxDrawFastHLine ; 3022 | : rect ( n n n n n -- ) m5gfxDrawRect ; 3023 | : frect ( n n n n n -- ) m5gfxFillRect ; 3024 | : rrect ( n n n n n n -- ) m5gfxDrawRoundRect ; 3025 | : frrect ( n n n n n n -- ) m5gfxFillRoundRect ; 3026 | : circle ( n n n n -- ) m5gfxDrawCircle ; 3027 | : fcircle ( n n n n -- ) m5gfxFillCircle ; 3028 | : ellipsis ( n n n n n -- ) m5gfxDrawEllipse ; 3029 | : fellipsis ( n n n n n -- ) m5gfxFillEllipse ; 3030 | : line ( n n n n n -- ) m5gfxDrawLine ; 3031 | : triangle ( n n n n n n n -- ) m5gfxDrawTriangle ; 3032 | : ftriangle ( n n n n n n n -- ) m5gfxFillTriangle ; 3033 | : bezier ( n n n n n n n -- ) m5gfxDrawBezier ; 3034 | : bezier4 ( n n n n n n n n n -- ) m5gfxDrawBezier4 ; 3035 | : arc ( n n n n n n n -- ) m5gfxDrawArc ; 3036 | : farc ( n n n n n n n -- ) m5gfxFillArc ; 3037 | ( gpio ) 3038 | : setgpio ( n -- ) M5Gpio.setGpio ; 3039 | : resetgpio ( n -- ) M5Gpio.resetGpio ; 3040 | : getgpio ( n -- ) M5Gpio.getGpio ; 3041 | 3042 | ' default-type is type 3043 | ' default-key is key 3044 | ' default-key? is key? 3045 | ' raw-terminate is terminate 3046 | only forth definitions 3047 | 3048 | also ledc also serial also SPIFFS 3049 | 3050 | ( Map Arduino / ESP32 things to shorter names. ) 3051 | : pin ( n pin# -- ) swap digitalWrite ; 3052 | : adc ( n -- n ) analogRead ; 3053 | : duty ( n n -- ) 255 min 8191 255 */ ledcWrite ; 3054 | : freq ( n n -- ) 1000 * 13 ledcSetup drop ; 3055 | : tone ( n n -- ) 1000 * ledcWriteTone drop ; 3056 | 3057 | ( Basic Ardiuno Constants ) 3058 | 0 constant LOW 3059 | 1 constant HIGH 3060 | 1 constant INPUT 3061 | 2 constant OUTPUT 3062 | 2 constant LED 3063 | 3064 | ( Startup Setup ) 3065 | -1 echo ! 3066 | 115200 Serial.begin 3067 | 100 ms 3068 | -1 z" /spiffs" 10 SPIFFS.begin drop 3069 | 3070 | ( set M5Cardputer GPIO ) 3071 | 0 constant GPIO0 ( Cardputer Button B0 ) 3072 | 1 constant GPIO1 ( Grove PortA G1 ) 3073 | 2 constant GPIO2 ( Grove PortA G2 ) 3074 | GPIO0 INPUT pinMode 3075 | GPIO1 OUTPUT pinMode 3076 | GPIO2 OUTPUT pinMode 3077 | : m5button? ( -- n ) GPIO0 digitalRead 0 = if 1 else 0 then ; 3078 | ( setup M5Cardputer console ) 3079 | : m5autoexec s" /spiffs/autoexec.fs" 2dup file-exists? if included else 2drop then ; 3080 | : m5keyboardchk m5button? 0= if m5key-off else m5key-on m5autoexec then ; 3081 | m5keyboardchk 3082 | m5gfx-off 3083 | led OUTPUT pinMode 3084 | high led pin 3085 | 3086 | 3087 | internals definitions also ESP 3088 | : esp32-stats 3089 | getChipModel z>s type ." " 3090 | getCpuFreqMHz . ." MHz " 3091 | getChipCores . ." cores " 3092 | getFlashChipSize . ." bytes flash" cr 3093 | ." System Heap: " getFreeHeap getHeapSize free. cr 3094 | ." " getMaxAllocHeap . ." bytes max contiguous" cr ; 3095 | ' esp32-stats internals boot-prompt ! 3096 | only forth definitions 3097 | 3098 | ( Setup entry ) 3099 | internals : ok ." ESP32forth" raw-ok ; forth 3100 | ( Lazy loaded HTTP Daemon ) 3101 | : httpd r| 3102 | 3103 | vocabulary httpd httpd definitions 3104 | also sockets 3105 | also internals 3106 | 3107 | 1 constant max-connections 3108 | 2048 constant chunk-size 3109 | create chunk chunk-size allot 3110 | 0 value chunk-filled 3111 | 256 constant body-chunk-size 3112 | create body-chunk body-chunk-size allot 3113 | 0 value body-1st-read 3114 | 0 value body-read 3115 | 3116 | -1 value sockfd -1 value clientfd 3117 | sockaddr httpd-port sockaddr client variable client-len 3118 | 3119 | : client-type ( a n -- ) clientfd write-file throw ; 3120 | : client-read ( -- n ) 0 >r rp@ 1 clientfd read-file throw 1 <> throw ; 3121 | : client-emit ( ch -- ) >r rp@ 1 client-type rdrop ; 3122 | : client-cr 13 client-emit nl client-emit ; 3123 | 3124 | : server ( port -- ) 3125 | httpd-port ->port! ." Listening on port " httpd-port ->port@ . cr 3126 | AF_INET SOCK_STREAM 0 socket to sockfd 3127 | ( sockfd SOL_SOCKET SO_REUSEADDR 1 >r rp@ 4 setsockopt rdrop throw ) 3128 | sockfd non-block throw 3129 | sockfd httpd-port sizeof(sockaddr_in) bind throw 3130 | sockfd max-connections listen throw 3131 | ; 3132 | 3133 | : upper ( ch -- ch ) 3134 | dup [char] a >= over [char] z <= and if 95 and then ; 3135 | : strcase= ( a n a n -- f ) 3136 | >r swap r@ <> if rdrop 2drop 0 exit then r> 3137 | for aft 3138 | 2dup c@ upper swap c@ upper <> if rdrop 2drop 0 exit then 3139 | 1+ swap 1+ swap 3140 | then next 3141 | 2drop -1 3142 | ; 3143 | 3144 | variable goal variable goal# 3145 | : end< ( n -- f ) chunk-filled < ; 3146 | : in@<> ( n ch -- f ) >r chunk + c@ r> <> ; 3147 | : skipto ( n ch -- n ) 3148 | >r begin dup r@ in@<> over end< and while 1+ repeat rdrop ; 3149 | : skipover ( n ch -- n ) skipto 1+ ; 3150 | : eat ( n ch -- n a n ) >r dup r> skipover swap 2dup - 1- >r chunk + r> ; 3151 | : crnl= ( n -- f ) dup chunk + c@ 13 = swap 1+ chunk + c@ nl = and ; 3152 | : header ( a n -- a n ) 3153 | goal# ! goal ! 0 nl skipover 3154 | begin dup end< while 3155 | dup crnl= if drop chunk 0 exit then 3156 | [char] : eat goal @ goal# @ strcase= if 1+ 13 eat rot drop exit then 3157 | nl skipover 3158 | repeat drop chunk 0 3159 | ; 3160 | : content-length ( -- n ) 3161 | s" Content-Length" header s>number? 0= if 0 then ; 3162 | : body ( -- a n ) ( reads a part of body ) 3163 | body-1st-read if 3164 | body-read content-length >= if 3165 | 0 0 exit 3166 | then 3167 | body-chunk body-chunk-size clientfd read-file throw dup +to body-read 3168 | body-chunk swap exit 3169 | then 3170 | -1 to body-1st-read 3171 | 0 to body-read 3172 | 0 nl skipover 3173 | begin dup end< while 3174 | dup crnl= if 3175 | 2 + chunk-filled over - swap chunk + swap 3176 | dup +to body-read exit 3177 | then 3178 | nl skipover 3179 | repeat drop chunk 0 3180 | ; 3181 | : completed? ( -- f ) 3182 | 0 begin dup end< while 3183 | dup crnl= if drop -1 exit then 3184 | nl skipover 3185 | repeat drop 0 3186 | ; 3187 | : read-headers 3188 | 0 to body-1st-read 3189 | 0 to chunk-filled 3190 | begin completed? 0= while 3191 | chunk chunk-filled + chunk-size chunk-filled - 3192 | clientfd read-file throw +to chunk-filled 3193 | repeat 3194 | ; 3195 | 3196 | : handleClient 3197 | clientfd close-file drop 3198 | -1 to clientfd 3199 | sockfd client client-len sockaccept 3200 | dup 0< if drop 0 exit then 3201 | to clientfd 3202 | chunk chunk-size erase 3203 | read-headers 3204 | -1 3205 | ; 3206 | 3207 | : hasHeader ( a n -- f ) 2drop header 0 0 strcase= 0= ; 3208 | : method ( -- a n ) 0 bl eat rot drop ; 3209 | : path ( -- a n ) 0 bl skipover bl eat rot drop ; 3210 | : send ( a n -- ) client-type ; 3211 | 3212 | : response ( mime$ result$ status -- ) 3213 | s" HTTP/1.0 " client-type <# #s #> client-type 3214 | bl client-emit client-type client-cr 3215 | s" Content-type: " client-type client-type client-cr 3216 | client-cr ; 3217 | : ok-response ( mime$ -- ) s" OK" 200 response ; 3218 | : bad-response ( -- ) s" text/plain" s" Bad Request" 400 response ; 3219 | : notfound-response ( -- ) s" text/plain" s" Not Found" 404 response ; 3220 | 3221 | only forth definitions 3222 | httpd 3223 | | evaluate ; 3224 | ( Lazy loaded Server Terminal ) 3225 | 3226 | defer web-interface 3227 | :noname r~ 3228 | httpd 3229 | also streams also httpd 3230 | vocabulary web-interface also web-interface definitions 3231 | 3232 | r| 3233 | 3234 | 3235 | esp32forth 3236 | 3257 | 3258 | 3259 | 3260 |

ESP32forth v7

3261 | Upload File:
3262 | 3263 | 3264 | 3265 | 3266 | 3267 |
3268 | 3269 |
3270 | 3322 | | constant index-html# constant index-html 3323 | 3324 | variable webserver 3325 | 2000 constant out-size 3326 | 200 stream input-stream 3327 | out-size stream output-stream 3328 | create out-string out-size 1+ allot align 3329 | 3330 | : handle-index 3331 | s" text/html" ok-response 3332 | index-html index-html# send 3333 | ; 3334 | 3335 | : handle-input 3336 | begin body dup >r input-stream >stream pause r> 0= until 3337 | out-string out-size output-stream stream> 3338 | s" text/plain" ok-response 3339 | out-string z>s send 3340 | ; 3341 | 3342 | : serve-type ( a n -- ) output-stream >stream ; 3343 | : serve-key ( -- n ) input-stream stream>ch ; 3344 | 3345 | : handle1 3346 | handleClient if 3347 | s" /" path str= if handle-index exit then 3348 | s" /input" path str= if handle-input exit then 3349 | notfound-response 3350 | then 3351 | ; 3352 | 3353 | : do-serve begin handle1 pause again ; 3354 | ' do-serve 1000 1000 task webserver-task 3355 | 3356 | : server ( port -- ) 3357 | server 3358 | ['] serve-key is key 3359 | ['] serve-type is type 3360 | webserver-task start-task 3361 | ; 3362 | 3363 | only forth definitions 3364 | web-interface 3365 | ~ evaluate ; is web-interface 3366 | 3367 | ( Lazy loaded Server Terminal ) 3368 | 3369 | :noname [ ' web-interface >body @ ] literal execute 3370 | r| 3371 | also streams also sockets also WiFi also web-interface 3372 | 3373 | : login ( z z -- ) 3374 | WIFI_MODE_STA Wifi.mode 3375 | WiFi.begin begin WiFi.localIP 0= while 100 ms repeat WiFi.localIP ip. cr 3376 | z" forth" MDNS.begin if ." MDNS started" else ." MDNS failed" then cr ; 3377 | : webui ( z z -- ) login 80 server ; 3378 | 3379 | only forth definitions 3380 | web-interface 3381 | | evaluate ; is web-interface 3382 | : login web-interface forth r| login | evaluate ; 3383 | : webui web-interface forth r| webui | evaluate ; 3384 | vocabulary registers registers definitions 3385 | 3386 | ( Tools for working with bit masks ) 3387 | : m! ( val shift mask a -- ) 3388 | dup >r @ over invert and >r >r lshift r> and r> or r> ! ; 3389 | : m@ ( shift mask a -- val ) @ and swap rshift ; 3390 | 3391 | only forth definitions 3392 | ( Lazy loaded Telnet ) 3393 | : telnetd r| 3394 | 3395 | vocabulary telnetd telnetd definitions also sockets 3396 | 3397 | -1 value sockfd -1 value clientfd 3398 | sockaddr telnet-port sockaddr client variable client-len 3399 | 3400 | defer broker 3401 | 3402 | : telnet-emit ( ch -- ) >r rp@ 1 clientfd write-file rdrop if broker then ; 3403 | : telnet-type ( a n -- ) for aft dup c@ telnet-emit 1+ then next drop ; 3404 | : telnet-key ( -- n ) 0 >r rp@ 1 clientfd read-file swap 1 <> or if rdrop broker then r> ; 3405 | 3406 | : connection ( n -- ) 3407 | dup 0< if drop exit then to clientfd 3408 | 0 echo ! 3409 | ['] telnet-key is key 3410 | ['] telnet-type is type quit ; 3411 | 3412 | : wait-for-connection 3413 | begin 3414 | sockfd client client-len sockaccept 3415 | dup 0 >= if exit else drop then 3416 | again 3417 | ; 3418 | 3419 | : broker-connection 3420 | rp0 rp! sp0 sp! 3421 | begin 3422 | ['] default-key is key ['] default-type is type 3423 | -1 echo ! 3424 | ." Listening on port " telnet-port ->port@ . cr 3425 | wait-for-connection 3426 | ." Connected: " dup . cr connection 3427 | again ; 3428 | ' broker-connection is broker 3429 | 3430 | : server ( port -- ) 3431 | telnet-port ->port! 3432 | AF_INET SOCK_STREAM 0 socket to sockfd 3433 | sockfd non-block throw 3434 | sockfd telnet-port sizeof(sockaddr_in) bind throw 3435 | sockfd 1 listen throw broker ; 3436 | 3437 | only forth definitions 3438 | telnetd 3439 | | evaluate ; 3440 | internals DEFINED? assembler-source [IF] 3441 | assembler-source evaluate 3442 | [THEN] forth 3443 | internals DEFINED? xtensa-assembler-source [IF] 3444 | xtensa-assembler-source evaluate 3445 | [THEN] forth 3446 | internals DEFINED? riscv-assembler-source [IF] 3447 | riscv-assembler-source evaluate 3448 | [THEN] forth 3449 | 3450 | internals DEFINED? camera-source [IF] 3451 | camera-source evaluate 3452 | [THEN] forth 3453 | 3454 | internals DEFINED? interrupts-source [IF] 3455 | interrupts-source evaluate 3456 | [THEN] forth 3457 | 3458 | internals DEFINED? oled-source [IF] 3459 | oled-source evaluate 3460 | [THEN] forth 3461 | 3462 | DEFINED? rmt-builtins [IF] 3463 | vocabulary rmt rmt definitions 3464 | transfer rmt-builtins 3465 | forth definitions 3466 | [THEN] 3467 | 3468 | internals DEFINED? serial-bluetooth-source [IF] 3469 | serial-bluetooth-source evaluate 3470 | [THEN] forth 3471 | 3472 | internals DEFINED? spi-flash-source [IF] 3473 | spi-flash-source evaluate 3474 | [THEN] forth 3475 | internals definitions 3476 | 3477 | ( Change default block source on arduino ) 3478 | : arduino-default-use s" /spiffs/blocks.fb" open-blocks ; 3479 | ' arduino-default-use is default-use 3480 | 3481 | ( Setup remember file ) 3482 | : arduino-remember-filename s" /spiffs/myforth" ; 3483 | ' arduino-remember-filename is remember-filename 3484 | 3485 | ( Check for autoexec.fs and run if present. 3486 | Failing that, try to revive save image. ) 3487 | : autoexec 3488 | ( Allow skip start files if key hit within 100 ms ) 3489 | 10 for key? if rdrop exit then 10 ms next 3490 | s" /spiffs/autoexec.fs" 2dup file-exists? 3491 | if included else 2drop then 3492 | ['] revive catch drop ; 3493 | ' autoexec ( leave on the stack for fini.fs ) 3494 | 3495 | forth definitions 3496 | internals definitions 3497 | ( TODO: Figure out why this has to happen so late. ) 3498 | transfer internals-builtins 3499 | forth definitions internals 3500 | ( Bring a forth to the top of the vocabulary. ) 3501 | transfer forth 3502 | ( Move heap to save point, with a gap. ) 3503 | setup-saving-base 3504 | forth 3505 | execute ( assumes an xt for autoboot is on the dstack ) 3506 | ok 3507 | )"""; 3508 | 3509 | // Work around lack of ftruncate 3510 | static cell_t ResizeFile(cell_t fd, cell_t size) { 3511 | struct stat st; 3512 | char buf[256]; 3513 | cell_t t = fstat(fd, &st); 3514 | if (t < 0) { return errno; } 3515 | if (size < st.st_size) { 3516 | // TODO: Implement truncation 3517 | return ENOSYS; 3518 | } 3519 | cell_t oldpos = lseek(fd, 0, SEEK_CUR); 3520 | if (oldpos < 0) { return errno; } 3521 | t = lseek(fd, 0, SEEK_END); 3522 | if (t < 0) { return errno; } 3523 | memset(buf, 0, sizeof(buf)); 3524 | while (st.st_size < size) { 3525 | cell_t len = sizeof(buf); 3526 | if (size - st.st_size < len) { 3527 | len = size - st.st_size; 3528 | } 3529 | t = write(fd, buf, len); 3530 | if (t != len) { 3531 | return errno; 3532 | } 3533 | st.st_size += t; 3534 | } 3535 | t = lseek(fd, oldpos, SEEK_SET); 3536 | if (t < 0) { return errno; } 3537 | return 0; 3538 | } 3539 | void setup() { 3540 | // for M5Cardputer 3541 | lcdInit(); // do disp->init() and createSprite() as eaarly as possible 3542 | lcdGfxInit(); 3543 | kbdInit(); 3544 | addLeds(); // init the RGB LED 3545 | // end "for M5Cardputer" 3546 | cell_t fh = heap_caps_get_free_size(MALLOC_CAP_INTERNAL); 3547 | cell_t hc = heap_caps_get_largest_free_block(MALLOC_CAP_INTERNAL); 3548 | if (fh - hc < MINIMUM_FREE_SYSTEM_HEAP) { 3549 | hc = fh - MINIMUM_FREE_SYSTEM_HEAP; 3550 | } 3551 | cell_t *heap = (cell_t *) malloc(hc); 3552 | forth_init(0, 0, heap, hc, boot, sizeof(boot)); 3553 | } 3554 | 3555 | void loop() { 3556 | g_sys->rp = forth_run(g_sys->rp); 3557 | } 3558 | -------------------------------------------------------------------------------- /src/theme_define.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file theme_define.h 3 | * @author Forairaaaaa 4 | * @brief 5 | * @version 0.6 6 | * @date 2023-09-20 7 | * 8 | * @copyright Copyright (c) 2023 9 | * 10 | */ 11 | #pragma once 12 | 13 | #define THEME_COLOR_BG (uint32_t)(0x333333) 14 | #define THEME_COLOR_SYSTEM_BAR (uint32_t)(0x99FF00) 15 | #define THEME_COLOR_SYSTEM_BAR_TEXT TFT_BLACK 16 | #define THEME_COLOR_KB_BAR TFT_LIGHTGREY 17 | #define THEME_COLOR_KB_BAR_ICON_BG TFT_DARKGREY 18 | #define THEME_COLOR_KB_BAR_ICON_TEXT TFT_WHITE 19 | #define THEME_COLOR_ICON (uint32_t)(0xE6E6E6) 20 | #define ICON_WIDTH 48 21 | #define ICON_GAP 20 22 | #define ICON_MARGIN_TOP 20 23 | #define ICON_TAG_MARGIN_TOP 5 24 | #define ICON_SELECTED_WIDTH 64 25 | #define FONT_BASIC &fonts::efontCN_16 26 | #define FONT_HEIGHT 16 27 | 28 | #define THEME_COLOR_KB_CAPS_LOCK TFT_SKYBLUE 29 | #define THEME_COLOR_KB_ALT TFT_YELLOW 30 | #define THEME_COLOR_KB_CTRL TFT_PINK 31 | #define THEME_COLOR_KB_FN TFT_ORANGE 32 | #define THEME_COLOR_KB_OPT TFT_DARKGREEN 33 | 34 | #define THEME_COLOR_REPL_TEXT TFT_WHITE 35 | // #define FONT_REPL &fonts::Font0 36 | #define FONT_REPL &fonts::efontCN_16 37 | #define FONT_SIZE_REPL 1 38 | // #define FONT_REPL_WIDTH _canvas->fontWidth() 39 | #define FONT_REPL_WIDTH 8 40 | #define FONT_REPL_HEIGHT 16 41 | 42 | -------------------------------------------------------------------------------- /tests/README: -------------------------------------------------------------------------------- 1 | 2 | This directory is intended for PlatformIO Test Runner and project tests. 3 | 4 | Unit Testing is a software testing method by which individual units of 5 | source code, sets of one or more MCU program modules together with associated 6 | control data, usage procedures, and operating procedures, are tested to 7 | determine whether they are fit for use. Unit testing finds problems early 8 | in the development cycle. 9 | 10 | More information about PlatformIO Unit Testing: 11 | - https://docs.platformio.org/en/latest/advanced/unit-testing/index.html 12 | --------------------------------------------------------------------------------