├── .gitattributes ├── .github └── workflows │ └── gradle.yml ├── .gitignore ├── .gitmodules ├── LICENSE ├── README.md ├── build.gradle ├── buildSrc ├── build.gradle └── src │ └── main │ └── java │ └── tools │ └── elmfer │ ├── CompileNatives.java │ ├── GenNativeSources.java │ └── SaveVersion.java ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── screenshots ├── Screenshot from 2024-04-09 02-17-52.png ├── Screenshot from 2024-04-28 21-40-35.png └── Screenshot from 2024-05-01 16-52-53.png ├── settings.gradle ├── src └── main │ ├── cpp │ ├── CMakeLists.txt │ ├── bridge │ │ ├── README.txt │ │ ├── cnmcuJava.cpp │ │ ├── cnmcuJava.h │ │ ├── com_elmfer_cnmcu_cpp_NativesUtils.cpp │ │ ├── com_elmfer_cnmcu_cpp_NativesUtils.h │ │ ├── com_elmfer_cnmcu_mcu_NanoMCU.cpp │ │ ├── com_elmfer_cnmcu_mcu_NanoMCU.h │ │ ├── com_elmfer_cnmcu_mcu_cpu_MOS6502.cpp │ │ ├── com_elmfer_cnmcu_mcu_cpu_MOS6502.h │ │ ├── com_elmfer_cnmcu_mcu_modules_CNEL.cpp │ │ ├── com_elmfer_cnmcu_mcu_modules_CNEL.h │ │ ├── com_elmfer_cnmcu_mcu_modules_CNGPIO.cpp │ │ ├── com_elmfer_cnmcu_mcu_modules_CNGPIO.h │ │ ├── com_elmfer_cnmcu_mcu_modules_CNRAM.cpp │ │ ├── com_elmfer_cnmcu_mcu_modules_CNRAM.h │ │ ├── com_elmfer_cnmcu_mcu_modules_CNROM.cpp │ │ ├── com_elmfer_cnmcu_mcu_modules_CNROM.h │ │ ├── com_elmfer_cnmcu_mcu_modules_CNUART.cpp │ │ ├── com_elmfer_cnmcu_mcu_modules_CNUART.h │ │ ├── com_elmfer_cnmcu_mesh_Meshes.cpp │ │ └── com_elmfer_cnmcu_mesh_Meshes.h │ └── cnmcu │ │ ├── CNEL.hpp │ │ ├── CNGPIO.hpp │ │ ├── CNRAM.hpp │ │ ├── CNROM.hpp │ │ ├── CNUART.cpp │ │ ├── CNUART.hpp │ │ ├── MeshLoader.cpp │ │ ├── MeshLoader.hpp │ │ ├── Nano.cpp │ │ ├── Nano.hpp │ │ ├── happly.h │ │ ├── mos6502.cpp │ │ └── mos6502.h │ ├── java │ └── com │ │ └── elmfer │ │ └── cnmcu │ │ ├── CodeNodeMicrocontrollers.java │ │ ├── CodeNodeMicrocontrollersClient.java │ │ ├── EventHandler.java │ │ ├── animation │ │ ├── ClockTimer.java │ │ └── Timer.java │ │ ├── blockentities │ │ ├── BlockEntities.java │ │ └── CNnanoBlockEntity.java │ │ ├── blocks │ │ ├── Blocks.java │ │ └── CNnanoBlock.java │ │ ├── config │ │ ├── Config.java │ │ └── ModSetup.java │ │ ├── cpp │ │ ├── NativesLoader.java │ │ ├── NativesUtils.java │ │ ├── StrongNativeObject.java │ │ └── WeakNativeObject.java │ │ ├── mcu │ │ ├── NanoMCU.java │ │ ├── Sketches.java │ │ ├── Toolchain.java │ │ ├── cpu │ │ │ └── MOS6502.java │ │ └── modules │ │ │ ├── CNEL.java │ │ │ ├── CNGPIO.java │ │ │ ├── CNRAM.java │ │ │ ├── CNROM.java │ │ │ └── CNUART.java │ │ ├── mesh │ │ ├── Mesh.java │ │ ├── MeshBuilder.java │ │ ├── Meshes.java │ │ └── VertexFormat.java │ │ ├── network │ │ ├── IDEScreenHeartbeatC2SPacket.java │ │ ├── IDEScreenMCUControlC2SPacket.java │ │ ├── IDEScreenSaveCodeC2SPacket.java │ │ ├── IDEScreenSyncS2CPacket.java │ │ ├── Packet.java │ │ ├── Packets.java │ │ └── UploadROMC2S2CPacket.java │ │ ├── ui │ │ ├── IDEScreen.java │ │ ├── QuickReferences.java │ │ ├── UIRender.java │ │ └── handler │ │ │ ├── IDEScreenHandler.java │ │ │ └── ScreenHandlers.java │ │ └── util │ │ ├── HTTPSFetcher.java │ │ └── ResourceLoader.java │ └── resources │ ├── assets │ └── cnmcu │ │ ├── blockstates │ │ └── nano.json │ │ ├── icon.png │ │ ├── meshes │ │ ├── nano_pcb.ply │ │ └── nano_smd.ply │ │ ├── models │ │ ├── block │ │ │ ├── nano_facing_east.json │ │ │ ├── nano_facing_north.json │ │ │ ├── nano_facing_south.json │ │ │ └── nano_facing_west.json │ │ └── item │ │ │ └── nano.json │ │ ├── setup │ │ └── imgui.ini │ │ └── textures │ │ ├── block │ │ ├── nano_pcb.png │ │ └── nano_smd.png │ │ └── item │ │ └── nano.png │ └── fabric.mod.json └── vasm ├── README.txt ├── cygwin1.dll ├── vasm6502_oldstyle-linux-x64 ├── vasm6502_oldstyle-macos-x64 ├── vasm6502_oldstyle-windows-x64.exe ├── vobjdump-linux-x64 ├── vobjdump-macos-x64 └── vobjdump-windows-x64.exe /.gitattributes: -------------------------------------------------------------------------------- 1 | # 2 | # https://help.github.com/articles/dealing-with-line-endings/ 3 | # 4 | # Linux start script should use lf 5 | /gradlew text eol=lf 6 | 7 | # These are Windows script files and should use crlf 8 | *.bat text eol=crlf 9 | 10 | -------------------------------------------------------------------------------- /.github/workflows/gradle.yml: -------------------------------------------------------------------------------- 1 | name: Publish on GitHub, CurseForge & Modrinth 2 | 3 | on: workflow_dispatch 4 | 5 | env: 6 | MINECRAFT_VERSION: 1.20.4 7 | JAVA_VERSION: 17 8 | MOD_VERSION: 0.0.10a 9 | MODRINTH_TOKEN: ${{ secrets.PUBLISH_MODRINTH_TOKEN }} 10 | CURSEFORGE_TOKEN: ${{ secrets.PUBLISH_CURSEFORGE_TOKEN }} 11 | GITHUB_TOKEN: ${{ secrets.PUBLISH_GITHUB_TOKEN }} 12 | PRODUCTION: true 13 | 14 | permissions: 15 | contents: write 16 | 17 | jobs: 18 | validate: 19 | runs-on: ubuntu-latest 20 | 21 | steps: 22 | - name: Checkout repository 23 | uses: actions/checkout@v4 24 | - name: Validate Gradle wrapper 25 | uses: gradle/actions/wrapper-validation@v3 26 | build: 27 | runs-on: ubuntu-latest 28 | needs: validate 29 | 30 | steps: 31 | - name: Checkout Repository 32 | uses: actions/checkout@v4 33 | with: 34 | submodules: recursive 35 | 36 | - name: Setup Java 37 | uses: actions/setup-java@v4 38 | with: 39 | distribution: "temurin" 40 | java-version: ${{ env.JAVA_VERSION }} 41 | 42 | - name: Setup Gradle 43 | uses: gradle/actions/setup-gradle@v3 44 | with: 45 | dependency-graph: generate-and-submit 46 | 47 | - name: Save Version 48 | run: ./gradlew saveVersion --console=plain 49 | 50 | - name: Commit updated mod version 51 | uses: stefanzweifel/git-auto-commit-action@v5 52 | with: 53 | commit_message: "Update mod version to ${{ env.MOD_VERSION }}-${{ env.MINECRAFT_VERSION }}" 54 | file_pattern: "gradle.properties *CodeNodeMicrocontrollers.java *fabric.mod.json" 55 | 56 | - name: Build Mod 57 | run: ./gradlew build --console=plain 58 | 59 | - name: Publish Mod (CurseForge/Modrinth/GitHub) 60 | uses: Kir-Antipov/mc-publish@v3.3 61 | with: 62 | modrinth-id: x3ZXt0cm 63 | modrinth-token: ${{ env.MODRINTH_TOKEN }} 64 | 65 | curseforge-id: 1011557 66 | curseforge-token: ${{ env.CURSEFORGE_TOKEN }} 67 | 68 | github-token: ${{ env.GITHUB_TOKEN }} 69 | 70 | name: "CodeNode Microcontrollers v${{ env.MOD_VERSION }} for Minecraft ${{ env.MINECRAFT_VERSION }}" 71 | version: "${{ env.MOD_VERSION }}-${{ env.MINECRAFT_VERSION }}" 72 | version-type: alpha 73 | 74 | loaders: fabric 75 | game-versions: "${{ env.MINECRAFT_VERSION }}" 76 | natives: 77 | strategy: 78 | matrix: 79 | include: 80 | - os: ubuntu-latest 81 | files: | 82 | build/natives/libcnmcu* 83 | vasm/vasm6502_oldstyle-linux-x64 84 | vasm/vobjdump-linux-x64 85 | - os: windows-latest 86 | files: | 87 | build/natives/Release/libcnmcu* 88 | vasm/vasm6502_oldstyle-windows-x64.exe 89 | vasm/vobjdump-windows-x64.exe 90 | vasm/cygwin1.dll 91 | - os: macos-latest 92 | files: | 93 | build/natives/libcnmcu* 94 | vasm/vasm6502_oldstyle-macos-x64 95 | vasm/vobjdump-macos-x64 96 | 97 | runs-on: ${{ matrix.os }} 98 | needs: build 99 | 100 | steps: 101 | - name: Checkout Repository 102 | uses: actions/checkout@v4 103 | with: 104 | submodules: recursive 105 | 106 | - name: Setup Java 107 | uses: actions/setup-java@v4 108 | with: 109 | distribution: "temurin" 110 | java-version: ${{ env.JAVA_VERSION }} 111 | 112 | - name: Setup Gradle 113 | uses: gradle/actions/setup-gradle@v3 114 | 115 | - name: Compile Natives 116 | run: ./gradlew compileNatives --console=plain 117 | 118 | - name: Upload Binary 119 | uses: softprops/action-gh-release@v2 120 | with: 121 | files: ${{ matrix.files }} 122 | tag_name: "${{ env.MOD_VERSION }}-${{ env.MINECRAFT_VERSION }}" -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # gradle 2 | 3 | .gradle/ 4 | build/ 5 | out/ 6 | classes/ 7 | 8 | # eclipse 9 | 10 | *.launch 11 | 12 | # idea 13 | 14 | .idea/ 15 | *.iml 16 | *.ipr 17 | *.iws 18 | 19 | # vscode 20 | 21 | .settings/ 22 | .vscode/ 23 | bin/ 24 | .classpath 25 | .project 26 | 27 | # macos 28 | 29 | *.DS_Store 30 | 31 | # fabric 32 | 33 | run/ 34 | 35 | # java 36 | 37 | hs_err_*.log 38 | replay_*.log 39 | *.hprof 40 | *.jfr 41 | /.apt_generated/ 42 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elmfrain/cnmcu/ff1d89707ad05085cd226b91a3ce5c0e92caa281/.gitmodules -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # CodeNode Micrcontrollers Mod 2 | 3 | A mod that adds mos6502 based microcontrollers to the Minecraft so you can automate your redstone contraptions with assembly code. 4 | 5 | **Note**: This mod is in Pre-Release (Alpha) stage so it may have bugs. If you find any bugs, please report them in the issues section. 6 | 7 | ![ScreenShot](./screenshots/Screenshot%20from%202024-04-28%2021-40-35.png) 8 | 9 | ## Table of Contents 10 | * [Documentation](#documentation) 11 | * [License](#license) 12 | 13 | ## Documentation 14 | 15 | Detailed documentation can be found in here: [CodeNode Microcontrollers Mod Documentation](https://elmfrain.github.io/code-node-docs/). This documentation contains examples and detailed information about the architecture of the microcontrollers. 16 | 17 | The instruction set of the 6502 can be referenced here: [Ultimate Commodore 64 Reference](https://www.pagetable.com/c64ref/6502) 18 | 19 | Within the mod, you can view quick references by clicking `Code Editor` > `Help` > `Documentation`. 20 | 21 | ![ScreenShot](./screenshots/Screenshot%20from%202024-05-01%2016-52-53.png) 22 | 23 | ## License 24 | 25 | This mod is licensed under the GNU General Public License v3.0. You can view the license [here](./LICENSE). 26 | 27 | The assembler used in this mod, **vasm**, is licensed under their own license. You can view the license in section *1.2* of the [vasm manual](http://sun.hasenbraten.de/vasm/release/vasm.html). 28 | 29 | **To clarify**: The license of the assembler, **vasm**, is not the same as the license of this mod. Rights are reserved to the respective owners of the assembler. -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | import tools.elmfer.GenNativeSources 2 | import tools.elmfer.CompileNatives 3 | import tools.elmfer.SaveVersion 4 | 5 | plugins { 6 | id 'fabric-loom' version '1.6-SNAPSHOT' 7 | id 'maven-publish' 8 | id "com.github.johnrengelman.shadow" version "8.1.1" 9 | } 10 | 11 | version = project.mod_version 12 | group = project.maven_group 13 | 14 | base { 15 | archivesName = project.archives_base_name 16 | } 17 | 18 | repositories { 19 | // Add repositories to retrieve artifacts from in here. 20 | // You should only use this when depending on other mods because 21 | // Loom adds the essential maven repositories to download Minecraft and libraries from automatically. 22 | // See https://docs.gradle.org/current/userguide/declaring_repositories.html 23 | // for more information about repositories. 24 | mavenCentral() 25 | } 26 | 27 | dependencies { 28 | // To change the versions see the gradle.properties file 29 | minecraft "com.mojang:minecraft:${project.minecraft_version}" 30 | mappings "net.fabricmc:yarn:${project.yarn_mappings}:v2" 31 | modImplementation "net.fabricmc:fabric-loader:${project.loader_version}" 32 | 33 | // Fabric API. This is technically optional, but you probably want it anyway. 34 | modImplementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_version}" 35 | 36 | shadow "io.github.spair:imgui-java-binding:${project.imgui_version}" 37 | shadow "io.github.spair:imgui-java-lwjgl3:${project.imgui_version}" 38 | 39 | shadow "io.github.spair:imgui-java-natives-windows:${project.imgui_version}" 40 | shadow "io.github.spair:imgui-java-natives-linux:${project.imgui_version}" 41 | shadow "io.github.spair:imgui-java-natives-macos:${project.imgui_version}" 42 | } 43 | 44 | processResources { 45 | inputs.property "version", project.version 46 | 47 | filesMatching("fabric.mod.json") { 48 | expand "version": project.version 49 | } 50 | } 51 | 52 | tasks.withType(JavaCompile).configureEach { 53 | it.options.release = 17 54 | } 55 | 56 | java { 57 | // Loom will automatically attach sourcesJar to a RemapSourcesJar task and to the "build" task 58 | // if it is present. 59 | // If you remove this line, sources will not be generated. 60 | withSourcesJar() 61 | 62 | sourceCompatibility = JavaVersion.VERSION_17 63 | targetCompatibility = JavaVersion.VERSION_17 64 | } 65 | 66 | jar { 67 | from("LICENSE") { 68 | rename { "${it}_${project.base.archivesName.get()}"} 69 | } 70 | 71 | // Bundle the imgui library aswell into a fat-jar 72 | duplicatesStrategy = DuplicatesStrategy.EXCLUDE 73 | from { 74 | project.configurations.shadow.collect { zipTree(it) } 75 | } 76 | } 77 | 78 | sourceSets.main.java { 79 | srcDir "src/main/cpp" 80 | } 81 | 82 | clean.doFirst { 83 | delete fileTree("src/main/cpp/bridge") { 84 | include "*.h" 85 | } 86 | } 87 | 88 | tasks.register("genNativeSources", GenNativeSources) { 89 | it.dependsOn assemble 90 | 91 | sourceDir "src/main/java" 92 | bridgeDir "src/main/cpp/bridge" 93 | 94 | } 95 | 96 | tasks.register("compileNatives", CompileNatives) { 97 | it.dependsOn genNativeSources 98 | 99 | sourceDir "src/main/cpp" 100 | buildDir "build/natives" 101 | targetDir "run/cnmcu/natives/" + project.mod_version 102 | } 103 | 104 | tasks.register("saveVersion", SaveVersion) 105 | 106 | shadowJar { 107 | configurations = [project.configurations.shadow] 108 | } 109 | 110 | // configure the maven publication 111 | publishing { 112 | publications { 113 | create("mavenJava", MavenPublication) { 114 | from components.java 115 | } 116 | } 117 | 118 | // See https://docs.gradle.org/current/userguide/publishing_maven.html for information on how to set up publishing. 119 | repositories { 120 | // Add repositories to publish to here. 121 | // Notice: This block does NOT have the same function as the block in the top level. 122 | // The repositories here will be used for publishing your artifact, not for 123 | // retrieving dependencies. 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /buildSrc/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'java' 3 | id 'eclipse' 4 | } 5 | 6 | repositories { 7 | mavenCentral() 8 | } 9 | 10 | ext { 11 | jnigenVersion = '2.4.0' 12 | } 13 | 14 | dependencies { 15 | implementation gradleApi() 16 | 17 | implementation "com.badlogicgames.gdx:gdx-jnigen:$jnigenVersion" 18 | } -------------------------------------------------------------------------------- /buildSrc/src/main/java/tools/elmfer/CompileNatives.java: -------------------------------------------------------------------------------- 1 | package tools.elmfer; 2 | 3 | import java.io.BufferedReader; 4 | import java.io.IOException; 5 | import java.io.InputStreamReader; 6 | import java.nio.file.Files; 7 | import java.nio.file.Path; 8 | import java.nio.file.StandardCopyOption; 9 | import java.util.function.Predicate; 10 | 11 | import org.gradle.api.DefaultTask; 12 | import org.gradle.api.tasks.Internal; 13 | import org.gradle.api.tasks.TaskAction; 14 | 15 | public class CompileNatives extends DefaultTask { 16 | 17 | private static final Predicate LIBS_FILTER = path -> { 18 | String name = path.getFileName().toString(); 19 | return name.endsWith(".so") || name.endsWith(".dll") || name.endsWith(".dylib"); 20 | }; 21 | 22 | @Internal 23 | private String sourceDir; 24 | @Internal 25 | private String buildDir; 26 | @Internal 27 | private String cmakeTarget; 28 | @Internal 29 | private String targetDir; 30 | @Internal 31 | private String buildType; 32 | 33 | private IOException copyError; 34 | 35 | public CompileNatives() { 36 | this.setGroup("build"); 37 | this.setDescription("Compiles native source files using CMake."); 38 | 39 | cmakeTarget = "cnmcu-natives"; 40 | buildType = "Release"; 41 | } 42 | 43 | @TaskAction 44 | void execute() throws Exception { 45 | if (sourceDir == null) 46 | throw new RuntimeException("You must specify source directory for generating native source files!"); 47 | 48 | if (buildDir == null) 49 | throw new RuntimeException("You must specify build directory for generating native source files!"); 50 | 51 | executeCommand("cmake --version", "CMake is not installed on your system!"); 52 | 53 | String absSourceDir = getProject().file(sourceDir).getAbsolutePath(); 54 | String absBuildDir = getProject().file(buildDir).getAbsolutePath(); 55 | 56 | executeCommand("cmake -S " + absSourceDir + " -B " + absBuildDir + " -DCMAKE_BUILD_TYPE=" + buildType, 57 | "Error configuring CMake project!"); 58 | 59 | executeCommand("cmake --build " + absBuildDir + " --parallel 4 --target " + cmakeTarget + " --config " + buildType, 60 | "Error compiling native source files!"); 61 | 62 | boolean inProduction = System.getenv("PRODUCTION") != null; 63 | if (!inProduction && targetDir != null) 64 | copyBinaries(); 65 | } 66 | 67 | public String getBuildType() { 68 | return buildType; 69 | } 70 | 71 | public void setBuildType(String buildType) { 72 | this.buildType = buildType; 73 | } 74 | 75 | public String getSourceDir() { 76 | return sourceDir; 77 | } 78 | 79 | public void setSourceDir(String sourceDir) { 80 | this.sourceDir = sourceDir; 81 | } 82 | 83 | public String getBuildDir() { 84 | return buildDir; 85 | } 86 | 87 | public void setBuildDir(String buildDir) { 88 | this.buildDir = buildDir; 89 | } 90 | 91 | public String getCmakeTarget() { 92 | return cmakeTarget; 93 | } 94 | 95 | public void setCmakeTarget(String cmakeTarget) { 96 | this.cmakeTarget = cmakeTarget; 97 | } 98 | 99 | public String getTargetDir() { 100 | return targetDir; 101 | } 102 | 103 | public void setTargetDir(String targetDir) { 104 | this.targetDir = targetDir; 105 | } 106 | 107 | private int executeCommand(String command, String failMessage) throws Exception { 108 | String os = getOS(); 109 | String shell = os.equals("windows") ? "cmd" : "sh"; 110 | String shellFlag = os.equals("windows") ? "/c" : "-c"; 111 | 112 | ProcessBuilder builder = new ProcessBuilder(shell, shellFlag, command); 113 | builder.redirectErrorStream(true); 114 | 115 | Process process = builder.start(); 116 | 117 | Thread outThread = new Thread(() -> { 118 | try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()))) { 119 | String line; 120 | while ((line = reader.readLine()) != null) 121 | System.out.println("[cmake] " + line); 122 | } catch (IOException e) { 123 | e.printStackTrace(); 124 | } 125 | }); 126 | outThread.start(); 127 | 128 | int exitCode = process.waitFor(); 129 | outThread.join(); 130 | 131 | if (exitCode != 0) 132 | throw new RuntimeException(failMessage); 133 | 134 | return exitCode; 135 | } 136 | 137 | // Copy binaries to target directory, if specified. 138 | // This is useful when you want to copy the compiled binaries to 139 | // quickly to aid in development 140 | private void copyBinaries() throws IOException { 141 | copyError = null; 142 | 143 | Path targetPath = getProject().file(targetDir).toPath(); 144 | 145 | Path buildDir = getProject().file(this.buildDir).toPath(); 146 | 147 | 148 | 149 | Files.walk(buildDir).filter(LIBS_FILTER).forEach(source -> { 150 | try { 151 | Path target = targetPath.resolve(source.getFileName()); 152 | 153 | Files.createDirectories(target.getParent()); 154 | Files.copy(source, target, StandardCopyOption.REPLACE_EXISTING); 155 | } catch (IOException e) { 156 | copyError = e; 157 | } 158 | }); 159 | 160 | if (copyError != null) 161 | throw copyError; 162 | } 163 | 164 | private String getOS() { 165 | String os = System.getProperty("os.name").toLowerCase(); 166 | if (os.contains("win")) 167 | return "windows"; 168 | else if (os.contains("mac")) 169 | return "macos"; 170 | else if (os.contains("nix") || os.contains("nux")) 171 | return "linux"; 172 | 173 | return "unknown"; 174 | } 175 | } 176 | -------------------------------------------------------------------------------- /buildSrc/src/main/java/tools/elmfer/GenNativeSources.java: -------------------------------------------------------------------------------- 1 | package tools.elmfer; 2 | 3 | import org.gradle.api.DefaultTask; 4 | import org.gradle.api.tasks.Internal; 5 | import org.gradle.api.tasks.TaskAction; 6 | 7 | import com.badlogic.gdx.jnigen.NativeCodeGenerator; 8 | 9 | public class GenNativeSources extends DefaultTask { 10 | 11 | public static final String GROUP = "build"; 12 | public static final String DESCRIPTION = "Creates JNI bridge .h and .cpp files."; 13 | 14 | private final String classPath; 15 | 16 | @Internal 17 | private String sourceDir; 18 | @Internal 19 | private String bridgeDir; 20 | 21 | public GenNativeSources() { 22 | String pathSeparator = getOS().equals("windows") ? ";" : ":"; 23 | 24 | classPath = getProject().getConfigurations().getByName("runtimeClasspath").getAsPath() + 25 | pathSeparator + "build/classes/java/main"; 26 | 27 | this.setGroup(GROUP); 28 | this.setDescription(DESCRIPTION); 29 | } 30 | 31 | @TaskAction 32 | void execute() throws Exception { 33 | if(sourceDir == null) 34 | throw new RuntimeException("You must specify source directory for generating native source files!"); 35 | 36 | if (bridgeDir == null) 37 | throw new RuntimeException("You must specify bridge directory for generating native source files!"); 38 | 39 | NativeCodeGenerator srcGen = new NativeCodeGenerator(); 40 | srcGen.generate(sourceDir, classPath, bridgeDir); 41 | } 42 | 43 | public String getSourceDir() { 44 | return sourceDir; 45 | } 46 | 47 | public void setSourceDir(String sourceDir) { 48 | this.sourceDir = sourceDir; 49 | } 50 | 51 | public String getBridgeDir() { 52 | return bridgeDir; 53 | } 54 | 55 | public void setBridgeDir(String bridgeDir) { 56 | this.bridgeDir = bridgeDir; 57 | } 58 | 59 | private String getOS() { 60 | String os = System.getProperty("os.name").toLowerCase(); 61 | if (os.contains("win")) 62 | return "windows"; 63 | else if (os.contains("mac")) 64 | return "macos"; 65 | else if (os.contains("nix") || os.contains("nux")) 66 | return "linux"; 67 | 68 | return "unknown"; 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /buildSrc/src/main/java/tools/elmfer/SaveVersion.java: -------------------------------------------------------------------------------- 1 | package tools.elmfer; 2 | 3 | import java.io.File; 4 | import java.io.FileInputStream; 5 | import java.io.IOException; 6 | import java.nio.file.Files; 7 | import java.util.ArrayList; 8 | import java.util.HashMap; 9 | import java.util.Map; 10 | 11 | import org.gradle.api.DefaultTask; 12 | import org.gradle.api.tasks.TaskAction; 13 | 14 | public class SaveVersion extends DefaultTask { 15 | 16 | public static final String GROUP = "build"; 17 | public static final String DESCRIPTION = "Saves the version of the project to a list of files."; 18 | 19 | private Map params = new HashMap<>(); 20 | 21 | // @formatter:off 22 | private FileEntry[] files = { 23 | 24 | new FileEntry("src/main/java/com/elmfer/cnmcu/CodeNodeMicrocontrollers.java", 25 | new Entry("public static final String MOD_VERSION", ";", 26 | "public static final String MOD_VERSION = \"%s-%s\"", "version", "mc_version")), 27 | 28 | new FileEntry("src/main/resources/fabric.mod.json", 29 | new Entry("\"version\":", ",", 30 | "\"version\": \"%s-%s\"", "version", "mc_version"), 31 | new Entry("\"minecraft\":", ",", 32 | "\"minecraft\": \"~%s\"", "mc_version")), 33 | 34 | new FileEntry("gradle.properties", 35 | new Entry("mod_version=", "\n", 36 | "mod_version=%s-%s", "version", "mc_version")), 37 | }; 38 | // @formatter:on 39 | 40 | public SaveVersion() { 41 | this.setGroup(GROUP); 42 | this.setDescription(DESCRIPTION); 43 | } 44 | 45 | @TaskAction 46 | public void execute() throws Exception { 47 | if(System.getenv("MINECRAFT_VERSION") != null) 48 | params.put("mc_version", System.getenv("MINECRAFT_VERSION")); 49 | else 50 | params.put("mc_version", getProject().property("minecraft_version").toString()); 51 | 52 | if(System.getenv("MOD_VERSION") != null) 53 | params.put("version", System.getenv("MOD_VERSION")); 54 | else 55 | params.put("version", getProject().property("mod_version").toString()); 56 | 57 | for (FileEntry file : files) { 58 | File f = getProject().file(file.path); 59 | String content = readFile(f); 60 | 61 | if(f == null) { 62 | System.out.println("File not found: " + file.path + ", skipping..."); 63 | continue; 64 | } 65 | 66 | for (Entry entry : file.entries) { 67 | String start = entry.start; 68 | String end = entry.end; 69 | 70 | String value = entry.format(params); 71 | content = content.replaceAll(start + ".*?" + end, value + end); 72 | } 73 | 74 | writeFile(f, content); 75 | } 76 | } 77 | 78 | private static String readFile(File file) { 79 | try { 80 | int fileSize = (int) file.length(); 81 | byte[] buffer = new byte[fileSize]; 82 | 83 | FileInputStream fis = new FileInputStream(file); 84 | fis.read(buffer); 85 | fis.close(); 86 | 87 | return new String(buffer); 88 | } catch (IOException e) { 89 | e.printStackTrace(); 90 | } 91 | 92 | return null; 93 | } 94 | 95 | private static void writeFile(File file, String content) { 96 | try { 97 | Files.write(file.toPath(), content.getBytes()); 98 | } catch (IOException e) { 99 | e.printStackTrace(); 100 | } 101 | } 102 | 103 | private static class Entry { 104 | private String start; 105 | private String end; 106 | private String format; 107 | private String params[]; 108 | 109 | Entry(String start, String end, String format, String... params) { 110 | this.start = start; 111 | this.end = end; 112 | this.format = format; 113 | this.params = params; 114 | } 115 | 116 | String format(Map globalParams) { 117 | ArrayList params = new ArrayList<>(); 118 | 119 | for(String param : this.params) { 120 | if(globalParams.containsKey(param)) 121 | params.add(globalParams.get(param)); 122 | else 123 | params.add(""); 124 | } 125 | 126 | return String.format(format, params.toArray()); 127 | } 128 | } 129 | 130 | private static class FileEntry { 131 | private String path; 132 | private Entry entries[]; 133 | 134 | FileEntry(String path, Entry... entries) { 135 | this.path = path; 136 | this.entries = entries; 137 | } 138 | } 139 | } 140 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Done to increase the memory available to gradle. 2 | org.gradle.jvmargs=-Xmx1G 3 | org.gradle.parallel=true 4 | 5 | # Fabric Properties 6 | # check these on https://fabricmc.net/develop 7 | minecraft_version=1.20.4 8 | yarn_mappings=1.20.4+build.3 9 | loader_version=0.15.9 10 | 11 | # Mod Properties 12 | mod_version=0.0.10a-1.20.4 13 | maven_group=com.elmfer.cnmcu 14 | archives_base_name=cnmcu 15 | 16 | # Dependencies 17 | fabric_version=0.96.11+1.20.4 18 | imgui_version=1.86.4 -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elmfrain/cnmcu/ff1d89707ad05085cd226b91a3ce5c0e92caa281/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip 4 | networkTimeout=10000 5 | validateDistributionUrl=true 6 | zipStoreBase=GRADLE_USER_HOME 7 | zipStorePath=wrapper/dists 8 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%"=="" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%"=="" set DIRNAME=. 29 | @rem This is normally unused 30 | set APP_BASE_NAME=%~n0 31 | set APP_HOME=%DIRNAME% 32 | 33 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 34 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 35 | 36 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 37 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 38 | 39 | @rem Find java.exe 40 | if defined JAVA_HOME goto findJavaFromJavaHome 41 | 42 | set JAVA_EXE=java.exe 43 | %JAVA_EXE% -version >NUL 2>&1 44 | if %ERRORLEVEL% equ 0 goto execute 45 | 46 | echo. 1>&2 47 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 48 | echo. 1>&2 49 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2 50 | echo location of your Java installation. 1>&2 51 | 52 | goto fail 53 | 54 | :findJavaFromJavaHome 55 | set JAVA_HOME=%JAVA_HOME:"=% 56 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 57 | 58 | if exist "%JAVA_EXE%" goto execute 59 | 60 | echo. 1>&2 61 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 62 | echo. 1>&2 63 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2 64 | echo location of your Java installation. 1>&2 65 | 66 | goto fail 67 | 68 | :execute 69 | @rem Setup the command line 70 | 71 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 72 | 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if %ERRORLEVEL% equ 0 goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | set EXIT_CODE=%ERRORLEVEL% 85 | if %EXIT_CODE% equ 0 set EXIT_CODE=1 86 | if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% 87 | exit /b %EXIT_CODE% 88 | 89 | :mainEnd 90 | if "%OS%"=="Windows_NT" endlocal 91 | 92 | :omega 93 | -------------------------------------------------------------------------------- /screenshots/Screenshot from 2024-04-09 02-17-52.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elmfrain/cnmcu/ff1d89707ad05085cd226b91a3ce5c0e92caa281/screenshots/Screenshot from 2024-04-09 02-17-52.png -------------------------------------------------------------------------------- /screenshots/Screenshot from 2024-04-28 21-40-35.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elmfrain/cnmcu/ff1d89707ad05085cd226b91a3ce5c0e92caa281/screenshots/Screenshot from 2024-04-28 21-40-35.png -------------------------------------------------------------------------------- /screenshots/Screenshot from 2024-05-01 16-52-53.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elmfrain/cnmcu/ff1d89707ad05085cd226b91a3ce5c0e92caa281/screenshots/Screenshot from 2024-05-01 16-52-53.png -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | pluginManagement { 2 | repositories { 3 | maven { 4 | name = 'Fabric' 5 | url = 'https://maven.fabricmc.net/' 6 | } 7 | mavenCentral() 8 | gradlePluginPortal() 9 | } 10 | } -------------------------------------------------------------------------------- /src/main/cpp/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.13) 2 | 3 | set(CMAKE_CXX_STANDARD 17) 4 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 5 | set(CMAKE_CXX_EXTENSIONS OFF) 6 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O2") 7 | set(CMAKE_TRY_COMPILE_TARGET_TYPE "STATIC_LIBRARY") 8 | set(MOD_ID "cnmcu") 9 | 10 | project("${MOD_ID}-natives") 11 | 12 | find_package(Java REQUIRED) 13 | set(JAVA_AWT_LIBRARY NotNeeded) 14 | set(JAVA_JVM_LIBRARY NotNeeded) 15 | find_package(JNI REQUIRED) 16 | 17 | file(GLOB JNI_BRIDGE_SOURCES "bridge/*.cpp") 18 | 19 | set(PROJECT_SOURCES 20 | cnmcu/mos6502.cpp 21 | cnmcu/Nano.cpp 22 | cnmcu/MeshLoader.cpp 23 | cnmcu/CNUART.cpp 24 | 25 | ${JNI_BRIDGE_SOURCES} 26 | bridge/cnmcuJava.cpp 27 | ) 28 | 29 | set(PROJECT_INCLUDES 30 | bridge 31 | cnmcu 32 | ${JNI_INCLUDE_DIRS} 33 | ) 34 | 35 | add_library(${PROJECT_NAME} SHARED ${PROJECT_SOURCES}) 36 | 37 | target_include_directories(${PROJECT_NAME} PRIVATE ${PROJECT_INCLUDES}) 38 | 39 | target_link_libraries(${PROJECT_NAME} ${PROJECT_LIBRARIES}) 40 | 41 | # force off-tree build 42 | if(${CMAKE_SOURCE_DIR} STREQUAL ${CMAKE_BINARY_DIR}) 43 | message(FATAL_ERROR "CMake generation is not allowed within the source directory! 44 | Remove the CMakeCache.txt file and try again from another folder, e.g.: 45 | mkdir build && cd build 46 | cmake .. 47 | ") 48 | endif() 49 | 50 | # default to Release build 51 | if(NOT CMAKE_BUILD_TYPE) 52 | set(CMAKE_BUILD_TYPE Release CACHE STRING 53 | "Choose the type of build, options are: None Debug Release RelWithDebInfo MinSizeRel." 54 | FORCE) 55 | endif() 56 | 57 | # Determine operating system and set NATIVES_OS 58 | if(WIN32) 59 | set(NATIVES_OS "windows") 60 | elseif(APPLE) 61 | set(NATIVES_OS "macos") 62 | elseif(UNIX AND NOT APPLE) 63 | set(NATIVES_OS "linux") 64 | else() 65 | message(FATAL_ERROR "Unsupported operating system") 66 | endif() 67 | 68 | # Determine target platform architecture and set NATIVES_PLATFORM 69 | if(CMAKE_SYSTEM_PROCESSOR MATCHES "amd64|AMD64|x86_64|x86|X86|i386|i686") 70 | set(NATIVES_PLATFORM "x") 71 | elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "arm|ARM|aarch64|AARCH64") 72 | set(NATIVES_PLATFORM "arm") 73 | else() 74 | message(FATAL_ERROR "Unsupported processor architecture") 75 | endif() 76 | 77 | # Determine architecture and set NATIVES_BITS 78 | if(CMAKE_SIZEOF_VOID_P EQUAL 8) 79 | set(NATIVES_BITS "64") 80 | elseif(CMAKE_SIZEOF_VOID_P EQUAL 4) 81 | set(NATIVES_BITS "32") 82 | else() 83 | message(FATAL_ERROR "Unsupported architecture") 84 | endif() 85 | if(NATIVES_PLATFORM STREQUAL "x" AND NATIVES_BITS STREQUAL "32") 86 | set(NATIVES_BITS "86") 87 | endif() 88 | 89 | set_target_properties(${PROJECT_NAME} PROPERTIES 90 | PREFIX "lib" 91 | OUTPUT_NAME "${MOD_ID}-${NATIVES_OS}-${NATIVES_PLATFORM}${NATIVES_BITS}" 92 | ) 93 | -------------------------------------------------------------------------------- /src/main/cpp/bridge/README.txt: -------------------------------------------------------------------------------- 1 | All the files in this directory are generated by the build process. Do not modify them directly. 2 | 3 | Except for the following files: 4 | - cnmcuJava.h 5 | - cnmcuJava.cpp 6 | 7 | These files are generated by the `genNativesSources` task in the gradle build script, excluding the above. -------------------------------------------------------------------------------- /src/main/cpp/bridge/cnmcuJava.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | JNIEnv* cnmcuJava::env; 4 | JavaVM* cnmcuJava::vm; 5 | 6 | jclass cnmcuJava::NullPointerException; 7 | jclass cnmcuJava::IllegalArgumentException; 8 | jclass cnmcuJava::IllegalStateException; 9 | jclass cnmcuJava::RuntimeException; 10 | 11 | 12 | 13 | jclass cnmcuJava::System; 14 | jfieldID cnmcuJava::System_out_id; 15 | jobject cnmcuJava::System_out; 16 | 17 | jclass cnmcuJava::PrintStream; 18 | jmethodID cnmcuJava::PrintStream_print; 19 | 20 | 21 | 22 | jclass cnmcuJava::Mesh; 23 | jmethodID cnmcuJava::Mesh_loadPositions; 24 | jmethodID cnmcuJava::Mesh_loadNormals; 25 | jmethodID cnmcuJava::Mesh_loadIndices; 26 | jmethodID cnmcuJava::Mesh_loadColors; 27 | jmethodID cnmcuJava::Mesh_loadUvs; 28 | 29 | 30 | 31 | jclass cnmcuJava::NanoMCU; 32 | 33 | jclass cnmcuJava::MOS6502; 34 | jmethodID cnmcuJava::MOS6502_init; 35 | 36 | jclass cnmcuJava::CNGPIO; 37 | jmethodID cnmcuJava::CNGPIO_init; 38 | 39 | jclass cnmcuJava::CNRAM; 40 | jmethodID cnmcuJava::CNRAM_init; 41 | 42 | jclass cnmcuJava::CNROM; 43 | jmethodID cnmcuJava::CNROM_init; 44 | 45 | jclass cnmcuJava::CNEL; 46 | jmethodID cnmcuJava::CNEL_init; 47 | 48 | jclass cnmcuJava::CNUART; 49 | jmethodID cnmcuJava::CNUART_init; 50 | 51 | bool cnmcuJava::initialized = false; 52 | 53 | void cnmcuJava::init(JNIEnv* env) 54 | { 55 | if(initialized) 56 | return; 57 | 58 | cnmcuJava::env = env; 59 | env->GetJavaVM(&vm); 60 | 61 | 62 | // Exceptions 63 | GET_CLASS(NullPointerException, "java/lang/NullPointerException"); 64 | GET_CLASS(IllegalArgumentException, "java/lang/IllegalArgumentException"); 65 | GET_CLASS(IllegalStateException, "java/lang/IllegalStateException"); 66 | GET_CLASS(RuntimeException, "java/lang/RuntimeException"); 67 | 68 | 69 | // System.out 70 | GET_CLASS(System, "java/lang/System"); 71 | GET_STATIC_FIELD_ID(System_out_id, System, "out", "Ljava/io/PrintStream;"); 72 | System_out = env->GetStaticObjectField(System, System_out_id); 73 | System_out = env->NewGlobalRef(System_out); 74 | 75 | GET_CLASS(PrintStream, "java/io/PrintStream"); 76 | GET_METHOD_ID(PrintStream_print, PrintStream, "print", "(Ljava/lang/String;)V"); 77 | 78 | 79 | // For mesh loading 80 | GET_CLASS(Mesh, "com/elmfer/cnmcu/mesh/Mesh"); 81 | GET_METHOD_ID(Mesh_loadPositions, Mesh, "loadPositions", "(Ljava/nio/ByteBuffer;I)V"); 82 | GET_METHOD_ID(Mesh_loadNormals, Mesh, "loadNormals", "(Ljava/nio/ByteBuffer;I)V"); 83 | GET_METHOD_ID(Mesh_loadIndices, Mesh, "loadIndices", "(Ljava/nio/ByteBuffer;I)V"); 84 | GET_METHOD_ID(Mesh_loadColors, Mesh, "loadColors", "(Ljava/nio/ByteBuffer;I)V"); 85 | GET_METHOD_ID(Mesh_loadUvs, Mesh, "loadUvs", "(Ljava/nio/ByteBuffer;I)V"); 86 | 87 | 88 | // For CNMCU 89 | GET_CLASS(NanoMCU, "com/elmfer/cnmcu/mcu/NanoMCU"); 90 | 91 | GET_CLASS(MOS6502, "com/elmfer/cnmcu/mcu/cpu/MOS6502"); 92 | GET_METHOD_ID(MOS6502_init, MOS6502, "", "(J)V"); 93 | 94 | GET_CLASS(CNGPIO, "com/elmfer/cnmcu/mcu/modules/CNGPIO"); 95 | GET_METHOD_ID(CNGPIO_init, CNGPIO, "", "(J)V"); 96 | 97 | GET_CLASS(CNRAM, "com/elmfer/cnmcu/mcu/modules/CNRAM"); 98 | GET_METHOD_ID(CNRAM_init, CNRAM, "", "(J)V"); 99 | 100 | GET_CLASS(CNROM, "com/elmfer/cnmcu/mcu/modules/CNROM"); 101 | GET_METHOD_ID(CNROM_init, CNROM, "", "(J)V"); 102 | 103 | GET_CLASS(CNEL, "com/elmfer/cnmcu/mcu/modules/CNEL"); 104 | GET_METHOD_ID(CNEL_init, CNEL, "", "(J)V"); 105 | 106 | GET_CLASS(CNUART, "com/elmfer/cnmcu/mcu/modules/CNUART"); 107 | GET_METHOD_ID(CNUART_init, CNUART, "", "(J)V"); 108 | 109 | initialized = true; 110 | } 111 | 112 | void cnmcuJava::printf(const char* format, ...) 113 | { 114 | if(!initialized) 115 | return; 116 | 117 | va_list args; 118 | va_start(args, format); 119 | 120 | char buffer[512] = {0}; 121 | vsnprintf(buffer, sizeof(buffer) - 1, format, args); 122 | 123 | va_end(args); 124 | 125 | jstring str = env->NewStringUTF(buffer); 126 | env->CallVoidMethod(System_out, PrintStream_print, str); 127 | env->DeleteLocalRef(str); 128 | } -------------------------------------------------------------------------------- /src/main/cpp/bridge/cnmcuJava.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #define CHECK_FOR_EXCEPTION() \ 6 | if(env->ExceptionCheck()) \ 7 | { \ 8 | env->ExceptionDescribe(); \ 9 | env->ExceptionClear(); \ 10 | return; \ 11 | } \ 12 | 13 | #define GET_CLASS(var, name) \ 14 | (var) = env->FindClass(name); \ 15 | CHECK_FOR_EXCEPTION(); \ 16 | (var) = (jclass) env->NewGlobalRef(var); \ 17 | CHECK_FOR_EXCEPTION(); \ 18 | 19 | #define GET_METHOD_ID(var, clazz, name, sig) \ 20 | (var) = env->GetMethodID(clazz, name, sig); \ 21 | CHECK_FOR_EXCEPTION(); \ 22 | 23 | #define GET_STATIC_METHOD_ID(var, clazz, name, sig) \ 24 | (var) = env->GetStaticMethodID(clazz, name, sig); \ 25 | CHECK_FOR_EXCEPTION(); \ 26 | 27 | #define GET_FIELD_ID(var, clazz, name, sig) \ 28 | (var) = env->GetFieldID(clazz, name, sig); \ 29 | CHECK_FOR_EXCEPTION(); \ 30 | 31 | #define GET_STATIC_FIELD_ID(var, clazz, name, sig) \ 32 | (var) = env->GetStaticFieldID(clazz, name, sig); \ 33 | CHECK_FOR_EXCEPTION(); \ 34 | 35 | class cnmcuJava 36 | { 37 | public: 38 | static JNIEnv* env; 39 | static JavaVM* vm; 40 | 41 | 42 | // Exceptions 43 | static jclass NullPointerException; 44 | static jclass IllegalArgumentException; 45 | static jclass IllegalStateException; 46 | static jclass RuntimeException; 47 | 48 | 49 | // System.out 50 | static jclass System; 51 | static jfieldID System_out_id; 52 | static jobject System_out; 53 | 54 | static jclass PrintStream; 55 | static jmethodID PrintStream_print; 56 | 57 | 58 | // For mesh loading 59 | static jclass Mesh; 60 | static jmethodID Mesh_loadPositions; 61 | static jmethodID Mesh_loadNormals; 62 | static jmethodID Mesh_loadIndices; 63 | static jmethodID Mesh_loadColors; 64 | static jmethodID Mesh_loadUvs; 65 | 66 | 67 | // For CNMCU 68 | static jclass NanoMCU; 69 | 70 | static jclass MOS6502; 71 | static jmethodID MOS6502_init; 72 | 73 | static jclass CNGPIO; 74 | static jmethodID CNGPIO_init; 75 | 76 | static jclass CNRAM; 77 | static jmethodID CNRAM_init; 78 | 79 | static jclass CNROM; 80 | static jmethodID CNROM_init; 81 | 82 | static jclass CNEL; 83 | static jmethodID CNEL_init; 84 | 85 | static jclass CNUART; 86 | static jmethodID CNUART_init; 87 | 88 | static bool initialized; 89 | 90 | static void init(JNIEnv* env); 91 | static void printf(const char* format, ...); 92 | }; -------------------------------------------------------------------------------- /src/main/cpp/bridge/com_elmfer_cnmcu_cpp_NativesUtils.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | static inline jlong wrapped_Java_com_elmfer_cnmcu_cpp_NativesUtils_getByteBufferAddress 3 | (JNIEnv* env, jclass clazz, jobject obj_buffer, char* buffer) { 4 | 5 | //@line:12 6 | 7 | return (jlong) env->GetDirectBufferAddress(obj_buffer); 8 | 9 | } 10 | 11 | JNIEXPORT jlong JNICALL Java_com_elmfer_cnmcu_cpp_NativesUtils_getByteBufferAddress(JNIEnv* env, jclass clazz, jobject obj_buffer) { 12 | char* buffer = (char*)(obj_buffer?env->GetDirectBufferAddress(obj_buffer):0); 13 | 14 | jlong JNI_returnValue = wrapped_Java_com_elmfer_cnmcu_cpp_NativesUtils_getByteBufferAddress(env, clazz, obj_buffer, buffer); 15 | 16 | 17 | return JNI_returnValue; 18 | } 19 | 20 | -------------------------------------------------------------------------------- /src/main/cpp/bridge/com_elmfer_cnmcu_cpp_NativesUtils.h: -------------------------------------------------------------------------------- 1 | /* DO NOT EDIT THIS FILE - it is machine generated */ 2 | #include 3 | /* Header for class com_elmfer_cnmcu_cpp_NativesUtils */ 4 | 5 | #ifndef _Included_com_elmfer_cnmcu_cpp_NativesUtils 6 | #define _Included_com_elmfer_cnmcu_cpp_NativesUtils 7 | #ifdef __cplusplus 8 | extern "C" { 9 | #endif 10 | /* 11 | * Class: com_elmfer_cnmcu_cpp_NativesUtils 12 | * Method: getByteBufferAddress 13 | * Signature: (Ljava/nio/ByteBuffer;)J 14 | */ 15 | JNIEXPORT jlong JNICALL Java_com_elmfer_cnmcu_cpp_NativesUtils_getByteBufferAddress 16 | (JNIEnv *, jclass, jobject); 17 | 18 | #ifdef __cplusplus 19 | } 20 | #endif 21 | #endif 22 | -------------------------------------------------------------------------------- /src/main/cpp/bridge/com_elmfer_cnmcu_mcu_NanoMCU.h: -------------------------------------------------------------------------------- 1 | /* DO NOT EDIT THIS FILE - it is machine generated */ 2 | #include 3 | /* Header for class com_elmfer_cnmcu_mcu_NanoMCU */ 4 | 5 | #ifndef _Included_com_elmfer_cnmcu_mcu_NanoMCU 6 | #define _Included_com_elmfer_cnmcu_mcu_NanoMCU 7 | #ifdef __cplusplus 8 | extern "C" { 9 | #endif 10 | /* 11 | * Class: com_elmfer_cnmcu_mcu_NanoMCU 12 | * Method: createMCU 13 | * Signature: ()J 14 | */ 15 | JNIEXPORT jlong JNICALL Java_com_elmfer_cnmcu_mcu_NanoMCU_createMCU 16 | (JNIEnv *, jclass); 17 | 18 | /* 19 | * Class: com_elmfer_cnmcu_mcu_NanoMCU 20 | * Method: deleteMCU 21 | * Signature: (J)V 22 | */ 23 | JNIEXPORT void JNICALL Java_com_elmfer_cnmcu_mcu_NanoMCU_deleteMCU 24 | (JNIEnv *, jclass, jlong); 25 | 26 | /* 27 | * Class: com_elmfer_cnmcu_mcu_NanoMCU 28 | * Method: tick 29 | * Signature: (J[I[I)V 30 | */ 31 | JNIEXPORT void JNICALL Java_com_elmfer_cnmcu_mcu_NanoMCU_tick 32 | (JNIEnv *, jclass, jlong, jintArray, jintArray); 33 | 34 | /* 35 | * Class: com_elmfer_cnmcu_mcu_NanoMCU 36 | * Method: cycle 37 | * Signature: (J)V 38 | */ 39 | JNIEXPORT void JNICALL Java_com_elmfer_cnmcu_mcu_NanoMCU_cycle 40 | (JNIEnv *, jclass, jlong); 41 | 42 | /* 43 | * Class: com_elmfer_cnmcu_mcu_NanoMCU 44 | * Method: reset 45 | * Signature: (J)V 46 | */ 47 | JNIEXPORT void JNICALL Java_com_elmfer_cnmcu_mcu_NanoMCU_reset 48 | (JNIEnv *, jclass, jlong); 49 | 50 | /* 51 | * Class: com_elmfer_cnmcu_mcu_NanoMCU 52 | * Method: setPowered 53 | * Signature: (JZ)V 54 | */ 55 | JNIEXPORT void JNICALL Java_com_elmfer_cnmcu_mcu_NanoMCU_setPowered 56 | (JNIEnv *, jclass, jlong, jboolean); 57 | 58 | /* 59 | * Class: com_elmfer_cnmcu_mcu_NanoMCU 60 | * Method: isPowered 61 | * Signature: (J)Z 62 | */ 63 | JNIEXPORT jboolean JNICALL Java_com_elmfer_cnmcu_mcu_NanoMCU_isPowered 64 | (JNIEnv *, jclass, jlong); 65 | 66 | /* 67 | * Class: com_elmfer_cnmcu_mcu_NanoMCU 68 | * Method: setClockPause 69 | * Signature: (JZ)V 70 | */ 71 | JNIEXPORT void JNICALL Java_com_elmfer_cnmcu_mcu_NanoMCU_setClockPause 72 | (JNIEnv *, jclass, jlong, jboolean); 73 | 74 | /* 75 | * Class: com_elmfer_cnmcu_mcu_NanoMCU 76 | * Method: isClockPaused 77 | * Signature: (J)Z 78 | */ 79 | JNIEXPORT jboolean JNICALL Java_com_elmfer_cnmcu_mcu_NanoMCU_isClockPaused 80 | (JNIEnv *, jclass, jlong); 81 | 82 | /* 83 | * Class: com_elmfer_cnmcu_mcu_NanoMCU 84 | * Method: numCycles 85 | * Signature: (J)J 86 | */ 87 | JNIEXPORT jlong JNICALL Java_com_elmfer_cnmcu_mcu_NanoMCU_numCycles 88 | (JNIEnv *, jclass, jlong); 89 | 90 | /* 91 | * Class: com_elmfer_cnmcu_mcu_NanoMCU 92 | * Method: setNumCycles 93 | * Signature: (JJ)V 94 | */ 95 | JNIEXPORT void JNICALL Java_com_elmfer_cnmcu_mcu_NanoMCU_setNumCycles 96 | (JNIEnv *, jclass, jlong, jlong); 97 | 98 | /* 99 | * Class: com_elmfer_cnmcu_mcu_NanoMCU 100 | * Method: busAddress 101 | * Signature: (J)I 102 | */ 103 | JNIEXPORT jint JNICALL Java_com_elmfer_cnmcu_mcu_NanoMCU_busAddress 104 | (JNIEnv *, jclass, jlong); 105 | 106 | /* 107 | * Class: com_elmfer_cnmcu_mcu_NanoMCU 108 | * Method: busData 109 | * Signature: (J)I 110 | */ 111 | JNIEXPORT jint JNICALL Java_com_elmfer_cnmcu_mcu_NanoMCU_busData 112 | (JNIEnv *, jclass, jlong); 113 | 114 | /* 115 | * Class: com_elmfer_cnmcu_mcu_NanoMCU 116 | * Method: busRW 117 | * Signature: (J)Z 118 | */ 119 | JNIEXPORT jboolean JNICALL Java_com_elmfer_cnmcu_mcu_NanoMCU_busRW 120 | (JNIEnv *, jclass, jlong); 121 | 122 | /* 123 | * Class: com_elmfer_cnmcu_mcu_NanoMCU 124 | * Method: CPU 125 | * Signature: (J)Lcom/elmfer/cnmcu/mcu/cpu/MOS6502; 126 | */ 127 | JNIEXPORT jobject JNICALL Java_com_elmfer_cnmcu_mcu_NanoMCU_CPU 128 | (JNIEnv *, jclass, jlong); 129 | 130 | /* 131 | * Class: com_elmfer_cnmcu_mcu_NanoMCU 132 | * Method: GPIO 133 | * Signature: (J)Lcom/elmfer/cnmcu/mcu/modules/CNGPIO; 134 | */ 135 | JNIEXPORT jobject JNICALL Java_com_elmfer_cnmcu_mcu_NanoMCU_GPIO 136 | (JNIEnv *, jclass, jlong); 137 | 138 | /* 139 | * Class: com_elmfer_cnmcu_mcu_NanoMCU 140 | * Method: RAM 141 | * Signature: (J)Lcom/elmfer/cnmcu/mcu/modules/CNRAM; 142 | */ 143 | JNIEXPORT jobject JNICALL Java_com_elmfer_cnmcu_mcu_NanoMCU_RAM 144 | (JNIEnv *, jclass, jlong); 145 | 146 | /* 147 | * Class: com_elmfer_cnmcu_mcu_NanoMCU 148 | * Method: ROM 149 | * Signature: (J)Lcom/elmfer/cnmcu/mcu/modules/CNROM; 150 | */ 151 | JNIEXPORT jobject JNICALL Java_com_elmfer_cnmcu_mcu_NanoMCU_ROM 152 | (JNIEnv *, jclass, jlong); 153 | 154 | /* 155 | * Class: com_elmfer_cnmcu_mcu_NanoMCU 156 | * Method: EL 157 | * Signature: (J)Lcom/elmfer/cnmcu/mcu/modules/CNEL; 158 | */ 159 | JNIEXPORT jobject JNICALL Java_com_elmfer_cnmcu_mcu_NanoMCU_EL 160 | (JNIEnv *, jclass, jlong); 161 | 162 | /* 163 | * Class: com_elmfer_cnmcu_mcu_NanoMCU 164 | * Method: UART 165 | * Signature: (J)Lcom/elmfer/cnmcu/mcu/modules/CNUART; 166 | */ 167 | JNIEXPORT jobject JNICALL Java_com_elmfer_cnmcu_mcu_NanoMCU_UART 168 | (JNIEnv *, jclass, jlong); 169 | 170 | #ifdef __cplusplus 171 | } 172 | #endif 173 | #endif 174 | -------------------------------------------------------------------------------- /src/main/cpp/bridge/com_elmfer_cnmcu_mcu_cpu_MOS6502.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | //@line:103 4 | 5 | #include "mos6502.h" 6 | JNIEXPORT void JNICALL Java_com_elmfer_cnmcu_mcu_cpu_MOS6502_NMI(JNIEnv* env, jclass clazz, jlong ptr) { 7 | 8 | 9 | //@line:107 10 | 11 | mos6502* cpu = reinterpret_cast(ptr); 12 | cpu->NMI(); 13 | 14 | 15 | } 16 | 17 | JNIEXPORT void JNICALL Java_com_elmfer_cnmcu_mcu_cpu_MOS6502_IRQ(JNIEnv* env, jclass clazz, jlong ptr) { 18 | 19 | 20 | //@line:112 21 | 22 | mos6502* cpu = reinterpret_cast(ptr); 23 | cpu->IRQ(); 24 | 25 | 26 | } 27 | 28 | JNIEXPORT void JNICALL Java_com_elmfer_cnmcu_mcu_cpu_MOS6502_Reset(JNIEnv* env, jclass clazz, jlong ptr) { 29 | 30 | 31 | //@line:117 32 | 33 | mos6502* cpu = reinterpret_cast(ptr); 34 | cpu->Reset(); 35 | 36 | 37 | } 38 | 39 | JNIEXPORT jint JNICALL Java_com_elmfer_cnmcu_mcu_cpu_MOS6502_GetPC(JNIEnv* env, jclass clazz, jlong ptr) { 40 | 41 | 42 | //@line:122 43 | 44 | mos6502* cpu = reinterpret_cast(ptr); 45 | return static_cast(cpu->GetPC()); 46 | 47 | 48 | } 49 | 50 | JNIEXPORT jint JNICALL Java_com_elmfer_cnmcu_mcu_cpu_MOS6502_GetS(JNIEnv* env, jclass clazz, jlong ptr) { 51 | 52 | 53 | //@line:127 54 | 55 | mos6502* cpu = reinterpret_cast(ptr); 56 | return static_cast(cpu->GetS()); 57 | 58 | 59 | } 60 | 61 | JNIEXPORT jint JNICALL Java_com_elmfer_cnmcu_mcu_cpu_MOS6502_GetP(JNIEnv* env, jclass clazz, jlong ptr) { 62 | 63 | 64 | //@line:132 65 | 66 | mos6502* cpu = reinterpret_cast(ptr); 67 | return static_cast(cpu->GetP()); 68 | 69 | 70 | } 71 | 72 | JNIEXPORT jint JNICALL Java_com_elmfer_cnmcu_mcu_cpu_MOS6502_GetA(JNIEnv* env, jclass clazz, jlong ptr) { 73 | 74 | 75 | //@line:137 76 | 77 | mos6502* cpu = reinterpret_cast(ptr); 78 | return static_cast(cpu->GetA()); 79 | 80 | 81 | } 82 | 83 | JNIEXPORT jint JNICALL Java_com_elmfer_cnmcu_mcu_cpu_MOS6502_GetX(JNIEnv* env, jclass clazz, jlong ptr) { 84 | 85 | 86 | //@line:142 87 | 88 | mos6502* cpu = reinterpret_cast(ptr); 89 | return static_cast(cpu->GetX()); 90 | 91 | 92 | } 93 | 94 | JNIEXPORT jint JNICALL Java_com_elmfer_cnmcu_mcu_cpu_MOS6502_GetY(JNIEnv* env, jclass clazz, jlong ptr) { 95 | 96 | 97 | //@line:147 98 | 99 | mos6502* cpu = reinterpret_cast(ptr); 100 | return static_cast(cpu->GetY()); 101 | 102 | 103 | } 104 | 105 | JNIEXPORT void JNICALL Java_com_elmfer_cnmcu_mcu_cpu_MOS6502_SetState(JNIEnv* env, jclass clazz, jlong ptr, jintArray obj_state) { 106 | int* state = (int*)env->GetPrimitiveArrayCritical(obj_state, 0); 107 | 108 | 109 | //@line:152 110 | 111 | mos6502* cpu = reinterpret_cast(ptr); 112 | cpu->SetState(state); 113 | 114 | env->ReleasePrimitiveArrayCritical(obj_state, state, 0); 115 | 116 | } 117 | 118 | -------------------------------------------------------------------------------- /src/main/cpp/bridge/com_elmfer_cnmcu_mcu_cpu_MOS6502.h: -------------------------------------------------------------------------------- 1 | /* DO NOT EDIT THIS FILE - it is machine generated */ 2 | #include 3 | /* Header for class com_elmfer_cnmcu_mcu_cpu_MOS6502 */ 4 | 5 | #ifndef _Included_com_elmfer_cnmcu_mcu_cpu_MOS6502 6 | #define _Included_com_elmfer_cnmcu_mcu_cpu_MOS6502 7 | #ifdef __cplusplus 8 | extern "C" { 9 | #endif 10 | /* 11 | * Class: com_elmfer_cnmcu_mcu_cpu_MOS6502 12 | * Method: NMI 13 | * Signature: (J)V 14 | */ 15 | JNIEXPORT void JNICALL Java_com_elmfer_cnmcu_mcu_cpu_MOS6502_NMI 16 | (JNIEnv *, jclass, jlong); 17 | 18 | /* 19 | * Class: com_elmfer_cnmcu_mcu_cpu_MOS6502 20 | * Method: IRQ 21 | * Signature: (J)V 22 | */ 23 | JNIEXPORT void JNICALL Java_com_elmfer_cnmcu_mcu_cpu_MOS6502_IRQ 24 | (JNIEnv *, jclass, jlong); 25 | 26 | /* 27 | * Class: com_elmfer_cnmcu_mcu_cpu_MOS6502 28 | * Method: Reset 29 | * Signature: (J)V 30 | */ 31 | JNIEXPORT void JNICALL Java_com_elmfer_cnmcu_mcu_cpu_MOS6502_Reset 32 | (JNIEnv *, jclass, jlong); 33 | 34 | /* 35 | * Class: com_elmfer_cnmcu_mcu_cpu_MOS6502 36 | * Method: GetPC 37 | * Signature: (J)I 38 | */ 39 | JNIEXPORT jint JNICALL Java_com_elmfer_cnmcu_mcu_cpu_MOS6502_GetPC 40 | (JNIEnv *, jclass, jlong); 41 | 42 | /* 43 | * Class: com_elmfer_cnmcu_mcu_cpu_MOS6502 44 | * Method: GetS 45 | * Signature: (J)I 46 | */ 47 | JNIEXPORT jint JNICALL Java_com_elmfer_cnmcu_mcu_cpu_MOS6502_GetS 48 | (JNIEnv *, jclass, jlong); 49 | 50 | /* 51 | * Class: com_elmfer_cnmcu_mcu_cpu_MOS6502 52 | * Method: GetP 53 | * Signature: (J)I 54 | */ 55 | JNIEXPORT jint JNICALL Java_com_elmfer_cnmcu_mcu_cpu_MOS6502_GetP 56 | (JNIEnv *, jclass, jlong); 57 | 58 | /* 59 | * Class: com_elmfer_cnmcu_mcu_cpu_MOS6502 60 | * Method: GetA 61 | * Signature: (J)I 62 | */ 63 | JNIEXPORT jint JNICALL Java_com_elmfer_cnmcu_mcu_cpu_MOS6502_GetA 64 | (JNIEnv *, jclass, jlong); 65 | 66 | /* 67 | * Class: com_elmfer_cnmcu_mcu_cpu_MOS6502 68 | * Method: GetX 69 | * Signature: (J)I 70 | */ 71 | JNIEXPORT jint JNICALL Java_com_elmfer_cnmcu_mcu_cpu_MOS6502_GetX 72 | (JNIEnv *, jclass, jlong); 73 | 74 | /* 75 | * Class: com_elmfer_cnmcu_mcu_cpu_MOS6502 76 | * Method: GetY 77 | * Signature: (J)I 78 | */ 79 | JNIEXPORT jint JNICALL Java_com_elmfer_cnmcu_mcu_cpu_MOS6502_GetY 80 | (JNIEnv *, jclass, jlong); 81 | 82 | /* 83 | * Class: com_elmfer_cnmcu_mcu_cpu_MOS6502 84 | * Method: SetState 85 | * Signature: (J[I)V 86 | */ 87 | JNIEXPORT void JNICALL Java_com_elmfer_cnmcu_mcu_cpu_MOS6502_SetState 88 | (JNIEnv *, jclass, jlong, jintArray); 89 | 90 | #ifdef __cplusplus 91 | } 92 | #endif 93 | #endif 94 | -------------------------------------------------------------------------------- /src/main/cpp/bridge/com_elmfer_cnmcu_mcu_modules_CNEL.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | //@line:123 4 | 5 | #include "cnmcuJava.h" 6 | #include "Nano.hpp" 7 | JNIEXPORT jlong JNICALL Java_com_elmfer_cnmcu_mcu_modules_CNEL_size(JNIEnv* env, jclass clazz, jlong ptr) { 8 | 9 | 10 | //@line:128 11 | 12 | CNEL* cnel = reinterpret_cast*>(ptr); 13 | return cnel->size(); 14 | 15 | 16 | } 17 | 18 | JNIEXPORT jobject JNICALL Java_com_elmfer_cnmcu_mcu_modules_CNEL_iclRegistersData(JNIEnv* env, jclass clazz, jlong ptr) { 19 | 20 | 21 | //@line:133 22 | 23 | CNEL* cnel = reinterpret_cast*>(ptr); 24 | return env->NewDirectByteBuffer(cnel->iclRegistersData(), CodeNodeNano::EL_SIZE); 25 | 26 | 27 | } 28 | 29 | JNIEXPORT jobject JNICALL Java_com_elmfer_cnmcu_mcu_modules_CNEL_iflRegistersData(JNIEnv* env, jclass clazz, jlong ptr) { 30 | 31 | 32 | //@line:138 33 | 34 | CNEL* cnel = reinterpret_cast*>(ptr); 35 | return env->NewDirectByteBuffer(cnel->iflRegistersData(), CodeNodeNano::EL_SIZE); 36 | 37 | 38 | } 39 | 40 | JNIEXPORT void JNICALL Java_com_elmfer_cnmcu_mcu_modules_CNEL_triggerEvent(JNIEnv* env, jclass clazz, jlong ptr, jint event) { 41 | 42 | 43 | //@line:143 44 | 45 | CNEL* cnel = reinterpret_cast*>(ptr); 46 | cnel->triggerEvent(event); 47 | 48 | 49 | } 50 | 51 | JNIEXPORT jboolean JNICALL Java_com_elmfer_cnmcu_mcu_modules_CNEL_shouldInterrupt(JNIEnv* env, jclass clazz, jlong ptr) { 52 | 53 | 54 | //@line:148 55 | 56 | CNEL* cnel = reinterpret_cast*>(ptr); 57 | return cnel->shouldInterrupt(); 58 | 59 | 60 | } 61 | 62 | JNIEXPORT jint JNICALL Java_com_elmfer_cnmcu_mcu_modules_CNEL_read(JNIEnv* env, jclass clazz, jlong ptr, jint address) { 63 | 64 | 65 | //@line:153 66 | 67 | CNEL* cnel = reinterpret_cast*>(ptr); 68 | return static_cast(cnel->read(address)); 69 | 70 | 71 | } 72 | 73 | JNIEXPORT void JNICALL Java_com_elmfer_cnmcu_mcu_modules_CNEL_write(JNIEnv* env, jclass clazz, jlong ptr, jint address, jint data) { 74 | 75 | 76 | //@line:158 77 | 78 | CNEL* cnel = reinterpret_cast*>(ptr); 79 | uint16_t addr = static_cast(address); 80 | uint8_t dat = static_cast(data); 81 | cnel->write(addr, dat); 82 | 83 | 84 | } 85 | 86 | -------------------------------------------------------------------------------- /src/main/cpp/bridge/com_elmfer_cnmcu_mcu_modules_CNEL.h: -------------------------------------------------------------------------------- 1 | /* DO NOT EDIT THIS FILE - it is machine generated */ 2 | #include 3 | /* Header for class com_elmfer_cnmcu_mcu_modules_CNEL */ 4 | 5 | #ifndef _Included_com_elmfer_cnmcu_mcu_modules_CNEL 6 | #define _Included_com_elmfer_cnmcu_mcu_modules_CNEL 7 | #ifdef __cplusplus 8 | extern "C" { 9 | #endif 10 | /* 11 | * Class: com_elmfer_cnmcu_mcu_modules_CNEL 12 | * Method: size 13 | * Signature: (J)J 14 | */ 15 | JNIEXPORT jlong JNICALL Java_com_elmfer_cnmcu_mcu_modules_CNEL_size 16 | (JNIEnv *, jclass, jlong); 17 | 18 | /* 19 | * Class: com_elmfer_cnmcu_mcu_modules_CNEL 20 | * Method: iclRegistersData 21 | * Signature: (J)Ljava/nio/ByteBuffer; 22 | */ 23 | JNIEXPORT jobject JNICALL Java_com_elmfer_cnmcu_mcu_modules_CNEL_iclRegistersData 24 | (JNIEnv *, jclass, jlong); 25 | 26 | /* 27 | * Class: com_elmfer_cnmcu_mcu_modules_CNEL 28 | * Method: iflRegistersData 29 | * Signature: (J)Ljava/nio/ByteBuffer; 30 | */ 31 | JNIEXPORT jobject JNICALL Java_com_elmfer_cnmcu_mcu_modules_CNEL_iflRegistersData 32 | (JNIEnv *, jclass, jlong); 33 | 34 | /* 35 | * Class: com_elmfer_cnmcu_mcu_modules_CNEL 36 | * Method: triggerEvent 37 | * Signature: (JI)V 38 | */ 39 | JNIEXPORT void JNICALL Java_com_elmfer_cnmcu_mcu_modules_CNEL_triggerEvent 40 | (JNIEnv *, jclass, jlong, jint); 41 | 42 | /* 43 | * Class: com_elmfer_cnmcu_mcu_modules_CNEL 44 | * Method: shouldInterrupt 45 | * Signature: (J)Z 46 | */ 47 | JNIEXPORT jboolean JNICALL Java_com_elmfer_cnmcu_mcu_modules_CNEL_shouldInterrupt 48 | (JNIEnv *, jclass, jlong); 49 | 50 | /* 51 | * Class: com_elmfer_cnmcu_mcu_modules_CNEL 52 | * Method: read 53 | * Signature: (JI)I 54 | */ 55 | JNIEXPORT jint JNICALL Java_com_elmfer_cnmcu_mcu_modules_CNEL_read 56 | (JNIEnv *, jclass, jlong, jint); 57 | 58 | /* 59 | * Class: com_elmfer_cnmcu_mcu_modules_CNEL 60 | * Method: write 61 | * Signature: (JII)V 62 | */ 63 | JNIEXPORT void JNICALL Java_com_elmfer_cnmcu_mcu_modules_CNEL_write 64 | (JNIEnv *, jclass, jlong, jint, jint); 65 | 66 | #ifdef __cplusplus 67 | } 68 | #endif 69 | #endif 70 | -------------------------------------------------------------------------------- /src/main/cpp/bridge/com_elmfer_cnmcu_mcu_modules_CNGPIO.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | //@line:145 4 | 5 | #include "cnmcuJava.h" 6 | #include "Nano.hpp" 7 | JNIEXPORT jlong JNICALL Java_com_elmfer_cnmcu_mcu_modules_CNGPIO_size(JNIEnv* env, jclass clazz, jlong ptr) { 8 | 9 | 10 | //@line:150 11 | 12 | CNGPIO* gpio = reinterpret_cast*>(ptr); 13 | return static_cast(gpio->size()); 14 | 15 | 16 | } 17 | 18 | JNIEXPORT jobject JNICALL Java_com_elmfer_cnmcu_mcu_modules_CNGPIO_pvFrontData(JNIEnv* env, jclass clazz, jlong ptr) { 19 | 20 | 21 | //@line:155 22 | 23 | CNGPIO* gpio = reinterpret_cast*>(ptr); 24 | return env->NewDirectByteBuffer(gpio->pvFrontData(), CodeNodeNano::GPIO_NUM_PINS); 25 | 26 | 27 | } 28 | 29 | JNIEXPORT jobject JNICALL Java_com_elmfer_cnmcu_mcu_modules_CNGPIO_pvBackData(JNIEnv* env, jclass clazz, jlong ptr) { 30 | 31 | 32 | //@line:160 33 | 34 | CNGPIO* gpio = reinterpret_cast*>(ptr); 35 | return env->NewDirectByteBuffer(gpio->pvBackData(), CodeNodeNano::GPIO_NUM_PINS); 36 | 37 | 38 | } 39 | 40 | JNIEXPORT jobject JNICALL Java_com_elmfer_cnmcu_mcu_modules_CNGPIO_dirData(JNIEnv* env, jclass clazz, jlong ptr) { 41 | 42 | 43 | //@line:165 44 | 45 | CNGPIO* gpio = reinterpret_cast*>(ptr); 46 | return env->NewDirectByteBuffer(gpio->dirData(), CodeNodeNano::GPIO_NUM_PINS / 8); 47 | 48 | 49 | } 50 | 51 | JNIEXPORT jobject JNICALL Java_com_elmfer_cnmcu_mcu_modules_CNGPIO_intData(JNIEnv* env, jclass clazz, jlong ptr) { 52 | 53 | 54 | //@line:170 55 | 56 | CNGPIO* gpio = reinterpret_cast*>(ptr); 57 | return env->NewDirectByteBuffer(gpio->intData(), CodeNodeNano::GPIO_NUM_PINS / 2); 58 | 59 | 60 | } 61 | 62 | JNIEXPORT jobject JNICALL Java_com_elmfer_cnmcu_mcu_modules_CNGPIO_iflData(JNIEnv* env, jclass clazz, jlong ptr) { 63 | 64 | 65 | //@line:175 66 | 67 | CNGPIO* gpio = reinterpret_cast*>(ptr); 68 | return env->NewDirectByteBuffer(gpio->iflData(), CodeNodeNano::GPIO_NUM_PINS / 8); 69 | 70 | 71 | } 72 | 73 | JNIEXPORT jint JNICALL Java_com_elmfer_cnmcu_mcu_modules_CNGPIO_read(JNIEnv* env, jclass clazz, jlong ptr, jint address) { 74 | 75 | 76 | //@line:180 77 | 78 | CNGPIO* gpio = reinterpret_cast*>(ptr); 79 | uint16_t addr = static_cast(address); 80 | uint8_t val = gpio->read(address); 81 | return static_cast(val); 82 | 83 | 84 | } 85 | 86 | JNIEXPORT void JNICALL Java_com_elmfer_cnmcu_mcu_modules_CNGPIO_write(JNIEnv* env, jclass clazz, jlong ptr, jint address, jint value) { 87 | 88 | 89 | //@line:187 90 | 91 | CNGPIO* gpio = reinterpret_cast*>(ptr); 92 | uint16_t addr = static_cast(address); 93 | uint8_t val = static_cast(value); 94 | gpio->write(addr, val); 95 | 96 | 97 | } 98 | 99 | JNIEXPORT jboolean JNICALL Java_com_elmfer_cnmcu_mcu_modules_CNGPIO_shouldInterrupt(JNIEnv* env, jclass clazz, jlong ptr) { 100 | 101 | 102 | //@line:194 103 | 104 | CNGPIO* gpio = reinterpret_cast*>(ptr); 105 | return static_cast(gpio->shouldInterrupt()); 106 | 107 | 108 | } 109 | 110 | -------------------------------------------------------------------------------- /src/main/cpp/bridge/com_elmfer_cnmcu_mcu_modules_CNGPIO.h: -------------------------------------------------------------------------------- 1 | /* DO NOT EDIT THIS FILE - it is machine generated */ 2 | #include 3 | /* Header for class com_elmfer_cnmcu_mcu_modules_CNGPIO */ 4 | 5 | #ifndef _Included_com_elmfer_cnmcu_mcu_modules_CNGPIO 6 | #define _Included_com_elmfer_cnmcu_mcu_modules_CNGPIO 7 | #ifdef __cplusplus 8 | extern "C" { 9 | #endif 10 | /* 11 | * Class: com_elmfer_cnmcu_mcu_modules_CNGPIO 12 | * Method: size 13 | * Signature: (J)J 14 | */ 15 | JNIEXPORT jlong JNICALL Java_com_elmfer_cnmcu_mcu_modules_CNGPIO_size 16 | (JNIEnv *, jclass, jlong); 17 | 18 | /* 19 | * Class: com_elmfer_cnmcu_mcu_modules_CNGPIO 20 | * Method: pvFrontData 21 | * Signature: (J)Ljava/nio/ByteBuffer; 22 | */ 23 | JNIEXPORT jobject JNICALL Java_com_elmfer_cnmcu_mcu_modules_CNGPIO_pvFrontData 24 | (JNIEnv *, jclass, jlong); 25 | 26 | /* 27 | * Class: com_elmfer_cnmcu_mcu_modules_CNGPIO 28 | * Method: pvBackData 29 | * Signature: (J)Ljava/nio/ByteBuffer; 30 | */ 31 | JNIEXPORT jobject JNICALL Java_com_elmfer_cnmcu_mcu_modules_CNGPIO_pvBackData 32 | (JNIEnv *, jclass, jlong); 33 | 34 | /* 35 | * Class: com_elmfer_cnmcu_mcu_modules_CNGPIO 36 | * Method: dirData 37 | * Signature: (J)Ljava/nio/ByteBuffer; 38 | */ 39 | JNIEXPORT jobject JNICALL Java_com_elmfer_cnmcu_mcu_modules_CNGPIO_dirData 40 | (JNIEnv *, jclass, jlong); 41 | 42 | /* 43 | * Class: com_elmfer_cnmcu_mcu_modules_CNGPIO 44 | * Method: intData 45 | * Signature: (J)Ljava/nio/ByteBuffer; 46 | */ 47 | JNIEXPORT jobject JNICALL Java_com_elmfer_cnmcu_mcu_modules_CNGPIO_intData 48 | (JNIEnv *, jclass, jlong); 49 | 50 | /* 51 | * Class: com_elmfer_cnmcu_mcu_modules_CNGPIO 52 | * Method: iflData 53 | * Signature: (J)Ljava/nio/ByteBuffer; 54 | */ 55 | JNIEXPORT jobject JNICALL Java_com_elmfer_cnmcu_mcu_modules_CNGPIO_iflData 56 | (JNIEnv *, jclass, jlong); 57 | 58 | /* 59 | * Class: com_elmfer_cnmcu_mcu_modules_CNGPIO 60 | * Method: read 61 | * Signature: (JI)I 62 | */ 63 | JNIEXPORT jint JNICALL Java_com_elmfer_cnmcu_mcu_modules_CNGPIO_read 64 | (JNIEnv *, jclass, jlong, jint); 65 | 66 | /* 67 | * Class: com_elmfer_cnmcu_mcu_modules_CNGPIO 68 | * Method: write 69 | * Signature: (JII)V 70 | */ 71 | JNIEXPORT void JNICALL Java_com_elmfer_cnmcu_mcu_modules_CNGPIO_write 72 | (JNIEnv *, jclass, jlong, jint, jint); 73 | 74 | /* 75 | * Class: com_elmfer_cnmcu_mcu_modules_CNGPIO 76 | * Method: shouldInterrupt 77 | * Signature: (J)Z 78 | */ 79 | JNIEXPORT jboolean JNICALL Java_com_elmfer_cnmcu_mcu_modules_CNGPIO_shouldInterrupt 80 | (JNIEnv *, jclass, jlong); 81 | 82 | #ifdef __cplusplus 83 | } 84 | #endif 85 | #endif 86 | -------------------------------------------------------------------------------- /src/main/cpp/bridge/com_elmfer_cnmcu_mcu_modules_CNRAM.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | //@line:78 4 | 5 | #include "cnmcuJava.h" 6 | #include "Nano.hpp" 7 | JNIEXPORT jlong JNICALL Java_com_elmfer_cnmcu_mcu_modules_CNRAM_size(JNIEnv* env, jclass clazz, jlong ptr) { 8 | 9 | 10 | //@line:83 11 | 12 | return static_cast(CodeNodeNano::RAM_SIZE); 13 | 14 | 15 | } 16 | 17 | JNIEXPORT jobject JNICALL Java_com_elmfer_cnmcu_mcu_modules_CNRAM_data(JNIEnv* env, jclass clazz, jlong ptr) { 18 | 19 | 20 | //@line:87 21 | 22 | CNRAM* ram = reinterpret_cast*>(ptr); 23 | return env->NewDirectByteBuffer(ram->data(), CodeNodeNano::RAM_SIZE); 24 | 25 | 26 | } 27 | 28 | JNIEXPORT jbyte JNICALL Java_com_elmfer_cnmcu_mcu_modules_CNRAM_read(JNIEnv* env, jclass clazz, jlong ptr, jint address) { 29 | 30 | 31 | //@line:92 32 | 33 | CNRAM* ram = reinterpret_cast*>(ptr); 34 | uint16_t addr = static_cast(address); 35 | return static_cast(ram->read(addr)); 36 | 37 | 38 | } 39 | 40 | JNIEXPORT void JNICALL Java_com_elmfer_cnmcu_mcu_modules_CNRAM_write(JNIEnv* env, jclass clazz, jlong ptr, jint address, jbyte value) { 41 | 42 | 43 | //@line:98 44 | 45 | CNRAM* ram = reinterpret_cast*>(ptr); 46 | uint16_t addr = static_cast(address); 47 | uint8_t val = static_cast(value); 48 | ram->write(addr, val); 49 | 50 | 51 | } 52 | 53 | -------------------------------------------------------------------------------- /src/main/cpp/bridge/com_elmfer_cnmcu_mcu_modules_CNRAM.h: -------------------------------------------------------------------------------- 1 | /* DO NOT EDIT THIS FILE - it is machine generated */ 2 | #include 3 | /* Header for class com_elmfer_cnmcu_mcu_modules_CNRAM */ 4 | 5 | #ifndef _Included_com_elmfer_cnmcu_mcu_modules_CNRAM 6 | #define _Included_com_elmfer_cnmcu_mcu_modules_CNRAM 7 | #ifdef __cplusplus 8 | extern "C" { 9 | #endif 10 | /* 11 | * Class: com_elmfer_cnmcu_mcu_modules_CNRAM 12 | * Method: size 13 | * Signature: (J)J 14 | */ 15 | JNIEXPORT jlong JNICALL Java_com_elmfer_cnmcu_mcu_modules_CNRAM_size 16 | (JNIEnv *, jclass, jlong); 17 | 18 | /* 19 | * Class: com_elmfer_cnmcu_mcu_modules_CNRAM 20 | * Method: data 21 | * Signature: (J)Ljava/nio/ByteBuffer; 22 | */ 23 | JNIEXPORT jobject JNICALL Java_com_elmfer_cnmcu_mcu_modules_CNRAM_data 24 | (JNIEnv *, jclass, jlong); 25 | 26 | /* 27 | * Class: com_elmfer_cnmcu_mcu_modules_CNRAM 28 | * Method: read 29 | * Signature: (JI)B 30 | */ 31 | JNIEXPORT jbyte JNICALL Java_com_elmfer_cnmcu_mcu_modules_CNRAM_read 32 | (JNIEnv *, jclass, jlong, jint); 33 | 34 | /* 35 | * Class: com_elmfer_cnmcu_mcu_modules_CNRAM 36 | * Method: write 37 | * Signature: (JIB)V 38 | */ 39 | JNIEXPORT void JNICALL Java_com_elmfer_cnmcu_mcu_modules_CNRAM_write 40 | (JNIEnv *, jclass, jlong, jint, jbyte); 41 | 42 | #ifdef __cplusplus 43 | } 44 | #endif 45 | #endif 46 | -------------------------------------------------------------------------------- /src/main/cpp/bridge/com_elmfer_cnmcu_mcu_modules_CNROM.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | //@line:92 4 | 5 | #include "cnmcuJava.h" 6 | #include "Nano.hpp" 7 | JNIEXPORT jlong JNICALL Java_com_elmfer_cnmcu_mcu_modules_CNROM_size(JNIEnv* env, jclass clazz, jlong ptr) { 8 | 9 | 10 | //@line:97 11 | 12 | return static_cast(CodeNodeNano::ROM_SIZE); 13 | 14 | 15 | } 16 | 17 | JNIEXPORT jobject JNICALL Java_com_elmfer_cnmcu_mcu_modules_CNROM_data(JNIEnv* env, jclass clazz, jlong ptr) { 18 | 19 | 20 | //@line:101 21 | 22 | CNROM* rom = reinterpret_cast*>(ptr); 23 | return env->NewDirectByteBuffer(rom->data(), CodeNodeNano::ROM_SIZE); 24 | 25 | 26 | } 27 | 28 | JNIEXPORT jbyte JNICALL Java_com_elmfer_cnmcu_mcu_modules_CNROM_read(JNIEnv* env, jclass clazz, jlong ptr, jint address) { 29 | 30 | 31 | //@line:106 32 | 33 | CNROM* rom = reinterpret_cast*>(ptr); 34 | uint16_t addr = static_cast(address); 35 | return static_cast(rom->read(addr)); 36 | 37 | 38 | } 39 | 40 | JNIEXPORT void JNICALL Java_com_elmfer_cnmcu_mcu_modules_CNROM_write(JNIEnv* env, jclass clazz, jlong ptr, jint address, jbyte value) { 41 | 42 | 43 | //@line:112 44 | 45 | CNROM* rom = reinterpret_cast*>(ptr); 46 | uint16_t addr = static_cast(address); 47 | uint8_t val = static_cast(value); 48 | rom->write(addr, val); 49 | 50 | 51 | } 52 | 53 | JNIEXPORT jboolean JNICALL Java_com_elmfer_cnmcu_mcu_modules_CNROM_isWriteProtected(JNIEnv* env, jclass clazz, jlong ptr) { 54 | 55 | 56 | //@line:119 57 | 58 | CNROM* rom = reinterpret_cast*>(ptr); 59 | return static_cast(rom->isWriteProtected()); 60 | 61 | 62 | } 63 | 64 | JNIEXPORT void JNICALL Java_com_elmfer_cnmcu_mcu_modules_CNROM_setWriteProtected(JNIEnv* env, jclass clazz, jlong ptr, jboolean writeProtected) { 65 | 66 | 67 | //@line:123 68 | 69 | CNROM* rom = reinterpret_cast*>(ptr); 70 | rom->setWriteProtect(static_cast(writeProtected)); 71 | 72 | 73 | } 74 | 75 | -------------------------------------------------------------------------------- /src/main/cpp/bridge/com_elmfer_cnmcu_mcu_modules_CNROM.h: -------------------------------------------------------------------------------- 1 | /* DO NOT EDIT THIS FILE - it is machine generated */ 2 | #include 3 | /* Header for class com_elmfer_cnmcu_mcu_modules_CNROM */ 4 | 5 | #ifndef _Included_com_elmfer_cnmcu_mcu_modules_CNROM 6 | #define _Included_com_elmfer_cnmcu_mcu_modules_CNROM 7 | #ifdef __cplusplus 8 | extern "C" { 9 | #endif 10 | /* 11 | * Class: com_elmfer_cnmcu_mcu_modules_CNROM 12 | * Method: size 13 | * Signature: (J)J 14 | */ 15 | JNIEXPORT jlong JNICALL Java_com_elmfer_cnmcu_mcu_modules_CNROM_size 16 | (JNIEnv *, jclass, jlong); 17 | 18 | /* 19 | * Class: com_elmfer_cnmcu_mcu_modules_CNROM 20 | * Method: data 21 | * Signature: (J)Ljava/nio/ByteBuffer; 22 | */ 23 | JNIEXPORT jobject JNICALL Java_com_elmfer_cnmcu_mcu_modules_CNROM_data 24 | (JNIEnv *, jclass, jlong); 25 | 26 | /* 27 | * Class: com_elmfer_cnmcu_mcu_modules_CNROM 28 | * Method: read 29 | * Signature: (JI)B 30 | */ 31 | JNIEXPORT jbyte JNICALL Java_com_elmfer_cnmcu_mcu_modules_CNROM_read 32 | (JNIEnv *, jclass, jlong, jint); 33 | 34 | /* 35 | * Class: com_elmfer_cnmcu_mcu_modules_CNROM 36 | * Method: write 37 | * Signature: (JIB)V 38 | */ 39 | JNIEXPORT void JNICALL Java_com_elmfer_cnmcu_mcu_modules_CNROM_write 40 | (JNIEnv *, jclass, jlong, jint, jbyte); 41 | 42 | /* 43 | * Class: com_elmfer_cnmcu_mcu_modules_CNROM 44 | * Method: isWriteProtected 45 | * Signature: (J)Z 46 | */ 47 | JNIEXPORT jboolean JNICALL Java_com_elmfer_cnmcu_mcu_modules_CNROM_isWriteProtected 48 | (JNIEnv *, jclass, jlong); 49 | 50 | /* 51 | * Class: com_elmfer_cnmcu_mcu_modules_CNROM 52 | * Method: setWriteProtected 53 | * Signature: (JZ)V 54 | */ 55 | JNIEXPORT void JNICALL Java_com_elmfer_cnmcu_mcu_modules_CNROM_setWriteProtected 56 | (JNIEnv *, jclass, jlong, jboolean); 57 | 58 | #ifdef __cplusplus 59 | } 60 | #endif 61 | #endif 62 | -------------------------------------------------------------------------------- /src/main/cpp/bridge/com_elmfer_cnmcu_mcu_modules_CNUART.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | //@line:91 4 | 5 | #include "cnmcuJava.h" 6 | #include "Nano.hpp" 7 | JNIEXPORT jlong JNICALL Java_com_elmfer_cnmcu_mcu_modules_CNUART_size(JNIEnv* env, jclass clazz, jlong ptr) { 8 | 9 | 10 | //@line:96 11 | 12 | CNUART* uart = reinterpret_cast(ptr); 13 | return uart->size(); 14 | 15 | 16 | } 17 | 18 | JNIEXPORT void JNICALL Java_com_elmfer_cnmcu_mcu_modules_CNUART_reset(JNIEnv* env, jclass clazz, jlong ptr) { 19 | 20 | 21 | //@line:101 22 | 23 | CNUART* uart = reinterpret_cast(ptr); 24 | uart->reset(); 25 | 26 | 27 | } 28 | 29 | JNIEXPORT jboolean JNICALL Java_com_elmfer_cnmcu_mcu_modules_CNUART_shouldInterrupt(JNIEnv* env, jclass clazz, jlong ptr) { 30 | 31 | 32 | //@line:106 33 | 34 | CNUART* uart = reinterpret_cast(ptr); 35 | return uart->shouldInterrupt(); 36 | 37 | 38 | } 39 | 40 | JNIEXPORT jobject JNICALL Java_com_elmfer_cnmcu_mcu_modules_CNUART_registerData(JNIEnv* env, jclass clazz, jlong ptr) { 41 | 42 | 43 | //@line:111 44 | 45 | CNUART* uart = reinterpret_cast(ptr); 46 | return env->NewDirectByteBuffer(uart->registerData(), uart->size()); 47 | 48 | 49 | } 50 | 51 | JNIEXPORT void JNICALL Java_com_elmfer_cnmcu_mcu_modules_CNUART_write(JNIEnv* env, jclass clazz, jlong ptr, jint address, jint data) { 52 | 53 | 54 | //@line:116 55 | 56 | CNUART* uart = reinterpret_cast(ptr); 57 | uint16_t addr = address; 58 | uint16_t dat = data; 59 | uart->write(addr, dat); 60 | 61 | 62 | } 63 | 64 | JNIEXPORT jint JNICALL Java_com_elmfer_cnmcu_mcu_modules_CNUART_read(JNIEnv* env, jclass clazz, jlong ptr, jint address) { 65 | 66 | 67 | //@line:123 68 | 69 | CNUART* uart = reinterpret_cast(ptr); 70 | uint16_t addr = address; 71 | return static_cast(uart->read(addr)); 72 | 73 | 74 | } 75 | 76 | -------------------------------------------------------------------------------- /src/main/cpp/bridge/com_elmfer_cnmcu_mcu_modules_CNUART.h: -------------------------------------------------------------------------------- 1 | /* DO NOT EDIT THIS FILE - it is machine generated */ 2 | #include 3 | /* Header for class com_elmfer_cnmcu_mcu_modules_CNUART */ 4 | 5 | #ifndef _Included_com_elmfer_cnmcu_mcu_modules_CNUART 6 | #define _Included_com_elmfer_cnmcu_mcu_modules_CNUART 7 | #ifdef __cplusplus 8 | extern "C" { 9 | #endif 10 | /* 11 | * Class: com_elmfer_cnmcu_mcu_modules_CNUART 12 | * Method: size 13 | * Signature: (J)J 14 | */ 15 | JNIEXPORT jlong JNICALL Java_com_elmfer_cnmcu_mcu_modules_CNUART_size 16 | (JNIEnv *, jclass, jlong); 17 | 18 | /* 19 | * Class: com_elmfer_cnmcu_mcu_modules_CNUART 20 | * Method: reset 21 | * Signature: (J)V 22 | */ 23 | JNIEXPORT void JNICALL Java_com_elmfer_cnmcu_mcu_modules_CNUART_reset 24 | (JNIEnv *, jclass, jlong); 25 | 26 | /* 27 | * Class: com_elmfer_cnmcu_mcu_modules_CNUART 28 | * Method: shouldInterrupt 29 | * Signature: (J)Z 30 | */ 31 | JNIEXPORT jboolean JNICALL Java_com_elmfer_cnmcu_mcu_modules_CNUART_shouldInterrupt 32 | (JNIEnv *, jclass, jlong); 33 | 34 | /* 35 | * Class: com_elmfer_cnmcu_mcu_modules_CNUART 36 | * Method: registerData 37 | * Signature: (J)Ljava/nio/ByteBuffer; 38 | */ 39 | JNIEXPORT jobject JNICALL Java_com_elmfer_cnmcu_mcu_modules_CNUART_registerData 40 | (JNIEnv *, jclass, jlong); 41 | 42 | /* 43 | * Class: com_elmfer_cnmcu_mcu_modules_CNUART 44 | * Method: write 45 | * Signature: (JII)V 46 | */ 47 | JNIEXPORT void JNICALL Java_com_elmfer_cnmcu_mcu_modules_CNUART_write 48 | (JNIEnv *, jclass, jlong, jint, jint); 49 | 50 | /* 51 | * Class: com_elmfer_cnmcu_mcu_modules_CNUART 52 | * Method: read 53 | * Signature: (JI)I 54 | */ 55 | JNIEXPORT jint JNICALL Java_com_elmfer_cnmcu_mcu_modules_CNUART_read 56 | (JNIEnv *, jclass, jlong, jint); 57 | 58 | #ifdef __cplusplus 59 | } 60 | #endif 61 | #endif 62 | -------------------------------------------------------------------------------- /src/main/cpp/bridge/com_elmfer_cnmcu_mesh_Meshes.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | //@line:101 4 | 5 | #include "MeshLoader.hpp" 6 | #include "cnmcuJava.h" 7 | #include 8 | JNIEXPORT void JNICALL Java_com_elmfer_cnmcu_mesh_Meshes_parsePLY(JNIEnv* env, jclass clazz, jbyteArray obj_data, jobject mesh) { 9 | char* data = (char*)env->GetPrimitiveArrayCritical(obj_data, 0); 10 | 11 | 12 | //@line:107 13 | 14 | cnmcuJava::init(env); 15 | size_t dataSize = static_cast(env->GetArrayLength(obj_data)); 16 | try { 17 | MeshLoader::loadPLY(env, data, dataSize, mesh); 18 | } catch (const std::exception& e) { 19 | env->ThrowNew(cnmcuJava::IllegalArgumentException, e.what()); 20 | } 21 | 22 | env->ReleasePrimitiveArrayCritical(obj_data, data, 0); 23 | 24 | } 25 | 26 | -------------------------------------------------------------------------------- /src/main/cpp/bridge/com_elmfer_cnmcu_mesh_Meshes.h: -------------------------------------------------------------------------------- 1 | /* DO NOT EDIT THIS FILE - it is machine generated */ 2 | #include 3 | /* Header for class com_elmfer_cnmcu_mesh_Meshes */ 4 | 5 | #ifndef _Included_com_elmfer_cnmcu_mesh_Meshes 6 | #define _Included_com_elmfer_cnmcu_mesh_Meshes 7 | #ifdef __cplusplus 8 | extern "C" { 9 | #endif 10 | #undef com_elmfer_cnmcu_mesh_Meshes_POSITION_COMPONENTS 11 | #define com_elmfer_cnmcu_mesh_Meshes_POSITION_COMPONENTS 3L 12 | #undef com_elmfer_cnmcu_mesh_Meshes_NORMAL_COMPONENTS 13 | #define com_elmfer_cnmcu_mesh_Meshes_NORMAL_COMPONENTS 3L 14 | #undef com_elmfer_cnmcu_mesh_Meshes_COLOR_COMPONENTS 15 | #define com_elmfer_cnmcu_mesh_Meshes_COLOR_COMPONENTS 4L 16 | #undef com_elmfer_cnmcu_mesh_Meshes_UV_COMPONENTS 17 | #define com_elmfer_cnmcu_mesh_Meshes_UV_COMPONENTS 2L 18 | #undef com_elmfer_cnmcu_mesh_Meshes_FACE_INDICIES 19 | #define com_elmfer_cnmcu_mesh_Meshes_FACE_INDICIES 4L 20 | /* 21 | * Class: com_elmfer_cnmcu_mesh_Meshes 22 | * Method: parsePLY 23 | * Signature: ([BLcom/elmfer/cnmcu/mesh/Mesh;)V 24 | */ 25 | JNIEXPORT void JNICALL Java_com_elmfer_cnmcu_mesh_Meshes_parsePLY 26 | (JNIEnv *, jclass, jbyteArray, jobject); 27 | 28 | #ifdef __cplusplus 29 | } 30 | #endif 31 | #endif 32 | -------------------------------------------------------------------------------- /src/main/cpp/cnmcu/CNEL.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | template 6 | class CNEL 7 | { 8 | public: 9 | void reset() 10 | { 11 | memset(iclRegisters, 0, N); 12 | memset(iflRegisters, 0, N); 13 | } 14 | private: 15 | uint8_t iclRegisters[N]; 16 | uint8_t iflRegisters[N]; 17 | public: 18 | CNEL() { reset(); } 19 | 20 | size_t size() const { return N * 2; } 21 | 22 | uint8_t* iclRegistersData() { return iclRegisters; } 23 | uint8_t* iflRegistersData() { return iflRegisters; } 24 | 25 | void triggerEvent(int eventId) 26 | { 27 | if(N * 8 <= eventId) 28 | return; 29 | 30 | iflRegisters[eventId / 8] |= 1 << (eventId % 8); 31 | } 32 | 33 | bool shouldInterrupt() const 34 | { 35 | for(size_t i = 0; i < N; i++) 36 | if(iflRegisters[i] & iclRegisters[i]) 37 | return true; 38 | 39 | return false; 40 | } 41 | 42 | uint8_t read(uint16_t address) const 43 | { 44 | if(N * 2 <= address) 45 | return 0; 46 | 47 | if(address < N) 48 | return iclRegisters[address]; 49 | 50 | return iflRegisters[address - N]; 51 | } 52 | 53 | void write(uint16_t address, uint8_t value) 54 | { 55 | if(N * 2 <= address) 56 | return; 57 | 58 | if(address < N) 59 | iclRegisters[address] = value; 60 | else 61 | iflRegisters[address - N] &= ~value; 62 | } 63 | }; -------------------------------------------------------------------------------- /src/main/cpp/cnmcu/CNGPIO.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | template 9 | class CNGPIO 10 | { 11 | public: 12 | enum IRQType : uint8_t 13 | { 14 | NO_INTERRUPT = 0x0, 15 | LOW = 0x1, 16 | HIGH = 0x2, 17 | RISING = 0x3, 18 | FALLING = 0x4, 19 | CHANGE = 0x5, 20 | ANALOG_CHANGE = 0x6, 21 | ANALOG_RISING = 0x7, 22 | ANALOG_FALLING = 0x8, 23 | NO_CHANGE = 0x9 24 | }; 25 | private: 26 | constexpr static int GPIOPV = 0; 27 | constexpr static int GPIODIR = 1; 28 | constexpr static int GPIOINT = 2; 29 | constexpr static int GPIOIFL = 3; 30 | 31 | int mapAddress(uint16_t* address) const 32 | { 33 | if(*address < N) 34 | return GPIOPV;// 0x0000 35 | *address -= N; 36 | if(*address < N / 8) // 0x0040 37 | return GPIODIR; 38 | *address -= N / 8; 39 | if(*address < N / 2) // 0x0048 40 | return GPIOINT; 41 | *address -= N / 2; 42 | if(*address < N / 8) // 0x0068 43 | return GPIOIFL; 44 | *address -= N / 8; 45 | return -1; 46 | } 47 | 48 | bool triggersInterrupt(IRQType type, uint8_t pv, uint8_t pvOld) const 49 | { 50 | pv &= 0xF; 51 | pvOld &= 0xF; 52 | 53 | switch(type) 54 | { 55 | case LOW: 56 | return pv == 0; 57 | case HIGH: 58 | return pv > 0; 59 | case RISING: 60 | return (pv > 0) && (pvOld == 0); 61 | case FALLING: 62 | return (pv == 0) && (pvOld > 0); 63 | case CHANGE: 64 | return (pv > 0) != (pvOld > 0); 65 | case ANALOG_CHANGE: 66 | return pv != pvOld; 67 | case ANALOG_RISING: 68 | return pv > pvOld; 69 | case ANALOG_FALLING: 70 | return pv < pvOld; 71 | case NO_CHANGE: 72 | return pv == pvOld; 73 | default: 74 | return false; 75 | } 76 | } 77 | 78 | uint8_t gpiopvFront[N]; 79 | uint8_t gpiopvBack[N]; 80 | 81 | uint8_t gpiodir[N / 8]; 82 | uint8_t gpioint[N / 2]; 83 | uint8_t gpioifl[N / 8]; 84 | public: 85 | void reset() 86 | { 87 | memset(gpiopvFront, 0, N); 88 | memset(gpiopvBack, 0, N); 89 | memset(gpiodir, 0, N / 8); 90 | memset(gpioint, 0, N / 2); 91 | memset(gpioifl, 0, N / 8); 92 | } 93 | 94 | CNGPIO() { reset(); } 95 | CNGPIO(CNGPIO&& other) { *this = std::move(other); } 96 | CNGPIO& operator=(CNGPIO&& other) 97 | { 98 | memcpy(gpiopvFront, other.gpiopvFront, N); 99 | memcpy(gpiopvBack, other.gpiopvBack, N); 100 | memcpy(gpiodir, other.gpiodir, N / 8); 101 | memcpy(gpioint, other.gpioint, N / 2); 102 | memcpy(gpioifl, other.gpioifl, N / 8); 103 | return *this; 104 | } 105 | 106 | size_t size() const 107 | { 108 | return N + N / 8 + N / 2 + N / 8; 109 | } 110 | 111 | uint8_t* pvFrontData() { return gpiopvFront; } 112 | uint8_t* pvBackData() { return gpiopvBack; } 113 | uint8_t* dirData() { return gpiodir; } 114 | uint8_t* intData() { return gpioint; } 115 | uint8_t* iflData() { return gpioifl; } 116 | 117 | bool isInput(size_t pin) const 118 | { 119 | if(pin >= N || pin < 0) 120 | return false; 121 | 122 | return (gpiodir[pin / 8] & (1 << (pin % 8))) == 0; 123 | } 124 | 125 | uint8_t read(uint16_t address) const 126 | { 127 | int buffer = mapAddress(&address); 128 | 129 | switch(buffer) 130 | { 131 | case GPIOPV: 132 | return gpiopvFront[address]; 133 | case GPIODIR: 134 | return gpiodir[address]; 135 | case GPIOINT: 136 | return gpioint[address]; 137 | case GPIOIFL: 138 | return gpioifl[address]; 139 | default: 140 | return 0; 141 | } 142 | } 143 | 144 | void write(uint16_t address, uint8_t value) 145 | { 146 | int bufferID = mapAddress(&address); 147 | 148 | bool isInput; 149 | 150 | switch(bufferID) 151 | { 152 | case GPIOPV: 153 | isInput = (gpiodir[address / 8] & (1 << (address % 8))) == 0; 154 | if(isInput) 155 | return; 156 | gpiopvFront[address] = value; 157 | return; 158 | case GPIODIR: 159 | gpiodir[address] = value; 160 | return; 161 | case GPIOINT: 162 | gpioint[address] = value; 163 | return; 164 | case GPIOIFL: 165 | for(int i = 0; i < 8; i++) 166 | { 167 | if((value & (1 << i)) == 0) continue; 168 | 169 | IRQType irqType = static_cast((gpioint[address * 4 + i / 2] >> ((i % 2) * 4)) & 0xF); 170 | 171 | if(irqType == LOW || irqType == HIGH) 172 | { 173 | uint8_t pv = gpiopvBack[address * 8 + i] & 0xF; 174 | if(irqType == LOW && pv == 0) 175 | continue; 176 | else if(irqType == HIGH && pv > 0) 177 | continue; 178 | } 179 | 180 | gpioifl[address] &= ~(1 << i); 181 | } 182 | return; 183 | } 184 | } 185 | 186 | void tickInterrupts() 187 | { 188 | // Handle input interrupts 189 | for(size_t i = 0; i < N; i++) 190 | { 191 | bool isInput = (gpiodir[i / 8] & (1 << (i % 8))) == 0; 192 | if(!isInput) 193 | { 194 | gpioifl[i / 8] &= ~(1 << (i % 8)); // Clear interrupt flag when pin is not an input 195 | continue; 196 | } 197 | IRQType irqType = static_cast((gpioint[i / 2] >> ((i % 2) * 4)) & 0xF); 198 | if(irqType == NO_INTERRUPT) 199 | { 200 | gpioifl[i / 8] &= ~(1 << (i % 8)); // Clear interrupt flag when pin is not an input 201 | continue; 202 | } 203 | 204 | uint8_t pv = gpiopvFront[i]; 205 | uint8_t pvOld = gpiopvBack[i]; 206 | bool triggers = triggersInterrupt(irqType, pv, pvOld); 207 | if(triggers) 208 | gpioifl[i / 8] |= (1 << (i % 8)); 209 | } 210 | 211 | // Trigger interrupt if any of the interrupt flags are set 212 | } 213 | 214 | void copyBuffers() 215 | { 216 | memcpy(gpiopvBack, gpiopvFront, N); 217 | } 218 | 219 | bool shouldInterrupt() const 220 | { 221 | // Trigger interrupt if any of the interrupt flags are set 222 | for(size_t i = 0; i < N / 8; i++) 223 | { 224 | if(gpioifl[i] != 0) 225 | return true; 226 | } 227 | 228 | return false; 229 | } 230 | }; -------------------------------------------------------------------------------- /src/main/cpp/cnmcu/CNRAM.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | template 8 | class CNRAM 9 | { 10 | public: 11 | void reset() 12 | { 13 | for(size_t i = 0; i < N; i++) 14 | ram[i] = 0; 15 | } 16 | 17 | CNRAM() 18 | { 19 | reset(); 20 | } 21 | 22 | CNRAM(const uint8_t* data, size_t dataSize) 23 | { 24 | size_t numBytesToRead = std::min(dataSize, N); 25 | for(size_t i = 0; i < N; i++) 26 | ram[i] = i < numBytesToRead ? data[i] : 0; 27 | } 28 | 29 | CNRAM(CNRAM&& other) 30 | { 31 | *this = std::move(other); 32 | } 33 | 34 | CNRAM& operator=(CNRAM&& other) 35 | { 36 | for(size_t i = 0; i < N; i++) 37 | ram[i] = other.ram[i]; 38 | return *this; 39 | } 40 | 41 | size_t size() const { return N; } 42 | uint8_t* data() { return ram; } 43 | 44 | uint8_t read(uint16_t address) const { return address < N ? ram[address] : 0; } 45 | void write(uint16_t address, uint8_t value) { if(address < N) ram[address] = value; } 46 | private: 47 | uint8_t ram[N]; 48 | }; -------------------------------------------------------------------------------- /src/main/cpp/cnmcu/CNROM.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | template 8 | class CNROM 9 | { 10 | public: 11 | CNROM() 12 | { 13 | for(size_t i = 0; i < N; i++) 14 | rom[i] = 0; 15 | } 16 | 17 | CNROM(const uint8_t* data, size_t dataSize) 18 | { 19 | for(size_t i = 0; i < N; i++) 20 | rom[i] = 0; 21 | 22 | size_t numBytesToRead = std::min(dataSize, N); 23 | for(size_t i = 0; i < numBytesToRead; i++) 24 | rom[i] = data[i]; 25 | } 26 | 27 | CNROM(CNROM&& other) 28 | { 29 | *this = std::move(other); 30 | } 31 | 32 | CNROM& operator=(CNROM&& other) 33 | { 34 | for(size_t i = 0; i < N; i++) 35 | rom[i] = other.rom[i]; 36 | return *this; 37 | } 38 | 39 | size_t size() { return N; } 40 | uint8_t* data() { return rom; } 41 | 42 | uint8_t read(uint16_t address) const 43 | { 44 | return address < N ? rom[address] : 0; 45 | } 46 | 47 | void write(uint16_t address, uint8_t value) 48 | { 49 | if(writeProtect) 50 | return; 51 | 52 | if(address < N) 53 | rom[address] = value; 54 | } 55 | 56 | void setWriteProtect(bool writeProtect) { this->writeProtect = writeProtect; } 57 | bool isWriteProtected() const { return writeProtect; } 58 | private: 59 | uint8_t rom[N]; 60 | bool writeProtect = true; 61 | }; -------------------------------------------------------------------------------- /src/main/cpp/cnmcu/CNUART.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | class CNUART 7 | { 8 | private: 9 | uint8_t registers[8]; 10 | public: 11 | enum ParityType : uint8_t 12 | { 13 | ODD = 0, 14 | EVEN = 1 15 | }; 16 | 17 | enum StatusFlags : uint8_t 18 | { 19 | PARITY_ERROR = 0, 20 | FRAME_ERROR = 1, 21 | OVERRUN_ERROR = 2, 22 | RX_BUFFER_FULL = 3, 23 | TX_BUFFER_EMPTY = 4, 24 | IRQ = 7 25 | }; 26 | 27 | enum CommandFlags : uint8_t 28 | { 29 | RX_INTERRUPT_ENABLE = 0, 30 | TX_INTERRUPT_ENABLE = 1, 31 | ECHO_ENABLE = 2, 32 | PARITY_ENABLE = 3, 33 | PARITY_TYPE = 4, 34 | RX_PIN_ENABLE = 5, 35 | TX_PIN_ENABLE = 6 36 | }; 37 | 38 | constexpr static int STATUS_REG = 0; 39 | constexpr static int CONTROL_REG = 1; 40 | constexpr static int COMMAND_REG = 2; 41 | constexpr static int TX_DATA_REG = 3; 42 | constexpr static int RX_DATA_REG = 4; 43 | constexpr static int TX_PIN_REG = 5; 44 | constexpr static int RX_PIN_REG = 6; 45 | constexpr static int INTERNAL_REG = 7; 46 | 47 | constexpr static int INTERNAL_CLOCK = 115200; // Hz 48 | 49 | CNUART(); 50 | 51 | constexpr size_t size() const { return sizeof(registers); } 52 | 53 | void reset(); 54 | void tick(); 55 | 56 | bool shouldInterrupt() const; 57 | 58 | int txPin() const; 59 | int rxPin() const; 60 | 61 | uint8_t txOut() const; 62 | void rxIn(uint8_t value); 63 | 64 | uint8_t* registerData(); 65 | 66 | void write(uint16_t address, uint8_t value); 67 | uint8_t read(uint16_t address); 68 | private: 69 | uint8_t txOuput; 70 | uint8_t rxInput; 71 | int64_t cycles; 72 | int64_t cyclesTarget; 73 | 74 | int stopBits() const; 75 | int wordLength() const; 76 | int baudRate() const; 77 | int frameLength() const; 78 | 79 | bool rxInterruptEnabled() const; 80 | bool txInterruptEnabled() const; 81 | bool echoEnabled() const; 82 | bool parityEnabled() const; 83 | ParityType parityType() const; 84 | 85 | int txIndex(); 86 | void txIndexInc(); 87 | int rxIndex(); 88 | void rxIndexInc(); 89 | 90 | bool getParity(uint8_t value) const; 91 | void doTx(); 92 | void doRx(); 93 | }; -------------------------------------------------------------------------------- /src/main/cpp/cnmcu/MeshLoader.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | #include 7 | 8 | #include 9 | 10 | class MeshLoader 11 | { 12 | public: 13 | // From https://stackoverflow.com/questions/7781898 14 | struct membuf : std::streambuf 15 | { 16 | membuf(char* begin, char* end) { 17 | this->setg(begin, begin, end); 18 | } 19 | }; 20 | 21 | static void loadPLY(JNIEnv* env, const char* modelBuffer, size_t bufferSize, jobject mesh); 22 | private: 23 | static void genNormals(int numVertices, const float* positions, float* normals); 24 | static std::unique_ptr loadProperties(happly::Element& vertData, const char* properties, JNIEnv* env, jobject mesh, jmethodID method); 25 | static std::unique_ptr loadColors(happly::Element& vertData, const char* properties, JNIEnv* env, jobject mesh, jmethodID method); 26 | }; -------------------------------------------------------------------------------- /src/main/cpp/cnmcu/Nano.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | CodeNodeNano::CodeNodeNano() 4 | : cpu(read, write, cycle) 5 | , cyclesCounter(0) 6 | , cyclesTarget(0) 7 | , m_busAddress(0) 8 | , m_busData(0) 9 | , m_busRw(false) 10 | , poweredOn(false) 11 | , clockPaused(false) 12 | { 13 | memset(pinOutputs, 0, GPIO_NUM_PINS); 14 | } 15 | 16 | void CodeNodeNano::tick() 17 | { 18 | if(!poweredOn || clockPaused) 19 | return; 20 | 21 | cyclesTarget += CLOCK_FREQUENCY / GAME_TICK_RATE; 22 | 23 | gpio.tickInterrupts(); 24 | gpio.copyBuffers(); 25 | 26 | if (gpio.isInput(uart.rxPin())) 27 | uart.rxIn(gpio.read(uart.rxPin())); // RX 28 | 29 | uart.tick(); 30 | 31 | currentInstance = this; 32 | cpu.Run(cyclesTarget - cyclesCounter, cyclesCounter); 33 | 34 | memcpy(pinOutputs, gpio.pvFrontData(), GPIO_NUM_PINS); 35 | if (!gpio.isInput(uart.txPin())) 36 | pinOutputs[uart.txPin()] = uart.txOut(); // TX 37 | } 38 | 39 | void CodeNodeNano::cycle() 40 | { 41 | if(!poweredOn || !clockPaused) 42 | return; 43 | 44 | gpio.tickInterrupts(); 45 | gpio.copyBuffers(); 46 | 47 | currentInstance = this; 48 | cpu.Run(1, cyclesCounter); 49 | cyclesTarget = cyclesCounter; 50 | } 51 | 52 | void CodeNodeNano::reset() 53 | { 54 | currentInstance = this; 55 | ram.reset(); 56 | // rom.reset(); 57 | gpio.reset(); 58 | el.reset(); 59 | uart.reset(); 60 | memset(pinOutputs, 0, GPIO_NUM_PINS); 61 | cpu.Reset(); 62 | cyclesCounter = 0; 63 | cyclesTarget = 0; 64 | } 65 | 66 | void CodeNodeNano::powerOn() 67 | { 68 | if(poweredOn) 69 | return; 70 | 71 | poweredOn = true; 72 | reset(); 73 | } 74 | 75 | void CodeNodeNano::powerOff() 76 | { 77 | if(!poweredOn) 78 | return; 79 | 80 | poweredOn = false; 81 | } 82 | 83 | bool CodeNodeNano::isPoweredOn() const 84 | { 85 | return poweredOn; 86 | } 87 | 88 | mos6502& CodeNodeNano::CPU() 89 | { 90 | return cpu; 91 | } 92 | 93 | CNGPIO& CodeNodeNano::GPIO() 94 | { 95 | return gpio; 96 | } 97 | 98 | CNRAM& CodeNodeNano::RAM() 99 | { 100 | return ram; 101 | } 102 | 103 | CNROM& CodeNodeNano::ROM() 104 | { 105 | return rom; 106 | } 107 | 108 | CNEL& CodeNodeNano::EL() 109 | { 110 | return el; 111 | } 112 | 113 | CNUART& CodeNodeNano::UART() 114 | { 115 | return uart; 116 | } 117 | 118 | CodeNodeNano* CodeNodeNano::currentInstance = nullptr; 119 | 120 | uint8_t CodeNodeNano::read(uint16_t address) 121 | { 122 | if(currentInstance == nullptr) 123 | return 0; 124 | 125 | currentInstance->m_busAddress = address; 126 | currentInstance->m_busData = 0; 127 | currentInstance->m_busRw = false; 128 | 129 | if(0xFFFF - ROM_SIZE < address) 130 | { 131 | currentInstance->m_busData = currentInstance->rom.read(address - (0x10000 - ROM_SIZE)); 132 | return currentInstance->m_busData; 133 | } 134 | else if(0x7000 <= address && address < (0x7000 + currentInstance->gpio.size())) 135 | { 136 | currentInstance->m_busData = currentInstance->gpio.read(address - 0x7000); 137 | return currentInstance->m_busData; 138 | } 139 | else if(0x7100 <= address && address < (0x7100 + currentInstance->el.size())) 140 | { 141 | currentInstance->m_busData = currentInstance->el.read(address - 0x7100); 142 | return currentInstance->m_busData; 143 | } 144 | else if(0x7200 <= address && address < (0x7200 + currentInstance->uart.size())) 145 | { 146 | currentInstance->m_busData = currentInstance->uart.read(address - 0x7200); 147 | return currentInstance->m_busData; 148 | } 149 | 150 | return (currentInstance->m_busData = currentInstance->ram.read(address)); 151 | } 152 | 153 | void CodeNodeNano::write(uint16_t address, uint8_t value) 154 | { 155 | if(currentInstance == nullptr) 156 | return; 157 | 158 | currentInstance->m_busAddress = address; 159 | currentInstance->m_busData = value; 160 | currentInstance->m_busRw = true; 161 | 162 | if(0xFFFF - ROM_SIZE < address) 163 | { 164 | currentInstance->rom.write(address - (0x10000 - ROM_SIZE), value); 165 | return; 166 | } 167 | else if(0x7000 <= address && address < (0x7000 + currentInstance->gpio.size())) 168 | { 169 | currentInstance->gpio.write(address - 0x7000, value); 170 | return; 171 | } 172 | else if(0x7100 <= address && address < (0x7100 + currentInstance->el.size())) 173 | { 174 | currentInstance->el.write(address - 0x7100, value); 175 | return; 176 | } 177 | else if(0x7200 <= address && address < (0x7200 + currentInstance->uart.size())) 178 | { 179 | currentInstance->uart.write(address - 0x7200, value); 180 | return; 181 | } 182 | 183 | currentInstance->ram.write(address, value); 184 | } 185 | 186 | void CodeNodeNano::cycle(mos6502* cpu) 187 | { 188 | if(currentInstance == nullptr) 189 | return; 190 | 191 | bool shouldInterrupt = currentInstance->gpio.shouldInterrupt(); 192 | shouldInterrupt |= currentInstance->el.shouldInterrupt(); 193 | shouldInterrupt |= currentInstance->uart.shouldInterrupt(); 194 | 195 | if(shouldInterrupt) 196 | cpu->IRQ(); 197 | } -------------------------------------------------------------------------------- /src/main/cpp/cnmcu/Nano.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include "CNGPIO.hpp" 5 | #include "CNRAM.hpp" 6 | #include "CNROM.hpp" 7 | #include "CNEL.hpp" 8 | #include "CNUART.hpp" 9 | 10 | #define GAME_TICK_RATE 20 // 20 Hz 11 | 12 | class CodeNodeNano 13 | { 14 | public: 15 | constexpr static size_t GPIO_NUM_PINS = 64; // Supports 64 pins, only 4 of which are used 16 | constexpr static size_t RAM_SIZE = 512; // 512 bytes 17 | constexpr static size_t ROM_SIZE = 8192; // 8 KB 18 | constexpr static size_t EL_SIZE = 8; // 8 bytes 19 | constexpr static size_t CLOCK_FREQUENCY = GAME_TICK_RATE * 40; // 800 Hz 20 | 21 | CodeNodeNano(); 22 | 23 | void tick(); 24 | void cycle(); 25 | void reset(); 26 | 27 | void powerOn(); 28 | void powerOff(); 29 | bool isPoweredOn() const; 30 | void pauseClock() { clockPaused = true; } 31 | void resumeClock() { clockPaused = false; } 32 | bool isClockPaused() const { return clockPaused; } 33 | uint64_t numCycles() const { return cyclesCounter; } 34 | void setNumCycles(uint64_t cycles) { cyclesCounter = cycles; cyclesTarget = cycles;} 35 | 36 | uint16_t busAddress() const { return m_busAddress; } 37 | uint8_t busData() const { return m_busData; } 38 | bool busRw() const { return m_busRw; } 39 | 40 | mos6502& CPU(); 41 | CNGPIO& GPIO(); 42 | CNRAM& RAM(); 43 | CNROM& ROM(); 44 | CNEL& EL(); 45 | CNUART& UART(); 46 | uint8_t* pinOutputDrivers() { return pinOutputs; } 47 | private: 48 | mos6502 cpu; 49 | CNGPIO gpio; 50 | CNRAM ram; 51 | CNROM rom; 52 | CNEL el; 53 | CNUART uart; 54 | uint64_t cyclesCounter; 55 | uint64_t cyclesTarget; 56 | uint8_t pinOutputs[GPIO_NUM_PINS]; // "Pin output drivers" 57 | 58 | uint16_t m_busAddress; 59 | uint8_t m_busData; 60 | bool m_busRw; 61 | 62 | bool poweredOn; 63 | bool clockPaused; 64 | 65 | static CodeNodeNano* currentInstance; 66 | static uint8_t read(uint16_t address); 67 | static void write(uint16_t address, uint8_t value); 68 | static void cycle(mos6502* cpu); 69 | }; -------------------------------------------------------------------------------- /src/main/cpp/cnmcu/mos6502.h: -------------------------------------------------------------------------------- 1 | //============================================================================ 2 | // Name : mos6502 3 | // Author : Gianluca Ghettini 4 | // Version : 1.0 5 | // Copyright : 6 | // Description : A MOS 6502 CPU emulator written in C++ 7 | //============================================================================ 8 | 9 | #pragma once 10 | #include 11 | 12 | class mos6502 13 | { 14 | private: 15 | // register reset values 16 | uint8_t reset_A; 17 | uint8_t reset_X; 18 | uint8_t reset_Y; 19 | uint8_t reset_sp; 20 | uint8_t reset_status; 21 | 22 | // registers 23 | uint8_t A; // accumulator 24 | uint8_t X; // X-index 25 | uint8_t Y; // Y-index 26 | 27 | // stack pointer 28 | uint8_t sp; 29 | 30 | // program counter 31 | uint16_t pc; 32 | 33 | // status register 34 | uint8_t status; 35 | 36 | typedef void (mos6502::*CodeExec)(uint16_t); 37 | typedef uint16_t (mos6502::*AddrExec)(); 38 | 39 | struct Instr 40 | { 41 | AddrExec addr; 42 | CodeExec code; 43 | uint8_t cycles; 44 | }; 45 | 46 | static Instr InstrTable[256]; 47 | 48 | void Exec(Instr i); 49 | 50 | bool illegalOpcode; 51 | 52 | // addressing modes 53 | uint16_t Addr_ACC(); // ACCUMULATOR 54 | uint16_t Addr_IMM(); // IMMEDIATE 55 | uint16_t Addr_ABS(); // ABSOLUTE 56 | uint16_t Addr_ZER(); // ZERO PAGE 57 | uint16_t Addr_ZEX(); // INDEXED-X ZERO PAGE 58 | uint16_t Addr_ZEY(); // INDEXED-Y ZERO PAGE 59 | uint16_t Addr_ABX(); // INDEXED-X ABSOLUTE 60 | uint16_t Addr_ABY(); // INDEXED-Y ABSOLUTE 61 | uint16_t Addr_IMP(); // IMPLIED 62 | uint16_t Addr_REL(); // RELATIVE 63 | uint16_t Addr_INX(); // INDEXED-X INDIRECT 64 | uint16_t Addr_INY(); // INDEXED-Y INDIRECT 65 | uint16_t Addr_ABI(); // ABSOLUTE INDIRECT 66 | 67 | // opcodes (grouped as per datasheet) 68 | void Op_ADC(uint16_t src); 69 | void Op_AND(uint16_t src); 70 | void Op_ASL(uint16_t src); void Op_ASL_ACC(uint16_t src); 71 | void Op_BCC(uint16_t src); 72 | void Op_BCS(uint16_t src); 73 | 74 | void Op_BEQ(uint16_t src); 75 | void Op_BIT(uint16_t src); 76 | void Op_BMI(uint16_t src); 77 | void Op_BNE(uint16_t src); 78 | void Op_BPL(uint16_t src); 79 | 80 | void Op_BRK(uint16_t src); 81 | void Op_BVC(uint16_t src); 82 | void Op_BVS(uint16_t src); 83 | void Op_CLC(uint16_t src); 84 | void Op_CLD(uint16_t src); 85 | 86 | void Op_CLI(uint16_t src); 87 | void Op_CLV(uint16_t src); 88 | void Op_CMP(uint16_t src); 89 | void Op_CPX(uint16_t src); 90 | void Op_CPY(uint16_t src); 91 | 92 | void Op_DEC(uint16_t src); 93 | void Op_DEX(uint16_t src); 94 | void Op_DEY(uint16_t src); 95 | void Op_EOR(uint16_t src); 96 | void Op_INC(uint16_t src); 97 | 98 | void Op_INX(uint16_t src); 99 | void Op_INY(uint16_t src); 100 | void Op_JMP(uint16_t src); 101 | void Op_JSR(uint16_t src); 102 | void Op_LDA(uint16_t src); 103 | 104 | void Op_LDX(uint16_t src); 105 | void Op_LDY(uint16_t src); 106 | void Op_LSR(uint16_t src); void Op_LSR_ACC(uint16_t src); 107 | void Op_NOP(uint16_t src); 108 | void Op_ORA(uint16_t src); 109 | 110 | void Op_PHA(uint16_t src); 111 | void Op_PHP(uint16_t src); 112 | void Op_PLA(uint16_t src); 113 | void Op_PLP(uint16_t src); 114 | void Op_ROL(uint16_t src); void Op_ROL_ACC(uint16_t src); 115 | 116 | void Op_ROR(uint16_t src); void Op_ROR_ACC(uint16_t src); 117 | void Op_RTI(uint16_t src); 118 | void Op_RTS(uint16_t src); 119 | void Op_SBC(uint16_t src); 120 | void Op_SEC(uint16_t src); 121 | void Op_SED(uint16_t src); 122 | 123 | void Op_SEI(uint16_t src); 124 | void Op_STA(uint16_t src); 125 | void Op_STX(uint16_t src); 126 | void Op_STY(uint16_t src); 127 | void Op_TAX(uint16_t src); 128 | 129 | void Op_TAY(uint16_t src); 130 | void Op_TSX(uint16_t src); 131 | void Op_TXA(uint16_t src); 132 | void Op_TXS(uint16_t src); 133 | void Op_TYA(uint16_t src); 134 | 135 | void Op_ILLEGAL(uint16_t src); 136 | 137 | // IRQ, reset, NMI vectors 138 | static const uint16_t irqVectorH = 0xFFFF; 139 | static const uint16_t irqVectorL = 0xFFFE; 140 | static const uint16_t rstVectorH = 0xFFFD; 141 | static const uint16_t rstVectorL = 0xFFFC; 142 | static const uint16_t nmiVectorH = 0xFFFB; 143 | static const uint16_t nmiVectorL = 0xFFFA; 144 | 145 | // read/write/clock-cycle callbacks 146 | typedef void (*BusWrite)(uint16_t, uint8_t); 147 | typedef uint8_t (*BusRead)(uint16_t); 148 | typedef void (*ClockCycle)(mos6502*); 149 | BusRead Read; 150 | BusWrite Write; 151 | ClockCycle Cycle; 152 | 153 | // stack operations 154 | inline void StackPush(uint8_t byte); 155 | inline uint8_t StackPop(); 156 | 157 | public: 158 | enum CycleMethod { 159 | INST_COUNT, 160 | CYCLE_COUNT, 161 | }; 162 | mos6502(BusRead r, BusWrite w, ClockCycle c = nullptr); 163 | void NMI(); 164 | void IRQ(); 165 | void Reset(); 166 | void Run( 167 | int32_t cycles, 168 | uint64_t& cycleCount, 169 | CycleMethod cycleMethod = CYCLE_COUNT); 170 | void RunEternally(); // until it encounters a illegal opcode 171 | // useful when running e.g. WOZ Monitor 172 | // no need to worry about cycle exhaus- 173 | // tion 174 | uint16_t GetPC(); 175 | uint8_t GetS(); 176 | uint8_t GetP(); 177 | uint8_t GetA(); 178 | uint8_t GetX(); 179 | uint8_t GetY(); 180 | void SetResetS(uint8_t value); 181 | void SetResetP(uint8_t value); 182 | void SetResetA(uint8_t value); 183 | void SetResetX(uint8_t value); 184 | void SetResetY(uint8_t value); 185 | uint8_t GetResetS(); 186 | uint8_t GetResetP(); 187 | uint8_t GetResetA(); 188 | uint8_t GetResetX(); 189 | uint8_t GetResetY(); 190 | void SetState(int state[]); 191 | }; -------------------------------------------------------------------------------- /src/main/java/com/elmfer/cnmcu/CodeNodeMicrocontrollers.java: -------------------------------------------------------------------------------- 1 | package com.elmfer.cnmcu; 2 | 3 | import org.slf4j.Logger; 4 | import org.slf4j.LoggerFactory; 5 | 6 | import com.elmfer.cnmcu.blockentities.BlockEntities; 7 | import com.elmfer.cnmcu.blocks.Blocks; 8 | import com.elmfer.cnmcu.config.Config; 9 | import com.elmfer.cnmcu.config.ModSetup; 10 | import com.elmfer.cnmcu.cpp.NativesLoader; 11 | import com.elmfer.cnmcu.network.Packets; 12 | import com.elmfer.cnmcu.ui.handler.ScreenHandlers; 13 | 14 | import net.fabricmc.api.ModInitializer; 15 | import net.minecraft.util.Identifier; 16 | 17 | public class CodeNodeMicrocontrollers implements ModInitializer { 18 | 19 | public static final String MOD_NAME = "CodeNode Microcontrollers"; 20 | public static final String MOD_ID = "cnmcu"; 21 | public static final String MOD_VERSION = "0.0.10a-1.20.4"; 22 | 23 | public static final Logger LOGGER = LoggerFactory.getLogger(MOD_ID); 24 | 25 | @Override 26 | public void onInitialize() { 27 | ModSetup.createDirectories(); 28 | ModSetup.downloadNatives(); 29 | ModSetup.downloadToolchain(); 30 | 31 | checkForUpdates(); 32 | 33 | NativesLoader.loadNatives(); 34 | 35 | Blocks.init(); 36 | BlockEntities.init(); 37 | ScreenHandlers.init(); 38 | 39 | Packets.initServerPackets(); 40 | } 41 | 42 | public static void checkForUpdates() { 43 | if (!Config.adviseUpdates()) 44 | return; 45 | 46 | ModSetup.checkForUpdates(); 47 | 48 | if (ModSetup.isUpdateAvailable()) { 49 | String latestForMCVersions = String.join(", ", ModSetup.getLatestForMinecraftVersions()); 50 | LOGGER.info("An update is available for CodeNode Microcontrollers: " + ModSetup.getLatestVersion() 51 | + " for Minecraft " + latestForMCVersions); 52 | } else if (!ModSetup.wasAbleToCheckForUpdates()) { 53 | LOGGER.info("CodeNode Microcontrollers was unable to check for updates."); 54 | } else { 55 | LOGGER.info("CodeNode Microcontrollers is up to date."); 56 | } 57 | } 58 | 59 | public static Identifier id(String path) { 60 | return new Identifier(MOD_ID, path); 61 | } 62 | } -------------------------------------------------------------------------------- /src/main/java/com/elmfer/cnmcu/CodeNodeMicrocontrollersClient.java: -------------------------------------------------------------------------------- 1 | package com.elmfer.cnmcu; 2 | 3 | import org.slf4j.Logger; 4 | import org.slf4j.LoggerFactory; 5 | 6 | import com.elmfer.cnmcu.config.ModSetup; 7 | import com.elmfer.cnmcu.network.Packets; 8 | import com.elmfer.cnmcu.ui.IDEScreen; 9 | import com.elmfer.cnmcu.ui.handler.ScreenHandlers; 10 | 11 | import net.fabricmc.api.ClientModInitializer; 12 | import net.minecraft.client.gui.screen.ingame.HandledScreens; 13 | 14 | public class CodeNodeMicrocontrollersClient implements ClientModInitializer { 15 | 16 | public static final Logger LOGGER = LoggerFactory.getLogger(CodeNodeMicrocontrollers.MOD_ID + "-client"); 17 | 18 | @Override 19 | public void onInitializeClient() { 20 | ModSetup.imguiIniFile(); 21 | 22 | HandledScreens.register(ScreenHandlers.IDE_SCREEN_HANDLER, IDEScreen::new); 23 | 24 | Packets.initClientPackets(); 25 | 26 | EventHandler.registerClientEventHandlers(); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/com/elmfer/cnmcu/EventHandler.java: -------------------------------------------------------------------------------- 1 | package com.elmfer.cnmcu; 2 | 3 | import com.elmfer.cnmcu.config.Config; 4 | import com.elmfer.cnmcu.config.ModSetup; 5 | import com.elmfer.cnmcu.mcu.Toolchain; 6 | import com.elmfer.cnmcu.ui.UIRender; 7 | 8 | import imgui.ImGui; 9 | import imgui.ImGuiIO; 10 | import imgui.flag.ImGuiConfigFlags; 11 | import imgui.gl3.ImGuiImplGl3; 12 | import imgui.glfw.ImGuiImplGlfw; 13 | import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientLifecycleEvents; 14 | import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderContext; 15 | import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderEvents; 16 | import net.minecraft.client.MinecraftClient; 17 | import net.minecraft.text.MutableText; 18 | import net.minecraft.text.PlainTextContent; 19 | 20 | public class EventHandler { 21 | 22 | public final static ImGuiImplGlfw IMGUI_GLFW = new ImGuiImplGlfw(); 23 | public final static ImGuiImplGl3 IMGUI_GL3 = new ImGuiImplGl3(); 24 | 25 | private static boolean hasNotifiedPlayerAboutUpdate = false; 26 | 27 | public static void registerClientEventHandlers() { 28 | ClientLifecycleEvents.CLIENT_STARTED.register(EventHandler::onClientStarted); 29 | ClientLifecycleEvents.CLIENT_STOPPING.register(EventHandler::onClientStopping); 30 | WorldRenderEvents.START.register(EventHandler::onStartRenderWorld); 31 | WorldRenderEvents.END.register(EventHandler::onEndRenderWorld); 32 | } 33 | 34 | private static void onStartRenderWorld(WorldRenderContext context) { 35 | if (!hasNotifiedPlayerAboutUpdate) 36 | notifyPlayerAboutUpdate(); 37 | 38 | UIRender.newFrame(); 39 | 40 | EventHandler.IMGUI_GLFW.newFrame(); 41 | } 42 | 43 | private static void onEndRenderWorld(WorldRenderContext context) { 44 | UIRender.renderBatch(); 45 | } 46 | 47 | private static void onClientStarted(MinecraftClient client) { 48 | ImGui.createContext(); 49 | 50 | IMGUI_GLFW.init(client.getWindow().getHandle(), true); 51 | IMGUI_GL3.init("#version 150"); 52 | 53 | ImGuiIO io = ImGui.getIO(); 54 | 55 | io.setIniFilename(ModSetup.IMGUI_INI_FILE); 56 | io.setDisplaySize(client.getWindow().getWidth(), client.getWindow().getHeight()); 57 | io.setConfigFlags(ImGuiConfigFlags.DockingEnable); 58 | } 59 | 60 | private static void onClientStopping(MinecraftClient client) { 61 | Config.save(); 62 | Config.waitForSave(); 63 | Toolchain.saveConfig(); 64 | Toolchain.waitForSave(); 65 | } 66 | 67 | private static void notifyPlayerAboutUpdate() { 68 | if (hasNotifiedPlayerAboutUpdate) 69 | return; 70 | 71 | hasNotifiedPlayerAboutUpdate = true; 72 | 73 | MinecraftClient client = MinecraftClient.getInstance(); 74 | client.execute(() -> { 75 | if (!ModSetup.hasCheckedForUpdates() || !ModSetup.isUpdateAvailable()) 76 | return; 77 | 78 | MutableText updateMessage = MutableText 79 | .of(new PlainTextContent.Literal("An update is available for CodeNode Microcontrollers: v")); 80 | updateMessage.setStyle(updateMessage.getStyle().withColor(0xFF5CFF5C)); 81 | 82 | MutableText version = MutableText.of(new PlainTextContent.Literal(ModSetup.getLatestVersion() + " ")); 83 | version.setStyle(version.getStyle().withColor(0xFFFFF41F)); 84 | 85 | MutableText forMCVersions = MutableText.of(new PlainTextContent.Literal( 86 | "for Minecraft " + String.join(", ", ModSetup.getLatestForMinecraftVersions()))); 87 | forMCVersions.setStyle(forMCVersions.getStyle().withColor(0xFF85A9FF)); 88 | 89 | updateMessage.getSiblings().add(version); 90 | updateMessage.getSiblings().add(forMCVersions); 91 | 92 | client.player.sendMessage(updateMessage); 93 | }); 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /src/main/java/com/elmfer/cnmcu/animation/ClockTimer.java: -------------------------------------------------------------------------------- 1 | package com.elmfer.cnmcu.animation; 2 | 3 | import org.lwjgl.glfw.GLFW; 4 | 5 | public class ClockTimer { 6 | public final double tps; 7 | private double nextTick; 8 | 9 | public ClockTimer(double tps) { 10 | this.tps = tps; 11 | this.nextTick = GLFW.glfwGetTime(); 12 | } 13 | 14 | public int ticksPassed() { 15 | double currentTime = GLFW.glfwGetTime(); 16 | int ticks = 0; 17 | 18 | while (currentTime > nextTick) { 19 | nextTick += 1.0 / tps; 20 | ticks++; 21 | } 22 | 23 | return ticks; 24 | } 25 | 26 | public double partialTicks() { 27 | double currentTime = GLFW.glfwGetTime(); 28 | return (currentTime + 1.0 / tps - nextTick) * tps; 29 | } 30 | 31 | public double lerp(double start, double end) { 32 | return start + (end - start) * partialTicks(); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/com/elmfer/cnmcu/animation/Timer.java: -------------------------------------------------------------------------------- 1 | package com.elmfer.cnmcu.animation; 2 | 3 | import org.lwjgl.glfw.GLFW; 4 | 5 | public class Timer { 6 | public final double time; 7 | private double startTime; 8 | private boolean hasExpired = false; 9 | 10 | public Timer(double time) { 11 | this.time = time; 12 | this.startTime = GLFW.glfwGetTime(); 13 | } 14 | 15 | public Timer expire() { 16 | hasExpired = true; 17 | return this; 18 | } 19 | 20 | public boolean hasExpired() { 21 | if(hasExpired) return true; 22 | return (hasExpired = GLFW.glfwGetTime() - startTime >= time); 23 | } 24 | 25 | public double getProgress() { 26 | return (GLFW.glfwGetTime() - startTime) / time; 27 | } 28 | 29 | public void reset() { 30 | hasExpired = false; 31 | startTime = GLFW.glfwGetTime(); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/com/elmfer/cnmcu/blockentities/BlockEntities.java: -------------------------------------------------------------------------------- 1 | package com.elmfer.cnmcu.blockentities; 2 | 3 | import com.elmfer.cnmcu.CodeNodeMicrocontrollers; 4 | import com.elmfer.cnmcu.blocks.Blocks; 5 | 6 | import net.fabricmc.fabric.api.object.builder.v1.block.entity.FabricBlockEntityTypeBuilder; 7 | import net.minecraft.block.entity.BlockEntityType; 8 | import net.minecraft.registry.Registries; 9 | import net.minecraft.registry.Registry; 10 | 11 | public class BlockEntities { 12 | public static void init() { 13 | 14 | } 15 | 16 | public static final BlockEntityType CN_NANO = Registry.register(Registries.BLOCK_ENTITY_TYPE, 17 | CodeNodeMicrocontrollers.id("nano"), 18 | FabricBlockEntityTypeBuilder.create(CNnanoBlockEntity::new, Blocks.CN_NANO_BLOCK).build(null)); 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/com/elmfer/cnmcu/blocks/Blocks.java: -------------------------------------------------------------------------------- 1 | package com.elmfer.cnmcu.blocks; 2 | 3 | import com.elmfer.cnmcu.CodeNodeMicrocontrollers; 4 | 5 | import net.fabricmc.fabric.api.item.v1.FabricItemSettings; 6 | import net.fabricmc.fabric.api.object.builder.v1.block.FabricBlockSettings; 7 | import net.minecraft.block.Block; 8 | import net.minecraft.item.BlockItem; 9 | import net.minecraft.item.Item; 10 | import net.minecraft.registry.Registries; 11 | import net.minecraft.registry.Registry; 12 | 13 | public class Blocks { 14 | public static final CNnanoBlock CN_NANO_BLOCK = new CNnanoBlock(FabricBlockSettings.create().strength(0.5f)); 15 | 16 | public static T register(String name, T block) { 17 | T b = Registry.register(Registries.BLOCK, CodeNodeMicrocontrollers.id(name), block); 18 | BlockItem item = new BlockItem(b, new FabricItemSettings()); 19 | item.appendBlocks(Item.BLOCK_ITEMS, item); 20 | Registry.register(Registries.ITEM, CodeNodeMicrocontrollers.id(name), item); 21 | return b; 22 | } 23 | 24 | public static void init() { 25 | register("nano", CN_NANO_BLOCK); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/com/elmfer/cnmcu/blocks/CNnanoBlock.java: -------------------------------------------------------------------------------- 1 | package com.elmfer.cnmcu.blocks; 2 | 3 | import org.jetbrains.annotations.Nullable; 4 | 5 | import com.elmfer.cnmcu.blockentities.BlockEntities; 6 | import com.elmfer.cnmcu.blockentities.CNnanoBlockEntity; 7 | import com.mojang.serialization.MapCodec; 8 | 9 | import net.minecraft.block.Block; 10 | import net.minecraft.block.BlockRenderType; 11 | import net.minecraft.block.BlockState; 12 | import net.minecraft.block.BlockWithEntity; 13 | import net.minecraft.block.ShapeContext; 14 | import net.minecraft.block.SideShapeType; 15 | import net.minecraft.block.entity.BlockEntity; 16 | import net.minecraft.block.entity.BlockEntityTicker; 17 | import net.minecraft.block.entity.BlockEntityType; 18 | import net.minecraft.entity.player.PlayerEntity; 19 | import net.minecraft.item.ItemPlacementContext; 20 | import net.minecraft.screen.NamedScreenHandlerFactory; 21 | import net.minecraft.state.StateManager; 22 | import net.minecraft.state.property.DirectionProperty; 23 | import net.minecraft.state.property.Properties; 24 | import net.minecraft.util.ActionResult; 25 | import net.minecraft.util.Hand; 26 | import net.minecraft.util.hit.BlockHitResult; 27 | import net.minecraft.util.math.BlockPos; 28 | import net.minecraft.util.math.Direction; 29 | import net.minecraft.util.shape.VoxelShape; 30 | import net.minecraft.util.shape.VoxelShapes; 31 | import net.minecraft.world.BlockView; 32 | import net.minecraft.world.World; 33 | import net.minecraft.world.WorldView; 34 | 35 | public class CNnanoBlock extends BlockWithEntity { 36 | public static final MapCodec CODEC = createCodec(CNnanoBlock::new); 37 | 38 | public static final DirectionProperty FACING = Properties.HORIZONTAL_FACING; 39 | 40 | protected CNnanoBlock(Settings settings) { 41 | super(settings); 42 | } 43 | 44 | @Override 45 | public MapCodec getCodec() { 46 | return CODEC; 47 | } 48 | 49 | @Override 50 | public BlockEntity createBlockEntity(BlockPos pos, BlockState state) { 51 | return new CNnanoBlockEntity(pos, state); 52 | } 53 | 54 | @Override 55 | public boolean canPlaceAt(BlockState state, WorldView world, BlockPos pos) { 56 | BlockPos blockPos = pos.down(); 57 | return this.canPlaceAbove(world, blockPos, world.getBlockState(blockPos)); 58 | } 59 | 60 | protected boolean canPlaceAbove(WorldView world, BlockPos pos, BlockState state) { 61 | return state.isSideSolid(world, pos, Direction.UP, SideShapeType.RIGID); 62 | } 63 | 64 | @Override 65 | public BlockState getPlacementState(ItemPlacementContext context) { 66 | return getDefaultState().with(FACING, context.getHorizontalPlayerFacing()); 67 | } 68 | 69 | @Override 70 | protected void appendProperties(StateManager.Builder builder) { 71 | builder.add(FACING); 72 | } 73 | 74 | @Override 75 | public boolean emitsRedstonePower(BlockState state) { 76 | return true; 77 | } 78 | 79 | @Override 80 | public int getWeakRedstonePower(BlockState state, BlockView world, BlockPos pos, Direction direction) { 81 | BlockEntity blockEntity = world.getBlockEntity(pos); 82 | 83 | if (!(blockEntity instanceof CNnanoBlockEntity)) 84 | return 0; 85 | 86 | CNnanoBlockEntity entity = (CNnanoBlockEntity) blockEntity; 87 | 88 | if (entity.mcu == null || !entity.mcu.isPowered()) 89 | return 0; 90 | 91 | Direction blockDir = state.get(FACING); 92 | Direction localDir = getLocalDirection(blockDir, direction); 93 | 94 | switch (localDir) { 95 | case EAST: 96 | return entity.mcu.rightOutput; 97 | case SOUTH: 98 | return entity.mcu.backOutput; 99 | case WEST: 100 | return entity.mcu.leftOutput; 101 | case NORTH: 102 | return entity.mcu.frontOutput; 103 | default: 104 | return 0; 105 | } 106 | } 107 | 108 | @Nullable 109 | @Override 110 | public BlockEntityTicker getTicker(World world, BlockState state, 111 | BlockEntityType type) { 112 | if (world.isClient) 113 | return null; 114 | 115 | return CNnanoBlock.validateTicker(type, BlockEntities.CN_NANO, world.isClient ? null : CNnanoBlockEntity::tick); 116 | } 117 | 118 | @Override 119 | public BlockRenderType getRenderType(BlockState state) { 120 | return BlockRenderType.MODEL; 121 | } 122 | 123 | @Override 124 | public ActionResult onUse(BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand, 125 | BlockHitResult hit) { 126 | if (!world.isClient) { 127 | NamedScreenHandlerFactory screenHandlerFactory = state.createScreenHandlerFactory(world, pos); 128 | 129 | if (screenHandlerFactory != null) 130 | player.openHandledScreen(screenHandlerFactory); 131 | } 132 | 133 | return ActionResult.SUCCESS; 134 | } 135 | 136 | @Override 137 | public VoxelShape getOutlineShape(BlockState state, BlockView world, BlockPos pos, ShapeContext context) { 138 | return VoxelShapes.cuboid(0.0, 0.0, 0.0, 1.0, 0.125, 1.0); 139 | } 140 | 141 | public static Direction getGlobalDirection(Direction facing, Direction direction) { 142 | switch (facing) { 143 | case EAST: 144 | return direction.rotateYClockwise(); 145 | case SOUTH: 146 | return direction.getOpposite(); 147 | case WEST: 148 | return direction.rotateYCounterclockwise(); 149 | default: 150 | return direction; 151 | } 152 | } 153 | 154 | public static Direction getLocalDirection(Direction facing, Direction direction) { 155 | switch (facing) { 156 | case WEST: 157 | return direction.rotateYCounterclockwise(); 158 | case NORTH: 159 | return direction.getOpposite(); 160 | case EAST: 161 | return direction.rotateYClockwise(); 162 | default: 163 | return direction; 164 | } 165 | } 166 | } 167 | -------------------------------------------------------------------------------- /src/main/java/com/elmfer/cnmcu/config/Config.java: -------------------------------------------------------------------------------- 1 | package com.elmfer.cnmcu.config; 2 | 3 | import java.io.BufferedReader; 4 | import java.io.File; 5 | import java.io.FileNotFoundException; 6 | import java.io.FileReader; 7 | import java.io.IOException; 8 | import java.nio.file.Files; 9 | import java.nio.file.Paths; 10 | import java.util.concurrent.CompletableFuture; 11 | 12 | import com.elmfer.cnmcu.CodeNodeMicrocontrollers; 13 | import com.elmfer.cnmcu.mcu.Sketches; 14 | import com.google.gson.Gson; 15 | import com.google.gson.GsonBuilder; 16 | import com.google.gson.JsonObject; 17 | import com.google.gson.JsonParser; 18 | 19 | public class Config { 20 | public static final File CONFIG_FILE = new File("config/" + CodeNodeMicrocontrollers.MOD_ID + ".json"); 21 | 22 | private static JsonObject config = new JsonObject(); 23 | private static CompletableFuture saveTask; 24 | private static boolean firstTimeUse = false; 25 | 26 | static { 27 | try { 28 | BufferedReader reader = new BufferedReader(new FileReader(CONFIG_FILE)); 29 | 30 | config = JsonParser.parseReader(reader).getAsJsonObject(); 31 | } catch (FileNotFoundException e) { 32 | CodeNodeMicrocontrollers.LOGGER.warn("Config file not found, creating new one..."); 33 | 34 | config.addProperty("adviseUpdates", adviseUpdates()); 35 | config.addProperty("showRegistersInHex", showRegistersInHex()); 36 | config.addProperty("showDocs", showDocs()); 37 | config.addProperty("maxNumBackups", maxNumBackups()); 38 | config.addProperty("lastSaveFilePath", lastSaveFilePath()); 39 | 40 | firstTimeUse = true; 41 | save(); 42 | } 43 | } 44 | 45 | private Config() { 46 | } 47 | 48 | public static boolean isFirstTimeUse() { 49 | return firstTimeUse; 50 | } 51 | 52 | public static boolean adviseUpdates() { 53 | if (config.has("adviseUpdates")) 54 | return config.get("adviseUpdates").getAsBoolean(); 55 | 56 | return true; 57 | } 58 | 59 | public static void setAdviseUpdates(boolean adviseUpdates) { 60 | config.addProperty("adviseUpdates", adviseUpdates); 61 | } 62 | 63 | public static boolean showRegistersInHex() { 64 | if (config.has("showRegistersInHex")) 65 | return config.get("showRegistersInHex").getAsBoolean(); 66 | 67 | return true; 68 | } 69 | 70 | public static void setShowRegistersInHex(boolean showRegistersInHex) { 71 | config.addProperty("showRegistersInHex", showRegistersInHex); 72 | } 73 | 74 | public static boolean showDocs() { 75 | if (config.has("showDocs")) 76 | return config.get("showDocs").getAsBoolean(); 77 | 78 | return false; 79 | } 80 | 81 | public static void setShowDocs(boolean showDocs) { 82 | config.addProperty("showDocs", showDocs); 83 | } 84 | 85 | public static int maxNumBackups() { 86 | if (config.has("maxNumBackups")) 87 | return config.get("maxNumBackups").getAsInt(); 88 | 89 | return 30; 90 | } 91 | 92 | public static void setMaxNumBackups(int maxNumBackups) { 93 | config.addProperty("maxNumBackups", maxNumBackups); 94 | } 95 | 96 | public static String lastSaveFilePath() { 97 | if (config.has("lastSaveFilePath")) 98 | return config.get("lastSaveFilePath").getAsString(); 99 | 100 | return Paths.get(Sketches.SKETCHES_PATH, "untitled.s").toAbsolutePath().toString(); 101 | } 102 | 103 | public static void setLastSaveFilePath(String lastSaveFilePath) { 104 | try { 105 | String path = Paths.get(lastSaveFilePath).toAbsolutePath().toString(); 106 | config.addProperty("lastSaveFilePath", path); 107 | } catch (Exception e) { 108 | 109 | } 110 | } 111 | 112 | public static void save() { 113 | waitForSave(); 114 | 115 | Gson gson = new GsonBuilder().setPrettyPrinting().create(); 116 | String json = gson.toJson(config); 117 | 118 | saveTask = CompletableFuture.runAsync(() -> { 119 | try { 120 | Files.write(CONFIG_FILE.toPath(), json.getBytes()); 121 | } catch (IOException e) { 122 | CodeNodeMicrocontrollers.LOGGER.error("Failed to save config file", e); 123 | } 124 | saveTask = null; 125 | }); 126 | } 127 | 128 | public static void waitForSave() { 129 | if (saveTask != null) 130 | saveTask.join(); 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /src/main/java/com/elmfer/cnmcu/cpp/NativesLoader.java: -------------------------------------------------------------------------------- 1 | package com.elmfer.cnmcu.cpp; 2 | 3 | import com.elmfer.cnmcu.CodeNodeMicrocontrollers; 4 | 5 | public class NativesLoader { 6 | 7 | private NativesLoader() { 8 | } 9 | 10 | public static final String NATIVES_OS = getOS(); 11 | public static final String NATIVES_PLATFORM = getPlatform(); 12 | public static final String NATIVES_BITS = getBits(); 13 | public static final String NATIVES_EXT = getExtension(); 14 | public static final String EXE_EXT = NATIVES_OS.equals("windows") ? ".exe" : ""; 15 | public static final String BINARIES_PATH = CodeNodeMicrocontrollers.MOD_ID + "/natives/" + CodeNodeMicrocontrollers.MOD_VERSION; 16 | 17 | private static boolean loaded = false; 18 | 19 | public static void loadNatives() { 20 | if (loaded) 21 | return; 22 | 23 | CodeNodeMicrocontrollers.LOGGER.info("Loading native library..."); 24 | 25 | if (NATIVES_OS.equals("unknown") || NATIVES_PLATFORM.equals("unknown") || NATIVES_BITS.equals("unknown")) 26 | throw new RuntimeException("Unable to use " + CodeNodeMicrocontrollers.MOD_NAME + " on this platform!"); 27 | 28 | String libName = getBinaryFilename(); 29 | String workingDir = System.getProperty("user.dir") + "/"; 30 | String libPath = workingDir + BINARIES_PATH + "/" + libName; 31 | 32 | try { 33 | System.load(libPath); 34 | loaded = true; 35 | } catch (Exception e) { 36 | throw new RuntimeException("Failed to load native library: " + libPath, e); 37 | } 38 | } 39 | 40 | public static String getBinaryFilename() { 41 | return "lib" + CodeNodeMicrocontrollers.MOD_ID + "-" + NATIVES_OS + "-" + NATIVES_PLATFORM + NATIVES_BITS 42 | + NATIVES_EXT; 43 | } 44 | 45 | public static String getExecutableFilename(String name) { 46 | return name + "-" + NATIVES_OS + "-" + NATIVES_PLATFORM + NATIVES_BITS + EXE_EXT; 47 | } 48 | 49 | private static String getOS() { 50 | String os = System.getProperty("os.name").toLowerCase(); 51 | if (os.contains("win")) 52 | return "windows"; 53 | else if (os.contains("mac")) 54 | return "macos"; 55 | else if (os.contains("nix") || os.contains("nux")) 56 | return "linux"; 57 | 58 | return "unknown"; 59 | } 60 | 61 | private static String getPlatform() { 62 | String arch = System.getProperty("os.arch").toLowerCase(); 63 | 64 | if (arch.matches("arm") || arch.matches("aarch64")) 65 | return "arm"; 66 | else if (arch.matches("x86") || arch.matches("i386") || arch.matches("i686") || arch.matches("amd64") 67 | || arch.matches("x86_64")) 68 | return "x"; 69 | 70 | return "unknown"; 71 | } 72 | 73 | private static String getBits() { 74 | String arch = System.getProperty("os.arch").toLowerCase(); 75 | 76 | if (arch.matches("x86") || arch.matches("i386") || arch.matches("arm")) { 77 | if (NATIVES_PLATFORM.equals("x")) 78 | return "86"; 79 | return "32"; 80 | } else if (arch.matches("amd64") || arch.matches("x86_64") || arch.matches("aarch64")) 81 | return "64"; 82 | 83 | return "unknown"; 84 | } 85 | 86 | private static String getExtension() { 87 | if (NATIVES_OS.equals("windows")) 88 | return ".dll"; 89 | else if (NATIVES_OS.equals("macos")) 90 | return ".dylib"; 91 | 92 | return ".so"; 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /src/main/java/com/elmfer/cnmcu/cpp/NativesUtils.java: -------------------------------------------------------------------------------- 1 | package com.elmfer.cnmcu.cpp; 2 | 3 | import java.nio.ByteBuffer; 4 | 5 | public class NativesUtils { 6 | 7 | private NativesUtils() { 8 | } 9 | 10 | // @formatter:off 11 | 12 | public static native long getByteBufferAddress(ByteBuffer buffer); /* 13 | return (jlong) env->GetDirectBufferAddress(obj_buffer); 14 | */ 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/com/elmfer/cnmcu/cpp/StrongNativeObject.java: -------------------------------------------------------------------------------- 1 | package com.elmfer.cnmcu.cpp; 2 | 3 | import java.lang.reflect.Method; 4 | import java.util.ArrayList; 5 | import java.util.Map; 6 | import java.util.concurrent.ConcurrentHashMap; 7 | 8 | import com.elmfer.cnmcu.mcu.NanoMCU; 9 | 10 | /** 11 | * This class is used to store the native pointer of a native object. 12 | * It is used to track the native object's life cycle. Java code is 13 | * responsible for the life cycle of the native object. 14 | */ 15 | public class StrongNativeObject { 16 | 17 | private static final Map, Method[]> FINALIZERS = new ConcurrentHashMap<>(); 18 | 19 | static { 20 | FINALIZERS.put(NanoMCU.class, getFinalizers(NanoMCU.class)); 21 | } 22 | 23 | private long nativePtr = 0; 24 | 25 | protected StrongNativeObject() { 26 | } 27 | 28 | protected long getNativePtr() { 29 | return nativePtr; 30 | } 31 | 32 | protected void setNativePtr(long ptr) { 33 | nativePtr = ptr; 34 | } 35 | 36 | public void deleteNativeObject() { 37 | if (nativePtr == 0) { 38 | return; 39 | } 40 | 41 | Method[] finalizers = FINALIZERS.get(getClass()); 42 | 43 | if (finalizers == null) 44 | throw new RuntimeException("No finalizers found for class " + getClass().getName()); 45 | 46 | for (Method finalizer : finalizers) { 47 | try { 48 | finalizer.invoke(this); 49 | } catch (Exception e) { 50 | throw new RuntimeException(e); 51 | } 52 | } 53 | 54 | nativePtr = 0; 55 | } 56 | 57 | @Override 58 | public int hashCode() { 59 | return Long.hashCode(nativePtr); 60 | } 61 | 62 | @Override 63 | public boolean equals(Object obj) { 64 | if (obj instanceof StrongNativeObject) { 65 | StrongNativeObject other = (StrongNativeObject) obj; 66 | return nativePtr == other.nativePtr; 67 | } 68 | return false; 69 | } 70 | 71 | /** 72 | * Collect all the finalizer methods for a given class with the help of 73 | * reflection. 74 | */ 75 | private static Method[] getFinalizers(Class clazz) { 76 | ArrayList finalizers = new ArrayList<>(); 77 | for (Class c = clazz; c != StrongNativeObject.class; c = c.getSuperclass()) { 78 | try { 79 | Method finalizer = c.getDeclaredMethod("deleteNative"); 80 | finalizer.setAccessible(true); 81 | finalizers.add(finalizer); 82 | } catch (IllegalArgumentException | NoClassDefFoundError | SecurityException e) { 83 | throw new RuntimeException(e); 84 | } catch (NoSuchMethodException e) { 85 | } 86 | } 87 | 88 | int numFinalizers = finalizers.size(); 89 | Method[] finalizerArray = new Method[numFinalizers]; 90 | finalizers.toArray(finalizerArray); 91 | 92 | return finalizerArray; 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /src/main/java/com/elmfer/cnmcu/cpp/WeakNativeObject.java: -------------------------------------------------------------------------------- 1 | package com.elmfer.cnmcu.cpp; 2 | 3 | import java.lang.reflect.Method; 4 | import java.util.ArrayList; 5 | import java.util.Map; 6 | import java.util.concurrent.ConcurrentHashMap; 7 | 8 | /** 9 | * This class is used to store the native pointer of a native object. 10 | * It is used to track the native object's life cycle. Java code is 11 | * not responisble for the life cycle of the native object, therefore 12 | * it can only borrow the native object (if it is still valid). 13 | */ 14 | public class WeakNativeObject { 15 | 16 | private static final Map, Method[]> INVALIDATORS = new ConcurrentHashMap<>(); 17 | 18 | static { 19 | INVALIDATORS.put(WeakNativeObject.class, getInvalidators(WeakNativeObject.class)); 20 | } 21 | 22 | private long nativePtr = 0; 23 | 24 | protected WeakNativeObject() { 25 | } 26 | 27 | protected long getNativePtr() { 28 | return nativePtr; 29 | } 30 | 31 | protected void setNativePtr(long ptr) { 32 | nativePtr = ptr; 33 | } 34 | 35 | public void invalidateNativeObject() { 36 | nativePtr = 0; 37 | 38 | Method[] invalidators = INVALIDATORS.get(getClass()); 39 | 40 | if (invalidators == null) 41 | return; 42 | 43 | for (Method invalidator : invalidators) { 44 | try { 45 | invalidator.invoke(this); 46 | } catch (Exception e) { 47 | throw new RuntimeException(e); 48 | } 49 | } 50 | } 51 | 52 | /* 53 | * Check if the native object is still valid. 54 | */ 55 | public boolean isNativeObjectValid() { 56 | return nativePtr != 0; 57 | } 58 | 59 | @Override 60 | public int hashCode() { 61 | return Long.hashCode(nativePtr); 62 | } 63 | 64 | @Override 65 | public boolean equals(Object obj) { 66 | if (obj instanceof WeakNativeObject) { 67 | WeakNativeObject other = (WeakNativeObject) obj; 68 | return nativePtr == other.nativePtr; 69 | } 70 | return false; 71 | } 72 | 73 | /** 74 | * Collect all invalidators of the class and its super classes with the help of 75 | * reflection. 76 | */ 77 | private static Method[] getInvalidators(Class clazz) { 78 | ArrayList invalidators = new ArrayList<>(); 79 | for (Class c = clazz; c != WeakNativeObject.class; c = c.getSuperclass()) { 80 | try { 81 | Method invalidator = c.getDeclaredMethod("invalidateNative"); 82 | invalidator.setAccessible(true); 83 | invalidators.add(invalidator); 84 | } catch (IllegalArgumentException | NoClassDefFoundError | SecurityException e) { 85 | throw new RuntimeException(e); 86 | } catch (NoSuchMethodException e) { 87 | } 88 | } 89 | 90 | int numInvalidators = invalidators.size(); 91 | Method[] finalizers = new Method[numInvalidators]; 92 | invalidators.toArray(finalizers); 93 | 94 | return finalizers; 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /src/main/java/com/elmfer/cnmcu/mcu/Sketches.java: -------------------------------------------------------------------------------- 1 | package com.elmfer.cnmcu.mcu; 2 | 3 | import java.io.IOException; 4 | import java.nio.file.Files; 5 | import java.nio.file.Path; 6 | import java.nio.file.Paths; 7 | import java.text.SimpleDateFormat; 8 | import java.util.concurrent.CompletableFuture; 9 | 10 | import com.elmfer.cnmcu.CodeNodeMicrocontrollers; 11 | import com.elmfer.cnmcu.config.Config; 12 | import com.ibm.icu.util.Calendar; 13 | 14 | import imgui.ImGui; 15 | import imgui.extension.texteditor.TextEditor; 16 | 17 | public class Sketches { 18 | 19 | public static final String SKETCHES_PATH = CodeNodeMicrocontrollers.MOD_ID + "/sketches"; 20 | public static final String BACKUP_PATH = SKETCHES_PATH + "/backups"; 21 | 22 | private static CompletableFuture backupSaveTask; 23 | 24 | private static TextEditor filePreview = new TextEditor(); 25 | private static String[] backups = new String[0]; 26 | private static long[] backupTimes = new long[0]; 27 | 28 | static { 29 | filePreview.setShowWhitespaces(false); 30 | filePreview.setReadOnly(true); 31 | } 32 | 33 | public static void saveBackup(String code) { 34 | saveBackup(code, "s"); 35 | } 36 | 37 | public static void saveBackup(String code, String fileExtension) { 38 | if (backupSaveTask != null && !backupSaveTask.isDone()) 39 | backupSaveTask.join(); 40 | 41 | backupSaveTask = CompletableFuture.runAsync(() -> { 42 | Path path = Paths.get(BACKUP_PATH, getBackupFileName() + "." + fileExtension); 43 | 44 | try { 45 | deleteOldestBackup(); 46 | 47 | Files.write(path, code.getBytes()); 48 | } catch (Exception e) { 49 | e.printStackTrace(); 50 | } 51 | }); 52 | } 53 | 54 | public static String[] listBackups() { 55 | try { 56 | Path[] list = Files.list(Paths.get(BACKUP_PATH)).toArray(Path[]::new); 57 | 58 | backups = new String[list.length]; 59 | backupTimes = new long[list.length]; 60 | 61 | for (int i = 0; i < list.length; i++) { 62 | backups[i] = list[i].getFileName().toString(); 63 | backupTimes[i] = Files.getLastModifiedTime(list[i]).toMillis(); 64 | } 65 | 66 | // Sort backups by last modified time 67 | for (int i = 0; i < backups.length - 1; i++) { 68 | for (int j = i + 1; j < backups.length; j++) { 69 | if (backupTimes[i] < backupTimes[j]) { 70 | String tempBackup = backups[i]; 71 | backups[i] = backups[j]; 72 | backups[j] = tempBackup; 73 | 74 | long tempTime = backupTimes[i]; 75 | backupTimes[i] = backupTimes[j]; 76 | backupTimes[j] = tempTime; 77 | } 78 | } 79 | } 80 | 81 | return backups; 82 | } catch (IOException e) { 83 | e.printStackTrace(); 84 | } 85 | 86 | return backups; 87 | } 88 | 89 | private static int selectedBackup = -1; 90 | public static void genLoadBackupUI() { 91 | float windowWidth = ImGui.getWindowWidth(); 92 | 93 | ImGui.beginChild("##SketchBackups", windowWidth / 2, 0, false); 94 | 95 | ImGui.text("Latest Backups"); 96 | ImGui.separator(); 97 | 98 | ImGui.beginTable("##BackupsTable", 2); 99 | 100 | ImGui.tableSetupColumn("File Name", 0); 101 | ImGui.tableSetupColumn("From", 0); 102 | 103 | ImGui.tableHeadersRow(); 104 | 105 | for (int i = 0; i < backups.length; i++) { 106 | ImGui.tableNextRow(); 107 | 108 | ImGui.tableSetColumnIndex(0); 109 | if (ImGui.selectable(String.format("%02d %s", i + 1, backups[i]), selectedBackup == i)) { 110 | selectedBackup = i; 111 | filePreview.setText(loadBackup(backups[i])); 112 | } 113 | 114 | ImGui.tableSetColumnIndex(1); 115 | ImGui.text(formatTimeElapsed(backupTimes[i])); 116 | } 117 | 118 | ImGui.endTable(); 119 | 120 | ImGui.endChild(); 121 | 122 | ImGui.sameLine(); 123 | 124 | filePreview.render("SketchBackupPreview"); 125 | } 126 | 127 | public static String loadSketch(String path) { 128 | try { 129 | String code = Files.readString(Paths.get(path)); 130 | return code; 131 | } catch (IOException e) { 132 | e.printStackTrace(); 133 | } 134 | 135 | return ""; 136 | } 137 | 138 | public static void saveSketch(String code, String path) { 139 | try { 140 | Files.write(Paths.get(path), code.getBytes()); 141 | } catch (IOException e) { 142 | e.printStackTrace(); 143 | } 144 | } 145 | 146 | public static String loadBackup(String backupName) { 147 | try { 148 | return Files.readString(Paths.get(BACKUP_PATH, backupName)); 149 | } catch (IOException e) { 150 | e.printStackTrace(); 151 | } 152 | 153 | return ""; 154 | } 155 | 156 | public static String getSelectedBackup() { 157 | return filePreview.getText(); 158 | } 159 | 160 | private static String formatTimeElapsed(long lastTime) { 161 | long time = System.currentTimeMillis() - lastTime; 162 | long seconds = time / 1000; 163 | long minutes = seconds / 60; 164 | long hours = minutes / 60; 165 | long days = hours / 24; 166 | 167 | if (days > 0) 168 | return days + " days ago"; 169 | if (hours > 0) 170 | return hours + " hours ago"; 171 | if (minutes > 0) 172 | return minutes + " minutes ago"; 173 | if (seconds > 0) 174 | return seconds + " seconds ago"; 175 | 176 | return "Just now"; 177 | } 178 | 179 | private static String getBackupFileName() { 180 | return new SimpleDateFormat("yyyy-MM-dd_HH-mm-ss").format(Calendar.getInstance().getTime()); 181 | } 182 | 183 | private static void deleteOldestBackup() throws IOException { 184 | Path[] backups = Files.list(Paths.get(BACKUP_PATH)).toArray(Path[]::new); 185 | 186 | // If there are more than the maximum number of backups, delete the oldest one 187 | if (backups.length < Config.maxNumBackups()) 188 | return; 189 | 190 | Path oldest = backups[0]; 191 | long oldestTime = Files.getLastModifiedTime(oldest).toMillis(); 192 | 193 | for (Path backup : backups) { 194 | long time = Files.getLastModifiedTime(backup).toMillis(); 195 | 196 | if (time < oldestTime) { 197 | oldest = backup; 198 | oldestTime = time; 199 | } 200 | } 201 | 202 | Files.delete(oldest); 203 | } 204 | } 205 | -------------------------------------------------------------------------------- /src/main/java/com/elmfer/cnmcu/mcu/cpu/MOS6502.java: -------------------------------------------------------------------------------- 1 | package com.elmfer.cnmcu.mcu.cpu; 2 | 3 | import com.elmfer.cnmcu.cpp.WeakNativeObject; 4 | 5 | import net.minecraft.nbt.NbtCompound; 6 | 7 | /** 8 | * Reference to a MOS 6502 CPU object 9 | * it is a weak reference, so it will be invalidated if the native 10 | * object is deleted. 11 | */ 12 | public class MOS6502 extends WeakNativeObject { 13 | 14 | /** 15 | * Constructor 16 | * 17 | * Called in the mod's native code, do not call directly. 18 | */ 19 | protected MOS6502(long ptr) { 20 | setNativePtr(ptr); 21 | } 22 | 23 | public void NMI() { 24 | assert isNativeObjectValid(); 25 | 26 | NMI(getNativePtr()); 27 | } 28 | 29 | public void IRQ() { 30 | assert isNativeObjectValid(); 31 | 32 | IRQ(getNativePtr()); 33 | } 34 | 35 | public void Reset() { 36 | assert isNativeObjectValid(); 37 | 38 | Reset(getNativePtr()); 39 | } 40 | 41 | public int getPC() { 42 | assert isNativeObjectValid(); 43 | 44 | return GetPC(getNativePtr()); 45 | } 46 | 47 | public int getS() { 48 | assert isNativeObjectValid(); 49 | 50 | return GetS(getNativePtr()); 51 | } 52 | 53 | public int getP() { 54 | assert isNativeObjectValid(); 55 | 56 | return GetP(getNativePtr()); 57 | } 58 | 59 | public int getA() { 60 | assert isNativeObjectValid(); 61 | 62 | return GetA(getNativePtr()); 63 | } 64 | 65 | public int getX() { 66 | assert isNativeObjectValid(); 67 | 68 | return GetX(getNativePtr()); 69 | } 70 | 71 | public int getY() { 72 | assert isNativeObjectValid(); 73 | 74 | return GetY(getNativePtr()); 75 | } 76 | 77 | public void writeNbt(NbtCompound nbt) { 78 | assert isNativeObjectValid(); 79 | 80 | NbtCompound cpuNbt = new NbtCompound(); 81 | cpuNbt.putInt("pc", getPC()); 82 | cpuNbt.putInt("s", getS()); 83 | cpuNbt.putInt("p", getP()); 84 | cpuNbt.putInt("a", getA()); 85 | cpuNbt.putInt("x", getX()); 86 | cpuNbt.putInt("y", getY()); 87 | 88 | nbt.put("mos6502", cpuNbt); 89 | } 90 | 91 | public void readNbt(NbtCompound nbt) { 92 | assert isNativeObjectValid(); 93 | 94 | NbtCompound state = nbt.getCompound("mos6502"); 95 | int[] stateArray = new int[] { state.getInt("pc"), state.getInt("s"), state.getInt("p"), state.getInt("a"), 96 | state.getInt("x"), state.getInt("y") }; 97 | 98 | SetState(getNativePtr(), stateArray); 99 | } 100 | 101 | // @formatter:off 102 | 103 | /*JNI 104 | #include "mos6502.h" 105 | */ 106 | 107 | private static native void NMI(long ptr); /* 108 | mos6502* cpu = reinterpret_cast(ptr); 109 | cpu->NMI(); 110 | */ 111 | 112 | private static native void IRQ(long ptr);/* 113 | mos6502* cpu = reinterpret_cast(ptr); 114 | cpu->IRQ(); 115 | */ 116 | 117 | private static native void Reset(long ptr); /* 118 | mos6502* cpu = reinterpret_cast(ptr); 119 | cpu->Reset(); 120 | */ 121 | 122 | private static native int GetPC(long ptr); /* 123 | mos6502* cpu = reinterpret_cast(ptr); 124 | return static_cast(cpu->GetPC()); 125 | */ 126 | 127 | private static native int GetS(long ptr); /* 128 | mos6502* cpu = reinterpret_cast(ptr); 129 | return static_cast(cpu->GetS()); 130 | */ 131 | 132 | private static native int GetP(long ptr); /* 133 | mos6502* cpu = reinterpret_cast(ptr); 134 | return static_cast(cpu->GetP()); 135 | */ 136 | 137 | private static native int GetA(long ptr);/* 138 | mos6502* cpu = reinterpret_cast(ptr); 139 | return static_cast(cpu->GetA()); 140 | */ 141 | 142 | private static native int GetX(long ptr); /* 143 | mos6502* cpu = reinterpret_cast(ptr); 144 | return static_cast(cpu->GetX()); 145 | */ 146 | 147 | private static native int GetY(long ptr); /* 148 | mos6502* cpu = reinterpret_cast(ptr); 149 | return static_cast(cpu->GetY()); 150 | */ 151 | 152 | private static native void SetState(long ptr, int state[]); /* 153 | mos6502* cpu = reinterpret_cast(ptr); 154 | cpu->SetState(state); 155 | */ 156 | } 157 | -------------------------------------------------------------------------------- /src/main/java/com/elmfer/cnmcu/mcu/modules/CNEL.java: -------------------------------------------------------------------------------- 1 | package com.elmfer.cnmcu.mcu.modules; 2 | 3 | import java.nio.ByteBuffer; 4 | 5 | import com.elmfer.cnmcu.cpp.WeakNativeObject; 6 | 7 | import net.minecraft.nbt.NbtCompound; 8 | 9 | /** 10 | * Reference to a CNEL object 11 | * 12 | * it is a weak reference, so it will be invalidated if the native 13 | * object is deleted. 14 | */ 15 | public class CNEL extends WeakNativeObject { 16 | 17 | public static enum EventType { 18 | GAME_TICK(0); 19 | 20 | private final int value; 21 | 22 | private EventType(int value) { 23 | this.value = value; 24 | } 25 | 26 | public int getValue() { 27 | return value; 28 | } 29 | } 30 | 31 | private final long size; 32 | 33 | /** 34 | * Constructor 35 | * 36 | * Called in the mod's native code, do not call directly. 37 | */ 38 | protected CNEL(long ptr) { 39 | setNativePtr(ptr); 40 | 41 | size = size(getNativePtr()); 42 | } 43 | 44 | public long getSize() { 45 | assert isNativeObjectValid(); 46 | 47 | return size; 48 | } 49 | 50 | public ByteBuffer getICLRegistersData() { 51 | assert isNativeObjectValid(); 52 | 53 | return iclRegistersData(getNativePtr()); 54 | } 55 | 56 | public ByteBuffer getIFLRegistersData() { 57 | assert isNativeObjectValid(); 58 | 59 | return iflRegistersData(getNativePtr()); 60 | } 61 | 62 | public void triggerEvent(EventType event) { 63 | assert isNativeObjectValid(); 64 | 65 | triggerEvent(getNativePtr(), event.value); 66 | } 67 | 68 | public boolean shouldInterrupt() { 69 | assert isNativeObjectValid(); 70 | 71 | return shouldInterrupt(getNativePtr()); 72 | } 73 | 74 | public int read(int address) { 75 | assert isNativeObjectValid(); 76 | 77 | return read(address); 78 | } 79 | 80 | public void write(int address, int data) { 81 | assert isNativeObjectValid(); 82 | 83 | write(address, data); 84 | } 85 | 86 | public void writeNbt(NbtCompound nbt) { 87 | assert isNativeObjectValid(); 88 | 89 | NbtCompound elNbt = new NbtCompound(); 90 | 91 | ByteBuffer iclRegistersData = getICLRegistersData(); 92 | ByteBuffer iflRegistersData = getIFLRegistersData(); 93 | 94 | byte[] iclData = new byte[iclRegistersData.remaining()]; 95 | byte[] iflData = new byte[iflRegistersData.remaining()]; 96 | 97 | iclRegistersData.get(iclData); 98 | iflRegistersData.get(iflData); 99 | 100 | elNbt.putByteArray("iclRegistersData", iclData); 101 | elNbt.putByteArray("iflRegistersData", iflData); 102 | 103 | nbt.put("el", elNbt); 104 | } 105 | 106 | public void readNbt(NbtCompound nbt) { 107 | assert isNativeObjectValid(); 108 | 109 | NbtCompound elNbt = nbt.getCompound("el"); 110 | 111 | ByteBuffer iclRegistersData = getICLRegistersData(); 112 | ByteBuffer iflRegistersData = getIFLRegistersData(); 113 | 114 | byte[] iclData = elNbt.getByteArray("iclRegistersData"); 115 | byte[] iflData = elNbt.getByteArray("iflRegistersData"); 116 | 117 | iclRegistersData.put(iclData); 118 | iflRegistersData.put(iflData); 119 | } 120 | 121 | // @formatter:off 122 | 123 | /*JNI 124 | #include "cnmcuJava.h" 125 | #include "Nano.hpp" 126 | */ 127 | 128 | private static native long size(long ptr); /* 129 | CNEL* cnel = reinterpret_cast*>(ptr); 130 | return cnel->size(); 131 | */ 132 | 133 | private static native ByteBuffer iclRegistersData(long ptr); /* 134 | CNEL* cnel = reinterpret_cast*>(ptr); 135 | return env->NewDirectByteBuffer(cnel->iclRegistersData(), CodeNodeNano::EL_SIZE); 136 | */ 137 | 138 | private static native ByteBuffer iflRegistersData(long ptr); /* 139 | CNEL* cnel = reinterpret_cast*>(ptr); 140 | return env->NewDirectByteBuffer(cnel->iflRegistersData(), CodeNodeNano::EL_SIZE); 141 | */ 142 | 143 | private static native void triggerEvent(long ptr, int event); /* 144 | CNEL* cnel = reinterpret_cast*>(ptr); 145 | cnel->triggerEvent(event); 146 | */ 147 | 148 | private static native boolean shouldInterrupt(long ptr); /* 149 | CNEL* cnel = reinterpret_cast*>(ptr); 150 | return cnel->shouldInterrupt(); 151 | */ 152 | 153 | private static native int read(long ptr, int address); /* 154 | CNEL* cnel = reinterpret_cast*>(ptr); 155 | return static_cast(cnel->read(address)); 156 | */ 157 | 158 | private static native void write(long ptr, int address, int data); /* 159 | CNEL* cnel = reinterpret_cast*>(ptr); 160 | uint16_t addr = static_cast(address); 161 | uint8_t dat = static_cast(data); 162 | cnel->write(addr, dat); 163 | */ 164 | } 165 | -------------------------------------------------------------------------------- /src/main/java/com/elmfer/cnmcu/mcu/modules/CNGPIO.java: -------------------------------------------------------------------------------- 1 | package com.elmfer.cnmcu.mcu.modules; 2 | 3 | import java.nio.ByteBuffer; 4 | 5 | import com.elmfer.cnmcu.cpp.WeakNativeObject; 6 | 7 | import net.minecraft.nbt.NbtCompound; 8 | 9 | /** 10 | * Reference to a CNGPIO object 11 | * 12 | * it is a weak reference, so it will be invalidated if the native 13 | * object is deleted. 14 | */ 15 | public class CNGPIO extends WeakNativeObject { 16 | 17 | private final long size; 18 | 19 | /** 20 | * Constructor 21 | * 22 | * Called in the mod's native code, do not call directly. 23 | */ 24 | protected CNGPIO(long ptr) { 25 | setNativePtr(ptr); 26 | 27 | size = size(getNativePtr()); 28 | } 29 | 30 | public long getSize() { 31 | assert isNativeObjectValid(); 32 | 33 | return size; 34 | } 35 | 36 | public ByteBuffer getPVFrontData() { 37 | assert isNativeObjectValid(); 38 | 39 | return pvFrontData(getNativePtr()); 40 | } 41 | 42 | public ByteBuffer getPVBackData() { 43 | assert isNativeObjectValid(); 44 | 45 | return pvBackData(getNativePtr()); 46 | } 47 | 48 | public ByteBuffer getDirData() { 49 | assert isNativeObjectValid(); 50 | 51 | return dirData(getNativePtr()); 52 | } 53 | 54 | public ByteBuffer getIntData() { 55 | assert isNativeObjectValid(); 56 | 57 | return intData(getNativePtr()); 58 | } 59 | 60 | public ByteBuffer getIFLData() { 61 | assert isNativeObjectValid(); 62 | 63 | return iflData(getNativePtr()); 64 | } 65 | 66 | public int read(int address) { 67 | assert isNativeObjectValid(); 68 | 69 | return read(getNativePtr(), address); 70 | } 71 | 72 | public void write(int address, int value) { 73 | assert isNativeObjectValid(); 74 | 75 | write(getNativePtr(), address, value); 76 | } 77 | 78 | public boolean shouldInterrupt() { 79 | assert isNativeObjectValid(); 80 | 81 | return shouldInterrupt(getNativePtr()); 82 | } 83 | 84 | public void writeNbt(NbtCompound nbt) { 85 | assert isNativeObjectValid(); 86 | 87 | NbtCompound gpioNbt = new NbtCompound(); 88 | 89 | ByteBuffer buffer = getPVFrontData(); 90 | byte[] pvFrontData = new byte[buffer.remaining()]; 91 | buffer.get(pvFrontData); 92 | gpioNbt.putByteArray("pvFrontData", pvFrontData); 93 | 94 | buffer = getPVBackData(); 95 | byte[] pvBackData = new byte[buffer.remaining()]; 96 | buffer.get(pvBackData); 97 | gpioNbt.putByteArray("pvBackData", pvBackData); 98 | 99 | buffer = getDirData(); 100 | byte[] dirData = new byte[buffer.remaining()]; 101 | buffer.get(dirData); 102 | gpioNbt.putByteArray("dirData", dirData); 103 | 104 | buffer = getIntData(); 105 | byte[] intData = new byte[buffer.remaining()]; 106 | buffer.get(intData); 107 | gpioNbt.putByteArray("intData", intData); 108 | 109 | buffer = getIFLData(); 110 | byte[] iflData = new byte[buffer.remaining()]; 111 | buffer.get(iflData); 112 | gpioNbt.putByteArray("iflData", iflData); 113 | 114 | nbt.put("gpio", gpioNbt); 115 | } 116 | 117 | public void readNbt(NbtCompound nbt) { 118 | assert isNativeObjectValid(); 119 | 120 | NbtCompound gpioNbt = nbt.getCompound("gpio"); 121 | 122 | ByteBuffer buffer = getPVFrontData(); 123 | byte[] pvFrontData = gpioNbt.getByteArray("pvFrontData"); 124 | buffer.put(pvFrontData); 125 | 126 | buffer = getPVBackData(); 127 | byte[] pvBackData = gpioNbt.getByteArray("pvBackData"); 128 | buffer.put(pvBackData); 129 | 130 | buffer = getDirData(); 131 | byte[] dirData = gpioNbt.getByteArray("dirData"); 132 | buffer.put(dirData); 133 | 134 | buffer = getIntData(); 135 | byte[] intData = gpioNbt.getByteArray("intData"); 136 | buffer.put(intData); 137 | 138 | buffer = getIFLData(); 139 | byte[] iflData = gpioNbt.getByteArray("iflData"); 140 | buffer.put(iflData); 141 | } 142 | 143 | // @formatter:off 144 | 145 | /*JNI 146 | #include "cnmcuJava.h" 147 | #include "Nano.hpp" 148 | */ 149 | 150 | private static native long size(long ptr); /* 151 | CNGPIO* gpio = reinterpret_cast*>(ptr); 152 | return static_cast(gpio->size()); 153 | */ 154 | 155 | private static native ByteBuffer pvFrontData(long ptr); /* 156 | CNGPIO* gpio = reinterpret_cast*>(ptr); 157 | return env->NewDirectByteBuffer(gpio->pvFrontData(), CodeNodeNano::GPIO_NUM_PINS); 158 | */ 159 | 160 | private static native ByteBuffer pvBackData(long ptr); /* 161 | CNGPIO* gpio = reinterpret_cast*>(ptr); 162 | return env->NewDirectByteBuffer(gpio->pvBackData(), CodeNodeNano::GPIO_NUM_PINS); 163 | */ 164 | 165 | private static native ByteBuffer dirData(long ptr); /* 166 | CNGPIO* gpio = reinterpret_cast*>(ptr); 167 | return env->NewDirectByteBuffer(gpio->dirData(), CodeNodeNano::GPIO_NUM_PINS / 8); 168 | */ 169 | 170 | private static native ByteBuffer intData(long ptr); /* 171 | CNGPIO* gpio = reinterpret_cast*>(ptr); 172 | return env->NewDirectByteBuffer(gpio->intData(), CodeNodeNano::GPIO_NUM_PINS / 2); 173 | */ 174 | 175 | private static native ByteBuffer iflData(long ptr); /* 176 | CNGPIO* gpio = reinterpret_cast*>(ptr); 177 | return env->NewDirectByteBuffer(gpio->iflData(), CodeNodeNano::GPIO_NUM_PINS / 8); 178 | */ 179 | 180 | private static native int read(long ptr, int address); /* 181 | CNGPIO* gpio = reinterpret_cast*>(ptr); 182 | uint16_t addr = static_cast(address); 183 | uint8_t val = gpio->read(address); 184 | return static_cast(val); 185 | */ 186 | 187 | private static native void write(long ptr, int address, int value); /* 188 | CNGPIO* gpio = reinterpret_cast*>(ptr); 189 | uint16_t addr = static_cast(address); 190 | uint8_t val = static_cast(value); 191 | gpio->write(addr, val); 192 | */ 193 | 194 | private static native boolean shouldInterrupt(long ptr); /* 195 | CNGPIO* gpio = reinterpret_cast*>(ptr); 196 | return static_cast(gpio->shouldInterrupt()); 197 | */ 198 | } 199 | -------------------------------------------------------------------------------- /src/main/java/com/elmfer/cnmcu/mcu/modules/CNRAM.java: -------------------------------------------------------------------------------- 1 | package com.elmfer.cnmcu.mcu.modules; 2 | 3 | import java.nio.ByteBuffer; 4 | 5 | import com.elmfer.cnmcu.cpp.WeakNativeObject; 6 | 7 | import net.minecraft.nbt.NbtCompound; 8 | 9 | /** 10 | * Reference to a CNRAM object 11 | * it is a weak reference, so it will be invalidated if the native 12 | * object is deleted. 13 | */ 14 | public class CNRAM extends WeakNativeObject { 15 | 16 | private final long size; 17 | 18 | /** 19 | * Constructor 20 | * 21 | * Called in the mod's native code, do not call directly. 22 | */ 23 | protected CNRAM(long ptr) { 24 | setNativePtr(ptr); 25 | 26 | size = size(getNativePtr()); 27 | } 28 | 29 | public long getSize() { 30 | assert isNativeObjectValid(); 31 | 32 | return size; 33 | } 34 | 35 | public ByteBuffer getData() { 36 | assert isNativeObjectValid(); 37 | 38 | return data(getNativePtr()); 39 | } 40 | 41 | public byte read(int address) { 42 | assert isNativeObjectValid(); 43 | 44 | return read(getNativePtr(), address); 45 | } 46 | 47 | public void write(int address, byte value) { 48 | assert isNativeObjectValid(); 49 | 50 | write(getNativePtr(), address, value); 51 | } 52 | 53 | public void writeNbt(NbtCompound nbt) { 54 | assert isNativeObjectValid(); 55 | 56 | NbtCompound ramNbt = new NbtCompound(); 57 | 58 | ByteBuffer buffer = getData(); 59 | byte[] data = new byte[buffer.remaining()]; 60 | buffer.get(data); 61 | ramNbt.putByteArray("data", data); 62 | 63 | nbt.put("ram", ramNbt); 64 | } 65 | 66 | public void readNbt(NbtCompound nbt) { 67 | assert isNativeObjectValid(); 68 | 69 | NbtCompound ramNbt = nbt.getCompound("ram"); 70 | 71 | ByteBuffer buffer = getData(); 72 | byte[] data = ramNbt.getByteArray("data"); 73 | buffer.put(data); 74 | } 75 | 76 | // @formatter:off 77 | 78 | /*JNI 79 | #include "cnmcuJava.h" 80 | #include "Nano.hpp" 81 | */ 82 | 83 | private static native long size(long ptr); /* 84 | return static_cast(CodeNodeNano::RAM_SIZE); 85 | */ 86 | 87 | private static native ByteBuffer data(long ptr); /* 88 | CNRAM* ram = reinterpret_cast*>(ptr); 89 | return env->NewDirectByteBuffer(ram->data(), CodeNodeNano::RAM_SIZE); 90 | */ 91 | 92 | private static native byte read(long ptr, int address); /* 93 | CNRAM* ram = reinterpret_cast*>(ptr); 94 | uint16_t addr = static_cast(address); 95 | return static_cast(ram->read(addr)); 96 | */ 97 | 98 | private static native void write(long ptr, int address, byte value); /* 99 | CNRAM* ram = reinterpret_cast*>(ptr); 100 | uint16_t addr = static_cast(address); 101 | uint8_t val = static_cast(value); 102 | ram->write(addr, val); 103 | */ 104 | } 105 | -------------------------------------------------------------------------------- /src/main/java/com/elmfer/cnmcu/mcu/modules/CNROM.java: -------------------------------------------------------------------------------- 1 | package com.elmfer.cnmcu.mcu.modules; 2 | 3 | import java.nio.ByteBuffer; 4 | 5 | import com.elmfer.cnmcu.cpp.WeakNativeObject; 6 | 7 | import net.minecraft.nbt.NbtCompound; 8 | 9 | /** 10 | * Reference to a CNROM object it is a weak reference, so it will be invalidated 11 | * if the native object is deleted. 12 | */ 13 | public class CNROM extends WeakNativeObject { 14 | private final long size; 15 | 16 | private boolean writeProtected; 17 | 18 | /** 19 | * Constructor 20 | * 21 | * Called in the mod's native code, do not call directly. 22 | */ 23 | protected CNROM(long ptr) { 24 | setNativePtr(ptr); 25 | 26 | size = size(getNativePtr()); 27 | writeProtected = isWriteProtected(getNativePtr()); 28 | } 29 | 30 | public long getSize() { 31 | assert isNativeObjectValid(); 32 | 33 | return size; 34 | } 35 | 36 | public ByteBuffer getData() { 37 | assert isNativeObjectValid(); 38 | 39 | return data(getNativePtr()); 40 | } 41 | 42 | public byte read(int address) { 43 | assert isNativeObjectValid(); 44 | 45 | return read(getNativePtr(), address); 46 | } 47 | 48 | public void write(int address, byte value) { 49 | assert isNativeObjectValid(); 50 | 51 | write(getNativePtr(), address, value); 52 | } 53 | 54 | public void setWriteProtected(boolean writeProtected) { 55 | assert isNativeObjectValid(); 56 | 57 | setWriteProtected(getNativePtr(), writeProtected); 58 | this.writeProtected = writeProtected; 59 | } 60 | 61 | public boolean isWriteProtected() { 62 | assert isNativeObjectValid(); 63 | 64 | return writeProtected; 65 | } 66 | 67 | public void writeNbt(NbtCompound nbt) { 68 | assert isNativeObjectValid(); 69 | 70 | NbtCompound romNbt = new NbtCompound(); 71 | ByteBuffer data = getData(); 72 | byte[] bytes = new byte[data.remaining()]; 73 | data.get(bytes); 74 | romNbt.putByteArray("data", bytes); 75 | romNbt.putBoolean("writeProtected", isWriteProtected()); 76 | 77 | nbt.put("rom", romNbt); 78 | } 79 | 80 | public void readNbt(NbtCompound nbt) { 81 | assert isNativeObjectValid(); 82 | 83 | NbtCompound romNbt = nbt.getCompound("rom"); 84 | byte[] bytes = romNbt.getByteArray("data"); 85 | ByteBuffer data = getData(); 86 | data.put(bytes); 87 | setWriteProtected(romNbt.getBoolean("writeProtected")); 88 | } 89 | 90 | // @formatter:off 91 | 92 | /*JNI 93 | #include "cnmcuJava.h" 94 | #include "Nano.hpp" 95 | */ 96 | 97 | private static native long size(long ptr); /* 98 | return static_cast(CodeNodeNano::ROM_SIZE); 99 | */ 100 | 101 | private static native ByteBuffer data(long ptr); /* 102 | CNROM* rom = reinterpret_cast*>(ptr); 103 | return env->NewDirectByteBuffer(rom->data(), CodeNodeNano::ROM_SIZE); 104 | */ 105 | 106 | private static native byte read(long ptr, int address); /* 107 | CNROM* rom = reinterpret_cast*>(ptr); 108 | uint16_t addr = static_cast(address); 109 | return static_cast(rom->read(addr)); 110 | */ 111 | 112 | private static native void write(long ptr, int address, byte value); /* 113 | CNROM* rom = reinterpret_cast*>(ptr); 114 | uint16_t addr = static_cast(address); 115 | uint8_t val = static_cast(value); 116 | rom->write(addr, val); 117 | */ 118 | 119 | private static native boolean isWriteProtected(long ptr); /* 120 | CNROM* rom = reinterpret_cast*>(ptr); 121 | return static_cast(rom->isWriteProtected()); 122 | */ 123 | private static native void setWriteProtected(long ptr, boolean writeProtected); /* 124 | CNROM* rom = reinterpret_cast*>(ptr); 125 | rom->setWriteProtect(static_cast(writeProtected)); 126 | */ 127 | } 128 | -------------------------------------------------------------------------------- /src/main/java/com/elmfer/cnmcu/mcu/modules/CNUART.java: -------------------------------------------------------------------------------- 1 | package com.elmfer.cnmcu.mcu.modules; 2 | 3 | import java.nio.ByteBuffer; 4 | 5 | import com.elmfer.cnmcu.cpp.WeakNativeObject; 6 | 7 | import net.minecraft.nbt.NbtCompound; 8 | 9 | /* 10 | * Reference to a CNUART object 11 | * 12 | * it is a weak reference, so it will be invalidated if the native 13 | * object is deleted. 14 | */ 15 | public class CNUART extends WeakNativeObject { 16 | 17 | private final long size; 18 | 19 | /** 20 | * Constructor 21 | * 22 | * Called in the mod's native code, do not call directly. 23 | */ 24 | protected CNUART(long ptr) { 25 | setNativePtr(ptr); 26 | 27 | size = size(getNativePtr()); 28 | } 29 | 30 | public long getSize() { 31 | assert isNativeObjectValid(); 32 | 33 | return size; 34 | } 35 | 36 | public void reset() { 37 | assert isNativeObjectValid(); 38 | 39 | reset(getNativePtr()); 40 | } 41 | 42 | public boolean shouldInterrupt() { 43 | assert isNativeObjectValid(); 44 | 45 | return shouldInterrupt(getNativePtr()); 46 | } 47 | 48 | public ByteBuffer getRegisterData() { 49 | assert isNativeObjectValid(); 50 | 51 | return registerData(getNativePtr()); 52 | } 53 | 54 | public void write(int address, int data) { 55 | assert isNativeObjectValid(); 56 | 57 | write(getNativePtr(), address, data); 58 | } 59 | 60 | public int read(int address) { 61 | assert isNativeObjectValid(); 62 | 63 | return read(getNativePtr(), address); 64 | } 65 | 66 | public void writeNbt(NbtCompound nbt) { 67 | assert isNativeObjectValid(); 68 | 69 | NbtCompound uartNbt = new NbtCompound(); 70 | 71 | ByteBuffer registerData = getRegisterData(); 72 | byte[] data = new byte[registerData.remaining()]; 73 | registerData.get(data); 74 | uartNbt.putByteArray("registerData", data); 75 | 76 | nbt.put("uart", uartNbt); 77 | } 78 | 79 | public void readNbt(NbtCompound nbt) { 80 | assert isNativeObjectValid(); 81 | 82 | NbtCompound uartNbt = nbt.getCompound("uart"); 83 | 84 | byte[] data = uartNbt.getByteArray("registerData"); 85 | ByteBuffer registerData = getRegisterData(); 86 | registerData.put(data); 87 | } 88 | 89 | // @formatter:off 90 | 91 | /*JNI 92 | #include "cnmcuJava.h" 93 | #include "Nano.hpp" 94 | */ 95 | 96 | private static native long size(long ptr); /* 97 | CNUART* uart = reinterpret_cast(ptr); 98 | return uart->size(); 99 | */ 100 | 101 | private static native void reset(long ptr); /* 102 | CNUART* uart = reinterpret_cast(ptr); 103 | uart->reset(); 104 | */ 105 | 106 | private static native boolean shouldInterrupt(long ptr); /* 107 | CNUART* uart = reinterpret_cast(ptr); 108 | return uart->shouldInterrupt(); 109 | */ 110 | 111 | private static native ByteBuffer registerData(long ptr); /* 112 | CNUART* uart = reinterpret_cast(ptr); 113 | return env->NewDirectByteBuffer(uart->registerData(), uart->size()); 114 | */ 115 | 116 | private static native void write(long ptr, int address, int data); /* 117 | CNUART* uart = reinterpret_cast(ptr); 118 | uint16_t addr = address; 119 | uint16_t dat = data; 120 | uart->write(addr, dat); 121 | */ 122 | 123 | private static native int read(long ptr, int address); /* 124 | CNUART* uart = reinterpret_cast(ptr); 125 | uint16_t addr = address; 126 | return static_cast(uart->read(addr)); 127 | */ 128 | } 129 | -------------------------------------------------------------------------------- /src/main/java/com/elmfer/cnmcu/mesh/Meshes.java: -------------------------------------------------------------------------------- 1 | package com.elmfer.cnmcu.mesh; 2 | 3 | import java.io.InputStream; 4 | import java.nio.ByteBuffer; 5 | import java.util.ArrayList; 6 | import java.util.HashMap; 7 | import java.util.Map; 8 | import java.util.Optional; 9 | 10 | import com.elmfer.cnmcu.CodeNodeMicrocontrollersClient; 11 | 12 | import net.minecraft.client.MinecraftClient; 13 | import net.minecraft.util.Identifier; 14 | 15 | public class Meshes { 16 | 17 | private static final Map meshes = new HashMap(); 18 | 19 | private static final int POSITION_COMPONENTS = 3; 20 | private static final int NORMAL_COMPONENTS = 3; 21 | private static final int COLOR_COMPONENTS = 4; 22 | private static final int UV_COMPONENTS = 2; 23 | private static final int FACE_INDICIES = 4; 24 | 25 | public static Mesh get(String name) { 26 | return meshes.get(name); 27 | } 28 | 29 | public static boolean hasMesh(String name) { 30 | return meshes.containsKey(name); 31 | } 32 | 33 | public static Mesh load(Identifier model) { 34 | try { 35 | // Load the model file 36 | InputStream modelStream = MinecraftClient.getInstance().getResourceManager().getResource(model).get().getInputStream(); 37 | byte[] modelData = modelStream.readAllBytes(); 38 | modelStream.close(); 39 | 40 | // Get the model name from the path 41 | String[] modelPath = model.getPath().split("/"); 42 | String modelName = modelPath[modelPath.length - 1].replace(".ply", ""); 43 | 44 | Mesh mesh = new Mesh(modelName); 45 | 46 | // Parse the PLY file 47 | parsePLY(modelData, mesh); 48 | 49 | meshes.put(modelName, mesh); 50 | return mesh; 51 | } catch (Exception e) { 52 | CodeNodeMicrocontrollersClient.LOGGER.error("Failed to load mesh: " + model, e); 53 | e.printStackTrace(); 54 | } 55 | 56 | return null; 57 | } 58 | 59 | public static Mesh meshFromBuilder(MeshBuilder builder) { 60 | if (builder.getVertexFormat() != VertexFormat.POS_UV_COLOR_NORM) 61 | throw new IllegalArgumentException("MeshBuilder must have a VertexFormat of POS_UV_COLOR_NORMAL"); 62 | 63 | Mesh mesh = new Mesh(""); 64 | 65 | ByteBuffer buffer = builder.getVertexData(); 66 | int vertexCount = builder.getVertexCount(); 67 | 68 | mesh.positions.ensureCapacity(vertexCount * POSITION_COMPONENTS); 69 | mesh.uvs = Optional.of(new ArrayList()); 70 | mesh.uvs.get().ensureCapacity(vertexCount * UV_COMPONENTS); 71 | mesh.normals.ensureCapacity(vertexCount * NORMAL_COMPONENTS); 72 | mesh.colors = Optional.of(new ArrayList()); 73 | mesh.colors.get().ensureCapacity(vertexCount * COLOR_COMPONENTS); 74 | 75 | for (int i = 0; i < vertexCount; i++) { 76 | mesh.positions.add(buffer.getFloat()); // pos x 77 | mesh.positions.add(buffer.getFloat()); // pos y 78 | mesh.positions.add(buffer.getFloat()); // pos z 79 | mesh.uvs.get().add(buffer.getFloat()); // tex s 80 | mesh.uvs.get().add(buffer.getFloat()); // tex t 81 | mesh.colors.get().add((buffer.get() & 0xFF) / 255.0f); // color r 82 | mesh.colors.get().add((buffer.get() & 0xFF) / 255.0f); // color g 83 | mesh.colors.get().add((buffer.get() & 0xFF) / 255.0f); // color b 84 | mesh.colors.get().add((buffer.get() & 0xFF) / 255.0f); // color a 85 | mesh.normals.add(buffer.getFloat()); // norm x 86 | mesh.normals.add(buffer.getFloat()); // norm y 87 | mesh.normals.add(buffer.getFloat()); // norm z 88 | } 89 | 90 | mesh.indices.ensureCapacity(builder.getIndexCount()); 91 | buffer = builder.getIndexData(); 92 | 93 | while (buffer.hasRemaining()) 94 | mesh.indices.add(buffer.getInt()); 95 | 96 | return mesh; 97 | } 98 | 99 | // @formatter:off 100 | 101 | /*JNI 102 | #include "MeshLoader.hpp" 103 | #include "cnmcuJava.h" 104 | #include 105 | */ 106 | 107 | private static native void parsePLY(byte[] data, Mesh mesh); /* 108 | cnmcuJava::init(env); 109 | size_t dataSize = static_cast(env->GetArrayLength(obj_data)); 110 | try { 111 | MeshLoader::loadPLY(env, data, dataSize, mesh); 112 | } catch (const std::exception& e) { 113 | env->ThrowNew(cnmcuJava::IllegalArgumentException, e.what()); 114 | } 115 | */ 116 | } -------------------------------------------------------------------------------- /src/main/java/com/elmfer/cnmcu/mesh/VertexFormat.java: -------------------------------------------------------------------------------- 1 | package com.elmfer.cnmcu.mesh; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | import org.lwjgl.opengl.GL11; 7 | import org.lwjgl.opengl.GL20; 8 | 9 | public final class VertexFormat { 10 | public static final VertexFormat POS = new VertexFormat(); 11 | public static final VertexFormat POS_UV = new VertexFormat(); 12 | public static final VertexFormat POS_COLOR = new VertexFormat(); 13 | public static final VertexFormat POS_UV_COLOR = new VertexFormat(); 14 | public static final VertexFormat POS_UV_COLOR_TEXID = new VertexFormat(); 15 | public static final VertexFormat POS_UV_COLOR_NORM = new VertexFormat(); 16 | 17 | static { 18 | POS.addAttrib(AttribUsage.POSITION, AttribType.FLOAT, 3); 19 | 20 | POS_UV.addAttrib(AttribUsage.POSITION, AttribType.FLOAT, 3).addAttrib(AttribUsage.UV, AttribType.FLOAT, 2); 21 | 22 | POS_COLOR.addAttrib(AttribUsage.POSITION, AttribType.FLOAT, 3).addAttrib(AttribUsage.COLOR, 23 | AttribType.UNSIGNED_BYTE, 4, true); 24 | 25 | POS_UV_COLOR.addAttrib(AttribUsage.POSITION, AttribType.FLOAT, 3).addAttrib(AttribUsage.UV, AttribType.FLOAT, 2) 26 | .addAttrib(AttribUsage.COLOR, AttribType.UNSIGNED_BYTE, 4, true); 27 | 28 | POS_UV_COLOR_TEXID.addAttrib(AttribUsage.POSITION, AttribType.FLOAT, 3) 29 | .addAttrib(AttribUsage.UV, AttribType.FLOAT, 2) 30 | .addAttrib(AttribUsage.COLOR, AttribType.UNSIGNED_BYTE, 4, true) 31 | .addAttrib(AttribUsage.TEXID, AttribType.UNSIGNED_BYTE, 1, false); 32 | 33 | POS_UV_COLOR_NORM.addAttrib(AttribUsage.POSITION, AttribType.FLOAT, 3) 34 | .addAttrib(AttribUsage.UV, AttribType.FLOAT, 2) 35 | .addAttrib(AttribUsage.COLOR, AttribType.UNSIGNED_BYTE, 4, true) 36 | .addAttrib(AttribUsage.NORMAL, AttribType.FLOAT, 3); 37 | } 38 | 39 | private final List attributes = new ArrayList(); 40 | 41 | public List getAttributes() { 42 | return attributes; 43 | } 44 | 45 | public VertexFormat addAttrib(AttribUsage usage, AttribType type, int size) { 46 | attributes.add(new VertexAttribute(usage, type, size)); 47 | return this; 48 | } 49 | 50 | public VertexFormat addAttrib(AttribUsage usage, AttribType type, int size, boolean normalized) { 51 | attributes.add(new VertexAttribute(usage, type, size, normalized)); 52 | return this; 53 | } 54 | 55 | public void apply() { 56 | int stride = 0; 57 | for (VertexAttribute attrib : attributes) 58 | stride += attrib.numBytes(); 59 | 60 | long pointer = 0; 61 | for (int i = 0; i < attributes.size(); i++) { 62 | VertexAttribute attrib = attributes.get(i); 63 | GL20.glEnableVertexAttribArray(i); 64 | GL20.glVertexAttribPointer(i, attrib.size, attrib.type.glType, attrib.normalized, stride, pointer); 65 | pointer += attrib.numBytes(); 66 | } 67 | } 68 | 69 | public void unapply() { 70 | for (int i = 0; i < attributes.size(); i++) 71 | GL20.glDisableVertexAttribArray(i); 72 | 73 | } 74 | 75 | public int getStride() { 76 | int stride = 0; 77 | for (VertexAttribute attrib : attributes) 78 | stride += attrib.numBytes(); 79 | return stride; 80 | } 81 | 82 | public static enum AttribUsage { 83 | POSITION, UV, COLOR, NORMAL, TEXID, OTHER 84 | } 85 | 86 | public static enum AttribType { 87 | FLOAT(GL11.GL_FLOAT, 4), INT(GL11.GL_INT, 4), UNSIGNED_INT(GL11.GL_UNSIGNED_INT, 4), SHORT(GL11.GL_SHORT, 2), 88 | UNSIGNED_SHORT(GL11.GL_UNSIGNED_SHORT, 2), BYTE(GL11.GL_BYTE, 1), UNSIGNED_BYTE(GL11.GL_UNSIGNED_BYTE, 1); 89 | 90 | private final int glType; 91 | private final int bytes; 92 | 93 | private AttribType(int glType, int bytes) { 94 | this.glType = glType; 95 | this.bytes = bytes; 96 | } 97 | 98 | public int getGLType() { 99 | return glType; 100 | } 101 | 102 | public int numBytes() { 103 | return bytes; 104 | } 105 | } 106 | 107 | public static class VertexAttribute { 108 | private final AttribUsage usage; 109 | private final AttribType type; 110 | private final int size; 111 | private boolean normalized = false; 112 | 113 | public VertexAttribute(AttribUsage usage, AttribType type, int size) { 114 | this.usage = usage; 115 | this.type = type; 116 | this.size = size; 117 | } 118 | 119 | public VertexAttribute(AttribUsage usage, AttribType type, int size, boolean normalized) { 120 | this(usage, type, size); 121 | this.normalized = normalized; 122 | } 123 | 124 | public AttribUsage getUsage() { 125 | return usage; 126 | } 127 | 128 | public AttribType getType() { 129 | return type; 130 | } 131 | 132 | public int getSize() { 133 | return size; 134 | } 135 | 136 | public int numBytes() { 137 | return size * type.bytes; 138 | } 139 | 140 | public boolean isNormalized() { 141 | return normalized; 142 | } 143 | 144 | public VertexAttribute setNormalized(boolean normalized) { 145 | this.normalized = normalized; 146 | return this; 147 | } 148 | } 149 | } -------------------------------------------------------------------------------- /src/main/java/com/elmfer/cnmcu/network/IDEScreenHeartbeatC2SPacket.java: -------------------------------------------------------------------------------- 1 | package com.elmfer.cnmcu.network; 2 | 3 | import java.util.UUID; 4 | 5 | import com.elmfer.cnmcu.blockentities.CNnanoBlockEntity; 6 | 7 | import net.fabricmc.fabric.api.networking.v1.PacketByteBufs; 8 | import net.fabricmc.fabric.api.networking.v1.PacketSender; 9 | import net.minecraft.network.PacketByteBuf; 10 | import net.minecraft.server.MinecraftServer; 11 | import net.minecraft.server.network.ServerPlayNetworkHandler; 12 | import net.minecraft.server.network.ServerPlayerEntity; 13 | 14 | public class IDEScreenHeartbeatC2SPacket extends Packet.C2S { 15 | 16 | public IDEScreenHeartbeatC2SPacket (UUID mcuId) { 17 | super(PacketByteBufs.create()); 18 | 19 | buffer.writeUuid(mcuId); 20 | } 21 | 22 | public static void recieve(MinecraftServer server, ServerPlayerEntity player, ServerPlayNetworkHandler handler, PacketByteBuf buf, PacketSender responseSender) { 23 | UUID mcuId = buf.readUuid(); 24 | 25 | server.execute(() -> { 26 | if (CNnanoBlockEntity.SCREEN_UPDATES.containsKey(mcuId)) 27 | CNnanoBlockEntity.SCREEN_UPDATES.get(mcuId).heartBeat(player.getUuid()); 28 | }); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/com/elmfer/cnmcu/network/IDEScreenMCUControlC2SPacket.java: -------------------------------------------------------------------------------- 1 | package com.elmfer.cnmcu.network; 2 | 3 | import java.util.UUID; 4 | 5 | import com.elmfer.cnmcu.blockentities.CNnanoBlockEntity; 6 | 7 | import net.fabricmc.fabric.api.networking.v1.PacketByteBufs; 8 | import net.fabricmc.fabric.api.networking.v1.PacketSender; 9 | import net.minecraft.network.PacketByteBuf; 10 | import net.minecraft.server.MinecraftServer; 11 | import net.minecraft.server.network.ServerPlayNetworkHandler; 12 | import net.minecraft.server.network.ServerPlayerEntity; 13 | 14 | public class IDEScreenMCUControlC2SPacket extends Packet.C2S { 15 | 16 | public IDEScreenMCUControlC2SPacket(UUID mcuId, Control control) { 17 | super(PacketByteBufs.create()); 18 | 19 | buffer.writeUuid(mcuId); 20 | buffer.writeInt(control.getId()); 21 | } 22 | 23 | public static void recieve(MinecraftServer server, ServerPlayerEntity player, ServerPlayNetworkHandler handler, PacketByteBuf buf, PacketSender responseSender) { 24 | UUID mcuId = buf.readUuid(); 25 | 26 | if (!CNnanoBlockEntity.SCREEN_UPDATES.containsKey(mcuId)) 27 | return; 28 | 29 | Control control = Control.values()[buf.readInt()]; 30 | CNnanoBlockEntity entity = CNnanoBlockEntity.SCREEN_UPDATES.get(mcuId).getEntity(); 31 | 32 | switch (control) { 33 | case POWER_ON: 34 | entity.mcu.setPowered(true); 35 | break; 36 | case POWER_OFF: 37 | entity.mcu.setPowered(false); 38 | break; 39 | case RESET: 40 | entity.mcu.reset(); 41 | break; 42 | case PAUSE_CLOCK: 43 | if (entity.mcu.isPowered()) 44 | entity.mcu.setClockPause(true); 45 | break; 46 | case RESUME_CLOCK: 47 | if (entity.mcu.isPowered()) 48 | entity.mcu.setClockPause(false); 49 | break; 50 | case CYCLE: 51 | if (entity.mcu.isClockPaused()) 52 | entity.mcu.cycle(); 53 | break; 54 | } 55 | } 56 | 57 | public static enum Control { 58 | POWER_ON(0), 59 | POWER_OFF(1), 60 | RESET(2), 61 | PAUSE_CLOCK(3), 62 | RESUME_CLOCK(4), 63 | CYCLE(5); 64 | 65 | private int id; 66 | 67 | private Control(int id) { 68 | this.id = id; 69 | } 70 | 71 | public int getId() { 72 | return id; 73 | } 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/main/java/com/elmfer/cnmcu/network/IDEScreenSaveCodeC2SPacket.java: -------------------------------------------------------------------------------- 1 | package com.elmfer.cnmcu.network; 2 | 3 | import java.util.UUID; 4 | 5 | import com.elmfer.cnmcu.blockentities.CNnanoBlockEntity; 6 | 7 | import net.fabricmc.fabric.api.networking.v1.PacketByteBufs; 8 | import net.fabricmc.fabric.api.networking.v1.PacketSender; 9 | import net.minecraft.network.PacketByteBuf; 10 | import net.minecraft.server.MinecraftServer; 11 | import net.minecraft.server.network.ServerPlayNetworkHandler; 12 | import net.minecraft.server.network.ServerPlayerEntity; 13 | 14 | public class IDEScreenSaveCodeC2SPacket extends Packet.C2S { 15 | 16 | public IDEScreenSaveCodeC2SPacket(String code, UUID mcuId) { 17 | super(PacketByteBufs.create()); 18 | 19 | buffer.writeUuid(mcuId); 20 | buffer.writeInt(code.length()); 21 | buffer.writeBytes(code.getBytes()); 22 | } 23 | 24 | public static void recieve(MinecraftServer server, ServerPlayerEntity player, ServerPlayNetworkHandler handler, PacketByteBuf buf, PacketSender responseSender) { 25 | UUID mcuId = buf.readUuid(); 26 | 27 | byte[] code = new byte[buf.readInt()]; 28 | buf.readBytes(code); 29 | 30 | String codeStr = new String(code); 31 | 32 | if (CNnanoBlockEntity.SCREEN_UPDATES.containsKey(mcuId)) { 33 | CNnanoBlockEntity entity = CNnanoBlockEntity.SCREEN_UPDATES.get(mcuId).getEntity(); 34 | entity.setCode(codeStr); 35 | entity.markDirty(); 36 | } 37 | 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/com/elmfer/cnmcu/network/IDEScreenSyncS2CPacket.java: -------------------------------------------------------------------------------- 1 | package com.elmfer.cnmcu.network; 2 | 3 | import com.elmfer.cnmcu.blockentities.CNnanoBlockEntity; 4 | import com.elmfer.cnmcu.mcu.NanoMCU; 5 | import com.elmfer.cnmcu.mcu.cpu.MOS6502; 6 | import com.elmfer.cnmcu.ui.IDEScreen; 7 | 8 | import net.fabricmc.fabric.api.networking.v1.PacketByteBufs; 9 | import net.fabricmc.fabric.api.networking.v1.PacketSender; 10 | import net.minecraft.client.MinecraftClient; 11 | import net.minecraft.client.network.ClientPlayNetworkHandler; 12 | import net.minecraft.network.PacketByteBuf; 13 | 14 | public class IDEScreenSyncS2CPacket extends Packet.S2C { 15 | 16 | public IDEScreenSyncS2CPacket(CNnanoBlockEntity blockEntity) { 17 | super(PacketByteBufs.create()); 18 | 19 | NanoMCU mcu = blockEntity.mcu; 20 | MOS6502 cpu = mcu.getCPU(); 21 | 22 | buffer.writeBoolean(mcu.isPowered()); 23 | buffer.writeBoolean(mcu.isClockPaused()); 24 | 25 | buffer.writeInt(cpu.getA()); 26 | buffer.writeInt(cpu.getX()); 27 | buffer.writeInt(cpu.getY()); 28 | buffer.writeInt(cpu.getPC()); 29 | buffer.writeInt(cpu.getS()); 30 | buffer.writeInt(cpu.getP()); 31 | buffer.writeLong(mcu.numCycles()); 32 | 33 | buffer.writeInt(mcu.busAddress()); 34 | buffer.writeInt(mcu.busData()); 35 | buffer.writeBoolean(mcu.busRW()); 36 | 37 | byte zeroPage[] = new byte[256]; 38 | blockEntity.mcu.getRAM().getData().get(zeroPage); 39 | buffer.writeByteArray(zeroPage); 40 | } 41 | 42 | public static void recieve(MinecraftClient client, ClientPlayNetworkHandler handler, PacketByteBuf buf, PacketSender responseSender) { 43 | if(!(client.currentScreen instanceof IDEScreen)) 44 | return; 45 | 46 | IDEScreen screen = (IDEScreen) client.currentScreen; 47 | 48 | CPUStatus cpuStatus = new CPUStatus(); 49 | BusStatus busStatus = new BusStatus(); 50 | 51 | screen.isPowered = buf.readBoolean(); 52 | screen.isClockPaused = buf.readBoolean(); 53 | 54 | cpuStatus.A = buf.readInt(); 55 | cpuStatus.X = buf.readInt(); 56 | cpuStatus.Y = buf.readInt(); 57 | cpuStatus.PC = buf.readInt(); 58 | cpuStatus.SP = buf.readInt(); 59 | cpuStatus.Flags = buf.readInt(); 60 | cpuStatus.Cycles = buf.readLong(); 61 | 62 | busStatus.Address = buf.readInt(); 63 | busStatus.Data = buf.readInt(); 64 | busStatus.RW = buf.readBoolean(); 65 | 66 | screen.cpuStatus = cpuStatus; 67 | screen.busStatus = busStatus; 68 | screen.zeroPage.clear(); 69 | buf.readVarInt(); 70 | buf.readBytes(screen.zeroPage); 71 | } 72 | 73 | public static class CPUStatus { 74 | public int A; 75 | public int X; 76 | public int Y; 77 | public int PC; 78 | public int SP; 79 | public int Flags; 80 | public long Cycles; 81 | } 82 | 83 | public static class BusStatus { 84 | public int Address; 85 | public int Data; 86 | public boolean RW; 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /src/main/java/com/elmfer/cnmcu/network/Packet.java: -------------------------------------------------------------------------------- 1 | 2 | package com.elmfer.cnmcu.network; 3 | 4 | import java.lang.reflect.Method; 5 | import java.util.Map; 6 | import java.util.concurrent.ConcurrentHashMap; 7 | 8 | import com.elmfer.cnmcu.CodeNodeMicrocontrollers; 9 | 10 | import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking; 11 | import net.fabricmc.fabric.api.networking.v1.PacketSender; 12 | import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking; 13 | import net.minecraft.client.MinecraftClient; 14 | import net.minecraft.client.network.ClientPlayNetworkHandler; 15 | import net.minecraft.network.PacketByteBuf; 16 | import net.minecraft.server.MinecraftServer; 17 | import net.minecraft.server.network.ServerPlayNetworkHandler; 18 | import net.minecraft.server.network.ServerPlayerEntity; 19 | import net.minecraft.util.Identifier; 20 | 21 | public class Packet { 22 | 23 | private static final Map, Identifier> CHANNEL_MAP = new ConcurrentHashMap<>(); 24 | 25 | protected PacketByteBuf buffer; 26 | 27 | public Packet(PacketByteBuf buffer) { 28 | this.buffer = buffer; 29 | } 30 | 31 | protected static void setChannel(Class clazz, String channelName) { 32 | CHANNEL_MAP.put(clazz, CodeNodeMicrocontrollers.id(channelName)); 33 | } 34 | 35 | protected static Identifier getChannel(Class clazz) { 36 | return CHANNEL_MAP.get(clazz); 37 | } 38 | 39 | protected Identifier getChannel() { 40 | return CHANNEL_MAP.get(this.getClass()); 41 | } 42 | 43 | public static abstract class S2C extends Packet { 44 | 45 | public S2C(PacketByteBuf buffer) { 46 | super(buffer); 47 | } 48 | 49 | protected static ClientPlayNetworking.PlayChannelHandler getHandler(Class clazz) { 50 | try { 51 | Method method = clazz.getMethod("recieve", MinecraftClient.class, ClientPlayNetworkHandler.class, 52 | PacketByteBuf.class, PacketSender.class); 53 | 54 | return (client, handler, buf, responseSender) -> { 55 | try { 56 | method.invoke(null, client, handler, buf, responseSender); 57 | } catch (Exception e) { 58 | e.printStackTrace(); 59 | } 60 | }; 61 | } catch (Exception e) { 62 | e.printStackTrace(); 63 | } 64 | 65 | return null; 66 | } 67 | 68 | public void send(ServerPlayerEntity player) { 69 | ServerPlayNetworking.send(player, getChannel(), buffer); 70 | } 71 | } 72 | 73 | public static abstract class C2S extends Packet { 74 | 75 | public C2S(PacketByteBuf buffer) { 76 | super(buffer); 77 | } 78 | 79 | protected static ServerPlayNetworking.PlayChannelHandler getHandler(Class clazz) { 80 | try { 81 | Method method = clazz.getMethod("recieve", MinecraftServer.class, ServerPlayerEntity.class, 82 | ServerPlayNetworkHandler.class, PacketByteBuf.class, PacketSender.class); 83 | 84 | return (server, player, handler, buf, responseSender) -> { 85 | try { 86 | method.invoke(null, server, player, handler, buf, responseSender); 87 | } catch (Exception e) { 88 | e.printStackTrace(); 89 | } 90 | }; 91 | } catch (Exception e) { 92 | e.printStackTrace(); 93 | } 94 | 95 | return null; 96 | } 97 | 98 | public void send() { 99 | ClientPlayNetworking.send(getChannel(), buffer); 100 | } 101 | } 102 | 103 | public static abstract class C2S2C extends Packet { 104 | 105 | static final Map TRANSACTIONS = new ConcurrentHashMap<>(); 106 | 107 | static int nextTransactionId = 0; 108 | 109 | private int transactionId; 110 | private boolean ready = false; 111 | 112 | public C2S2C(PacketByteBuf buffer) { 113 | super(buffer); 114 | 115 | transactionId = nextTransactionId++; 116 | buffer.writeInt(transactionId); 117 | } 118 | 119 | public C2S2C(PacketByteBuf responseBuffer, PacketByteBuf requestBuffer) { 120 | super(responseBuffer); 121 | 122 | this.transactionId = requestBuffer.readInt(); 123 | buffer.writeInt(transactionId); 124 | } 125 | 126 | protected static ServerPlayNetworking.PlayChannelHandler getServerHandler(Class clazz) { 127 | try { 128 | Method method = clazz.getMethod("recieveRequest", MinecraftServer.class, ServerPlayerEntity.class, 129 | ServerPlayNetworkHandler.class, PacketByteBuf.class, PacketSender.class); 130 | 131 | return (server, player, handler, buf, responseSender) -> { 132 | try { 133 | method.invoke(null, server, player, handler, buf, responseSender); 134 | } catch (Exception e) { 135 | e.printStackTrace(); 136 | } 137 | }; 138 | } catch (Exception e) { 139 | e.printStackTrace(); 140 | } 141 | 142 | return null; 143 | } 144 | 145 | protected static ClientPlayNetworking.PlayChannelHandler getClientHandler(Class clazz) { 146 | try { 147 | Method method = clazz.getMethod("recieveResponse", MinecraftClient.class, ClientPlayNetworkHandler.class, 148 | PacketByteBuf.class, PacketSender.class, clazz); 149 | 150 | return (client, handler, buf, responseSender) -> { 151 | try { 152 | C2S2C transaction = TRANSACTIONS.get(buf.readInt()); 153 | transaction.ready = true; 154 | TRANSACTIONS.remove(transaction.transactionId); 155 | method.invoke(null, client, handler, buf, responseSender, transaction); 156 | } catch (Exception e) { 157 | e.printStackTrace(); 158 | } 159 | }; 160 | } catch (Exception e) { 161 | e.printStackTrace(); 162 | } 163 | 164 | return null; 165 | } 166 | 167 | protected static Identifier getServerChannel(Class clazz) { 168 | return getChannel(clazz).withPath("server"); 169 | } 170 | 171 | protected static Identifier getClientChannel(Class clazz) { 172 | return getChannel(clazz).withPath("client"); 173 | } 174 | 175 | protected Identifier getServerChannel() { 176 | return getChannel().withPath("server"); 177 | } 178 | 179 | protected Identifier getClientChannel() { 180 | return getChannel().withPath("client"); 181 | } 182 | 183 | public void respond(ServerPlayerEntity player) { 184 | ServerPlayNetworking.send(player, getClientChannel(), buffer); 185 | } 186 | 187 | public void request() { 188 | if (TRANSACTIONS.containsKey(transactionId)) 189 | return; 190 | 191 | TRANSACTIONS.put(transactionId, this); 192 | ClientPlayNetworking.send(getServerChannel(), buffer); 193 | } 194 | 195 | public boolean isReady() { 196 | return ready; 197 | } 198 | } 199 | } 200 | -------------------------------------------------------------------------------- /src/main/java/com/elmfer/cnmcu/network/Packets.java: -------------------------------------------------------------------------------- 1 | package com.elmfer.cnmcu.network; 2 | 3 | import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking; 4 | import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking; 5 | 6 | public class Packets { 7 | 8 | public static void initClientPackets() { 9 | registerS2CPacket("ide_screen_sync", IDEScreenSyncS2CPacket.class); 10 | 11 | registerC2S2CClientPacket("upload_rom", UploadROMC2S2CPacket.class); 12 | } 13 | 14 | public static void initServerPackets() { 15 | registerC2SPacket("ide_screen_heartbeat", IDEScreenHeartbeatC2SPacket.class); 16 | registerC2SPacket("ide_screen_save_code", IDEScreenSaveCodeC2SPacket.class); 17 | registerC2SPacket("ide_screen_mcu_control", IDEScreenMCUControlC2SPacket.class); 18 | 19 | Packet.setChannel(IDEScreenSyncS2CPacket.class, "ide_screen_sync"); 20 | registerC2S2CServerPacket("upload_rom", UploadROMC2S2CPacket.class); 21 | } 22 | 23 | private static void registerS2CPacket(String channelName, Class packetClass) { 24 | Packet.setChannel(packetClass, channelName); 25 | ClientPlayNetworking.registerGlobalReceiver(Packet.getChannel(packetClass), Packet.S2C.getHandler(packetClass)); 26 | } 27 | 28 | private static void registerC2SPacket(String channelName, Class packetClass) { 29 | Packet.setChannel(packetClass, channelName); 30 | ServerPlayNetworking.registerGlobalReceiver(Packet.getChannel(packetClass), Packet.C2S.getHandler(packetClass)); 31 | } 32 | 33 | private static void registerC2S2CServerPacket(String channelName, Class packetClass) { 34 | Packet.setChannel(packetClass, channelName); 35 | ServerPlayNetworking.registerGlobalReceiver(Packet.C2S2C.getServerChannel(packetClass), 36 | Packet.C2S2C.getServerHandler(packetClass)); 37 | } 38 | 39 | private static void registerC2S2CClientPacket(String channelName, Class packetClass) { 40 | Packet.setChannel(packetClass, channelName); 41 | ClientPlayNetworking.registerGlobalReceiver(Packet.C2S2C.getClientChannel(packetClass), 42 | Packet.C2S2C.getClientHandler(packetClass)); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/com/elmfer/cnmcu/network/UploadROMC2S2CPacket.java: -------------------------------------------------------------------------------- 1 | package com.elmfer.cnmcu.network; 2 | 3 | import java.util.UUID; 4 | 5 | import com.elmfer.cnmcu.blockentities.CNnanoBlockEntity; 6 | import com.elmfer.cnmcu.mcu.NanoMCU; 7 | 8 | import net.fabricmc.api.EnvType; 9 | import net.fabricmc.api.Environment; 10 | import net.fabricmc.fabric.api.networking.v1.PacketByteBufs; 11 | import net.fabricmc.fabric.api.networking.v1.PacketSender; 12 | import net.minecraft.client.MinecraftClient; 13 | import net.minecraft.client.network.ClientPlayNetworkHandler; 14 | import net.minecraft.network.PacketByteBuf; 15 | import net.minecraft.server.MinecraftServer; 16 | import net.minecraft.server.network.ServerPlayNetworkHandler; 17 | import net.minecraft.server.network.ServerPlayerEntity; 18 | 19 | public class UploadROMC2S2CPacket extends Packet.C2S2C { 20 | 21 | public int bytesUploaded; 22 | public String message = ""; 23 | 24 | /** 25 | * Constructor for client to server packet 26 | * 27 | * @param buffer 28 | */ 29 | public UploadROMC2S2CPacket(UUID mcuId, byte[] rom) { 30 | super(PacketByteBufs.create()); 31 | 32 | buffer.writeUuid(mcuId); 33 | buffer.writeInt(rom.length); 34 | buffer.writeBytes(rom); 35 | } 36 | 37 | /** 38 | * Constructor for server to client packet 39 | * 40 | * @param buffer 41 | */ 42 | public UploadROMC2S2CPacket(PacketByteBuf requestBuffer) { 43 | super(PacketByteBufs.create(), requestBuffer); 44 | } 45 | 46 | public static void recieveRequest(MinecraftServer server, ServerPlayerEntity player, 47 | ServerPlayNetworkHandler handler, PacketByteBuf buf, PacketSender responseSender) { 48 | UploadROMC2S2CPacket packet = new UploadROMC2S2CPacket(buf); 49 | UUID mcuId = buf.readUuid(); 50 | 51 | if (!CNnanoBlockEntity.SCREEN_UPDATES.containsKey(mcuId)) { 52 | packet.buffer.writeInt(0); 53 | packet.buffer.writeString("MCU not found."); 54 | packet.respond(player); 55 | return; 56 | } 57 | 58 | int binarySize = buf.readInt(); 59 | NanoMCU mcu = CNnanoBlockEntity.SCREEN_UPDATES.get(mcuId).getEntity().mcu; 60 | 61 | if (mcu.getROM().getSize() != binarySize) { 62 | String message = String.format("Binary size mismatch. Expected: %d, Got: %d", mcu.getROM().getSize(), binarySize); 63 | packet.buffer.writeInt(0); 64 | packet.buffer.writeString(message); 65 | packet.respond(player); 66 | return; 67 | } 68 | 69 | server.execute(() -> { 70 | mcu.setPowered(false); 71 | 72 | byte[] rom = new byte[binarySize]; 73 | buf.readBytes(rom); 74 | 75 | mcu.getROM().getData().put(rom); 76 | 77 | mcu.setPowered(true); 78 | }); 79 | 80 | String message = String.format("Uploaded %d bytes.", binarySize); 81 | packet.buffer.writeInt(binarySize); 82 | packet.buffer.writeString(message); 83 | packet.respond(player); 84 | } 85 | 86 | @Environment(value=EnvType.CLIENT) 87 | public static void recieveResponse(MinecraftClient server, ClientPlayNetworkHandler handler, PacketByteBuf buf, 88 | PacketSender responseSender, UploadROMC2S2CPacket requestPacket) { 89 | 90 | requestPacket.bytesUploaded = buf.readInt(); 91 | requestPacket.message = buf.readString(); 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /src/main/java/com/elmfer/cnmcu/ui/handler/IDEScreenHandler.java: -------------------------------------------------------------------------------- 1 | package com.elmfer.cnmcu.ui.handler; 2 | 3 | import java.util.UUID; 4 | 5 | import com.elmfer.cnmcu.blockentities.CNnanoBlockEntity; 6 | 7 | import net.minecraft.entity.player.PlayerEntity; 8 | import net.minecraft.entity.player.PlayerInventory; 9 | import net.minecraft.item.ItemStack; 10 | import net.minecraft.network.PacketByteBuf; 11 | import net.minecraft.screen.ScreenHandler; 12 | 13 | public class IDEScreenHandler extends ScreenHandler { 14 | 15 | private UUID mcuID; 16 | private String code; 17 | 18 | public IDEScreenHandler(int syncId, PlayerInventory playerInventory, PacketByteBuf buf) { 19 | super(ScreenHandlers.IDE_SCREEN_HANDLER, syncId); 20 | 21 | mcuID = buf.readUuid(); 22 | 23 | byte[] code = new byte[buf.readInt()]; 24 | buf.readBytes(code); 25 | 26 | this.code = new String(code); 27 | } 28 | 29 | public IDEScreenHandler(int syncId, UUID mcuID) { 30 | super(ScreenHandlers.IDE_SCREEN_HANDLER, syncId); 31 | 32 | this.mcuID = mcuID; 33 | } 34 | 35 | public UUID getMcuID() { 36 | return mcuID; 37 | } 38 | 39 | public String getCode() { 40 | return code; 41 | } 42 | 43 | @Override 44 | public void onClosed(PlayerEntity player) { 45 | if (!player.getWorld().isClient() && CNnanoBlockEntity.SCREEN_UPDATES.containsKey(mcuID)) 46 | CNnanoBlockEntity.SCREEN_UPDATES.get(mcuID).removeListener(player.getUuid()); 47 | } 48 | 49 | @Override 50 | public ItemStack quickMove(PlayerEntity var1, int var2) { 51 | // TODO Auto-generated method stub 52 | return null; 53 | } 54 | 55 | @Override 56 | public boolean canUse(PlayerEntity var1) { 57 | // TODO Auto-generated method stub 58 | return true; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/main/java/com/elmfer/cnmcu/ui/handler/ScreenHandlers.java: -------------------------------------------------------------------------------- 1 | package com.elmfer.cnmcu.ui.handler; 2 | 3 | import com.elmfer.cnmcu.CodeNodeMicrocontrollers; 4 | 5 | import net.fabricmc.fabric.api.screenhandler.v1.ExtendedScreenHandlerType; 6 | import net.minecraft.registry.Registries; 7 | import net.minecraft.registry.Registry; 8 | import net.minecraft.screen.ScreenHandlerType; 9 | 10 | public class ScreenHandlers { 11 | 12 | public static final ScreenHandlerType IDE_SCREEN_HANDLER = new ExtendedScreenHandlerType<>((syncId, playerInventory, buf) -> new IDEScreenHandler(syncId, playerInventory, buf)); 13 | 14 | public static void init() { 15 | Registry.register(Registries.SCREEN_HANDLER, CodeNodeMicrocontrollers.id("ide"), IDE_SCREEN_HANDLER); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/com/elmfer/cnmcu/util/HTTPSFetcher.java: -------------------------------------------------------------------------------- 1 | package com.elmfer.cnmcu.util; 2 | 3 | import java.io.ByteArrayOutputStream; 4 | import java.io.IOException; 5 | import java.io.InputStream; 6 | import java.net.HttpURLConnection; 7 | import java.net.MalformedURLException; 8 | import java.net.URL; 9 | import java.nio.charset.StandardCharsets; 10 | import java.util.HashMap; 11 | import java.util.Map; 12 | 13 | import javax.net.ssl.HttpsURLConnection; 14 | 15 | import com.google.gson.JsonElement; 16 | import com.google.gson.JsonObject; 17 | import com.google.gson.JsonParser; 18 | 19 | public class HTTPSFetcher { 20 | private FetcherWorker worker; 21 | private byte[] contentData = null; 22 | private String stringData = null; 23 | private final Map headers = new HashMap<>(); 24 | 25 | public HTTPSFetcher(String url) { 26 | try { 27 | worker = new FetcherWorker(this, new URL(url)); 28 | } catch (MalformedURLException e) { 29 | e.printStackTrace(); 30 | } 31 | } 32 | 33 | public void start() { 34 | worker.start(); 35 | } 36 | 37 | public void addHeader(String key, String value) { 38 | headers.put(key, value); 39 | } 40 | 41 | public boolean fetchComplete() { 42 | return worker.complete; 43 | } 44 | 45 | public void waitForCompletion() { 46 | try { 47 | worker.join(); 48 | } catch (InterruptedException e) { 49 | e.printStackTrace(); 50 | } 51 | } 52 | 53 | public String stringContent() { 54 | if (worker.complete) { 55 | if (stringData == null) 56 | stringData = new String(contentData, StandardCharsets.UTF_8); 57 | return stringData; 58 | } 59 | 60 | return worker.status; 61 | } 62 | 63 | public JsonElement jsonContent() { 64 | if(worker.complete) { 65 | try { 66 | return JsonParser.parseString(stringContent()); 67 | } catch (Exception e) { 68 | return new JsonObject(); 69 | } 70 | } 71 | 72 | return new JsonObject(); 73 | } 74 | 75 | public byte[] byteContent() { 76 | return contentData; 77 | } 78 | 79 | public boolean hasFailed() { 80 | return worker.statusCode != HttpURLConnection.HTTP_OK; 81 | } 82 | 83 | public int statusCode() { 84 | return worker.statusCode; 85 | } 86 | 87 | /** Internal fetcher worker. **/ 88 | public static class FetcherWorker extends Thread { 89 | URL url; 90 | boolean complete = false; 91 | int statusCode = 200; 92 | String status = "Connecting"; 93 | HTTPSFetcher parent; 94 | 95 | FetcherWorker(HTTPSFetcher parent, URL url) { 96 | this.url = url; 97 | this.parent = parent; 98 | } 99 | 100 | @Override 101 | public void run() { 102 | try { 103 | HttpsURLConnection connection = (HttpsURLConnection) url.openConnection(); 104 | status = "Connected, Recieving Data"; 105 | 106 | for (Map.Entry entry : parent.headers.entrySet()) { 107 | connection.setRequestProperty(entry.getKey(), entry.getValue()); 108 | } 109 | 110 | connection.setRequestMethod("GET"); 111 | 112 | InputStream is = connection.getInputStream(); 113 | statusCode = connection.getResponseCode(); 114 | status = String.format("Recieved Data: %d", statusCode); 115 | 116 | ByteArrayOutputStream os = new ByteArrayOutputStream(); 117 | 118 | byte[] chunk = new byte[4096]; 119 | int bytesRead = 0; 120 | while (0 < (bytesRead = is.read(chunk))) { 121 | os.write(chunk, 0, bytesRead); 122 | } 123 | 124 | parent.contentData = os.toByteArray(); 125 | is.read(parent.contentData); 126 | 127 | is.close(); 128 | connection.disconnect(); 129 | 130 | complete = true; 131 | } catch (IOException e) { 132 | // TODO Auto-generated catch block 133 | statusCode = 0; 134 | status = String.format("Fetch Failed: %s", e.toString()); 135 | e.printStackTrace(); 136 | } 137 | } 138 | } 139 | } -------------------------------------------------------------------------------- /src/main/java/com/elmfer/cnmcu/util/ResourceLoader.java: -------------------------------------------------------------------------------- 1 | package com.elmfer.cnmcu.util; 2 | 3 | import java.io.InputStream; 4 | 5 | import net.minecraft.util.Identifier; 6 | 7 | /** 8 | * Mod's own resource loader for loading resources like models and textures. 9 | * This guarantees that an asset can be loaded at any time. 10 | * Useful for loading assets at the very start of the game when Minecraft's resource manager is not yet initialized. 11 | */ 12 | public class ResourceLoader { 13 | 14 | private ResourceLoader() { 15 | 16 | } 17 | 18 | public static InputStream getInputStream(Identifier location) { 19 | return ResourceLoader.class 20 | .getResourceAsStream("/assets/" + location.getNamespace() + "/" + location.getPath()); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/resources/assets/cnmcu/blockstates/nano.json: -------------------------------------------------------------------------------- 1 | { 2 | "variants": { 3 | "facing=north": { "model": "cnmcu:block/nano_facing_north" }, 4 | "facing=west": { "model": "cnmcu:block/nano_facing_west" }, 5 | "facing=east": { "model": "cnmcu:block/nano_facing_east" }, 6 | "facing=south": { "model": "cnmcu:block/nano_facing_south" } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/main/resources/assets/cnmcu/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elmfrain/cnmcu/ff1d89707ad05085cd226b91a3ce5c0e92caa281/src/main/resources/assets/cnmcu/icon.png -------------------------------------------------------------------------------- /src/main/resources/assets/cnmcu/meshes/nano_pcb.ply: -------------------------------------------------------------------------------- 1 | ply 2 | format ascii 1.0 3 | comment Created in Blender version 4.0.2 4 | element vertex 20 5 | property float x 6 | property float y 7 | property float z 8 | property float nx 9 | property float ny 10 | property float nz 11 | property uchar red 12 | property uchar green 13 | property uchar blue 14 | property uchar alpha 15 | property float s 16 | property float t 17 | element face 6 18 | property list uchar uint vertex_indices 19 | end_header 20 | 1 0.125 0 0.5773503 0.5773503 -0.5773503 254 254 254 255 1 1 21 | 1 0.125 1 0.5773503 0.5773503 0.5773503 254 254 254 255 1 0 22 | 1 0 1 0.5773503 -0.5773503 0.5773503 254 254 254 255 0.875 0 23 | 1 0 0 0.5773503 -0.5773503 -0.5773503 254 254 254 255 0.875 1 24 | 1 0.125 1 0.5773503 0.5773503 0.5773503 254 254 254 255 0 0 25 | 0 0.125 1 -0.5773503 0.5773503 0.5773503 254 254 254 255 1 -0 26 | 0 0 1 -0.5773503 -0.5773503 0.5773503 254 254 254 255 1 0.125 27 | 1 0 1 0.5773503 -0.5773503 0.5773503 254 254 254 255 0 0.125 28 | 1 0 0 0.5773503 -0.5773503 -0.5773503 254 254 254 255 1 0.875 29 | 0 0 0 -0.5773503 -0.5773503 -0.5773503 254 254 254 255 0 0.875 30 | 0 0.125 0 -0.5773503 0.5773503 -0.5773503 254 254 254 255 0 1 31 | 0 0.125 0 -0.5773503 0.5773503 -0.5773503 254 254 254 255 -7.450581e-09 0 32 | 0 0 0 -0.5773503 -0.5773503 -0.5773503 254 254 254 255 0.12499999 0 33 | 0 0 1 -0.5773503 -0.5773503 0.5773503 254 254 254 255 0.12499999 1 34 | 0 0.125 1 -0.5773503 0.5773503 0.5773503 254 254 254 255 2.2351742e-08 1 35 | 1 0 1 0.5773503 -0.5773503 0.5773503 254 254 254 255 1 0 36 | 0 0 1 -0.5773503 -0.5773503 0.5773503 254 254 254 255 0 0 37 | 0 0 0 -0.5773503 -0.5773503 -0.5773503 254 254 254 255 0 1 38 | 1 0 0 0.5773503 -0.5773503 -0.5773503 254 254 254 255 1 1 39 | 0 0.125 1 -0.5773503 0.5773503 0.5773503 254 254 254 255 0 0 40 | 4 0 1 2 3 41 | 4 4 5 6 7 42 | 4 0 8 9 10 43 | 4 11 12 13 14 44 | 4 15 16 17 18 45 | 4 10 19 1 0 46 | -------------------------------------------------------------------------------- /src/main/resources/assets/cnmcu/models/item/nano.json: -------------------------------------------------------------------------------- 1 | { 2 | "parent": "item/generated", 3 | "textures": { 4 | "layer0": "cnmcu:item/nano" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /src/main/resources/assets/cnmcu/setup/imgui.ini: -------------------------------------------------------------------------------- 1 | [Window][DockSpace] 2 | Pos=0,0 3 | Size=854,480 4 | Collapsed=0 5 | 6 | [Window][Debug##Default] 7 | Pos=60,60 8 | Size=400,400 9 | Collapsed=0 10 | 11 | [Window][Code Editor] 12 | Pos=493,0 13 | Size=361,300 14 | Collapsed=0 15 | DockId=0x00000007,0 16 | 17 | [Window][Console] 18 | Pos=493,302 19 | Size=361,178 20 | Collapsed=0 21 | DockId=0x00000008,0 22 | 23 | [Window][MCU Status] 24 | Pos=0,0 25 | Size=272,240 26 | Collapsed=0 27 | DockId=0x00000003,0 28 | 29 | [Window][CPU Status] 30 | Pos=0,242 31 | Size=272,238 32 | Collapsed=0 33 | DockId=0x00000004,0 34 | 35 | [Window][Zero Page Viewer] 36 | Pos=0,242 37 | Size=272,238 38 | Collapsed=0 39 | DockId=0x00000004,1 40 | 41 | [Docking][Data] 42 | DockSpace ID=0x3FC20BEE Window=0x9A404470 Pos=0,0 Size=854,480 Split=X 43 | DockNode ID=0x00000005 Parent=0x3FC20BEE SizeRef=491,480 Split=X 44 | DockNode ID=0x00000001 Parent=0x00000005 SizeRef=272,480 Split=Y Selected=0x70C4DE13 45 | DockNode ID=0x00000003 Parent=0x00000001 SizeRef=324,240 Selected=0x70C4DE13 46 | DockNode ID=0x00000004 Parent=0x00000001 SizeRef=324,238 Selected=0x0746A08A 47 | DockNode ID=0x00000002 Parent=0x00000005 SizeRef=217,480 CentralNode=1 48 | DockNode ID=0x00000006 Parent=0x3FC20BEE SizeRef=361,480 Split=Y Selected=0x2867833B 49 | DockNode ID=0x00000007 Parent=0x00000006 SizeRef=375,300 Selected=0x2867833B 50 | DockNode ID=0x00000008 Parent=0x00000006 SizeRef=375,178 Selected=0xF9BEF62A 51 | 52 | -------------------------------------------------------------------------------- /src/main/resources/assets/cnmcu/textures/block/nano_pcb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elmfrain/cnmcu/ff1d89707ad05085cd226b91a3ce5c0e92caa281/src/main/resources/assets/cnmcu/textures/block/nano_pcb.png -------------------------------------------------------------------------------- /src/main/resources/assets/cnmcu/textures/block/nano_smd.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elmfrain/cnmcu/ff1d89707ad05085cd226b91a3ce5c0e92caa281/src/main/resources/assets/cnmcu/textures/block/nano_smd.png -------------------------------------------------------------------------------- /src/main/resources/assets/cnmcu/textures/item/nano.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elmfrain/cnmcu/ff1d89707ad05085cd226b91a3ce5c0e92caa281/src/main/resources/assets/cnmcu/textures/item/nano.png -------------------------------------------------------------------------------- /src/main/resources/fabric.mod.json: -------------------------------------------------------------------------------- 1 | { 2 | "schemaVersion": 1, 3 | "id": "cnmcu", 4 | "version": "0.0.10a-1.20.4", 5 | "name": "CodeNode Microcontrollers", 6 | "description": "Adds redstone microcontrollers powered by 6502 processors. Automate your projects in 6502 assembly!", 7 | "authors": [ 8 | "elmfer" 9 | ], 10 | "contact": { 11 | "homepage": "https://fabricmc.net/", 12 | "sources": "https://github.com/FabricMC/fabric-example-mod" 13 | }, 14 | "license": "GNU GPLv3", 15 | "icon": "assets/cnmcu/icon.png", 16 | "environment": "*", 17 | "entrypoints": { 18 | "main": [ 19 | "com.elmfer.cnmcu.CodeNodeMicrocontrollers" 20 | ], 21 | "client": [ 22 | "com.elmfer.cnmcu.CodeNodeMicrocontrollersClient" 23 | ] 24 | }, 25 | "depends": { 26 | "fabricloader": ">=0.15.6", 27 | "minecraft": "~1.20.4", 28 | "java": ">=17", 29 | "fabric-api": "*" 30 | } 31 | } -------------------------------------------------------------------------------- /vasm/README.txt: -------------------------------------------------------------------------------- 1 | This directory contains binaries for the vasm assembler for all x64 platforms. These binaries came from http://www.compilers.de/vasm.html, and they are redistributed for the mod to easily download them upon first time use. 2 | 3 | Note: vasm is under their own license, located in section 1.2 of their vasm manual: http://sun.hasenbraten.de/vasm/release/vasm.html 4 | It is not under the same license as the mod. 5 | -------------------------------------------------------------------------------- /vasm/cygwin1.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elmfrain/cnmcu/ff1d89707ad05085cd226b91a3ce5c0e92caa281/vasm/cygwin1.dll -------------------------------------------------------------------------------- /vasm/vasm6502_oldstyle-linux-x64: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elmfrain/cnmcu/ff1d89707ad05085cd226b91a3ce5c0e92caa281/vasm/vasm6502_oldstyle-linux-x64 -------------------------------------------------------------------------------- /vasm/vasm6502_oldstyle-macos-x64: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elmfrain/cnmcu/ff1d89707ad05085cd226b91a3ce5c0e92caa281/vasm/vasm6502_oldstyle-macos-x64 -------------------------------------------------------------------------------- /vasm/vasm6502_oldstyle-windows-x64.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elmfrain/cnmcu/ff1d89707ad05085cd226b91a3ce5c0e92caa281/vasm/vasm6502_oldstyle-windows-x64.exe -------------------------------------------------------------------------------- /vasm/vobjdump-linux-x64: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elmfrain/cnmcu/ff1d89707ad05085cd226b91a3ce5c0e92caa281/vasm/vobjdump-linux-x64 -------------------------------------------------------------------------------- /vasm/vobjdump-macos-x64: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elmfrain/cnmcu/ff1d89707ad05085cd226b91a3ce5c0e92caa281/vasm/vobjdump-macos-x64 -------------------------------------------------------------------------------- /vasm/vobjdump-windows-x64.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elmfrain/cnmcu/ff1d89707ad05085cd226b91a3ce5c0e92caa281/vasm/vobjdump-windows-x64.exe --------------------------------------------------------------------------------