├── .formatter.exs ├── .gitignore ├── LICENSE ├── README.md ├── config └── config.exs ├── lib ├── ex_atom_vm.ex ├── mix │ └── tasks │ │ ├── check.ex │ │ ├── esp32_flash.ex │ │ ├── packbeam.ex │ │ ├── pico_flash.ex │ │ ├── stm32_flash.ex │ │ └── uf2create.ex └── packbeam.ex ├── mix.exs ├── priv ├── funcs.txt └── instructions.txt └── test ├── ex_atom_vm_test.exs └── test_helper.exs /.formatter.exs: -------------------------------------------------------------------------------- 1 | # Used by "mix format" 2 | [ 3 | inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"] 4 | ] 5 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # The directory Mix will write compiled artifacts to. 2 | /_build/ 3 | 4 | # If you run "mix test --cover", coverage assets end up here. 5 | /cover/ 6 | 7 | # The directory Mix downloads your dependencies sources to. 8 | /deps/ 9 | 10 | # Where third-party dependencies like ExDoc output generated docs. 11 | /doc/ 12 | 13 | # Ignore .fetch files in case you like to edit your project deps locally. 14 | /.fetch 15 | 16 | # If the VM crashes, it generates a dump, let's ignore it too. 17 | erl_crash.dump 18 | 19 | # Also ignore archive artifacts (built via "mix archive.build"). 20 | *.ez 21 | 22 | # Ignore package tarball (built via "mix hex.build"). 23 | exatomvm-*.tar 24 | 25 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ExAtomVM 2 | 3 | ExAtomVM provide a collection of [Mix](https://hexdocs.pm/mix/1.13/Mix.html) tasks that greatly simplify development and deployment of Elixir applications targeted for the AtomVM platform. 4 | 5 | The following operations are supported: 6 | 7 | * Packing compiled BEAM files into AVM files for use in AtomVM; 8 | * Flashing AVM files to micro-controllers (Currently, only ESP32 devices are supported). 9 | 10 | > Note. For information about how to use Mix plugins, see the [Mix](https://hexdocs.pm/mix/1.13/Mix.html) documentation. 11 | 12 | ## Dependencies 13 | 14 | To use this plugin to build packbeam files, you will need 15 | 16 | * [Erlang/OTP](https://erlang.org) 21, 22, or 23 17 | * [Elixir](https://elixir-lang.org) 1.13 (or higher) 18 | 19 | To flash an ExAtomVM project to an ESP32, you will need: 20 | 21 | * An ESP32 development module such as the Espressif DevKit C 22 | * A USB cable to connect the ESP32 development module to your workstation 23 | * [esptool](https://github.com/espressif/esptool) 24 | * (Optional) A serial console program, such as `minicom` 25 | 26 | Consult your local package manager for installation of these tools. 27 | 28 | ## Getting Started 29 | 30 | Start by creating a Mix project 31 | 32 | shell$ mix new my_project --module MyProject 33 | * creating README.md 34 | * creating .formatter.exs 35 | * creating .gitignore 36 | * creating mix.exs 37 | * creating lib 38 | * creating lib/my_project.ex 39 | * creating test 40 | * creating test/test_helper.exs 41 | * creating test/my_project_test.exs 42 | 43 | Your Mix project was created successfully. 44 | You can use "mix" to compile it, test it, and more: 45 | 46 | cd my_project 47 | mix test 48 | 49 | Run "mix help" for more commands. 50 | 51 | Edit the generated `mix.exs` to include the ExAtomVM dependency (`{:exatomvm, git: "https://github.com/atomvm/ExAtomVM/"}`), and add a properties list using the `atomvm` key containing a `start` and `flash_offset` entry: 52 | 53 | ## elixir 54 | defmodule MyProject.MixProject do 55 | use Mix.Project 56 | 57 | def project do 58 | [ 59 | app: :my_project, 60 | version: "0.1.0", 61 | elixir: "~> 1.13", 62 | start_permanent: Mix.env() == :prod, 63 | deps: deps(), 64 | atomvm: [ 65 | start: MyProject, 66 | flash_offset: 0x210000 67 | ] 68 | ] 69 | end 70 | 71 | # Run "mix help compile.app" to learn about applications. 72 | def application do 73 | [ 74 | extra_applications: [:logger] 75 | ] 76 | end 77 | 78 | # Run "mix help deps" to learn about dependencies. 79 | defp deps do 80 | [ 81 | {:exatomvm, git: "https://github.com/atomvm/ExAtomVM/"} 82 | # {:dep_from_hexpm, "~> 0.3.0"}, 83 | # {:dep_from_git, git: "https://github.com/elixir-lang/my_dep.git", tag: "0.1.0"} 84 | ] 85 | end 86 | end 87 | 88 | > Note. By convention, Mix dependencies are encapsulated in the private `deps` function in the project module (`mix.exs`). 89 | 90 | Edit the `my_project.ex` file so that it contains a `start` function: 91 | 92 | ## elixir 93 | defmodule MyProject do 94 | def start do 95 | :ok 96 | end 97 | end 98 | 99 | Run `mix deps.get` to download ExAtomVM into your `deps` directory: 100 | 101 | shell$ mix deps.get 102 | * Getting exatomvm (https://github.com/atomvm/ExAtomVM/) 103 | remote: Enumerating objects: 150, done. 104 | remote: Counting objects: 100% (29/29), done. 105 | remote: Compressing objects: 100% (17/17), done. 106 | remote: Total 150 (delta 14), reused 19 (delta 10), pack-reused 121 107 | origin/HEAD set to master 108 | 109 | Create a directory called `avm_deps` in the top level of your project directory: 110 | 111 | shell$ mkdir avm_deps 112 | 113 | Download a copy of the AtomVM-libs from the AtomVM Gitbub [release repository](https://github.com/atomvm/AtomVM/releases/). Extract the contents of this archive and copy the enclosed AVM files into your `avm_deps` directory. 114 | 115 | Afterwards, you should see something like: 116 | 117 | shell$ ls -l avm_deps 118 | total 264 119 | -rw-rw-r-- 1 frege wheel 11380 May 8 16:32 alisp.avm 120 | -rw-rw-r-- 1 frege wheel 48956 May 8 16:32 atomvmlib.avm 121 | -rw-rw-r-- 1 frege wheel 23540 May 8 16:32 eavmlib.avm 122 | -rw-rw-r-- 1 frege wheel 25456 May 8 16:32 estdlib.avm 123 | -rw-rw-r-- 1 frege wheel 1052 May 8 16:32 etest.avm 124 | -rw-rw-r-- 1 frege wheel 16356 May 8 16:32 exavmlib.avm 125 | 126 | Run the `atomvm.packbeam` Mix task to create a packbeam file: 127 | 128 | shell$ mix atomvm.packbeam 129 | ==> exatomvm 130 | Compiling 5 files (.ex) 131 | Generated exatomvm app 132 | ==> my_project 133 | Compiling 1 file (.ex) 134 | Generated my_project app 135 | 136 | The `my_project.avm` file should be created in the top level directory of your project: 137 | 138 | shell$ ls -l my_project.avm 139 | -rw-rw-r-- 1 frege wheel 144148 May 8 16:34 my_project.avm 140 | 141 | You can optionally use the [AtomVM Packbeam](https://github.com/atomvm/atomvm_packbeam) tool to view the contents of this AVM file. 142 | 143 | shell$ packbeam list my_project.avm 144 | Elixir.MyProject.beam * [500] 145 | Elixir.Mix.Tasks.Atomvm.Check.beam [5684] 146 | Elixir.Mix.Tasks.Atomvm.Packbeam.beam [5188] 147 | Elixir.ExAtomVM.PackBEAM.beam [3412] 148 | Elixir.ExAtomVM.beam [504] 149 | Elixir.Mix.Tasks.Atomvm.Esp32.Flash.beam [2048] 150 | atomvm.beam [412] 151 | console.beam [840] 152 | esp.beam [912] 153 | gpio.beam [1216] 154 | ... 155 | 156 | To flash your project to an ESP32 device, use the `atomvm.esp32.flash` mix task. You can optionally specify the USB device using the `--port` option:` 157 | 158 | shell% mix atomvm.esp32.flash --port /dev/tty.usbserial 159 | Generated my_project app 160 | esptool.py v3.2-dev 161 | Serial port /dev/tty.usbserial 162 | Connecting......... 163 | Chip is ESP32-D0WDQ6-V3 (revision 3) 164 | Features: WiFi, BT, Dual Core, 240MHz, VRef calibration in efuse, Coding Scheme None 165 | Crystal is 40MHz 166 | MAC: 30:c6:f7:2a:54:7c 167 | Uploading stub... 168 | Running stub... 169 | Stub running... 170 | Configuring flash size... 171 | Auto-detected Flash size: 4MB 172 | Flash will be erased from 0x00210000 to 0x00233fff... 173 | Writing at 0x00210000... (11 %) 174 | Writing at 0x00214000... (22 %) 175 | Writing at 0x00218000... (33 %) 176 | Writing at 0x0021c000... (44 %) 177 | Writing at 0x00220000... (55 %) 178 | Writing at 0x00224000... (66 %) 179 | Writing at 0x00228000... (77 %) 180 | Writing at 0x0022c000... (88 %) 181 | Writing at 0x00230000... (100 %) 182 | Wrote 147456 bytes at 0x00210000 in 13.0 seconds (91.0 kbit/s)... 183 | Hash of data verified. 184 | 185 | Leaving... 186 | Hard resetting via RTS pin... 187 | 188 | 189 | (Optional) To view the console output of your application, use a serial console program, such as `minicom`: 190 | 191 | shell$ minicom -D /dev/tty.usbserial 192 | rst:0x1 (POWERON_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT) 193 | configsip: 0, SPIWP:0xee 194 | clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00 195 | mode:DIO, clock div:2 196 | load:0x3fff0018,len:4 197 | load:0x3fff001c,len:6816 198 | ho 0 tail 12 room 4 199 | load:0x40078000,len:12108 200 | load:0x40080400,len:6664 201 | entry 0x40080774 202 | I (76) boot: Chip Revision: 3 203 | I (77) boot_comm: chip revision: 3, min. bootloader chip revision: 0 204 | I (42) boot: ESP-IDF v3.3.4-dirty 2nd stage bootloader 205 | I (42) boot: compile time 14:28:14 206 | I (42) boot: Enabling RNG early entropy source... 207 | I (47) boot: SPI Speed : 40MHz 208 | I (51) boot: SPI Mode : DIO 209 | I (55) boot: SPI Flash Size : 4MB 210 | I (59) boot: Partition Table: 211 | I (63) boot: ## Label Usage Type ST Offset Length 212 | I (70) boot: 0 nvs WiFi data 01 02 00009000 00006000 213 | I (77) boot: 1 phy_init RF data 01 01 0000f000 00001000 214 | I (85) boot: 2 factory factory app 00 00 00010000 001c0000 215 | I (92) boot: 3 lib.avm RF data 01 01 001d0000 00040000 216 | I (100) boot: 4 main.avm RF data 01 01 00210000 00100000 217 | I (107) boot: End of partition table 218 | I (112) boot_comm: chip revision: 3, min. application chip revision: 0 219 | I (119) esp_image: segment 0: paddr=0x00010020 vaddr=0x3f400020 size=0x2cb14 (183060) map 220 | I (194) esp_image: segment 1: paddr=0x0003cb3c vaddr=0x3ffb0000 size=0x034d4 ( 13524) load 221 | I (200) esp_image: segment 2: paddr=0x00040018 vaddr=0x400d0018 size=0xd38d8 (866520) map 222 | I (516) esp_image: segment 3: paddr=0x001138f8 vaddr=0x3ffb34d4 size=0x01524 ( 5412) load 223 | I (518) esp_image: segment 4: paddr=0x00114e24 vaddr=0x40080000 size=0x00400 ( 1024) load 224 | I (523) esp_image: segment 5: paddr=0x0011522c vaddr=0x40080400 size=0x17848 ( 96328) load 225 | I (573) esp_image: segment 6: paddr=0x0012ca7c vaddr=0x400c0000 size=0x00064 ( 100) load 226 | I (573) esp_image: segment 7: paddr=0x0012cae8 vaddr=0x50000000 size=0x00804 ( 2052) load 227 | I (595) boot: Loaded app from partition at offset 0x10000 228 | I (595) boot: Disabling RNG early entropy source... 229 | I (596) cpu_start: Pro cpu up. 230 | I (599) cpu_start: Application information: 231 | I (604) cpu_start: Project name: atomvvm-esp32 232 | I (610) cpu_start: App version: e34e0ed-dirty 233 | I (615) cpu_start: Compile time: Apr 3 2022 14:28:20 234 | I (621) cpu_start: ELF file SHA256: 30205fd9063bc42e... 235 | I (627) cpu_start: ESP-IDF: v3.3.4-dirty 236 | I (633) cpu_start: Starting app cpu, entry point is 0x40081410 237 | I (0) cpu_start: App cpu up. 238 | I (643) heap_init: Initializing. RAM available for dynamic allocation: 239 | I (650) heap_init: At 3FFAE6E0 len 00001920 (6 KiB): DRAM 240 | I (656) heap_init: At 3FFBAC98 len 00025368 (148 KiB): DRAM 241 | I (662) heap_init: At 3FFE0440 len 00003AE0 (14 KiB): D/IRAM 242 | I (669) heap_init: At 3FFE4350 len 0001BCB0 (111 KiB): D/IRAM 243 | I (675) heap_init: At 40097C48 len 000083B8 (32 KiB): IRAM 244 | I (681) cpu_start: Pro cpu start user code 245 | I (28) cpu_start: Starting scheduler on PRO CPU. 246 | I (0) cpu_start: Starting scheduler on APP CPU. 247 | 248 | ########################################################### 249 | 250 | ### ######## ####### ## ## ## ## ## ## 251 | ## ## ## ## ## ### ### ## ## ### ### 252 | ## ## ## ## ## #### #### ## ## #### #### 253 | ## ## ## ## ## ## ### ## ## ## ## ### ## 254 | ######### ## ## ## ## ## ## ## ## ## 255 | ## ## ## ## ## ## ## ## ## ## ## 256 | ## ## ## ####### ## ## ### ## ## 257 | 258 | ########################################################### 259 | 260 | I (130) AtomVM: Starting AtomVM revision 0.5.0 261 | I (130) AtomVM: Loaded BEAM partition main.avm at address 0x210000 (size=1048576 bytes) 262 | I (160) atomvm_adc: eFuse Two Point: NOT supported 263 | I (160) atomvm_adc: eFuse Vref: Supported 264 | I (160) AtomVM: Found startup beam Elixir.MyProject.beam 265 | I (160) AtomVM: Loaded BEAM partition lib.avm at address 0x1d0000 (size=262144 bytes) 266 | I (170) AtomVM: Starting Elixir.MyProject.beam... 267 | --- 268 | AtomVM finished with return value: ok 269 | I (180) AtomVM: AtomVM application terminated. Going to sleep forever ... 270 | 271 | ## Reference 272 | 273 | ### `mix.exs` Configuration 274 | 275 | To use this Mix plugin, add `ExAtomVM` to the dependencies list in your `mix.exs` project file. 276 | 277 | def project do [ 278 | ... 279 | deps: [ 280 | ... 281 | {:exatomvm, git: "https://github.com/atomvm/ExAtomVM/"}, 282 | ... 283 | ], 284 | ... 285 | atomvm: [ 286 | start: HelloWorld, 287 | flash_offset: 0x210000 288 | ] 289 | ] 290 | end 291 | 292 | In addition, you may specify AtomVM-specific configuration using the `atomvm` tag. The fields in this properties list are described in more detail below. 293 | 294 | ### The `atomvm.packbeam` task 295 | 296 | The `atomvm.packbeam` task is used to bundle your application into an AVM file that can be flashed to a micro-controller and executed by the AtomVM virtual machine. 297 | 298 | The `atomvm` properties list in the Mix project file (`mix.exs`) may contain the following entries related to this task: 299 | 300 | | Key | Type | Default | Value | 301 | |-----|------|----------|-------| 302 | | `start` | Module | - | The name of the module containing the `start/0` entrypoint function | 303 | 304 | Properties in the `mix.exs` file may be over-ridden on the command line using long-style flags (prefixed by `--`) by the same name as the properties key. For example, you can use the `--start` option to specify or override the `start` property in the above table. 305 | 306 | Example: 307 | 308 | shell$ mix atomvm.packbeam --start MyProject 309 | ==> exatomvm 310 | Compiling 5 files (.ex) 311 | Generated exatomvm app 312 | ==> my_project 313 | Compiling 1 file (.ex) 314 | Generated my_project app 315 | 316 | ### The `atomvm.esp32.flash` task 317 | 318 | The `atomvm.esp32.flash` task is used to flash your application to a micro-controller and executed by the AtomVM virtual machine. 319 | 320 | > Note. Before running this task, you must flash the AtomVM virtual machine to the device. See the [Getting Started](https://www.atomvm.net/doc/master/getting-started-guide.html) section if the [AtomVM documentation](https://www.atomvm.net/doc/master/) for information about how to flash the AtomVM image to a device. 321 | 322 | The `atomvm` properties list in the Mix project file (`mix.exs`) may contain the following entries related to this task: 323 | 324 | | Key | Type | Default | Value | 325 | |-----|------|----------|-------| 326 | | `flash_offset` | Address in hexademical format | 0x210000 | The name of the module containing the `start/0` entrypoint function | 327 | | `chip` | `esp32` | `esp32` | Chip type | 328 | | `port` | device path | `/dev/ttyUSB0` | Port to which device is connected on host computer | 329 | | `baud` | integer | 115200 | BAUD rate used when flashing to device | 330 | 331 | Properties in the `mix.exs` file may be over-ridden on the command line using long-style flags (prefixed by `--`) by the same name as the properties key. For example, you can use the `--port` option to specify or override the `port` property in the above table. 332 | 333 | If the `IDF_PATH` environment variable is set, then the `esptool.py` from the [IDF SDK](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/index.html) installation will be used to flash the application to the ESP32 device. Otherwise, this plugin will attempt to use the `esptool.py` program from the user's `PATH` environment variable. The [ESP Tool](https://github.com/espressif/esptool) Python3 application can be installed from source or via many popular package managers. Consult your local OS documentation for more information. 334 | 335 | Example: 336 | 337 | shell$ mix atomvm.esp32.flash --port /dev/tty.usbserial 338 | Generated my_project app 339 | esptool.py v3.2-dev 340 | Serial port /dev/tty.usbserial 341 | Connecting......... 342 | Chip is ESP32-D0WDQ6-V3 (revision 3) 343 | Features: WiFi, BT, Dual Core, 240MHz, VRef calibration in efuse, Coding Scheme None 344 | Crystal is 40MHz 345 | MAC: 30:c6:f7:2a:54:7c 346 | Uploading stub... 347 | Running stub... 348 | Stub running... 349 | Configuring flash size... 350 | Auto-detected Flash size: 4MB 351 | Flash will be erased from 0x00210000 to 0x00233fff... 352 | Writing at 0x00210000... (11 %) 353 | Writing at 0x00214000... (22 %) 354 | Writing at 0x00218000... (33 %) 355 | Writing at 0x0021c000... (44 %) 356 | Writing at 0x00220000... (55 %) 357 | Writing at 0x00224000... (66 %) 358 | Writing at 0x00228000... (77 %) 359 | Writing at 0x0022c000... (88 %) 360 | Writing at 0x00230000... (100 %) 361 | Wrote 147456 bytes at 0x00210000 in 13.0 seconds (91.0 kbit/s)... 362 | Hash of data verified. 363 | 364 | Leaving... 365 | Hard resetting via RTS pin... 366 | 367 | ### The `atomvm.stm32.flash` task 368 | 369 | The `atomvm.stm32.flash` task is used to flash your application to a micro-controller and executed by the AtomVM virtual machine. 370 | 371 | > Note. Before running this task, you must flash the AtomVM virtual machine to the device. See the [Getting Started](https://www.atomvm.net/doc/master/getting-started-guide.html) section if the [AtomVM documentation](https://www.atomvm.net/doc/master/) for information about how to flash the AtomVM image to a device. 372 | 373 | The `atomvm` properties list in the Mix project file (`mix.exs`) may contain the following entries related to this task: 374 | 375 | | Key | Type | Default | Value | 376 | |-----|------|----------|-------| 377 | | `stflash_path` | string | undefined | The full path to the `st-flash` utility, if not in users PATH | 378 | | `flash_offset` | Address in hexademical format | 0x8080000 | The beginning flash address to write to | 379 | 380 | Properties in the `mix.exs` file may be over-ridden on the command line using long-style flags (prefixed by `--`) by the same name as the properties key. For example, you can use the `--stflash_path` option to specify or override the `stflash_path` property in the above table. 381 | 382 | Example: 383 | 384 | shell$ mix atomvm.stm32.flash 385 | warning: GPIO.digital_write/2 is undefined (module GPIO is not available or is yet to be defined) 386 | lib/Blinky.ex:34 387 | 388 | warning: GPIO.set_pin_mode/2 is undefined (module GPIO is not available or is yet to be defined) 389 | lib/Blinky.ex:58 390 | 391 | warning: GPIO.set_pin_mode/2 is undefined (module GPIO is not available or is yet to be defined) 392 | lib/Blinky.ex:59 393 | 394 | warning: GPIO.set_pin_mode/2 is undefined (module GPIO is not available or is yet to be defined) 395 | lib/Blinky.ex:65 396 | 397 | warning: :atomvm.platform/0 is undefined (module :atomvm is not available or is yet to be defined) 398 | lib/Blinky.ex:48 399 | 400 | warning: :atomvm.platform/0 is undefined (module :atomvm is not available or is yet to be defined) 401 | lib/Blinky.ex:57 402 | 403 | st-flash 1.7.0 404 | 2023-10-31T10:47:20 INFO common.c: F42x/F43x: 256 KiB SRAM, 2048 KiB flash in at least 16 KiB pages. 405 | file Blinky.avm md5 checksum: 3dca925a9616d4d65dc9d87fbf19af, stlink checksum: 0x00767ad5 406 | 2023-10-31T10:47:20 INFO common.c: Attempting to write 156172 (0x2620c) bytes to stm32 address: 134742016 (0x8080000) 407 | EraseFlash - Sector:0x8 Size:0x20000 2023-10-31T10:47:22 INFO common.c: Flash page at addr: 0x08080000 erased 408 | EraseFlash - Sector:0x9 Size:0x20000 2023-10-31T10:47:24 INFO common.c: Flash page at addr: 0x080a0000 erased 409 | 2023-10-31T10:47:24 INFO common.c: Finished erasing 2 pages of 131072 (0x20000) bytes 410 | 2023-10-31T10:47:24 INFO common.c: Starting Flash write for F2/F4/F7/L4 411 | 2023-10-31T10:47:24 INFO flash_loader.c: Successfully loaded flash loader in sram 412 | 2023-10-31T10:47:24 INFO flash_loader.c: Clear DFSR 413 | 2023-10-31T10:47:24 INFO common.c: enabling 32-bit flash writes 414 | 2023-10-31T10:47:26 INFO common.c: Starting verification of write complete 415 | 2023-10-31T10:47:27 INFO common.c: Flash written and verified! jolly good! 416 | 417 | ### The `atomvm.pico.flash` task 418 | 419 | The `atomvm.pico.flash` task is used to flash your application to a micro-controller and executed by the AtomVM virtual machine. 420 | 421 | > Note. Before running this task, you must flash the AtomVM virtual machine to the device. See the [Getting Started](https://www.atomvm.net/doc/master/getting-started-guide.html) section if the [AtomVM documentation](https://www.atomvm.net/doc/master/) for information about how to flash the AtomVM image to a device. 422 | 423 | The `atomvm` properties list in the Mix project file (`mix.exs`) may contain the following entries related to this task: 424 | 425 | | Key | Type | Default | Value | 426 | |-----|------|----------|-------| 427 | | `pico_path` | string | "/run/media/${USER}/RPI-RP2" on linux; "/Volumes/RPI-RP2" on darwin (Mac) | The full path to the pico mount point | 428 | | `pico_reset` | string |"/dev/ttyACM*" on linux; "/dev/cu.usbmodem14*" on darwin | The full path to the pico device to reset if required | 429 | | `picotool` | string | undefined | The full path to picotool executable (currently optional) | 430 | 431 | Properties in the `mix.exs` file may be over-ridden on the command line using long-style flags (prefixed by `--`) by the same name as the properties key. For example, you can use the `--pico_path` option to specify or override the `pico_path` property in the above table. 432 | 433 | ### The `atomvm.uf2create` task 434 | 435 | The `atomvm.uf2create` is use to create uf2 files appropriate for pico devices from a packed .avm application file, if the packed file does not exist the `atomvm.packbeam` task will be used to create the file (after compilation in necessary). Normally using this task manually is not required, it is called automatically by the `atomvm.pico.flash` if a uf2 file has not already been created. 436 | 437 | The `atomvm` properties list in the Mix project file (`mix.exs`) may contain the following entries related to this task: 438 | 439 | | Key | Type | Default | Value | 440 | |-----|------|----------|-------| 441 | | `app_start` | Address in hexademical format | 0x10180000 | The flash address to place the application | 442 | 443 | Properties in the `mix.exs` file may be over-ridden on the command line using long-style flags (prefixed by `--`) by the same name as the properties key. For example, you can use the `--app_start` option to specify or override the `app_start` property in the above table. -------------------------------------------------------------------------------- /config/config.exs: -------------------------------------------------------------------------------- 1 | # This file is responsible for configuring your application 2 | # and its dependencies with the aid of the Mix.Config module. 3 | use Mix.Config 4 | 5 | # This configuration is loaded before any dependency and is restricted 6 | # to this project. If another project depends on this project, this 7 | # file won't be loaded nor affect the parent project. For this reason, 8 | # if you want to provide default values for your application for 9 | # third-party users, it should be done in your "mix.exs" file. 10 | 11 | # You can configure your application as: 12 | # 13 | # config :exatomvm, key: :value 14 | # 15 | # and access this configuration in your application as: 16 | # 17 | # Application.get_env(:exatomvm, :key) 18 | # 19 | # You can also configure a third-party app: 20 | # 21 | # config :logger, level: :info 22 | # 23 | 24 | # It is also possible to import configuration files, relative to this 25 | # directory. For example, you can emulate configuration per environment 26 | # by uncommenting the line below and defining dev.exs, test.exs and such. 27 | # Configuration from the imported file will override the ones defined 28 | # here (which is why it is important to import them last). 29 | # 30 | # import_config "#{Mix.env()}.exs" 31 | -------------------------------------------------------------------------------- /lib/ex_atom_vm.ex: -------------------------------------------------------------------------------- 1 | defmodule ExAtomVM do 2 | @moduledoc """ 3 | Documentation for ExAtomVM. 4 | """ 5 | 6 | @doc """ 7 | Hello world. 8 | 9 | ## Examples 10 | 11 | iex> ExAtomVM.hello() 12 | :world 13 | 14 | """ 15 | def hello do 16 | :world 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /lib/mix/tasks/check.ex: -------------------------------------------------------------------------------- 1 | defmodule Mix.Tasks.Atomvm.Check do 2 | alias Mix.Project 3 | 4 | def run(args) do 5 | Mix.Tasks.Compile.run(args) 6 | 7 | beams_path = Project.compile_path() 8 | 9 | instructions_check = check_instructions(beams_path) 10 | ext_calls_check = check_ext_calls(beams_path) 11 | 12 | with :ok <- instructions_check, 13 | :ok <- ext_calls_check do 14 | {:ok, []} 15 | else 16 | _any -> exit({:shutdown, 1}) 17 | end 18 | end 19 | 20 | defp extract_instructions({:beam_file, module_name, _exported_funcs, _, _, code}) do 21 | instructions = 22 | scan_instructions(code, fn 23 | {:bif, _func, _, args, _}, acc -> 24 | ["bif#{length(args)}" | acc] 25 | 26 | {:gc_bif, _func, _, _, args, _}, acc -> 27 | ["gc_bif#{length(args)}" | acc] 28 | 29 | {:init, _}, acc -> 30 | ["kill" | acc] 31 | 32 | {:test, :is_ne, _, _}, acc -> 33 | ["is_not_equal" | acc] 34 | 35 | {:test, :is_ne_exact, _, _}, acc -> 36 | ["is_not_eq_exact" | acc] 37 | 38 | {:test, :is_eq, _, _}, acc -> 39 | ["is_equal" | acc] 40 | 41 | {:test, test, _, _}, acc -> 42 | ["#{test}" | acc] 43 | 44 | instr, acc when is_tuple(instr) -> 45 | ["#{elem(instr, 0)}" | acc] 46 | 47 | instr, acc when is_atom(instr) -> 48 | ["#{instr}" | acc] 49 | end) 50 | 51 | {module_name, instructions} 52 | end 53 | 54 | defp extract_instructions(path) do 55 | files = list_beam_files(path) 56 | 57 | exported_by_mod = 58 | Enum.reduce(files, %{}, fn filename, acc -> 59 | file_path = Path.join(path, filename) 60 | 61 | {module_name, exported} = 62 | File.read!(file_path) 63 | |> :beam_disasm.file() 64 | |> extract_instructions() 65 | 66 | Map.put(acc, module_name, exported) 67 | end) 68 | 69 | exported_by_mod 70 | |> Map.values() 71 | |> List.flatten() 72 | |> Enum.uniq() 73 | |> Enum.into(MapSet.new()) 74 | end 75 | 76 | defp extract_ext_calls({:beam_file, module_name, _, _, _, code}) do 77 | ext_calls = 78 | scan_instructions(code, fn 79 | {:call_ext, _, {:extfunc, module, extfunc, arity}}, acc -> 80 | [{module, extfunc, arity} | acc] 81 | 82 | {:call_ext_last, _, {:extfunc, module, extfunc, arity}}, acc -> 83 | [{module, extfunc, arity} | acc] 84 | 85 | {:call_ext_only, _, {:extfunc, module, extfunc, arity}}, acc -> 86 | [{module, extfunc, arity} | acc] 87 | 88 | {:bif, func, _, args, _}, acc -> 89 | [{:erlang, func, length(args)} | acc] 90 | 91 | {:gc_bif, func, _, _, args, _}, acc -> 92 | [{:erlang, func, length(args)} | acc] 93 | 94 | _, acc -> 95 | acc 96 | end) 97 | 98 | {module_name, ext_calls} 99 | end 100 | 101 | def extract_exported({:beam_file, module_name, exported_funcs, _, _, _code}) do 102 | funcs = 103 | Enum.map(exported_funcs, fn {func_name, arity, _} -> 104 | "#{Atom.to_string(module_name)}:#{func_name}/#{arity}" 105 | end) 106 | |> Enum.uniq() 107 | 108 | {module_name, funcs} 109 | end 110 | 111 | def extract_exported(files) when is_list(files) do 112 | exported_by_mod = 113 | Enum.reduce(files, %{}, fn file_path, acc -> 114 | {module_name, exported} = 115 | File.read!(file_path) 116 | |> :beam_disasm.file() 117 | |> extract_exported() 118 | 119 | Map.put(acc, module_name, exported) 120 | end) 121 | 122 | exported_by_mod 123 | |> Map.values() 124 | |> List.flatten() 125 | |> Enum.uniq() 126 | |> Enum.into(MapSet.new()) 127 | end 128 | 129 | def extract_exported(path) do 130 | Mix.Tasks.Atomvm.Packbeam.beam_files(path) 131 | |> extract_exported() 132 | end 133 | 134 | defp extract_calls(path) do 135 | files = list_beam_files(path) 136 | 137 | calls_by_mod = 138 | Enum.reduce(files, %{}, fn filename, acc -> 139 | file_path = Path.join(path, filename) 140 | 141 | {module_name, ext_calls} = 142 | File.read!(file_path) 143 | |> :beam_disasm.file() 144 | |> extract_ext_calls() 145 | 146 | Map.put(acc, module_name, ext_calls) 147 | end) 148 | 149 | calls_by_mod 150 | |> Map.values() 151 | |> List.flatten() 152 | |> Enum.uniq() 153 | |> Enum.map(fn {m, f, a} -> "#{Atom.to_string(m)}:#{Atom.to_string(f)}/#{a}" end) 154 | |> Enum.into(MapSet.new()) 155 | end 156 | 157 | defp check_ext_calls(beams_path) do 158 | calls_set = extract_calls(beams_path) 159 | runtime_deps_beams = Mix.Tasks.Atomvm.Packbeam.runtime_deps_beams() 160 | 161 | exported_calls_set = 162 | MapSet.union(extract_exported(beams_path), extract_exported(runtime_deps_beams)) 163 | 164 | avail_funcs = 165 | Path.join(:code.priv_dir(:exatomvm), "funcs.txt") 166 | |> File.stream!() 167 | |> Stream.map(&String.replace(&1, "\n", "")) 168 | |> Enum.into(MapSet.new()) 169 | |> MapSet.union(exported_calls_set) 170 | 171 | missing = MapSet.difference(calls_set, avail_funcs) 172 | 173 | if MapSet.size(missing) != 0 do 174 | IO.puts("error: following modules or functions are not available on AtomVM:") 175 | print_list(missing) 176 | IO.puts("") 177 | 178 | :error 179 | else 180 | :ok 181 | end 182 | end 183 | 184 | defp check_instructions(beams_path) do 185 | instructions_set = extract_instructions(beams_path) 186 | 187 | avail_instructions = 188 | Path.join(:code.priv_dir(:exatomvm), "instructions.txt") 189 | |> File.stream!() 190 | |> Stream.map(&String.replace(&1, "\n", "")) 191 | |> Enum.into(MapSet.new()) 192 | 193 | missing_instructions = MapSet.difference(instructions_set, avail_instructions) 194 | 195 | if MapSet.size(missing_instructions) != 0 do 196 | if MapSet.member?(missing_instructions, "elixir_erl_pass:parens_map_field/2") do 197 | IO.puts(""" 198 | Error: 199 | using module.function() notation (with parentheses) to fetch 200 | map.field() is deprecated, 201 | you must remove the parentheses: map.field 202 | """) 203 | end 204 | IO.puts("error: following missing instructions are used:") 205 | print_list(missing_instructions) 206 | IO.puts("") 207 | 208 | :error 209 | else 210 | :ok 211 | end 212 | end 213 | 214 | defp print_list(enum) do 215 | enum 216 | |> Enum.to_list() 217 | |> Enum.map(fn s -> "* #{s}" end) 218 | |> Enum.join("\n") 219 | |> IO.puts() 220 | end 221 | 222 | defp list_beam_files(path) do 223 | path 224 | |> File.ls!() 225 | |> Enum.filter(&String.ends_with?(&1, ".beam")) 226 | end 227 | 228 | defp scan_instructions(code, fun) do 229 | Enum.map(code, fn {:function, _func_name, _, _, func_code} -> 230 | Enum.reduce(func_code, [], fun) 231 | end) 232 | |> List.flatten() 233 | |> Enum.uniq() 234 | end 235 | end 236 | -------------------------------------------------------------------------------- /lib/mix/tasks/esp32_flash.ex: -------------------------------------------------------------------------------- 1 | defmodule Mix.Tasks.Atomvm.Esp32.Flash do 2 | use Mix.Task 3 | alias Mix.Project 4 | alias Mix.Tasks.Atomvm.Packbeam 5 | 6 | @esp_tool_path "/components/esptool_py/esptool/esptool.py" 7 | 8 | def run(args) do 9 | config = Project.config() 10 | 11 | with {:atomvm, {:ok, avm_config}} <- {:atomvm, Keyword.fetch(config, :atomvm)}, 12 | {:args, {:ok, options}} <- {:args, parse_args(args)}, 13 | {:pack, {:ok, _}} <- {:pack, Packbeam.run(args)}, 14 | idf_path <- System.get_env("IDF_PATH", <<"">>) do 15 | chip = Map.get(options, :chip, Keyword.get(avm_config, :chip, "auto")) 16 | port = Map.get(options, :port, Keyword.get(avm_config, :port, "/dev/ttyUSB0")) 17 | baud = Map.get(options, :baud, Keyword.get(avm_config, :baud, "115200")) 18 | 19 | flash_offset = 20 | Map.get(options, :flash_offset, Keyword.get(avm_config, :flash_offset, 0x250000)) 21 | 22 | flash(idf_path, chip, port, baud, flash_offset) 23 | else 24 | {:atomvm, :error} -> 25 | IO.puts("error: missing AtomVM project config.") 26 | exit({:shutdown, 1}) 27 | 28 | {:args, :error} -> 29 | IO.puts("Syntax: ") 30 | exit({:shutdown, 1}) 31 | 32 | {:pack, _} -> 33 | IO.puts("error: failed PackBEAM, target will not be flashed.") 34 | exit({:shutdown, 1}) 35 | end 36 | end 37 | 38 | def flash(idf_path, chip, port, baud, flash_offset) do 39 | tool_args = [ 40 | "--chip", 41 | chip, 42 | "--baud", 43 | baud, 44 | "--before", 45 | "default_reset", 46 | "--after", 47 | "hard_reset", 48 | "write_flash", 49 | "-u", 50 | "--flash_mode", 51 | "keep", 52 | "--flash_freq", 53 | "keep", 54 | "--flash_size", 55 | "detect", 56 | "0x#{Integer.to_string(flash_offset, 16)}", 57 | "#{Project.config()[:app]}.avm" 58 | ] 59 | 60 | tool_args = if port == "auto", do: tool_args, else: ["--port", port] ++ tool_args 61 | 62 | tool_full_path = get_esptool_path(idf_path) 63 | System.cmd(tool_full_path, tool_args, stderr_to_stdout: true, into: IO.stream(:stdio, 1)) 64 | end 65 | 66 | defp get_esptool_path(<<"">>) do 67 | "esptool.py" 68 | end 69 | 70 | defp get_esptool_path(idf_path) do 71 | "#{idf_path}#{@esp_tool_path}" 72 | end 73 | 74 | defp parse_args(args) do 75 | parse_args(args, %{}) 76 | end 77 | 78 | defp parse_args([], accum) do 79 | {:ok, accum} 80 | end 81 | 82 | defp parse_args([<<"--port">>, port | t], accum) do 83 | parse_args(t, Map.put(accum, :port, port)) 84 | end 85 | 86 | defp parse_args([<<"--baud">>, baud | t], accum) do 87 | parse_args(t, Map.put(accum, :baud, baud)) 88 | end 89 | 90 | defp parse_args([<<"--chip">>, chip | t], accum) do 91 | parse_args(t, Map.put(accum, :chip, chip)) 92 | end 93 | 94 | defp parse_args([<<"--flash_offset">>, "0x" <> hex = flash_offset | t], accum) do 95 | {offset, _} = Integer.parse(hex, 16) 96 | parse_args(t, Map.put(accum, :flash_offset, offset)) 97 | end 98 | 99 | defp parse_args([_ | t], accum) do 100 | parse_args(t, accum) 101 | end 102 | end 103 | -------------------------------------------------------------------------------- /lib/mix/tasks/packbeam.ex: -------------------------------------------------------------------------------- 1 | defmodule Mix.Tasks.Atomvm.Packbeam do 2 | use Mix.Task 3 | alias ExAtomVM.PackBEAM 4 | alias Mix.Project 5 | alias Mix.Tasks.Atomvm.Check 6 | 7 | def run(args) do 8 | with {:check, {:ok, _}} <- {:check, Check.run(args)}, 9 | {:args, {:ok, options}} <- {:args, parse_args(args)}, 10 | config = Project.config(), 11 | {:atomvm, {:ok, avm_config}} <- {:atomvm, Keyword.fetch(config, :atomvm)}, 12 | {:start, {:ok, start_module}} <- 13 | {:start, Map.get(options, :start, Keyword.fetch(avm_config, :start))}, 14 | :ok <- pack_avm_deps(), 15 | :ok <- pack_priv(), 16 | start_beam_file = "#{Atom.to_string(start_module)}.beam", 17 | :ok <- pack_beams(Project.compile_path(), start_beam_file, "#{config[:app]}.avm") do 18 | {:ok, []} 19 | else 20 | {:check, _} -> 21 | IO.puts("error: failed check, .beam files will not be packed.") 22 | :error 23 | 24 | {:atomvm, :error} -> 25 | IO.puts("error: missing AtomVM project config.") 26 | :error 27 | 28 | {:start, :error} -> 29 | IO.puts("error: missing startup module.") 30 | :error 31 | 32 | nil -> 33 | IO.puts("error: ATOMVM_INSTALL_PREFIX env var is not set.") 34 | :error 35 | 36 | error -> 37 | IO.puts("error: unexpected error: #{inspect(error)}.") 38 | :error 39 | end 40 | end 41 | 42 | defp pack_avm_deps() do 43 | dep_beams = list_dep_beams() 44 | 45 | case avm_deps_path() do 46 | {:ok, avm_path} -> 47 | dep_avms = list_dep_avms(avm_path) 48 | PackBEAM.make_avm(dep_beams ++ dep_avms, "deps.avm") 49 | 50 | {:error, :no_avm_deps_path} -> 51 | PackBEAM.make_avm(dep_beams, "deps.avm") 52 | 53 | any -> 54 | any 55 | end 56 | end 57 | 58 | defp list_dep_avms(avm_path) do 59 | avm_path 60 | |> File.ls!() 61 | |> Enum.map(fn file -> {Path.join(avm_path, file), :avm} end) 62 | end 63 | 64 | defp list_dep_beams() do 65 | runtime_deps_beams() 66 | |> Enum.map(fn beam_file -> {beam_file, :beam} end) 67 | end 68 | 69 | def beam_files(path) do 70 | for file <- File.ls!(path), String.ends_with?(file, ".beam") do 71 | Path.join(path, file) 72 | end 73 | end 74 | 75 | defp pack_priv() do 76 | priv_dir_path = 77 | Project.config()[:app] 78 | |> Application.app_dir("priv") 79 | 80 | packbeam_inputs = 81 | case File.exists?(priv_dir_path) do 82 | true -> 83 | prefix = 84 | Project.config()[:app] 85 | |> Atom.to_string() 86 | |> Path.join("priv") 87 | 88 | priv_dir_path 89 | |> get_all_files() 90 | |> Enum.map(fn file -> 91 | {file, [file: Path.join(prefix, Path.relative_to(file, priv_dir_path))]} 92 | end) 93 | 94 | false -> 95 | [] 96 | end 97 | 98 | PackBEAM.make_avm(packbeam_inputs, "priv.avm") 99 | end 100 | 101 | defp get_all_files(dir) do 102 | all_files = Path.wildcard(Path.join(dir, "*")) 103 | 104 | regular_files = 105 | Enum.filter(all_files, fn path -> 106 | File.regular?(path) 107 | end) 108 | 109 | sub_dirs = 110 | Enum.filter(all_files, fn path -> 111 | File.dir?(path) 112 | end) 113 | 114 | sub_files = 115 | Enum.reduce(sub_dirs, [], fn sub_dir, accum -> 116 | get_all_files(sub_dir) ++ accum 117 | end) 118 | 119 | regular_files ++ sub_files 120 | end 121 | 122 | defp pack_beams(beams_path, start_beam_file, out) do 123 | beams_path 124 | |> File.ls!() 125 | |> Enum.filter(fn file -> String.ends_with?(file, ".beam") end) 126 | |> List.delete(start_beam_file) 127 | |> Enum.map(fn file -> {file, :beam} end) 128 | |> List.insert_at(0, {start_beam_file, :beam_start}) 129 | |> Enum.map(fn {file, opts} -> {Path.join(Project.compile_path(), file), opts} end) 130 | |> Enum.concat([{"deps.avm", :avm}, {"priv.avm", :avm}]) 131 | |> PackBEAM.make_avm(out) 132 | end 133 | 134 | defp avm_deps_path() do 135 | deps_path = Project.deps_path() 136 | 137 | with true <- String.ends_with?(deps_path, "/deps"), 138 | deps_len = String.length(deps_path), 139 | prj_path = String.slice(deps_path, 0, deps_len - 5), 140 | avm_deps_path = Path.join(prj_path, "/avm_deps"), 141 | true <- File.exists?(avm_deps_path) do 142 | {:ok, avm_deps_path} 143 | else 144 | _ -> 145 | with prefix when prefix != nil <- System.get_env("ATOMVM_INSTALL_PREFIX"), 146 | true <- File.exists?(prefix) do 147 | {:ok, Path.join(prefix, "lib/AtomVM/ebin/")} 148 | else 149 | _ -> 150 | IO.puts("No avm_deps directory found.") 151 | 152 | IO.puts( 153 | "This message can be safely ignored when standard libraries are already flashed to lib partition." 154 | ) 155 | 156 | {:error, :no_avm_deps_path} 157 | end 158 | end 159 | end 160 | 161 | def runtime_deps(deps) do 162 | Enum.reduce(deps, [], fn dep, acc -> 163 | if Keyword.get(dep.opts, :runtime, true) do 164 | ["#{dep.opts[:build]}/ebin" | runtime_deps(dep.deps) ++ acc] 165 | else 166 | acc 167 | end 168 | end) 169 | end 170 | 171 | def runtime_deps_beams() do 172 | Mix.Dep.cached() 173 | |> runtime_deps() 174 | |> Enum.reduce([], fn path, acc -> beam_files(path) ++ acc end) 175 | end 176 | 177 | defp parse_args(args) do 178 | parse_args(args, %{}) 179 | end 180 | 181 | defp parse_args([], accum) do 182 | {:ok, accum} 183 | end 184 | 185 | defp parse_args([<<"--start">>, start | t], accum) do 186 | parse_args(t, Map.put(accum, :start, start)) 187 | end 188 | 189 | defp parse_args([_ | t], accum) do 190 | parse_args(t, accum) 191 | end 192 | end 193 | -------------------------------------------------------------------------------- /lib/mix/tasks/pico_flash.ex: -------------------------------------------------------------------------------- 1 | defmodule Mix.Tasks.Atomvm.Pico.Flash do 2 | use Mix.Task 3 | alias Mix.Project 4 | alias Mix.Tasks.Atomvm.Uf2create 5 | 6 | def run(args) do 7 | config = Project.config() 8 | 9 | with {:atomvm, {:ok, avm_config}} <- {:atomvm, Keyword.fetch(config, :atomvm)}, 10 | {:args, {:ok, options}} <- {:args, parse_args(args)}, 11 | {:uf2, :ok} <- {:uf2, Uf2create.run(args)} do 12 | pico_path = 13 | Map.get(options, :pico_path, Keyword.get(avm_config, :pico_path, System.get_env("ATOMVM_PICO_MOUNT_PATH", get_default_mount()))) 14 | pico_reset = 15 | Map.get(options, :pico_reset, Keyword.get(avm_config, :pico_reset, System.get_env("ATOMVM_PICO_RESET_DEV", get_reset_base()))) 16 | picotool = 17 | Map.get(options, :picotool, Keyword.get(avm_config, :picotool, System.get_env("ATOMVM_PICOTOOL_PATH", "#{:os.find_executable(~c"picotool")}"))) 18 | 19 | do_flash(pico_path, pico_reset, picotool) 20 | else 21 | {:atomvm, :error} -> 22 | IO.puts("error: missing AtomVM project config.") 23 | exit({:shutdown, 1}) 24 | 25 | {:args, :error} -> 26 | IO.puts("Syntax: ") 27 | exit({:shutdown, 1}) 28 | 29 | {:uf2, _} -> 30 | IO.puts("error: failed to create uf2 file, target will not be flashed.") 31 | exit({:shutdown, 1}) 32 | end 33 | end 34 | 35 | defp parse_args(args) do 36 | parse_args(args, %{}) 37 | end 38 | 39 | defp parse_args([], accum) do 40 | {:ok, accum} 41 | end 42 | 43 | defp parse_args([<<"--pico_path">>, pico_path | t], accum) do 44 | parse_args(t, Map.put(accum, :pico_path, pico_path)) 45 | end 46 | 47 | defp parse_args([<<"--pico_reset">>, pico_reset | t], accum) do 48 | parse_args(t, Map.put(accum, :pico_reset, pico_reset)) 49 | end 50 | 51 | defp parse_args([<<"--picotool">>, picotool | t], accum) do 52 | parse_args(t, Map.put(accum, :picotool, picotool)) 53 | end 54 | 55 | defp parse_args([_ | t], accum) do 56 | parse_args(t, accum) 57 | end 58 | 59 | defp get_default_mount() do 60 | case :os.type() do 61 | {_fam, :linux} -> "/run/media/#{:os.getenv(~c"USER")}/RPI-RP2" 62 | {_fam, :darwin} -> "/Volumes/RPI-RP2" 63 | _ -> "" 64 | end 65 | end 66 | 67 | defp wait_for_mount(mount, count) when count < 30 do 68 | case File.stat(mount) do 69 | {:ok, filestat} -> 70 | case Map.get(filestat, :type) do 71 | :directory -> 72 | :ok 73 | _ -> 74 | IO.puts("Object found at #{mount} is not a directory") 75 | exit({:shutdown, 1}) 76 | end 77 | {:error, :enoent} -> 78 | Process.sleep(1000) 79 | wait_for_mount(mount, count + 1) 80 | error -> 81 | IO.puts("unexpected error: #{error} while checking pico mount path.") 82 | exit({:shutdown, 1}) 83 | end 84 | end 85 | 86 | defp wait_for_mount(_, 30) do 87 | IO.puts("error: Pico not mounted after 30 seconds. giving up...") 88 | exit({:shutdown, 1}) 89 | end 90 | 91 | defp check_pico_mount(mount) do 92 | case File.stat(<<"#{mount}">>) do 93 | {:ok, info} -> 94 | case Map.get(info, :type) do 95 | :directory -> 96 | :ok 97 | _ -> 98 | IO.puts("error: object at pico mount path not a directory. Abort!") 99 | exit({:shutdown, 1}) 100 | end 101 | _ -> 102 | IO.puts("error: Pico not mounted. Abort!") 103 | exit({:shutdown, 1}) 104 | end 105 | end 106 | 107 | defp get_stty_file_flag() do 108 | case :os.type() do 109 | {_fam, :linux} -> "-F" 110 | _ -> "-f" 111 | end 112 | end 113 | 114 | defp get_reset_base() do 115 | case :os.type() do 116 | {_fam, :linux} -> "/dev/ttyACM*" 117 | {_fam, :darwin} -> "/dev/cu.usbmodem14*" 118 | _ -> "" 119 | end 120 | end 121 | 122 | defp needs_reset(resetdev) do 123 | case Path.wildcard(resetdev) do 124 | [] -> 125 | false 126 | [device | _t] -> 127 | case File.stat(device) do 128 | {:ok, info} -> 129 | case Map.get(info, :type) do 130 | :device -> {true, device} 131 | _ -> false 132 | end 133 | _ -> 134 | false 135 | end 136 | _ -> 137 | false 138 | end 139 | end 140 | 141 | defp do_reset(resetdev, picotool) do 142 | flag = get_stty_file_flag() 143 | cmd_args = ["#{flag}", "#{resetdev}", "1200"] 144 | 145 | case System.cmd("stty", cmd_args) do 146 | {"", 0} -> 147 | # Pause to let the device settle 148 | Process.sleep(200) 149 | error -> 150 | case picotool do 151 | false -> 152 | IO.puts("Error: #{error}\nUnable to locate 'picotool', close the serial monitor before flashing, or install picotool for automatic disconnect and BOOTSEL mode.") 153 | exit({:shutdown, 1}) 154 | _ -> 155 | IO.puts("Warning: #{error}\nFor faster flashing remember to disconnect serial monitor first.") 156 | reset_args = ["reboot", "-f", "-u"] 157 | IO.puts("Disconnecting serial monitor with `picotool #{:lists.join(" ", reset_args)}` in 5 seconds...") 158 | Process.sleep(5000) 159 | case :string.trim(System.cmd(picotool, reset_args)) do 160 | {status, 0} -> 161 | case status do 162 | "The device was asked to reboot into BOOTSEL mode." -> 163 | :ok 164 | pt_error -> 165 | IO.puts("Failed to prepare pico for flashing: #{pt_error}") 166 | exit({:shutdown, 1}) 167 | end 168 | _ -> 169 | IO.puts("Failed to prepare pico for flashing: #{error}") 170 | end 171 | end 172 | end 173 | end 174 | 175 | defp do_flash(pico_path, pico_reset, picotool) do 176 | case needs_reset(pico_reset) do 177 | false -> 178 | :ok 179 | {true, reset_port} -> 180 | do_reset(reset_port, picotool) 181 | IO.puts("Waiting for the device at path #{pico_path} to settle and mount...") 182 | wait_for_mount(pico_path, 0) 183 | end 184 | 185 | check_pico_mount(pico_path) 186 | _bytes = File.copy!("#{Project.config()[:app]}.uf2", "#{pico_path}/#{Project.config()[:app]}.uf2", :infinity) 187 | IO.puts("Successfully loaded #{Project.config()[:app]} to the pico device at #{pico_path}.") 188 | end 189 | end 190 | -------------------------------------------------------------------------------- /lib/mix/tasks/stm32_flash.ex: -------------------------------------------------------------------------------- 1 | defmodule Mix.Tasks.Atomvm.Stm32.Flash do 2 | use Mix.Task 3 | alias Mix.Project 4 | alias Mix.Tasks.Atomvm.Packbeam 5 | 6 | def run(args) do 7 | config = Project.config() 8 | 9 | with {:atomvm, {:ok, avm_config}} <- {:atomvm, Keyword.fetch(config, :atomvm)}, 10 | {:args, {:ok, options}} <- {:args, parse_args(args)}, 11 | {:pack, {:ok, _}} <- {:pack, Packbeam.run(args)}, 12 | stflash_path <- System.get_env("ATOMVM_MIX_PLUGIN_STFLASH", <<"">>) do 13 | 14 | flash_offset = 15 | Map.get(options, :flash_offset, Keyword.get(avm_config, :flash_offset, 0x8080000)) 16 | 17 | flash(stflash_path, flash_offset) 18 | else 19 | {:atomvm, :error} -> 20 | IO.puts("error: missing AtomVM project config.") 21 | exit({:shutdown, 1}) 22 | 23 | {:args, :error} -> 24 | IO.puts("Syntax: ") 25 | exit({:shutdown, 1}) 26 | 27 | {:pack, _} -> 28 | IO.puts("error: failed PackBEAM, target will not be flashed.") 29 | exit({:shutdown, 1}) 30 | end 31 | end 32 | 33 | def flash(stflash_path, flash_offset) do 34 | tool_args = [ 35 | "--reset", 36 | "write", 37 | "#{Project.config()[:app]}.avm", 38 | "0x#{Integer.to_string(flash_offset, 16)}" 39 | ] 40 | 41 | tool_full_path = get_stflash_path(stflash_path) 42 | System.cmd(tool_full_path, tool_args, stderr_to_stdout: true, into: IO.stream(:stdio, 1)) 43 | end 44 | 45 | defp get_stflash_path(<<"">>) do 46 | "st-flash" 47 | end 48 | 49 | defp parse_args(args) do 50 | parse_args(args, %{}) 51 | end 52 | 53 | defp parse_args([], accum) do 54 | {:ok, accum} 55 | end 56 | 57 | defp parse_args([<<"--flash_offset">>, flash_offset | t], accum) do 58 | parse_args(t, Map.put(accum, :flash_offset, flash_offset)) 59 | end 60 | 61 | defp parse_args([_ | t], accum) do 62 | parse_args(t, accum) 63 | end 64 | end 65 | -------------------------------------------------------------------------------- /lib/mix/tasks/uf2create.ex: -------------------------------------------------------------------------------- 1 | defmodule Mix.Tasks.Atomvm.Uf2create do 2 | use Mix.Task 3 | alias Mix.Project 4 | alias Mix.Tasks.Atomvm.Packbeam 5 | # require :uf2tool 6 | 7 | def run(args) do 8 | config = Project.config() 9 | 10 | with {:atomvm, {:ok, avm_config}} <- {:atomvm, Keyword.fetch(config, :atomvm)}, 11 | {:args, {:ok, options}} <- {:args, parse_args(args)}, 12 | {:pack, {:ok, _}} <- {:pack, Packbeam.run(args)} do 13 | app_start = 14 | parse_addr(Keyword.get(avm_config, :app_start, Map.get(options, :app_start, System.get_env("ATOMVM_PICO_APP_START", "0x10180000")))) 15 | family_id = 16 | validate_fam(Keyword.get(avm_config, :family_id, Map.get(options, :family_id, System.get_env("ATOMVM_PICO_UF2_FAMILY", "rp2040")))) 17 | 18 | :ok = :uf2tool.uf2create("#{config[:app]}.uf2", family_id, app_start, "#{config[:app]}.avm") 19 | IO.puts("Created #{config[:app]}.uf2") 20 | else 21 | {:atomvm, :error} -> 22 | IO.puts("error: missing AtomVM project config.") 23 | exit({:shutdown, 1}) 24 | 25 | {:args, :error} -> 26 | IO.puts("Syntax: ") 27 | exit({:shutdown, 1}) 28 | 29 | {:pack, _} -> 30 | IO.puts("error: failed PackBEAM, uf2 file will not be created.") 31 | exit({:shutdown, 1}) 32 | end 33 | end 34 | 35 | defp parse_args(args) do 36 | parse_args(args, %{}) 37 | end 38 | 39 | defp parse_args([], accum) do 40 | {:ok, accum} 41 | end 42 | 43 | defp parse_args([<<"--app_start">>, app_start | t], accum) do 44 | parse_args(t, Map.put(accum, :app_start, app_start)) 45 | end 46 | 47 | defp parse_args([<<"--family_id">>, family_id | t], accum) do 48 | parse_args(t, Map.put(accum, :family_id, family_id)) 49 | end 50 | 51 | defp parse_args([_ | t], accum) do 52 | parse_args(t, accum) 53 | end 54 | 55 | defp parse_addr("0x" <> addrhex) do 56 | {address, ""} = Integer.parse(addrhex, 16) 57 | address 58 | end 59 | 60 | defp parse_addr("16#" <> addrhex) do 61 | {address, ""} = Integer.parse(addrhex, 16) 62 | address 63 | end 64 | 65 | defp parse_addr(addrdec) do 66 | {address, ""} = Integer.parse(addrdec) 67 | address 68 | end 69 | 70 | defp validate_fam(family) do 71 | case family do 72 | "rp2040" -> :rp2040 73 | ":rp2040" -> :rp2040 74 | :rp2040 -> :rp2040 75 | "rp2035" -> :data 76 | ":rp2035" -> :data 77 | :rp2035 -> :data 78 | "data" -> :data 79 | ":data" -> :data 80 | :data -> :data 81 | "universal" -> :universal 82 | ":universal" -> :universal 83 | :universal -> :universal 84 | unsupported -> 85 | IO.puts("Unsupported 'family_id' #{unsupported}") 86 | exit({:shutdown, 1}) 87 | end 88 | end 89 | end 90 | -------------------------------------------------------------------------------- /lib/packbeam.ex: -------------------------------------------------------------------------------- 1 | defmodule ExAtomVM.PackBEAM do 2 | @allowed_chunks MapSet.new([ 3 | ~c"AtU8", 4 | ~c"Code", 5 | ~c"ExpT", 6 | ~c"LocT", 7 | ~c"ImpT", 8 | ~c"LitU", 9 | ~c"FunT", 10 | ~c"StrT", 11 | ~c"LitT" 12 | ]) 13 | 14 | @avm_header <<0x23, 0x21, 0x2F, 0x75, 0x73, 0x72, 0x2F, 0x62, 0x69, 0x6E, 0x2F, 0x65, 0x6E, 15 | 0x76, 0x20, 0x41, 0x74, 0x6F, 0x6D, 0x56, 0x4D, 0x0A, 0x00, 0x00>> 16 | 17 | defp uncompress_literals(chunks) do 18 | with {~c"LitT", litt} <- List.keyfind(chunks, ~c"LitT", 0), 19 | <<_header::binary-size(4), data::binary>> <- litt do 20 | litu = :zlib.uncompress(data) 21 | 22 | chunks 23 | |> List.keyreplace(~c"LitT", 0, {~c"LitU", litu}) 24 | else 25 | nil -> chunks 26 | _ -> :error 27 | end 28 | end 29 | 30 | defp strip(chunks) do 31 | Enum.filter(chunks, fn {chunk_name, _} -> 32 | MapSet.member?(@allowed_chunks, chunk_name) 33 | end) 34 | end 35 | 36 | defp transform(beam_bytes) do 37 | with {:ok, module_name, chunks} <- :beam_lib.all_chunks(beam_bytes), 38 | u_chunks = uncompress_literals(chunks), 39 | s_chunks = strip(u_chunks), 40 | {:ok, bytes} <- :beam_lib.build_module(s_chunks) do 41 | {:ok, module_name, bytes} 42 | end 43 | end 44 | 45 | defp section_header_size(module_name) do 46 | 12 + byte_size(module_name) + 1 47 | end 48 | 49 | defp section_header(module_name, type, size) do 50 | reserved = 0 51 | 52 | flags = 53 | case type do 54 | :eof -> 0 55 | :beam_start -> 1 56 | :beam -> 2 57 | end 58 | 59 | <> 60 | end 61 | 62 | defp padding(size) do 63 | if rem(size, 4) != 0 do 64 | padding_size = 4 - rem(size, 4) 65 | {List.duplicate(0, padding_size), padding_size} 66 | else 67 | {[], 0} 68 | end 69 | end 70 | 71 | defp pack_module(module, opts) do 72 | with {:ok, beam_bytes} <- File.read(module), 73 | {:ok, module_atom, transformed_module} <- transform(beam_bytes) do 74 | module_name = "#{Atom.to_string(module_atom)}.beam" 75 | header_size = section_header_size(module_name) 76 | {header_padding, header_padding_size} = padding(header_size) 77 | {beam_padding, beam_padding_size} = padding(byte_size(transformed_module)) 78 | 79 | size = header_size + header_padding_size + byte_size(transformed_module) + beam_padding_size 80 | 81 | header = section_header(module_name, opts, size) 82 | {:ok, [header, header_padding, transformed_module, beam_padding]} 83 | else 84 | {:error, :enoent} = error -> 85 | IO.puts(:stderr, "Cannot find #{module}. Wrong module name?") 86 | error 87 | 88 | {:error, _} = error -> 89 | IO.puts(:stderr, "Cannot pack #{module}.") 90 | error 91 | end 92 | end 93 | 94 | def extract_avm_content(avm_file) do 95 | with {:ok, avm_bytes} <- File.read(avm_file), 96 | <<@avm_header, without_header::binary>> <- avm_bytes do 97 | without_header_size = byte_size(without_header) 98 | end_header_size = byte_size(section_header("end", :eof, 0)) 99 | 100 | {:ok, :binary.part(without_header, 0, without_header_size - end_header_size)} 101 | end 102 | end 103 | 104 | defp pack_any_file(file_path, opts) do 105 | with {:ok, file_bytes} <- File.read(file_path), 106 | {:ok, filename} <- Keyword.fetch(opts, :file) do 107 | header_size = section_header_size(filename) 108 | {header_padding, header_padding_size} = padding(header_size) 109 | {beam_padding, beam_padding_size} = padding(byte_size(file_bytes)) 110 | 111 | file_size = byte_size(file_bytes) 112 | size = header_size + header_padding_size + 4 + file_size + beam_padding_size 113 | 114 | header = section_header(filename, :beam, size) 115 | {:ok, [header, header_padding, <>, file_bytes, beam_padding]} 116 | end 117 | end 118 | 119 | defp pack_file(file, opts) do 120 | cond do 121 | String.ends_with?(file, ".beam") -> 122 | pack_module(file, opts) 123 | 124 | String.ends_with?(file, ".avm") -> 125 | extract_avm_content(file) 126 | 127 | true -> 128 | pack_any_file(file, opts) 129 | end 130 | end 131 | 132 | defp pack_files(modules) do 133 | Enum.reduce_while(modules, {:ok, []}, fn {module, opts}, {:ok, acc} -> 134 | case pack_file(module, opts) do 135 | {:ok, res} -> {:cont, {:ok, [acc | res]}} 136 | error -> {:halt, error} 137 | end 138 | end) 139 | end 140 | 141 | defp make_avm(modules) do 142 | with {:ok, packed} <- pack_files(modules) do 143 | {:ok, [@avm_header, packed, section_header("end", :eof, 0)]} 144 | end 145 | end 146 | 147 | def make_avm(modules, out) do 148 | with {:ok, bytes} <- make_avm(modules) do 149 | File.write(out, bytes) 150 | end 151 | end 152 | end 153 | -------------------------------------------------------------------------------- /mix.exs: -------------------------------------------------------------------------------- 1 | defmodule ExAtomVM.MixProject do 2 | use Mix.Project 3 | 4 | def project do 5 | [ 6 | app: :exatomvm, 7 | version: "0.1.0", 8 | elixir: "~> 1.8", 9 | start_permanent: Mix.env() == :prod, 10 | deps: deps() 11 | ] 12 | end 13 | 14 | # Run "mix help compile.app" to learn about applications. 15 | def application do 16 | [ 17 | extra_applications: [:logger] 18 | ] 19 | end 20 | 21 | # Run "mix help deps" to learn about dependencies. 22 | defp deps do 23 | [ 24 | {:uf2tool, "1.1.0"} 25 | # {:dep_from_hexpm, "~> 0.3.0"}, 26 | # {:dep_from_git, git: "https://github.com/elixir-lang/my_dep.git", tag: "0.1.0"} 27 | ] 28 | end 29 | end 30 | -------------------------------------------------------------------------------- /priv/funcs.txt: -------------------------------------------------------------------------------- 1 | ahttp_client:close/1 2 | ahttp_client:connect/4 3 | ahttp_client:module_info/0 4 | ahttp_client:module_info/1 5 | ahttp_client:recv/2 6 | ahttp_client:request/5 7 | ahttp_client:stream/2 8 | ahttp_client:stream_request_body/3 9 | alisp:booleanize/1 10 | alisp:eval/1 11 | alisp:module_info/0 12 | alisp:module_info/1 13 | alisp:run/1 14 | alisp_stdlib:*/1 15 | alisp_stdlib:+/1 16 | alisp_stdlib:-/1 17 | alisp_stdlib:=/1 18 | alisp_stdlib:append/1 19 | alisp_stdlib:binaryp/1 20 | alisp_stdlib:car/1 21 | alisp_stdlib:cdr/1 22 | alisp_stdlib:cons/1 23 | alisp_stdlib:floatp/1 24 | alisp_stdlib:identity/1 25 | alisp_stdlib:integerp/1 26 | alisp_stdlib:last/1 27 | alisp_stdlib:list/1 28 | alisp_stdlib:listp/1 29 | alisp_stdlib:mapcar/1 30 | alisp_stdlib:module_info/0 31 | alisp_stdlib:module_info/1 32 | alisp_stdlib:numberp/1 33 | alisp_stdlib:pidp/1 34 | alisp_stdlib:print/1 35 | alisp_stdlib:refp/1 36 | alisp_stdlib:remove-if/1 37 | alisp_stdlib:remove-if-not/1 38 | alisp_stdlib:tuple/1 39 | alisp_stdlib:tuplep/1 40 | arepl:module_info/0 41 | arepl:module_info/1 42 | arepl:start/0 43 | atomvm:add_avm_pack_binary/2 44 | atomvm:add_avm_pack_file/2 45 | atomvm:close_avm_pack/2 46 | atomvm:get_start_beam/1 47 | atomvm:module_info/0 48 | atomvm:module_info/1 49 | atomvm:platform/0 50 | atomvm:posix_clock_settime/2 51 | atomvm:posix_close/1 52 | atomvm:posix_closedir/1 53 | atomvm:posix_mkfifo/2 54 | atomvm:posix_open/2 55 | atomvm:posix_open/3 56 | atomvm:posix_opendir/1 57 | atomvm:posix_read/2 58 | atomvm:posix_readdir/1 59 | atomvm:posix_select_read/3 60 | atomvm:posix_select_stop/1 61 | atomvm:posix_select_write/3 62 | atomvm:posix_unlink/1 63 | atomvm:posix_write/2 64 | atomvm:rand_bytes/1 65 | atomvm:random/0 66 | atomvm:read_priv/2 67 | avm_pubsub:handle_call/3 68 | avm_pubsub:handle_info/2 69 | avm_pubsub:init/1 70 | avm_pubsub:module_info/0 71 | avm_pubsub:module_info/1 72 | avm_pubsub:pub/3 73 | avm_pubsub:start/0 74 | avm_pubsub:start/1 75 | avm_pubsub:sub/2 76 | avm_pubsub:sub/3 77 | avm_pubsub:terminate/2 78 | avm_pubsub:unsub/2 79 | avm_pubsub:unsub/3 80 | base64:decode/1 81 | base64:decode_to_string/1 82 | base64:encode/1 83 | base64:encode_to_string/1 84 | base64:module_info/0 85 | base64:module_info/1 86 | binary:at/2 87 | binary:copy/1 88 | binary:copy/2 89 | binary:decode_hex/1 90 | binary:encode_hex/1 91 | binary:encode_hex/2 92 | binary:first/1 93 | binary:last/1 94 | binary:module_info/0 95 | binary:module_info/1 96 | binary:part/3 97 | binary:split/2 98 | binary:split/3 99 | calendar:datetime_to_gregorian_seconds/1 100 | calendar:date_to_gregorian_days/1 101 | calendar:date_to_gregorian_days/3 102 | calendar:day_of_the_week/1 103 | calendar:day_of_the_week/3 104 | calendar:module_info/0 105 | calendar:module_info/1 106 | calendar:system_time_to_universal_time/2 107 | code:ensure_loaded/1 108 | code:load_abs/1 109 | code:load_binary/3 110 | code:module_info/0 111 | code:module_info/1 112 | console:flush/0 113 | console:flush/1 114 | console:module_info/0 115 | console:module_info/1 116 | console:print/1 117 | console:puts/1 118 | console:puts/2 119 | console:start/0 120 | crypto:crypto_one_time/4 121 | crypto:crypto_one_time/5 122 | crypto:hash/2 123 | crypto:module_info/0 124 | crypto:module_info/1 125 | crypto:strong_rand_bytes/1 126 | emscripten:module_info/0 127 | emscripten:module_info/1 128 | emscripten:promise_reject/1 129 | emscripten:promise_reject/2 130 | emscripten:promise_resolve/1 131 | emscripten:promise_resolve/2 132 | emscripten:register_blur_callback/1 133 | emscripten:register_blur_callback/2 134 | emscripten:register_blur_callback/3 135 | emscripten:register_click_callback/1 136 | emscripten:register_click_callback/2 137 | emscripten:register_click_callback/3 138 | emscripten:register_dblclick_callback/1 139 | emscripten:register_dblclick_callback/2 140 | emscripten:register_dblclick_callback/3 141 | emscripten:register_focus_callback/1 142 | emscripten:register_focus_callback/2 143 | emscripten:register_focus_callback/3 144 | emscripten:register_focusin_callback/1 145 | emscripten:register_focusin_callback/2 146 | emscripten:register_focusin_callback/3 147 | emscripten:register_focusout_callback/1 148 | emscripten:register_focusout_callback/2 149 | emscripten:register_focusout_callback/3 150 | emscripten:register_keydown_callback/1 151 | emscripten:register_keydown_callback/2 152 | emscripten:register_keydown_callback/3 153 | emscripten:register_keypress_callback/1 154 | emscripten:register_keypress_callback/2 155 | emscripten:register_keypress_callback/3 156 | emscripten:register_keyup_callback/1 157 | emscripten:register_keyup_callback/2 158 | emscripten:register_keyup_callback/3 159 | emscripten:register_mousedown_callback/1 160 | emscripten:register_mousedown_callback/2 161 | emscripten:register_mousedown_callback/3 162 | emscripten:register_mouseenter_callback/1 163 | emscripten:register_mouseenter_callback/2 164 | emscripten:register_mouseenter_callback/3 165 | emscripten:register_mouseleave_callback/1 166 | emscripten:register_mouseleave_callback/2 167 | emscripten:register_mouseleave_callback/3 168 | emscripten:register_mousemove_callback/1 169 | emscripten:register_mousemove_callback/2 170 | emscripten:register_mousemove_callback/3 171 | emscripten:register_mouseout_callback/1 172 | emscripten:register_mouseout_callback/2 173 | emscripten:register_mouseout_callback/3 174 | emscripten:register_mouseover_callback/1 175 | emscripten:register_mouseover_callback/2 176 | emscripten:register_mouseover_callback/3 177 | emscripten:register_mouseup_callback/1 178 | emscripten:register_mouseup_callback/2 179 | emscripten:register_mouseup_callback/3 180 | emscripten:register_resize_callback/1 181 | emscripten:register_resize_callback/2 182 | emscripten:register_resize_callback/3 183 | emscripten:register_scroll_callback/1 184 | emscripten:register_scroll_callback/2 185 | emscripten:register_scroll_callback/3 186 | emscripten:register_touchcancel_callback/1 187 | emscripten:register_touchcancel_callback/2 188 | emscripten:register_touchcancel_callback/3 189 | emscripten:register_touchend_callback/1 190 | emscripten:register_touchend_callback/2 191 | emscripten:register_touchend_callback/3 192 | emscripten:register_touchmove_callback/1 193 | emscripten:register_touchmove_callback/2 194 | emscripten:register_touchmove_callback/3 195 | emscripten:register_touchstart_callback/1 196 | emscripten:register_touchstart_callback/2 197 | emscripten:register_touchstart_callback/3 198 | emscripten:register_wheel_callback/1 199 | emscripten:register_wheel_callback/2 200 | emscripten:register_wheel_callback/3 201 | emscripten:run_script/1 202 | emscripten:run_script/2 203 | emscripten:unregister_blur_callback/1 204 | emscripten:unregister_click_callback/1 205 | emscripten:unregister_dblclick_callback/1 206 | emscripten:unregister_focus_callback/1 207 | emscripten:unregister_focusin_callback/1 208 | emscripten:unregister_focusout_callback/1 209 | emscripten:unregister_keydown_callback/1 210 | emscripten:unregister_keypress_callback/1 211 | emscripten:unregister_keyup_callback/1 212 | emscripten:unregister_mousedown_callback/1 213 | emscripten:unregister_mouseenter_callback/1 214 | emscripten:unregister_mouseleave_callback/1 215 | emscripten:unregister_mousemove_callback/1 216 | emscripten:unregister_mouseout_callback/1 217 | emscripten:unregister_mouseover_callback/1 218 | emscripten:unregister_mouseup_callback/1 219 | emscripten:unregister_resize_callback/1 220 | emscripten:unregister_scroll_callback/1 221 | emscripten:unregister_touchcancel_callback/1 222 | emscripten:unregister_touchend_callback/1 223 | emscripten:unregister_touchmove_callback/1 224 | emscripten:unregister_touchstart_callback/1 225 | emscripten:unregister_wheel_callback/1 226 | erlang:-/1 227 | erlang:!/2 228 | erlang:*/2 229 | erlang:++/2 230 | erlang:+/2 231 | erlang:-/2 232 | erlang:/=/2 233 | erlang:/2 239 | erlang:>=/2 240 | erlang:abs/1 241 | erlang:and/2 242 | erlang:apply/2 243 | erlang:apply/3 244 | erlang:atom_to_binary/1 245 | erlang:atom_to_binary/2 246 | erlang:atom_to_list/1 247 | erlang:band/2 248 | erlang:binary_to_atom/1 249 | erlang:binary_to_atom/2 250 | erlang:binary_to_existing_atom/1 251 | erlang:binary_to_existing_atom/2 252 | erlang:binary_to_float/1 253 | erlang:binary_to_integer/1 254 | erlang:binary_to_integer/2 255 | erlang:binary_to_list/1 256 | erlang:binary_to_term/1 257 | erlang:binary_to_term/2 258 | erlang:bit_size/1 259 | erlang:bnot/1 260 | erlang:bor/2 261 | erlang:bsl/2 262 | erlang:bsr/2 263 | erlang:bxor/2 264 | erlang:byte_size/1 265 | erlang:cancel_timer/1 266 | erlang:ceil/1 267 | erlang:delete_element/2 268 | erlang:demonitor/1 269 | erlang:demonitor/2 270 | erlang:display/1 271 | erlang:div/2 272 | erlang:element/2 273 | erlang:erase/1 274 | erlang:error/1 275 | erlang:error/2 276 | erlang:error/3 277 | erlang:exit/1 278 | erlang:exit/2 279 | erlang:fadd/2 280 | erlang:fdiv/2 281 | erlang:float_to_binary/1 282 | erlang:float_to_binary/2 283 | erlang:float_to_list/1 284 | erlang:float_to_list/2 285 | erlang:floor/1 286 | erlang:fmul/2 287 | erlang:fnegate/1 288 | erlang:fsub/2 289 | erlang:function_exported/3 290 | erlang:fun_to_list/1 291 | erlang:garbage_collect/0 292 | erlang:garbage_collect/1 293 | erlang:get/1 294 | erlang:get_module_info/1 295 | erlang:get_module_info/2 296 | erlang:group_leader/0 297 | erlang:group_leader/2 298 | erlang:hd/1 299 | erlang:insert_element/3 300 | erlang:integer_to_binary/1 301 | erlang:integer_to_binary/2 302 | erlang:integer_to_list/1 303 | erlang:integer_to_list/2 304 | erlang:iolist_size/1 305 | erlang:iolist_to_binary/1 306 | erlang:is_atom/1 307 | erlang:is_binary/1 308 | erlang:is_bitstring/1 309 | erlang:is_boolean/1 310 | erlang:is_float/1 311 | erlang:is_function/1 312 | erlang:is_integer/1 313 | erlang:is_list/1 314 | erlang:is_map/1 315 | erlang:is_map_key/2 316 | erlang:is_number/1 317 | erlang:is_pid/1 318 | erlang:is_process_alive/1 319 | erlang:is_reference/1 320 | erlang:is_tuple/1 321 | erlang:length/1 322 | erlang:link/1 323 | erlang:list_to_atom/1 324 | erlang:list_to_binary/1 325 | erlang:list_to_existing_atom/1 326 | erlang:list_to_float/1 327 | erlang:list_to_integer/1 328 | erlang:list_to_integer/2 329 | erlang:list_to_tuple/1 330 | erlang:localtime/0 331 | erlang:localtime/1 332 | erlang:make_fun/3 333 | erlang:make_ref/0 334 | erlang:make_tuple/2 335 | erlang:map_get/2 336 | erlang:map_size/1 337 | erlang:max/2 338 | erlang:md5/1 339 | erlang:memory/1 340 | erlang:min/2 341 | erlang:module_info/0 342 | erlang:module_info/1 343 | erlang:monitor/2 344 | erlang:monotonic_time/1 345 | erlang:not/1 346 | erlang:open_port/2 347 | erlang:or/2 348 | erlang:pid_to_list/1 349 | erlang:processes/0 350 | erlang:process_flag/2 351 | erlang:process_flag/3 352 | erlang:process_info/2 353 | erlang:put/2 354 | erlang:raise/2 355 | erlang:raise/3 356 | erlang:ref_to_list/1 357 | erlang:register/2 358 | erlang:rem/2 359 | erlang:round/1 360 | erlang:self/0 361 | erlang:send/2 362 | erlang:send_after/3 363 | erlang:setelement/3 364 | erlang:size/1 365 | erlang:spawn/1 366 | erlang:spawn/3 367 | erlang:spawn_link/1 368 | erlang:spawn_link/3 369 | erlang:spawn_opt/2 370 | erlang:spawn_opt/4 371 | erlang:start_timer/3 372 | erlang:start_timer/4 373 | erlang:system_flag/2 374 | erlang:system_info/1 375 | erlang:system_time/1 376 | erlang:term_to_binary/1 377 | erlang:throw/1 378 | erlang:timestamp/0 379 | erlang:tl/1 380 | erlang:trunc/1 381 | erlang:tuple_size/1 382 | erlang:tuple_to_list/1 383 | erlang:universaltime/0 384 | erlang:unlink/1 385 | erlang:unregister/1 386 | erlang:whereis/1 387 | erlang:xor/2 388 | erts_debug:flat_size/1 389 | erts_debug:module_info/0 390 | erts_debug:module_info/1 391 | esp32devmode:erase_net_config/0 392 | esp32devmode:handle_req/3 393 | esp32devmode:module_info/0 394 | esp32devmode:module_info/1 395 | esp32devmode:save_net_config/2 396 | esp32devmode:start_dev_mode/0 397 | esp32devmode:start_network/0 398 | esp32devmode:start_repl/1 399 | esp32init:module_info/0 400 | esp32init:module_info/1 401 | esp32init:start/0 402 | esp_adc:acquire/2 403 | esp_adc:acquire/4 404 | esp_adc:deinit/1 405 | esp_adc:handle_call/3 406 | esp_adc:handle_cast/2 407 | esp_adc:handle_info/2 408 | esp_adc:init/0 409 | esp_adc:init/1 410 | esp_adc:module_info/0 411 | esp_adc:module_info/1 412 | esp_adc:read/1 413 | esp_adc:read/2 414 | esp_adc:release_channel/1 415 | esp_adc:sample/2 416 | esp_adc:sample/3 417 | esp_adc:start/0 418 | esp_adc:start/1 419 | esp_adc:start/2 420 | esp_adc:stop/0 421 | esp_adc:stop/1 422 | esp_adc:terminate/2 423 | esp:deep_sleep/0 424 | esp:deep_sleep/1 425 | esp:deep_sleep_enable_gpio_wakeup/2 426 | esp:freq_hz/0 427 | esp:get_default_mac/0 428 | esp:get_mac/1 429 | esp:module_info/0 430 | esp:module_info/1 431 | esp:mount/4 432 | esp:nvs_erase_all/0 433 | esp:nvs_erase_all/1 434 | esp:nvs_erase_key/1 435 | esp:nvs_erase_key/2 436 | esp:nvs_fetch_binary/2 437 | esp:nvs_get_binary/1 438 | esp:nvs_get_binary/2 439 | esp:nvs_get_binary/3 440 | esp:nvs_put_binary/3 441 | esp:nvs_reformat/0 442 | esp:nvs_set_binary/2 443 | esp:nvs_set_binary/3 444 | esp:partition_list/0 445 | esp:reset_reason/0 446 | esp:restart/0 447 | esp:rtc_slow_get_binary/0 448 | esp:rtc_slow_set_binary/1 449 | esp:sleep_disable_ext1_wakeup_io/1 450 | esp:sleep_enable_ext0_wakeup/2 451 | esp:sleep_enable_ext1_wakeup/2 452 | esp:sleep_enable_ext1_wakeup_io/2 453 | esp:sleep_enable_ulp_wakeup/0 454 | esp:sleep_get_wakeup_cause/0 455 | esp:task_wdt_add_user/1 456 | esp:task_wdt_deinit/0 457 | esp:task_wdt_delete_user/1 458 | esp:task_wdt_init/1 459 | esp:task_wdt_reconfigure/1 460 | esp:task_wdt_reset_user/1 461 | esp:umount/1 462 | etest:assert_equals/2 463 | etest:assert_exception/1 464 | etest:assert_exception/2 465 | etest:assert_exception/3 466 | etest:assert_match/2 467 | etest:assert_true/1 468 | etest:flush_msg_queue/0 469 | etest:module_info/0 470 | etest:module_info/1 471 | etest:test/1 472 | gen_event:add_handler/3 473 | gen_event:delete_handler/3 474 | gen_event:handle_call/3 475 | gen_event:handle_cast/2 476 | gen_event:handle_info/2 477 | gen_event:init/1 478 | gen_event:module_info/0 479 | gen_event:module_info/1 480 | gen_event:notify/2 481 | gen_event:start/0 482 | gen_event:start/2 483 | gen_event:start_link/0 484 | gen_event:start_link/2 485 | gen_event:stop/1 486 | gen_event:sync_notify/2 487 | gen_event:terminate/2 488 | gen_server:behaviour_info/1 489 | gen_server:call/2 490 | gen_server:call/3 491 | gen_server:cast/2 492 | gen_server:init_it/4 493 | gen_server:init_it/5 494 | gen_server:module_info/0 495 | gen_server:module_info/1 496 | gen_server:reply/2 497 | gen_server:start/3 498 | gen_server:start/4 499 | gen_server:start_link/3 500 | gen_server:start_link/4 501 | gen_server:start_monitor/3 502 | gen_server:start_monitor/4 503 | gen_server:stop/1 504 | gen_server:stop/3 505 | gen_statem:behaviour_info/1 506 | gen_statem:call/2 507 | gen_statem:call/3 508 | gen_statem:cast/2 509 | gen_statem:handle_call/3 510 | gen_statem:handle_cast/2 511 | gen_statem:handle_info/2 512 | gen_statem:init/1 513 | gen_statem:module_info/0 514 | gen_statem:module_info/1 515 | gen_statem:reply/2 516 | gen_statem:start/3 517 | gen_statem:start/4 518 | gen_statem:start_link/3 519 | gen_statem:start_link/4 520 | gen_statem:stop/1 521 | gen_statem:stop/3 522 | gen_statem:terminate/2 523 | gen_tcp:accept/1 524 | gen_tcp:accept/2 525 | gen_tcp:close/1 526 | gen_tcp:connect/3 527 | gen_tcp:controlling_process/2 528 | gen_tcp_inet:accept/1 529 | gen_tcp_inet:accept/2 530 | gen_tcp_inet:close/1 531 | gen_tcp_inet:connect/3 532 | gen_tcp_inet:controlling_process/2 533 | gen_tcp_inet:listen/2 534 | gen_tcp_inet:module_info/0 535 | gen_tcp_inet:module_info/1 536 | gen_tcp_inet:peername/1 537 | gen_tcp_inet:port/1 538 | gen_tcp_inet:recv/2 539 | gen_tcp_inet:recv/3 540 | gen_tcp_inet:send/2 541 | gen_tcp_inet:sockname/1 542 | gen_tcp:listen/2 543 | gen_tcp:module_info/0 544 | gen_tcp:module_info/1 545 | gen_tcp:recv/2 546 | gen_tcp:recv/3 547 | gen_tcp:send/2 548 | gen_tcp_socket:accept/1 549 | gen_tcp_socket:accept/2 550 | gen_tcp_socket:close/1 551 | gen_tcp_socket:connect/3 552 | gen_tcp_socket:controlling_process/2 553 | gen_tcp_socket:handle_call/3 554 | gen_tcp_socket:handle_cast/2 555 | gen_tcp_socket:handle_info/2 556 | gen_tcp_socket:init/1 557 | gen_tcp_socket:listen/2 558 | gen_tcp_socket:module_info/0 559 | gen_tcp_socket:module_info/1 560 | gen_tcp_socket:peername/1 561 | gen_tcp_socket:port/1 562 | gen_tcp_socket:recv/2 563 | gen_tcp_socket:recv/3 564 | gen_tcp_socket:send/2 565 | gen_tcp_socket:sockname/1 566 | gen_tcp_socket:terminate/2 567 | gen_udp:close/1 568 | gen_udp:controlling_process/2 569 | gen_udp_inet:close/1 570 | gen_udp_inet:controlling_process/2 571 | gen_udp_inet:module_info/0 572 | gen_udp_inet:module_info/1 573 | gen_udp_inet:open/1 574 | gen_udp_inet:open/2 575 | gen_udp_inet:port/1 576 | gen_udp_inet:recv/2 577 | gen_udp_inet:recv/3 578 | gen_udp_inet:send/4 579 | gen_udp_inet:sockname/1 580 | gen_udp:module_info/0 581 | gen_udp:module_info/1 582 | gen_udp:open/1 583 | gen_udp:open/2 584 | gen_udp:recv/2 585 | gen_udp:recv/3 586 | gen_udp:send/4 587 | gen_udp_socket:close/1 588 | gen_udp_socket:controlling_process/2 589 | gen_udp_socket:handle_call/3 590 | gen_udp_socket:handle_cast/2 591 | gen_udp_socket:handle_info/2 592 | gen_udp_socket:init/1 593 | gen_udp_socket:module_info/0 594 | gen_udp_socket:module_info/1 595 | gen_udp_socket:open/1 596 | gen_udp_socket:open/2 597 | gen_udp_socket:port/1 598 | gen_udp_socket:recv/2 599 | gen_udp_socket:recv/3 600 | gen_udp_socket:send/4 601 | gen_udp_socket:sockname/1 602 | gen_udp_socket:terminate/2 603 | gpio:attach_interrupt/2 604 | gpio:close/1 605 | gpio:deep_sleep_hold_dis/0 606 | gpio:deep_sleep_hold_en/0 607 | gpio:deinit/1 608 | gpio:detach_interrupt/1 609 | gpio:digital_read/1 610 | gpio:digital_write/2 611 | gpio:hold_dis/1 612 | gpio:hold_en/1 613 | gpio:init/1 614 | gpio:module_info/0 615 | gpio:module_info/1 616 | gpio:open/0 617 | gpio:read/2 618 | gpio:remove_int/2 619 | gpio:set_direction/3 620 | gpio:set_int/3 621 | gpio:set_int/4 622 | gpio:set_level/3 623 | gpio:set_pin_mode/2 624 | gpio:set_pin_pull/2 625 | gpio:start/0 626 | gpio:stop/0 627 | http_server:module_info/0 628 | http_server:module_info/1 629 | http_server:parse_query_string/1 630 | http_server:reply/3 631 | http_server:reply/4 632 | http_server:start_server/2 633 | i2c:begin_transmission/2 634 | i2c:close/1 635 | i2c:end_transmission/1 636 | i2c:module_info/0 637 | i2c:module_info/1 638 | i2c:open/1 639 | i2c:read_bytes/3 640 | i2c:read_bytes/4 641 | i2c:write_byte/2 642 | i2c:write_bytes/2 643 | i2c:write_bytes/3 644 | i2c:write_bytes/4 645 | inet:close/1 646 | inet:module_info/0 647 | inet:module_info/1 648 | inet:peername/1 649 | inet:port/1 650 | inet:sockname/1 651 | io:format/1 652 | io:format/2 653 | io:get_line/1 654 | io_lib:format/2 655 | io_lib:latin1_char_list/1 656 | io_lib:module_info/0 657 | io_lib:module_info/1 658 | io:module_info/0 659 | io:module_info/1 660 | io:put_chars/1 661 | io:put_chars/2 662 | json_encoder:encode/1 663 | json_encoder:module_info/0 664 | json_encoder:module_info/1 665 | ledc:channel_config/1 666 | ledc:fade_func_install/1 667 | ledc:fade_func_uninstall/0 668 | ledc:fade_start/3 669 | ledc:get_duty/2 670 | ledc:get_freq/2 671 | ledc:module_info/0 672 | ledc:module_info/1 673 | ledc:set_duty/3 674 | ledc:set_fade_with_step/5 675 | ledc:set_fade_with_time/4 676 | ledc:set_freq/3 677 | ledc:stop/3 678 | ledc:timer_config/1 679 | ledc:update_duty/2 680 | lists:all/2 681 | lists:any/2 682 | lists:delete/2 683 | lists:duplicate/2 684 | lists:filter/2 685 | lists:filtermap/2 686 | lists:flatten/1 687 | lists:foldl/3 688 | lists:foldr/3 689 | lists:foreach/2 690 | lists:join/2 691 | lists:keydelete/3 692 | lists:keyfind/3 693 | lists:keymember/3 694 | lists:keyreplace/4 695 | lists:keystore/4 696 | lists:keytake/3 697 | lists:last/1 698 | lists:map/2 699 | lists:mapfoldl/3 700 | lists:member/2 701 | lists:module_info/0 702 | lists:module_info/1 703 | lists:nth/2 704 | lists:nthtail/2 705 | lists:reverse/1 706 | lists:reverse/2 707 | lists:search/2 708 | lists:seq/2 709 | lists:seq/3 710 | lists:sort/1 711 | lists:sort/2 712 | lists:split/2 713 | lists:sublist/2 714 | lists:usort/1 715 | lists:usort/2 716 | logger:alert/1 717 | logger:alert/2 718 | logger:alert/3 719 | logger:allow/2 720 | logger:compare/2 721 | logger:critical/1 722 | logger:critical/2 723 | logger:critical/3 724 | logger:debug/1 725 | logger:debug/2 726 | logger:debug/3 727 | logger:emergency/1 728 | logger:emergency/2 729 | logger:emergency/3 730 | logger:error/1 731 | logger:error/2 732 | logger:error/3 733 | logger:info/1 734 | logger:info/2 735 | logger:info/3 736 | logger:log/2 737 | logger:log/3 738 | logger:log/4 739 | logger:macro_log/3 740 | logger:macro_log/4 741 | logger:macro_log/5 742 | logger_manager:allow/2 743 | logger_manager:get_handlers/0 744 | logger_manager:get_id/0 745 | logger_manager:handle_call/3 746 | logger_manager:handle_cast/2 747 | logger_manager:handle_info/2 748 | logger_manager:init/1 749 | logger_manager:module_info/0 750 | logger_manager:module_info/1 751 | logger_manager:start_link/1 752 | logger_manager:stop/0 753 | logger_manager:terminate/2 754 | logger:module_info/0 755 | logger:module_info/1 756 | logger:notice/1 757 | logger:notice/2 758 | logger:notice/3 759 | logger_std_h:log/2 760 | logger_std_h:module_info/0 761 | logger_std_h:module_info/1 762 | logger:warning/1 763 | logger:warning/2 764 | logger:warning/3 765 | maps:filter/2 766 | maps:find/2 767 | maps:fold/3 768 | maps:foreach/2 769 | maps:from_keys/2 770 | maps:from_list/1 771 | maps:get/2 772 | maps:get/3 773 | maps:is_key/2 774 | maps:iterator/1 775 | maps:iterator/2 776 | maps:keys/1 777 | maps:map/2 778 | maps:merge/2 779 | maps:merge_with/3 780 | maps:module_info/0 781 | maps:module_info/1 782 | maps:new/0 783 | maps:next/1 784 | maps:put/3 785 | maps:remove/2 786 | maps:size/1 787 | maps:to_list/1 788 | maps:update/3 789 | maps:values/1 790 | math:acos/1 791 | math:acosh/1 792 | math:asin/1 793 | math:asinh/1 794 | math:atan/1 795 | math:atan2/2 796 | math:atanh/1 797 | math:ceil/1 798 | math:cos/1 799 | math:cosh/1 800 | math:exp/1 801 | math:floor/1 802 | math:fmod/2 803 | math:log/1 804 | math:log10/1 805 | math:log2/1 806 | math:module_info/0 807 | math:module_info/1 808 | math:pi/0 809 | math:pow/2 810 | math:sin/1 811 | math:sinh/1 812 | math:sqrt/1 813 | math:tan/1 814 | math:tanh/1 815 | net:getaddrinfo/1 816 | net:getaddrinfo/2 817 | net:getaddrinfo_nif/2 818 | net:module_info/0 819 | net:module_info/1 820 | network_fsm:module_info/0 821 | network_fsm:module_info/1 822 | network_fsm:start/1 823 | network_fsm:stop/0 824 | network_fsm:wait_for_ap/0 825 | network_fsm:wait_for_ap/1 826 | network_fsm:wait_for_ap/2 827 | network_fsm:wait_for_sta/0 828 | network_fsm:wait_for_sta/1 829 | network_fsm:wait_for_sta/2 830 | network:handle_call/3 831 | network:handle_cast/2 832 | network:handle_info/2 833 | network:init/1 834 | network:module_info/0 835 | network:module_info/1 836 | network:sta_rssi/0 837 | network:start/1 838 | network:start_link/1 839 | network:stop/0 840 | network:terminate/2 841 | network:wait_for_ap/0 842 | network:wait_for_ap/1 843 | network:wait_for_ap/2 844 | network:wait_for_sta/0 845 | network:wait_for_sta/1 846 | network:wait_for_sta/2 847 | pico:cyw43_arch_gpio_get/1 848 | pico:cyw43_arch_gpio_put/2 849 | pico:module_info/0 850 | pico:module_info/1 851 | pico:rtc_set_datetime/1 852 | port:call/2 853 | port:call/3 854 | port:module_info/0 855 | port:module_info/1 856 | proplists:compact/1 857 | proplists:delete/2 858 | proplists:from_map/1 859 | proplists:get_all_values/2 860 | proplists:get_bool/2 861 | proplists:get_value/2 862 | proplists:get_value/3 863 | proplists:is_defined/2 864 | proplists:lookup/2 865 | proplists:lookup_all/2 866 | proplists:module_info/0 867 | proplists:module_info/1 868 | proplists:property/1 869 | proplists:property/2 870 | proplists:to_map/1 871 | proplists:unfold/1 872 | queue:all/2 873 | queue:any/2 874 | queue:delete/2 875 | queue:delete_r/2 876 | queue:delete_with/2 877 | queue:delete_with_r/2 878 | queue:drop/1 879 | queue:drop_r/1 880 | queue:filter/2 881 | queue:filtermap/2 882 | queue:fold/3 883 | queue:from_list/1 884 | queue:get/1 885 | queue:get_r/1 886 | queue:in/2 887 | queue:in_r/2 888 | queue:is_empty/1 889 | queue:is_queue/1 890 | queue:join/2 891 | queue:len/1 892 | queue:member/2 893 | queue:module_info/0 894 | queue:module_info/1 895 | queue:new/0 896 | queue:out/1 897 | queue:out_r/1 898 | queue:peek/1 899 | queue:peek_r/1 900 | queue:reverse/1 901 | queue:split/2 902 | queue:to_list/1 903 | sets:add_element/2 904 | sets:del_element/2 905 | sets:filter/2 906 | sets:filtermap/2 907 | sets:fold/3 908 | sets:from_list/1 909 | sets:from_list/2 910 | sets:intersection/1 911 | sets:intersection/2 912 | sets:is_disjoint/2 913 | sets:is_element/2 914 | sets:is_empty/1 915 | sets:is_equal/2 916 | sets:is_set/1 917 | sets:is_subset/2 918 | sets:map/2 919 | sets:module_info/0 920 | sets:module_info/1 921 | sets:new/0 922 | sets:new/1 923 | sets:size/1 924 | sets:subtract/2 925 | sets:to_list/1 926 | sets:union/1 927 | sets:union/2 928 | sexp_lexer:module_info/0 929 | sexp_lexer:module_info/1 930 | sexp_lexer:string/1 931 | sexp_parser:module_info/0 932 | sexp_parser:module_info/1 933 | sexp_parser:parse/1 934 | sexp_serializer:module_info/0 935 | sexp_serializer:module_info/1 936 | sexp_serializer:serialize/1 937 | socket:accept/1 938 | socket:accept/2 939 | socket:bind/2 940 | socket:close/1 941 | socket:connect/2 942 | socket:listen/1 943 | socket:listen/2 944 | socket:module_info/0 945 | socket:module_info/1 946 | socket:nif_accept/1 947 | socket:nif_recv/2 948 | socket:nif_recvfrom/2 949 | socket:nif_select_read/2 950 | socket:nif_select_stop/1 951 | socket:nif_send/2 952 | socket:nif_sendto/3 953 | socket:open/3 954 | socket:peername/1 955 | socket:recv/1 956 | socket:recv/2 957 | socket:recv/3 958 | socket:recvfrom/1 959 | socket:recvfrom/2 960 | socket:recvfrom/3 961 | socket:send/2 962 | socket:sendto/3 963 | socket:setopt/3 964 | socket:shutdown/2 965 | socket:sockname/1 966 | spi:close/1 967 | spi:module_info/0 968 | spi:module_info/1 969 | spi:open/1 970 | spi:read_at/4 971 | spi:write/3 972 | spi:write_at/5 973 | spi:write_read/3 974 | ssl:close/1 975 | ssl:connect/3 976 | ssl:handle_call/3 977 | ssl:handle_cast/2 978 | ssl:handle_info/2 979 | ssl:init/1 980 | ssl:module_info/0 981 | ssl:module_info/1 982 | ssl:nif_close_notify/1 983 | ssl:nif_conf_authmode/2 984 | ssl:nif_config_defaults/3 985 | ssl:nif_config_init/0 986 | ssl:nif_conf_rng/2 987 | ssl:nif_ctr_drbg_init/0 988 | ssl:nif_ctr_drbg_seed/3 989 | ssl:nif_entropy_init/0 990 | ssl:nif_handshake_step/1 991 | ssl:nif_init/0 992 | ssl:nif_read/2 993 | ssl:nif_set_bio/2 994 | ssl:nif_set_hostname/2 995 | ssl:nif_setup/2 996 | ssl:nif_write/2 997 | ssl:recv/2 998 | ssl:send/2 999 | ssl:start/0 1000 | ssl:stop/0 1001 | ssl:terminate/2 1002 | string:find/2 1003 | string:find/3 1004 | string:module_info/0 1005 | string:module_info/1 1006 | string:split/2 1007 | string:split/3 1008 | string:to_lower/1 1009 | string:to_upper/1 1010 | string:trim/1 1011 | string:trim/2 1012 | supervisor:handle_call/3 1013 | supervisor:handle_cast/2 1014 | supervisor:handle_info/2 1015 | supervisor:init/1 1016 | supervisor:module_info/0 1017 | supervisor:module_info/1 1018 | supervisor:start_link/2 1019 | supervisor:start_link/3 1020 | timer_manager:cancel_timer/1 1021 | timer_manager:get_timer_refs/0 1022 | timer_manager:handle_call/3 1023 | timer_manager:handle_cast/2 1024 | timer_manager:handle_info/2 1025 | timer_manager:init/1 1026 | timer_manager:module_info/0 1027 | timer_manager:module_info/1 1028 | timer_manager:run_timer/5 1029 | timer_manager:send_after/3 1030 | timer_manager:send_after_timer/3 1031 | timer_manager:start/0 1032 | timer_manager:start_timer/3 1033 | timer_manager:terminate/2 1034 | timer:module_info/0 1035 | timer:module_info/1 1036 | timer:sleep/1 1037 | timestamp_util:delta/2 1038 | timestamp_util:delta_ms/2 1039 | timestamp_util:module_info/0 1040 | timestamp_util:module_info/1 1041 | uart:close/1 1042 | uart:module_info/0 1043 | uart:module_info/1 1044 | uart:open/1 1045 | uart:open/2 1046 | uart:read/1 1047 | uart:write/2 1048 | unicode:characters_to_binary/1 1049 | unicode:characters_to_binary/2 1050 | unicode:characters_to_binary/3 1051 | unicode:characters_to_list/1 1052 | unicode:characters_to_list/2 1053 | unicode:module_info/0 1054 | unicode:module_info/1 1055 | Elixir.Access:fetch!/2 1056 | Elixir.Access:fetch/2 1057 | Elixir.Access:get/2 1058 | Elixir.Access:get/3 1059 | Elixir.Access:__info__/1 1060 | Elixir.Access:module_info/0 1061 | Elixir.Access:module_info/1 1062 | Elixir.ArgumentError:exception/1 1063 | Elixir.ArgumentError:__info__/1 1064 | Elixir.ArgumentError:message/1 1065 | Elixir.ArgumentError:module_info/0 1066 | Elixir.ArgumentError:module_info/1 1067 | Elixir.ArgumentError:__struct__/0 1068 | Elixir.ArgumentError:__struct__/1 1069 | Elixir.ArithmeticError:exception/1 1070 | Elixir.ArithmeticError:__info__/1 1071 | Elixir.ArithmeticError:message/1 1072 | Elixir.ArithmeticError:module_info/0 1073 | Elixir.ArithmeticError:module_info/1 1074 | Elixir.ArithmeticError:__struct__/0 1075 | Elixir.ArithmeticError:__struct__/1 1076 | Elixir.AVMPort:call/2 1077 | Elixir.AVMPort:call/3 1078 | Elixir.AVMPort:__info__/1 1079 | Elixir.AVMPort:module_info/0 1080 | Elixir.AVMPort:module_info/1 1081 | Elixir.AVMPort:open/2 1082 | Elixir.BadArityError:exception/1 1083 | Elixir.BadArityError:__info__/1 1084 | Elixir.BadArityError:message/1 1085 | Elixir.BadArityError:module_info/0 1086 | Elixir.BadArityError:module_info/1 1087 | Elixir.BadArityError:__struct__/0 1088 | Elixir.BadArityError:__struct__/1 1089 | Elixir.BadBooleanError:exception/1 1090 | Elixir.BadBooleanError:__info__/1 1091 | Elixir.BadBooleanError:message/1 1092 | Elixir.BadBooleanError:module_info/0 1093 | Elixir.BadBooleanError:module_info/1 1094 | Elixir.BadBooleanError:__struct__/0 1095 | Elixir.BadBooleanError:__struct__/1 1096 | Elixir.BadFunctionError:exception/1 1097 | Elixir.BadFunctionError:__info__/1 1098 | Elixir.BadFunctionError:message/1 1099 | Elixir.BadFunctionError:module_info/0 1100 | Elixir.BadFunctionError:module_info/1 1101 | Elixir.BadFunctionError:__struct__/0 1102 | Elixir.BadFunctionError:__struct__/1 1103 | Elixir.BadMapError:exception/1 1104 | Elixir.BadMapError:__info__/1 1105 | Elixir.BadMapError:message/1 1106 | Elixir.BadMapError:module_info/0 1107 | Elixir.BadMapError:module_info/1 1108 | Elixir.BadMapError:__struct__/0 1109 | Elixir.BadMapError:__struct__/1 1110 | Elixir.BadStructError:exception/1 1111 | Elixir.BadStructError:__info__/1 1112 | Elixir.BadStructError:message/1 1113 | Elixir.BadStructError:module_info/0 1114 | Elixir.BadStructError:module_info/1 1115 | Elixir.BadStructError:__struct__/0 1116 | Elixir.BadStructError:__struct__/1 1117 | Elixir.Base:decode16!/1 1118 | Elixir.Base:decode16/1 1119 | Elixir.Base:decode16!/2 1120 | Elixir.Base:decode16/2 1121 | Elixir.Base:encode16/1 1122 | Elixir.Base:encode16/2 1123 | Elixir.Base:__info__/1 1124 | Elixir.Base:module_info/0 1125 | Elixir.Base:module_info/1 1126 | Elixir.Bitwise:~~~/1 1127 | Elixir.Bitwise:&&&/2 1128 | Elixir.Bitwise:<<>>/2 1130 | Elixir.Bitwise:^^^/2 1131 | Elixir.Bitwise:|||/2 1132 | Elixir.Bitwise:band/2 1133 | Elixir.Bitwise:bnot/1 1134 | Elixir.Bitwise:bor/2 1135 | Elixir.Bitwise:bsl/2 1136 | Elixir.Bitwise:bsr/2 1137 | Elixir.Bitwise:bxor/2 1138 | Elixir.Bitwise:__info__/1 1139 | Elixir.Bitwise:MACRO-__using__/2 1140 | Elixir.Bitwise:module_info/0 1141 | Elixir.Bitwise:module_info/1 1142 | Elixir.CaseClauseError:exception/1 1143 | Elixir.CaseClauseError:__info__/1 1144 | Elixir.CaseClauseError:message/1 1145 | Elixir.CaseClauseError:module_info/0 1146 | Elixir.CaseClauseError:module_info/1 1147 | Elixir.CaseClauseError:__struct__/0 1148 | Elixir.CaseClauseError:__struct__/1 1149 | Elixir.Code:ensure_compiled/1 1150 | Elixir.Code:ensure_compiled?/1 1151 | Elixir.Code:__info__/1 1152 | Elixir.Code:module_info/0 1153 | Elixir.Code:module_info/1 1154 | Elixir.Collectable:behaviour_info/1 1155 | Elixir.Collectable:impl_for!/1 1156 | Elixir.Collectable:impl_for/1 1157 | Elixir.Collectable:__info__/1 1158 | Elixir.Collectable:into/1 1159 | Elixir.Collectable.List:__impl__/1 1160 | Elixir.Collectable.List:__info__/1 1161 | Elixir.Collectable.List:into/1 1162 | Elixir.Collectable.List:module_info/0 1163 | Elixir.Collectable.List:module_info/1 1164 | Elixir.Collectable.Map:__impl__/1 1165 | Elixir.Collectable.Map:__info__/1 1166 | Elixir.Collectable.Map:into/1 1167 | Elixir.Collectable.Map:module_info/0 1168 | Elixir.Collectable.Map:module_info/1 1169 | Elixir.Collectable.MapSet:__impl__/1 1170 | Elixir.Collectable.MapSet:__info__/1 1171 | Elixir.Collectable.MapSet:into/1 1172 | Elixir.Collectable.MapSet:module_info/0 1173 | Elixir.Collectable.MapSet:module_info/1 1174 | Elixir.Collectable:module_info/0 1175 | Elixir.Collectable:module_info/1 1176 | Elixir.Collectable:__protocol__/1 1177 | Elixir.CondClauseError:exception/1 1178 | Elixir.CondClauseError:__info__/1 1179 | Elixir.CondClauseError:message/1 1180 | Elixir.CondClauseError:module_info/0 1181 | Elixir.CondClauseError:module_info/1 1182 | Elixir.CondClauseError:__struct__/0 1183 | Elixir.CondClauseError:__struct__/1 1184 | Elixir.Console:flush/0 1185 | Elixir.Console:flush/1 1186 | Elixir.Console:__info__/1 1187 | Elixir.Console:module_info/0 1188 | Elixir.Console:module_info/1 1189 | Elixir.Console:print/1 1190 | Elixir.Console:puts/1 1191 | Elixir.Console:puts/2 1192 | Elixir.Enum:all?/1 1193 | Elixir.Enum:all?/2 1194 | Elixir.Enum:any?/1 1195 | Elixir.Enum:any?/2 1196 | Elixir.Enum:at/2 1197 | Elixir.Enum:at/3 1198 | Elixir.Enum:chunk_by/2 1199 | Elixir.Enum:chunk_while/4 1200 | Elixir.Enum:count/1 1201 | Elixir.Enum:each/2 1202 | Elixir.Enumerable:behaviour_info/1 1203 | Elixir.Enumerable:count/1 1204 | Elixir.Enumerable:impl_for!/1 1205 | Elixir.Enumerable:impl_for/1 1206 | Elixir.Enumerable:__info__/1 1207 | Elixir.Enumerable.List:count/1 1208 | Elixir.Enumerable.List:__impl__/1 1209 | Elixir.Enumerable.List:__info__/1 1210 | Elixir.Enumerable.List:member?/2 1211 | Elixir.Enumerable.List:module_info/0 1212 | Elixir.Enumerable.List:module_info/1 1213 | Elixir.Enumerable.List:reduce/3 1214 | Elixir.Enumerable.List:slice/1 1215 | Elixir.Enumerable.List:slice/4 1216 | Elixir.Enumerable.Map:count/1 1217 | Elixir.Enumerable.Map:__impl__/1 1218 | Elixir.Enumerable.Map:__info__/1 1219 | Elixir.Enumerable.Map:member?/2 1220 | Elixir.Enumerable.Map:module_info/0 1221 | Elixir.Enumerable.Map:module_info/1 1222 | Elixir.Enumerable.Map:reduce/3 1223 | Elixir.Enumerable.MapSet:count/1 1224 | Elixir.Enumerable.MapSet:__impl__/1 1225 | Elixir.Enumerable.MapSet:__info__/1 1226 | Elixir.Enumerable.MapSet:member?/2 1227 | Elixir.Enumerable.MapSet:module_info/0 1228 | Elixir.Enumerable.MapSet:module_info/1 1229 | Elixir.Enumerable.MapSet:reduce/3 1230 | Elixir.Enumerable.MapSet:slice/1 1231 | Elixir.Enumerable.Map:slice/1 1232 | Elixir.Enumerable:member?/2 1233 | Elixir.Enumerable:module_info/0 1234 | Elixir.Enumerable:module_info/1 1235 | Elixir.Enumerable:__protocol__/1 1236 | Elixir.Enumerable.Range:count/1 1237 | Elixir.Enumerable.Range:__impl__/1 1238 | Elixir.Enumerable.Range:__info__/1 1239 | Elixir.Enumerable.Range:member?/2 1240 | Elixir.Enumerable.Range:module_info/0 1241 | Elixir.Enumerable.Range:module_info/1 1242 | Elixir.Enumerable.Range:reduce/3 1243 | Elixir.Enumerable.Range:slice/1 1244 | Elixir.Enumerable:reduce/3 1245 | Elixir.Enumerable:slice/1 1246 | Elixir.Enum:filter/2 1247 | Elixir.Enum:find/2 1248 | Elixir.Enum:find/3 1249 | Elixir.Enum:find_index/2 1250 | Elixir.Enum:find_value/2 1251 | Elixir.Enum:find_value/3 1252 | Elixir.Enum:flat_map/2 1253 | Elixir.Enum:__info__/1 1254 | Elixir.Enum:into/2 1255 | Elixir.Enum:into/3 1256 | Elixir.Enum:join/1 1257 | Elixir.Enum:join/2 1258 | Elixir.Enum:map/2 1259 | Elixir.Enum:map_join/2 1260 | Elixir.Enum:map_join/3 1261 | Elixir.Enum:member?/2 1262 | Elixir.Enum:module_info/0 1263 | Elixir.Enum:module_info/1 1264 | Elixir.Enum:reduce/3 1265 | Elixir.Enum:reject/2 1266 | Elixir.Enum:reverse/1 1267 | Elixir.Enum:slice/2 1268 | Elixir.Enum:slice/3 1269 | Elixir.Enum:split_with/2 1270 | Elixir.Enum:to_list/1 1271 | Elixir.ErlangError:exception/1 1272 | Elixir.ErlangError:__info__/1 1273 | Elixir.ErlangError:message/1 1274 | Elixir.ErlangError:module_info/0 1275 | Elixir.ErlangError:module_info/1 1276 | Elixir.ErlangError:normalize/2 1277 | Elixir.ErlangError:__struct__/0 1278 | Elixir.ErlangError:__struct__/1 1279 | Elixir.Exception:behaviour_info/1 1280 | Elixir.Exception:blame/3 1281 | Elixir.Exception:exception?/1 1282 | Elixir.Exception:format/2 1283 | Elixir.Exception:format/3 1284 | Elixir.Exception:format_banner/2 1285 | Elixir.Exception:format_banner/3 1286 | Elixir.Exception:format_exit/1 1287 | Elixir.Exception:format_fa/2 1288 | Elixir.Exception:format_file_line/2 1289 | Elixir.Exception:format_file_line/3 1290 | Elixir.Exception:format_mfa/3 1291 | Elixir.Exception:format_stacktrace/0 1292 | Elixir.Exception:format_stacktrace/1 1293 | Elixir.Exception:format_stacktrace_entry/1 1294 | Elixir.Exception:__info__/1 1295 | Elixir.Exception:message/1 1296 | Elixir.Exception:module_info/0 1297 | Elixir.Exception:module_info/1 1298 | Elixir.Exception:normalize/2 1299 | Elixir.Exception:normalize/3 1300 | Elixir.Esp.ADC:acquire/4 1301 | Elixir.Esp.ADC:deinit/1 1302 | Elixir.Esp.ADC:init/0 1303 | Elixir.Esp.ADC:release_channel/1 1304 | Elixir.Esp.ADC:sample/3 1305 | Elixir.FunctionClauseError:exception/1 1306 | Elixir.FunctionClauseError:__info__/1 1307 | Elixir.FunctionClauseError:message/1 1308 | Elixir.FunctionClauseError:module_info/0 1309 | Elixir.FunctionClauseError:module_info/1 1310 | Elixir.FunctionClauseError:__struct__/0 1311 | Elixir.FunctionClauseError:__struct__/1 1312 | Elixir.GPIO:attach_interrupt/2 1313 | Elixir.GPIO:close/1 1314 | Elixir.GPIO:deep_sleep_hold_dis/0 1315 | Elixir.GPIO:deep_sleep_hold_en/0 1316 | Elixir.GPIO:deinit/1 1317 | Elixir.GPIO:detach_interrupt/1 1318 | Elixir.GPIO:digital_read/1 1319 | Elixir.GPIO:digital_write/2 1320 | Elixir.GPIO:hold_dis/1 1321 | Elixir.GPIO:hold_en/1 1322 | Elixir.GPIO:__info__/1 1323 | Elixir.GPIO:init/1 1324 | Elixir.GPIO:module_info/0 1325 | Elixir.GPIO:module_info/1 1326 | Elixir.GPIO:open/0 1327 | Elixir.GPIO:read/2 1328 | Elixir.GPIO:remove_int/2 1329 | Elixir.GPIO:set_direction/3 1330 | Elixir.GPIO:set_int/3 1331 | Elixir.GPIO:set_level/3 1332 | Elixir.GPIO:set_pin_mode/2 1333 | Elixir.GPIO:set_pin_pull/2 1334 | Elixir.GPIO:stop/0 1335 | Elixir.I2C:begin_transmission/2 1336 | Elixir.I2C:close/1 1337 | Elixir.I2C:end_transmission/1 1338 | Elixir.I2C:__info__/1 1339 | Elixir.I2C:module_info/0 1340 | Elixir.I2C:module_info/1 1341 | Elixir.I2C:open/1 1342 | Elixir.I2C:read_bytes/3 1343 | Elixir.I2C:read_bytes/4 1344 | Elixir.I2C:write_byte/2 1345 | Elixir.I2C:write_bytes/2 1346 | Elixir.I2C:write_bytes/3 1347 | Elixir.I2C:write_bytes/4 1348 | Elixir.Integer:floor_div/2 1349 | Elixir.Integer:gcd/2 1350 | Elixir.Integer:__info__/1 1351 | Elixir.Integer:MACRO-is_even/2 1352 | Elixir.Integer:MACRO-is_odd/2 1353 | Elixir.Integer:mod/2 1354 | Elixir.Integer:module_info/0 1355 | Elixir.Integer:module_info/1 1356 | Elixir.Integer:to_charlist/1 1357 | Elixir.Integer:to_charlist/2 1358 | Elixir.Integer:to_string/1 1359 | Elixir.Integer:to_string/2 1360 | Elixir.IO:chardata_to_string/1 1361 | Elixir.IO:__info__/1 1362 | Elixir.IO:inspect/1 1363 | Elixir.IO:iodata_to_binary/1 1364 | Elixir.IO:module_info/0 1365 | Elixir.IO:module_info/1 1366 | Elixir.IO:puts/1 1367 | Elixir.Kernel:abs/1 1368 | Elixir.Kernel:div/2 1369 | Elixir.Kernel:__info__/1 1370 | Elixir.Kernel:inspect/1 1371 | Elixir.Kernel:inspect/2 1372 | Elixir.Kernel:max/2 1373 | Elixir.Kernel:min/2 1374 | Elixir.Kernel:module_info/0 1375 | Elixir.Kernel:module_info/1 1376 | Elixir.Kernel:rem/2 1377 | Elixir.Kernel:struct!/1 1378 | Elixir.Kernel:struct/1 1379 | Elixir.Kernel:struct!/2 1380 | Elixir.Kernel:struct/2 1381 | Elixir.KeyError:blame/2 1382 | Elixir.KeyError:exception/1 1383 | Elixir.KeyError:__info__/1 1384 | Elixir.KeyError:message/1 1385 | Elixir.KeyError:message/2 1386 | Elixir.KeyError:module_info/0 1387 | Elixir.KeyError:module_info/1 1388 | Elixir.KeyError:__struct__/0 1389 | Elixir.KeyError:__struct__/1 1390 | Elixir.Keyword:delete/2 1391 | Elixir.Keyword:fetch!/2 1392 | Elixir.Keyword:fetch/2 1393 | Elixir.Keyword:get/2 1394 | Elixir.Keyword:get/3 1395 | Elixir.Keyword:get_lazy/3 1396 | Elixir.Keyword:has_key?/2 1397 | Elixir.Keyword:__info__/1 1398 | Elixir.Keyword:keyword?/1 1399 | Elixir.Keyword:merge/2 1400 | Elixir.Keyword:module_info/0 1401 | Elixir.Keyword:module_info/1 1402 | Elixir.Keyword:pop!/2 1403 | Elixir.Keyword:pop/2 1404 | Elixir.Keyword:pop/3 1405 | Elixir.Keyword:put/3 1406 | Elixir.Keyword:split/2 1407 | Elixir.Keyword:take/2 1408 | Elixir.LEDC:channel_config/1 1409 | Elixir.LEDC:fade_func_install/1 1410 | Elixir.LEDC:fade_func_uninstall/0 1411 | Elixir.LEDC:fade_no_wait/0 1412 | Elixir.LEDC:fade_start/3 1413 | Elixir.LEDC:fade_wait_done/0 1414 | Elixir.LEDC:get_duty/2 1415 | Elixir.LEDC:get_freq/2 1416 | Elixir.LEDC:high_speed_mode/0 1417 | Elixir.LEDC:__info__/1 1418 | Elixir.LEDC:low_speed_mode/0 1419 | Elixir.LEDC:module_info/0 1420 | Elixir.LEDC:module_info/1 1421 | Elixir.LEDC:set_duty/3 1422 | Elixir.LEDC:set_fade_with_step/5 1423 | Elixir.LEDC:set_fade_with_time/4 1424 | Elixir.LEDC:set_freq/3 1425 | Elixir.LEDC:stop/3 1426 | Elixir.LEDC:timer_config/1 1427 | Elixir.LEDC:update_duty/2 1428 | Elixir.List:ascii_printable?/1 1429 | Elixir.List:ascii_printable?/2 1430 | Elixir.List.Chars.Atom:__impl__/1 1431 | Elixir.List.Chars.Atom:__info__/1 1432 | Elixir.List.Chars.Atom:module_info/0 1433 | Elixir.List.Chars.Atom:module_info/1 1434 | Elixir.List.Chars.Atom:to_charlist/1 1435 | Elixir.List.Chars:behaviour_info/1 1436 | Elixir.List.Chars.BitString:__impl__/1 1437 | Elixir.List.Chars.BitString:__info__/1 1438 | Elixir.List.Chars.BitString:module_info/0 1439 | Elixir.List.Chars.BitString:module_info/1 1440 | Elixir.List.Chars.BitString:to_charlist/1 1441 | Elixir.List.Chars.Float:__impl__/1 1442 | Elixir.List.Chars.Float:__info__/1 1443 | Elixir.List.Chars.Float:module_info/0 1444 | Elixir.List.Chars.Float:module_info/1 1445 | Elixir.List.Chars.Float:to_charlist/1 1446 | Elixir.List.Chars:impl_for!/1 1447 | Elixir.List.Chars:impl_for/1 1448 | Elixir.List.Chars:__info__/1 1449 | Elixir.List.Chars.Integer:__impl__/1 1450 | Elixir.List.Chars.Integer:__info__/1 1451 | Elixir.List.Chars.Integer:module_info/0 1452 | Elixir.List.Chars.Integer:module_info/1 1453 | Elixir.List.Chars.Integer:to_charlist/1 1454 | Elixir.List.Chars.List:__impl__/1 1455 | Elixir.List.Chars.List:__info__/1 1456 | Elixir.List.Chars.List:module_info/0 1457 | Elixir.List.Chars.List:module_info/1 1458 | Elixir.List.Chars.List:to_charlist/1 1459 | Elixir.List.Chars:module_info/0 1460 | Elixir.List.Chars:module_info/1 1461 | Elixir.List.Chars:__protocol__/1 1462 | Elixir.List.Chars:to_charlist/1 1463 | Elixir.List:delete/2 1464 | Elixir.List:duplicate/2 1465 | Elixir.List:first/1 1466 | Elixir.List:flatten/1 1467 | Elixir.List:foldl/3 1468 | Elixir.List:foldr/3 1469 | Elixir.List:improper?/1 1470 | Elixir.List:__info__/1 1471 | Elixir.List:insert_at/3 1472 | Elixir.List:keydelete/3 1473 | Elixir.List:keyfind/3 1474 | Elixir.List:keyfind/4 1475 | Elixir.List:keymember?/3 1476 | Elixir.List:last/1 1477 | Elixir.List:module_info/0 1478 | Elixir.List:module_info/1 1479 | Elixir.List:replace_at/3 1480 | Elixir.List:starts_with?/2 1481 | Elixir.List:to_atom/1 1482 | Elixir.List:to_existing_atom/1 1483 | Elixir.List:to_float/1 1484 | Elixir.List:to_integer/1 1485 | Elixir.List:to_integer/2 1486 | Elixir.List:to_string/1 1487 | Elixir.List:to_tuple/1 1488 | Elixir.List:update_at/3 1489 | Elixir.List:wrap/1 1490 | Elixir.Map:delete/2 1491 | Elixir.Map:equal?/2 1492 | Elixir.Map:fetch!/2 1493 | Elixir.Map:fetch/2 1494 | Elixir.Map:from_struct/1 1495 | Elixir.Map:get/2 1496 | Elixir.Map:get/3 1497 | Elixir.Map:has_key?/2 1498 | Elixir.Map:__info__/1 1499 | Elixir.Map:merge/2 1500 | Elixir.Map:module_info/0 1501 | Elixir.Map:module_info/1 1502 | Elixir.Map:new/1 1503 | Elixir.Map:put/3 1504 | Elixir.Map:replace!/3 1505 | Elixir.Map:replace/3 1506 | Elixir.MapSet:delete/2 1507 | Elixir.MapSet:difference/2 1508 | Elixir.MapSet:disjoint?/2 1509 | Elixir.MapSet:equal?/2 1510 | Elixir.MapSet:filter/2 1511 | Elixir.MapSet:__info__/1 1512 | Elixir.MapSet:intersection/2 1513 | Elixir.MapSet:member?/2 1514 | Elixir.MapSet:module_info/0 1515 | Elixir.MapSet:module_info/1 1516 | Elixir.MapSet:new/0 1517 | Elixir.MapSet:new/1 1518 | Elixir.MapSet:new/2 1519 | Elixir.MapSet:put/2 1520 | Elixir.MapSet:reject/2 1521 | Elixir.MapSet:size/1 1522 | Elixir.MapSet:split_with/2 1523 | Elixir.MapSet:__struct__/0 1524 | Elixir.MapSet:__struct__/1 1525 | Elixir.MapSet:subset?/2 1526 | Elixir.MapSet:symmetric_difference/2 1527 | Elixir.MapSet:to_list/1 1528 | Elixir.MapSet:union/2 1529 | Elixir.MatchError:exception/1 1530 | Elixir.MatchError:__info__/1 1531 | Elixir.MatchError:message/1 1532 | Elixir.MatchError:module_info/0 1533 | Elixir.MatchError:module_info/1 1534 | Elixir.MatchError:__struct__/0 1535 | Elixir.MatchError:__struct__/1 1536 | Elixir.Module:concat/2 1537 | Elixir.Module:__info__/1 1538 | Elixir.Module:module_info/0 1539 | Elixir.Module:module_info/1 1540 | Elixir.Process:alive?/1 1541 | Elixir.Process:cancel_timer/1 1542 | Elixir.Process:flag/2 1543 | Elixir.Process:flag/3 1544 | Elixir.Process:__info__/1 1545 | Elixir.Process:info/1 1546 | Elixir.Process:info/2 1547 | Elixir.Process:list/0 1548 | Elixir.Process:module_info/0 1549 | Elixir.Process:module_info/1 1550 | Elixir.Process:register/2 1551 | Elixir.Process:send/2 1552 | Elixir.Process:send_after/3 1553 | Elixir.Process:send_after/4 1554 | Elixir.Process:sleep/1 1555 | Elixir.Process:spawn/2 1556 | Elixir.Process:spawn/4 1557 | Elixir.Process:unregister/1 1558 | Elixir.Process:whereis/1 1559 | Elixir.Protocol.UndefinedError:exception/1 1560 | Elixir.Protocol.UndefinedError:__info__/1 1561 | Elixir.Protocol.UndefinedError:message/1 1562 | Elixir.Protocol.UndefinedError:module_info/0 1563 | Elixir.Protocol.UndefinedError:module_info/1 1564 | Elixir.Protocol.UndefinedError:__struct__/0 1565 | Elixir.Protocol.UndefinedError:__struct__/1 1566 | Elixir.Range:disjoint?/2 1567 | Elixir.Range:__info__/1 1568 | Elixir.Range:module_info/0 1569 | Elixir.Range:module_info/1 1570 | Elixir.Range:new/2 1571 | Elixir.Range:__struct__/0 1572 | Elixir.Range:__struct__/1 1573 | Elixir.RuntimeError:exception/1 1574 | Elixir.RuntimeError:__info__/1 1575 | Elixir.RuntimeError:message/1 1576 | Elixir.RuntimeError:module_info/0 1577 | Elixir.RuntimeError:module_info/1 1578 | Elixir.RuntimeError:__struct__/0 1579 | Elixir.RuntimeError:__struct__/1 1580 | Elixir.String.Chars.Atom:__impl__/1 1581 | Elixir.String.Chars.Atom:__info__/1 1582 | Elixir.String.Chars.Atom:module_info/0 1583 | Elixir.String.Chars.Atom:module_info/1 1584 | Elixir.String.Chars.Atom:to_string/1 1585 | Elixir.String.Chars:behaviour_info/1 1586 | Elixir.String.Chars.BitString:__impl__/1 1587 | Elixir.String.Chars.BitString:__info__/1 1588 | Elixir.String.Chars.BitString:module_info/0 1589 | Elixir.String.Chars.BitString:module_info/1 1590 | Elixir.String.Chars.BitString:to_string/1 1591 | Elixir.String.Chars.Float:__impl__/1 1592 | Elixir.String.Chars.Float:__info__/1 1593 | Elixir.String.Chars.Float:module_info/0 1594 | Elixir.String.Chars.Float:module_info/1 1595 | Elixir.String.Chars.Float:to_string/1 1596 | Elixir.String.Chars:impl_for!/1 1597 | Elixir.String.Chars:impl_for/1 1598 | Elixir.String.Chars:__info__/1 1599 | Elixir.String.Chars.Integer:__impl__/1 1600 | Elixir.String.Chars.Integer:__info__/1 1601 | Elixir.String.Chars.Integer:module_info/0 1602 | Elixir.String.Chars.Integer:module_info/1 1603 | Elixir.String.Chars.Integer:to_string/1 1604 | Elixir.String.Chars.List:__impl__/1 1605 | Elixir.String.Chars.List:__info__/1 1606 | Elixir.String.Chars.List:module_info/0 1607 | Elixir.String.Chars.List:module_info/1 1608 | Elixir.String.Chars.List:to_string/1 1609 | Elixir.String.Chars:module_info/0 1610 | Elixir.String.Chars:module_info/1 1611 | Elixir.String.Chars:__protocol__/1 1612 | Elixir.String.Chars:to_string/1 1613 | Elixir.System:__info__/1 1614 | Elixir.SystemLimitError:exception/1 1615 | Elixir.SystemLimitError:__info__/1 1616 | Elixir.SystemLimitError:message/1 1617 | Elixir.SystemLimitError:module_info/0 1618 | Elixir.SystemLimitError:module_info/1 1619 | Elixir.SystemLimitError:__struct__/0 1620 | Elixir.SystemLimitError:__struct__/1 1621 | Elixir.System:module_info/0 1622 | Elixir.System:module_info/1 1623 | Elixir.System:monotonic_time/1 1624 | Elixir.System:system_time/1 1625 | Elixir.TryClauseError:exception/1 1626 | Elixir.TryClauseError:__info__/1 1627 | Elixir.TryClauseError:message/1 1628 | Elixir.TryClauseError:module_info/0 1629 | Elixir.TryClauseError:module_info/1 1630 | Elixir.TryClauseError:__struct__/0 1631 | Elixir.TryClauseError:__struct__/1 1632 | Elixir.Tuple:delete_at/2 1633 | Elixir.Tuple:duplicate/2 1634 | Elixir.Tuple:__info__/1 1635 | Elixir.Tuple:insert_at/3 1636 | Elixir.Tuple:module_info/0 1637 | Elixir.Tuple:module_info/1 1638 | Elixir.Tuple:to_list/1 1639 | Elixir.UndefinedFunctionError:blame/2 1640 | Elixir.UndefinedFunctionError:exception/1 1641 | Elixir.UndefinedFunctionError:__info__/1 1642 | Elixir.UndefinedFunctionError:message/1 1643 | Elixir.UndefinedFunctionError:module_info/0 1644 | Elixir.UndefinedFunctionError:module_info/1 1645 | Elixir.UndefinedFunctionError:__struct__/0 1646 | Elixir.UndefinedFunctionError:__struct__/1 1647 | Elixir.WithClauseError:exception/1 1648 | Elixir.WithClauseError:__info__/1 1649 | Elixir.WithClauseError:message/1 1650 | Elixir.WithClauseError:module_info/0 1651 | Elixir.WithClauseError:module_info/1 1652 | Elixir.WithClauseError:__struct__/0 1653 | Elixir.WithClauseError:__struct__/1 1654 | elixir_env:to_caller/1 1655 | elixir_erl_pass:no_parens_remote/2 1656 | -------------------------------------------------------------------------------- /priv/instructions.txt: -------------------------------------------------------------------------------- 1 | label 2 | func_info 3 | int_call_end 4 | call 5 | call_last 6 | call_only 7 | call_ext 8 | call_ext_last 9 | bif0 10 | bif1 11 | bif2 12 | allocate 13 | allocate_heap 14 | allocate_zero 15 | allocate_heap_zero 16 | test_heap 17 | kill 18 | deallocate 19 | return 20 | send 21 | remove_message 22 | timeout 23 | loop_rec 24 | loop_rec_end 25 | wait 26 | wait_timeout 27 | is_lt 28 | is_ge 29 | is_equal 30 | is_not_equal 31 | is_eq_exact 32 | is_not_eq_exact 33 | is_integer 34 | is_float 35 | is_number 36 | is_atom 37 | is_pid 38 | is_reference 39 | is_port 40 | is_nil 41 | is_binary 42 | is_list 43 | is_nonempty_list 44 | is_tuple 45 | test_arity 46 | select_val 47 | select_tuple_arity 48 | jump 49 | catch 50 | catch_end 51 | move 52 | get_list 53 | get_tuple_element 54 | set_tuple_element 55 | put_list 56 | put_tuple 57 | put 58 | badmatch 59 | if_end 60 | case_end 61 | call_fun 62 | is_function 63 | call_ext_only 64 | bs_put_integer 65 | bs_put_binary 66 | bs_put_string 67 | fclearerror 68 | fcheckerror 69 | fmove 70 | fconv 71 | fadd 72 | fsub 73 | fmul 74 | fdiv 75 | fnegate 76 | make_fun2 77 | try 78 | try_end 79 | try_case 80 | try_case_end 81 | raise 82 | bs_init2 83 | bs_add 84 | apply 85 | apply_last 86 | is_boolean 87 | is_function2 88 | bs_start_match2 89 | bs_get_integer2 90 | bs_get_float2 91 | bs_get_binary2 92 | bs_skip_bits2 93 | bs_test_tail2 94 | bs_save2 95 | bs_restore2 96 | gc_bif1 97 | gc_bif2 98 | is_bitstr 99 | bs_context_to_binary 100 | bs_test_unit 101 | bs_match_string 102 | bs_init_writable 103 | bs_append 104 | bs_private_append 105 | trim 106 | bs_init_bits 107 | bs_get_utf8 108 | bs_skip_utf8 109 | bs_get_utf16 110 | bs_skip_utf16 111 | bs_get_utf32 112 | bs_skip_utf32 113 | bs_utf8_size 114 | bs_put_utf8 115 | bs_utf16_size 116 | bs_put_utf16 117 | bs_put_utf32 118 | recv_mark 119 | recv_set 120 | gc_bif3 121 | line 122 | put_map_assoc 123 | put_map_exact 124 | is_map 125 | has_map_fields 126 | get_map_elements 127 | is_tagged_tuple 128 | build_stacktrace 129 | raw_raise 130 | get_hd 131 | get_tl 132 | put_tuple2 133 | bs_get_tail 134 | bs_start_match3 135 | bs_get_position 136 | bs_set_position 137 | swap 138 | bs_start_match4 139 | make_fun3 140 | init_yregs 141 | recv_marker_bind 142 | recv_marker_clear 143 | recv_marker_reserve 144 | recv_marker_use 145 | bs_create_bin 146 | call_fun2 147 | badrecord 148 | update_record 149 | bs_match 150 | test 151 | -------------------------------------------------------------------------------- /test/ex_atom_vm_test.exs: -------------------------------------------------------------------------------- 1 | defmodule ExAtomVMTest do 2 | use ExUnit.Case 3 | doctest ExAtomVM 4 | 5 | test "greets the world" do 6 | assert ExAtomVM.hello() == :world 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /test/test_helper.exs: -------------------------------------------------------------------------------- 1 | ExUnit.start() 2 | --------------------------------------------------------------------------------