diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index acd6068..2228e07 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -49,6 +49,14 @@ body: label: Driver Version description: What version of the driver are you running? Check with `RPI a2version` options: + - 002C (fix nano editor) + - 002B (fix keyboard delay) + - 002A (reduce CPU usage) + - 0029 (fix hang after shell exit) + - 0028 (add live drive loading and regeneration) + - 0027 (add dynamic drive support) + - 0026 (add error handling) + - 0025 (update RPi.command) - 0024 (fix VT100 arrow keys) - 0023 (replaced periph.io with rpio) - 0022 (added version info) @@ -61,6 +69,7 @@ body: label: Shell Version description: What version of the shell are you running?` options: + - 000E (fix hang on exit) - 000D (added version info) - Older (pre-2022-Mar-01) - Not Applicable (bug not Shell related) diff --git a/.github/workflows/codacy-analysis.yml b/.github/workflows/codacy.yml similarity index 68% rename from .github/workflows/codacy-analysis.yml rename to .github/workflows/codacy.yml index d1f28af..787733a 100644 --- a/.github/workflows/codacy-analysis.yml +++ b/.github/workflows/codacy.yml @@ -1,3 +1,8 @@ +# This workflow uses actions that are not certified by GitHub. +# They are provided by a third-party and are governed by +# separate terms of service, privacy policy, and support +# documentation. + # This workflow checks out code, performs a Codacy security scan # and integrates the results with the # GitHub Advanced Security code scanning feature. For more information on @@ -10,25 +15,32 @@ name: Codacy Security Scan on: push: - branches: [ main ] + branches: [ "main" ] pull_request: # The branches below must be a subset of the branches above - branches: [ main ] + branches: [ "main" ] schedule: - - cron: '35 10 * * 0' + - cron: '33 3 * * 3' + +permissions: + contents: read jobs: codacy-security-scan: + permissions: + contents: read # for actions/checkout to fetch code + security-events: write # for github/codeql-action/upload-sarif to upload SARIF results + actions: read # only required for a private repository by github/codeql-action/upload-sarif to get the Action run status name: Codacy Security Scan runs-on: ubuntu-latest steps: # Checkout the repository to the GitHub Actions runner - name: Checkout code - uses: actions/checkout@v2 + uses: actions/checkout@v3 # Execute Codacy Analysis CLI and generate a SARIF output with the security issues identified during the analysis - name: Run Codacy Analysis CLI - uses: codacy/codacy-analysis-cli-action@1.1.0 + uses: codacy/codacy-analysis-cli-action@d840f886c4bd4edc059706d09c6a1586111c540b with: # Check https://github.com/codacy/codacy-analysis-cli#project-token to get your project token from your Codacy repository # You can also omit the token and run the tools that support default configurations @@ -44,6 +56,6 @@ jobs: # Upload the SARIF file generated in the previous step - name: Upload SARIF results file - uses: github/codeql-action/upload-sarif@v1 + uses: github/codeql-action/upload-sarif@v2 with: sarif_file: results.sarif diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml new file mode 100644 index 0000000..96067f8 --- /dev/null +++ b/.github/workflows/codeql.yml @@ -0,0 +1,76 @@ +# For most projects, this workflow file will not need changing; you simply need +# to commit it to your repository. +# +# You may wish to alter this file to override the set of languages analyzed, +# or to provide custom queries or build logic. +# +# ******** NOTE ******** +# We have attempted to detect the languages in your repository. Please check +# the `language` matrix defined below to confirm you have the correct set of +# supported CodeQL languages. +# +name: "CodeQL" + +on: + push: + branches: [ "main" ] + pull_request: + # The branches below must be a subset of the branches above + branches: [ "main" ] + schedule: + - cron: '27 10 * * 5' + +jobs: + analyze: + name: Analyze + runs-on: ubuntu-latest + permissions: + actions: read + contents: read + security-events: write + + strategy: + fail-fast: false + matrix: + language: [ 'go' ] + # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ] + # Use only 'java' to analyze code written in Java, Kotlin or both + # Use only 'javascript' to analyze code written in JavaScript, TypeScript or both + # Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support + + steps: + - name: Checkout repository + uses: actions/checkout@v3 + + # Initializes the CodeQL tools for scanning. + - name: Initialize CodeQL + uses: github/codeql-action/init@v2 + with: + languages: ${{ matrix.language }} + # If you wish to specify custom queries, you can do so here or in a config file. + # By default, queries listed here will override any specified in a config file. + # Prefix the list here with "+" to use these queries and those in the config file. + + # Details on CodeQL's query packs refer to : https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs + # queries: security-extended,security-and-quality + + + # Autobuild attempts to build any compiled languages (C/C++, C#, Go, or Java). + # If this step fails, then you should remove it and run the build manually (see below) + - name: Autobuild + uses: github/codeql-action/autobuild@v2 + + # ℹ️ Command-line programs to run using the OS shell. + # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun + + # If the Autobuild fails above, remove it and uncomment the following three lines. + # modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance. + + # - run: | + # echo "Run, Build Application using script" + # ./location_of_script_within_repo/buildscript.sh + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v2 + with: + category: "/language:${{matrix.language}}" diff --git a/Apple2/CommandFirmware.asm b/Apple2/CommandFirmware.asm index de28952..3ec96b2 100644 --- a/Apple2/CommandFirmware.asm +++ b/Apple2/CommandFirmware.asm @@ -1,4 +1,4 @@ -; Copyright Terence J. Boldt (c)2020-2022 +; Copyright Terence J. Boldt (c)2020-2024 ; Use of this source code is governed by an MIT ; license that can be found in the LICENSE file. diff --git a/Apple2/DriveFirmware.asm b/Apple2/DriveFirmware.asm index 087efd0..00e0efb 100644 --- a/Apple2/DriveFirmware.asm +++ b/Apple2/DriveFirmware.asm @@ -1,4 +1,4 @@ -; Copyright Terence J. Boldt (c)2020-2022 +; Copyright Terence J. Boldt (c)2020-2024 ; Use of this source code is governed by an MIT ; license that can be found in the LICENSE file. diff --git a/Apple2/FileAccessFirmware.asm b/Apple2/FileAccessFirmware.asm index b82f8ef..871c748 100644 --- a/Apple2/FileAccessFirmware.asm +++ b/Apple2/FileAccessFirmware.asm @@ -1,4 +1,4 @@ -; Copyright Terence J. Boldt (c)2020-2022 +; Copyright Terence J. Boldt (c)2020-2024 ; Use of this source code is governed by an MIT ; license that can be found in the LICENSE file. diff --git a/Apple2/MenuFirmware.asm b/Apple2/MenuFirmware.asm index e262c76..4c07fb1 100644 --- a/Apple2/MenuFirmware.asm +++ b/Apple2/MenuFirmware.asm @@ -1,4 +1,4 @@ -; Copyright Terence J. Boldt (c)2020-2022 +; Copyright Terence J. Boldt (c)2020-2024 ; Use of this source code is governed by an MIT ; license that can be found in the LICENSE file. @@ -188,7 +188,7 @@ finishRead: Text: .byte "Apple2-IO-RPi",$8d -.byte "(c)2020-2022 Terence J. Boldt",$8d +.byte "(c)2020-2024 Terence J. Boldt",$8d .byte $8d .byte "Waiting for RPi FW:000F..." end: diff --git a/Apple2/RPi.Command.asm b/Apple2/RPi.Command.asm index 529cbcc..e12b1d8 100644 --- a/Apple2/RPi.Command.asm +++ b/Apple2/RPi.Command.asm @@ -1,4 +1,4 @@ -; Copyright Terence J. Boldt (c)2021-2022 +; Copyright Terence J. Boldt (c)2021-2024 ; Use of this source code is governed by an MIT ; license that can be found in the LICENSE file. diff --git a/Apple2/Shell.asm b/Apple2/Shell.asm index b40169f..c7f7937 100755 --- a/Apple2/Shell.asm +++ b/Apple2/Shell.asm @@ -1,4 +1,4 @@ -; Copyright Terence J. Boldt (c)2021-2022 +; Copyright Terence J. Boldt (c)2021-2024 ; Use of this source code is governed by an MIT ; license that can be found in the LICENSE file. @@ -115,8 +115,6 @@ Start: lda #ShellCommand jsr SendByte jsr DumpOutput - lda #ResetCommand - jsr SendByte pla sta LastChar rts @@ -292,7 +290,7 @@ restoreChar: rts Text: -.byte "Apple2-IO-RPi Shell Version 000D",$8d -.byte "(c)2020-2022 Terence J. Boldt",$8d +.byte "Apple2-IO-RPi Shell Version 000E",$8d +.byte "(c)2020-2024 Terence J. Boldt",$8d .byte $8d .byte $00 diff --git a/Apple2/Startup.bas b/Apple2/Startup.bas new file mode 100644 index 0000000..c442551 --- /dev/null +++ b/Apple2/Startup.bas @@ -0,0 +1,14 @@ +10 HOME +11 PRINT "Apple2-IO-RPi" +12 PRINT "(c)2021-2024 Terence J. Boldt" +13 PRINT +14 PRINT "This drive is dynamically generated" +15 PRINT "from the current working directory on" +16 PRINT "the Raspberry Pi and is in RAM only." +17 PRINT +18 PRINT "To start a shell to the RPi, type:" +19 PRINT "-shell" +20 PRINT +21 PRINT "To add RPI command to ProDOS, type:" +22 PRINT "-rpi.command" +23 PRINT diff --git a/Apple2/Update.Firmware.bas b/Apple2/Update.Firmware.bas index e806b5a..63c0c05 100644 --- a/Apple2/Update.Firmware.bas +++ b/Apple2/Update.Firmware.bas @@ -1,5 +1,5 @@ 10 HOME -100 PRINT CHR$ (4)"BLOAD AT28C64B.BIN,A$2000" +100 PRINT CHR$ (4)"BLOAD AT28C64B,A$2000" 200 PRINT "Program the firmare in slot #" 300 INPUT SL 400 FW = 8192 + 256 * SL: REM Firmware source @@ -15,9 +15,11 @@ 1010 POKE PS,PG * 16 + 15: REM Set firmware page 1020 FOR X = 0 TO 255 1030 A = PEEK (FW + PG * 2048 + X) +1035 B = PEEK (EP + X): REM Skip if unchanged +1037 IF (A = B) THEN GOTO 1045 1040 POKE EP + X,A 1041 B = PEEK (EP + X) -1042 IF (B < > A) THEN GOTO 1041 +1042 IF (B < > A) THEN GOTO 1041: REM Wait for write 1045 HTAB (X / 256) * 39 + 1 1046 INVERSE : PRINT " ";: NORMAL 1050 NEXT X diff --git a/Apple2/assemble.sh b/Apple2/assemble.sh index 4013f1d..48c667d 100755 --- a/Apple2/assemble.sh +++ b/Apple2/assemble.sh @@ -43,21 +43,16 @@ ld65 FileAccessSlot0.o FileAccessSlot1.o FileAccessSlot2.o FileAccessSlot3.o Fil cat \ DriveFirmware.bin CommandFirmware.bin FileAccessFirmware.bin MenuFirmware.bin \ -> AT28C64B.bin +> ../RaspberryPi/driveimage/AT28C64B.bin ca65 Shell.asm -D HW_TYPE=$HW_TYPE -o Shell.o --listing Shell.lst || exit 1 -ld65 Shell.o -o Shell.bin -C ../.cicd/none.cfg || exit 1 +ld65 Shell.o -o ../RaspberryPi/driveimage/Shell.bin -C ../.cicd/none.cfg || exit 1 ca65 RPi.Command.asm -D HW_TYPE=$HW_TYPE -o RPi.Command.o --listing RPi.Command.lst || exit 1 -ld65 RPi.Command.o -o RPi.Command.bin -C ../.cicd/none.cfg || exit 1 +ld65 RPi.Command.o -o ../RaspberryPi/driveimage/RPi.Command.bin -C ../.cicd/none.cfg || exit 1 rm ./*.o rm DriveFirmware.bin rm MenuFirmware.bin rm CommandFirmware.bin rm FileAccessFirmware.bin - -ProDOS-Utilities -d ../RaspberryPi/Apple2-IO-RPi.hdv -c put -i AT28C64B.bin -p /APPLE2.IO.RPI/AT28C64B.BIN || exit 1 -ProDOS-Utilities -d ../RaspberryPi/Apple2-IO-RPi.hdv -c put -i Shell.bin -p /APPLE2.IO.RPI/SHELL || exit 1 -ProDOS-Utilities -d ../RaspberryPi/Apple2-IO-RPi.hdv -c put -i RPi.Command.bin -p /APPLE2.IO.RPI/RPI.COMMAND -a 0x2000 || exit 1 -ProDOS-Utilities -d ../RaspberryPi/Apple2-IO-RPi.hdv -c ls diff --git a/Apple2/compare.sh b/Apple2/compare.sh index 5588001..9bf7b6c 100755 --- a/Apple2/compare.sh +++ b/Apple2/compare.sh @@ -50,8 +50,8 @@ ca65 RPi.Command.asm -o RPi.Command.o --listing RPi.Command.lst.new || exit 1 ld65 RPi.Command.o -o RPi.Command.bin.new -C ../.cicd/none.cfg || exit 1 rm ./*.o -diff RPi.Command.bin RPi.Command.bin.new || exit 1 -diff AT28C64B.bin AT28C64B.bin.new || exit 1 -diff Shell.bin Shell.bin.new || exit 1 +diff ../RaspberryPi/driveimage/RPi.Command.bin RPi.Command.bin.new || exit 1 +diff ../RaspberryPi/driveimage/AT28C64B.bin AT28C64B.bin.new || exit 1 +diff ../RaspberryPi/driveimage/Shell.bin Shell.bin.new || exit 1 rm ./*.new diff --git a/Hardware/Apple2IORPi.kicad_sch b/Hardware/Apple2IORPi.kicad_sch index 1cf2ad6..4e9a2e9 100644 --- a/Hardware/Apple2IORPi.kicad_sch +++ b/Hardware/Apple2IORPi.kicad_sch @@ -2215,7 +2215,6 @@ ) ) - (junction (at 81.28 125.73) (diameter 0) (color 0 0 0 0) (uuid 015f5586-ba76-4a98-9114-f5cd2c67134d) ) @@ -5372,6 +5371,17 @@ (pin "1" (uuid 23ce4381-b2cf-485f-a79a-4eaeb44b0849)) (pin "2" (uuid 5c798329-52d9-4807-96d1-e4addb44a953)) (pin "3" (uuid 1ab7faf5-43ab-4823-ac26-34babc931942)) + (pin "4" (uuid a6beaca2-6c47-4b64-b05b-68e01b124788)) + (pin "5" (uuid 1105c92a-881e-46d4-8e4b-9bde4c23e61b)) + (pin "6" (uuid 8fc34fe0-9484-4245-8205-553010f1b481)) + (pin "10" (uuid c2aa5992-2edc-40ca-a38b-d7fae7282fe7)) + (pin "8" (uuid adc84294-f335-43bc-9753-ab775be88116)) + (pin "9" (uuid 6a40c532-5374-49ce-976b-f54013e33342)) + (pin "11" (uuid 42a24e3d-88de-4ad2-b4a4-aa8239aeb395)) + (pin "12" (uuid 11da2dcc-4454-4c7e-8c58-2bce3eaa5144)) + (pin "13" (uuid 2e13be03-f7c2-4a62-b785-e7ae915b9e7f)) + (pin "14" (uuid da86aea1-9c30-4f7e-997a-033cdf91b7de)) + (pin "7" (uuid 4c3530f0-d981-4724-9a3e-7368587db9a8)) ) (symbol (lib_id "Device:C") (at 340.36 214.63 0) (unit 1) @@ -5380,7 +5390,7 @@ (property "Reference" "C3" (id 0) (at 343.281 213.4616 0) (effects (font (size 1.27 1.27)) (justify left)) ) - (property "Value" "C" (id 1) (at 343.281 215.773 0) + (property "Value" "0.1 µF" (id 1) (at 343.281 215.773 0) (effects (font (size 1.27 1.27)) (justify left)) ) (property "Footprint" "Apple2:Capacitor" (id 2) (at 341.3252 218.44 0) @@ -5399,7 +5409,7 @@ (property "Reference" "C4" (id 0) (at 363.601 213.4616 0) (effects (font (size 1.27 1.27)) (justify left)) ) - (property "Value" "C" (id 1) (at 363.601 215.773 0) + (property "Value" "0.1 µF" (id 1) (at 363.601 215.773 0) (effects (font (size 1.27 1.27)) (justify left)) ) (property "Footprint" "Apple2:Capacitor" (id 2) (at 361.6452 218.44 0) @@ -5418,7 +5428,7 @@ (property "Reference" "C2" (id 0) (at 355.981 163.9316 0) (effects (font (size 1.27 1.27)) (justify left)) ) - (property "Value" "100n" (id 1) (at 355.981 166.243 0) + (property "Value" "0.1 µF" (id 1) (at 355.981 166.243 0) (effects (font (size 1.27 1.27)) (justify left)) ) (property "Footprint" "Apple2:Capacitor" (id 2) (at 354.0252 168.91 0) @@ -5437,7 +5447,7 @@ (property "Reference" "C1" (id 0) (at 347.091 163.9316 0) (effects (font (size 1.27 1.27)) (justify left)) ) - (property "Value" "100n" (id 1) (at 347.091 166.243 0) + (property "Value" "0.1 µF" (id 1) (at 347.091 166.243 0) (effects (font (size 1.27 1.27)) (justify left)) ) (property "Footprint" "Apple2:Capacitor" (id 2) (at 345.1352 168.91 0) @@ -5456,7 +5466,7 @@ (property "Reference" "C5" (id 0) (at 364.871 163.9316 0) (effects (font (size 1.27 1.27)) (justify left)) ) - (property "Value" "100n" (id 1) (at 364.871 166.243 0) + (property "Value" "0.1 µF" (id 1) (at 364.871 166.243 0) (effects (font (size 1.27 1.27)) (justify left)) ) (property "Footprint" "Apple2:Capacitor" (id 2) (at 362.9152 168.91 0) @@ -5475,7 +5485,7 @@ (property "Reference" "C6" (id 0) (at 373.761 163.9316 0) (effects (font (size 1.27 1.27)) (justify left)) ) - (property "Value" "100n" (id 1) (at 373.761 166.243 0) + (property "Value" "0.1 µF" (id 1) (at 373.761 166.243 0) (effects (font (size 1.27 1.27)) (justify left)) ) (property "Footprint" "Apple2:Capacitor" (id 2) (at 371.8052 168.91 0) @@ -5499,9 +5509,20 @@ (property "Datasheet" "http://www.ti.com/lit/gpn/sn74LS32" (id 3) (at 90.17 115.57 0) (effects (font (size 1.27 1.27)) hide) ) + (pin "1" (uuid cc16c7ae-9c92-4444-9ea3-06f9ccc367be)) + (pin "2" (uuid 2b647539-7ba0-4b65-8202-c7f85d2d58f9)) + (pin "3" (uuid 50ca56df-1595-45f9-a7e0-251682b904b5)) (pin "4" (uuid a103831a-5a8a-4886-aa57-f8b2b69f26ae)) (pin "5" (uuid 7749be9c-17a6-4091-9298-3d5fa8df10ec)) (pin "6" (uuid 3bcb06a4-6607-4f1e-a0cd-7aa6ae9163ca)) + (pin "10" (uuid c0e76e7a-0fb4-4013-8aaa-29cb294ffe58)) + (pin "8" (uuid 5f137c12-6ab8-4995-ba1f-413f9ce9e2c2)) + (pin "9" (uuid c1755b79-9175-43f1-afda-82992afcaef2)) + (pin "11" (uuid a8681920-4d26-4021-a997-9f1f2b834c00)) + (pin "12" (uuid 285a9aee-c73d-49dd-accb-b4fd7574646c)) + (pin "13" (uuid 4f3dc6d3-051d-45c5-b2dd-3963bfe3689b)) + (pin "14" (uuid 639e36f7-111e-4b5a-8bf9-f055939534d4)) + (pin "7" (uuid e6c23048-abcc-4757-8a23-cb990a469883)) ) (symbol (lib_id "74xx:74LS32") (at 156.21 116.84 0) (unit 3) @@ -5515,9 +5536,20 @@ (property "Datasheet" "http://www.ti.com/lit/gpn/sn74LS32" (id 3) (at 156.21 116.84 0) (effects (font (size 1.27 1.27)) hide) ) + (pin "1" (uuid 779317f9-cc98-4e89-9a76-f28baf44b6fa)) + (pin "2" (uuid 49c409f4-fd27-4e2c-832f-c60bfbac5d4e)) + (pin "3" (uuid 8dcb9ab7-4947-44c1-ac89-22253862dff0)) + (pin "4" (uuid 66e60965-5117-4e25-ad7f-b2cf278ec2ac)) + (pin "5" (uuid fb6bac8b-0e2c-4da6-818b-d1ea7142ed6e)) + (pin "6" (uuid 94865cfd-0c49-41e6-8a13-a58a16d75bbc)) (pin "10" (uuid 4b8e4218-9740-4574-b59e-9bff3b6ae8ff)) (pin "8" (uuid 1ac84470-ff35-4e92-8c90-2205b203daf4)) (pin "9" (uuid 221d5d88-9b3c-4368-a294-8824ee031e92)) + (pin "11" (uuid b847d6d8-0cff-4347-b9db-69f5fbae9fce)) + (pin "12" (uuid 1f3f8181-e232-4518-9c68-ff0472233c70)) + (pin "13" (uuid e8a48dd8-df61-4c94-9f94-7d52814e8ba7)) + (pin "14" (uuid 1bd2c934-42cb-4949-88cd-f950c843d8cb)) + (pin "7" (uuid d08e8d45-1956-48ad-8bf9-f281b2d51657)) ) (symbol (lib_id "74xx:74LS32") (at 90.17 128.27 0) (unit 4) @@ -5531,9 +5563,20 @@ (property "Datasheet" "http://www.ti.com/lit/gpn/sn74LS32" (id 3) (at 90.17 128.27 0) (effects (font (size 1.27 1.27)) hide) ) + (pin "1" (uuid 585e2bc6-286c-4625-8fd6-b5232bd11ab7)) + (pin "2" (uuid 0cb58e87-1a6a-4bb6-bc79-815fbe53ac1e)) + (pin "3" (uuid e80cdefa-a788-4379-9e16-8fce6a58c8f6)) + (pin "4" (uuid 6925452e-3b67-4990-985b-e7d15d56a159)) + (pin "5" (uuid 0dcdf4ae-d8c6-4c94-bd47-80574ee9be6c)) + (pin "6" (uuid 6bd577a4-e8c5-4ffc-8ac8-8560490f35cf)) + (pin "10" (uuid d04405d3-f64d-4059-a328-9c543c6b5b15)) + (pin "8" (uuid 13dbb77d-77d9-4fa7-a371-954174333f4c)) + (pin "9" (uuid c9730515-2c30-423f-be43-60d2694a504a)) (pin "11" (uuid c40083a4-145c-4ae4-9fae-3a0ea9941f61)) (pin "12" (uuid 63605522-e38d-450e-bf96-6c4425233163)) (pin "13" (uuid c6c30a7a-cde8-4cf9-9ed4-49502cc4e875)) + (pin "14" (uuid 9d1413a3-2a21-4384-81c0-ccdb307d1530)) + (pin "7" (uuid 81b0a24d-d7da-4f8b-b867-b8bfdf8f37a3)) ) (symbol (lib_id "74xx:74LS00") (at 66.04 91.44 0) (unit 1) @@ -5550,6 +5593,17 @@ (pin "1" (uuid a1353da8-7c89-45ab-8a28-9598589a1ee1)) (pin "2" (uuid 663afe67-91e0-47d7-9990-df9e79fade04)) (pin "3" (uuid de28b31e-94a2-4f20-b1a8-765f5ea36c3d)) + (pin "4" (uuid 928ed566-e3f5-4b4a-8fbe-74e8d4fb243c)) + (pin "5" (uuid 0111e7f3-1514-4ad6-99e9-7dcf9686622c)) + (pin "6" (uuid 2e30ebe3-0f45-4c48-a2c8-2a32a4994456)) + (pin "10" (uuid 81fada83-e47f-4376-9c67-24de0fe6ca83)) + (pin "8" (uuid 2a20ddeb-7832-46d2-9069-b4a9751b83f9)) + (pin "9" (uuid 723a7bad-bd47-43ad-a59c-9873ea940efa)) + (pin "11" (uuid b911021d-57a0-4580-bfb0-1c066032b8e2)) + (pin "12" (uuid b2977fbf-6144-4357-8280-a40f093efff3)) + (pin "13" (uuid 9d0af54b-1546-4921-9c0f-c0db7d734ba3)) + (pin "14" (uuid 59a11a98-19e7-4d62-aed2-d3e3d3ae09c4)) + (pin "7" (uuid b6a54b1c-e858-415d-b3a3-5977d8636f54)) ) (symbol (lib_id "74xx:74LS00") (at 86.36 91.44 0) (unit 2) @@ -5563,9 +5617,20 @@ (property "Datasheet" "http://www.ti.com/lit/gpn/sn74ls00" (id 3) (at 86.36 91.44 0) (effects (font (size 1.27 1.27)) hide) ) + (pin "1" (uuid f6e35044-4b94-4656-ad69-ecbdce343488)) + (pin "2" (uuid b05d6dae-4161-42fd-90cb-fcbb1d75834f)) + (pin "3" (uuid 978c0384-e1bf-42a4-8c02-2d11be0ea0f4)) (pin "4" (uuid ab17ec18-2f5f-445a-8747-86764dc204e3)) (pin "5" (uuid 4c5ec9dc-5867-41c9-9129-01962654b6ac)) (pin "6" (uuid 62d49ae3-b4dd-497f-84dc-640f11d71890)) + (pin "10" (uuid c462dede-8070-4817-bf28-efd02b5a8971)) + (pin "8" (uuid 8548fb42-2440-4cb0-9164-af5f85371f01)) + (pin "9" (uuid 2f8df34c-29f4-42dd-ab8c-4368a809795a)) + (pin "11" (uuid 9d83d9ee-f9be-4cba-b423-fb184e0ae57f)) + (pin "12" (uuid d25d0f52-0689-4fa0-a1db-a9b35e9053eb)) + (pin "13" (uuid e3ff334a-b52c-4eff-82fa-a3036b75a900)) + (pin "14" (uuid a18d26ab-a8eb-467c-bf6b-1d8aa89f73ed)) + (pin "7" (uuid 6433ba4d-ba73-46d7-8c1d-6ecfcb83d21a)) ) (symbol (lib_id "Memory_EPROM:27C256") (at 119.38 227.33 0) (unit 1) @@ -5620,9 +5685,20 @@ (property "Datasheet" "http://www.ti.com/lit/gpn/sn74ls00" (id 3) (at 72.39 125.73 0) (effects (font (size 1.27 1.27)) hide) ) + (pin "1" (uuid 827cdd9c-0f24-485d-a074-76e4898269fd)) + (pin "2" (uuid ee4941d0-c696-4b20-b624-cfc438e02399)) + (pin "3" (uuid daf39040-e60c-47e8-ad5f-568518b98138)) + (pin "4" (uuid 8e678bf1-fca0-4b04-afa2-9eccdc69dbd7)) + (pin "5" (uuid d761a1eb-f270-421f-a96e-8b0854e4136b)) + (pin "6" (uuid c012cfb6-f253-4bfd-b42d-737662112798)) (pin "10" (uuid 799282ec-97a5-4c03-8ff7-5165af090737)) (pin "8" (uuid f0a24549-c201-4561-a7f5-2fab088eeebf)) (pin "9" (uuid 143dfd14-68b7-4903-809b-91db1fa3ee07)) + (pin "11" (uuid 47c1541a-2e10-4704-88f5-e800260f6e7f)) + (pin "12" (uuid 52529a02-0f01-49f9-a2c0-65389efd06ad)) + (pin "13" (uuid 5e78440e-17f6-4b50-a177-2b94125a82ee)) + (pin "14" (uuid c919295a-a8fd-4a7e-ab91-0ba222db2c02)) + (pin "7" (uuid fb2920c4-9db1-4fb4-bdfa-c66fa60d5493)) ) (symbol (lib_id "74xx:74LS00") (at 68.58 113.03 0) (unit 4) @@ -5636,9 +5712,20 @@ (property "Datasheet" "http://www.ti.com/lit/gpn/sn74ls00" (id 3) (at 68.58 113.03 0) (effects (font (size 1.27 1.27)) hide) ) + (pin "1" (uuid 47fc3e6f-4fa5-4a44-bc28-18ea9d413f48)) + (pin "2" (uuid 9d776279-8d51-4909-b91c-2d921b28aea1)) + (pin "3" (uuid 44c4ea58-6a8c-412a-894a-499d6c6bcd28)) + (pin "4" (uuid c0cc858c-1ac0-4e47-a87d-831903da6485)) + (pin "5" (uuid 520224a7-0742-4623-93b1-a64ea9bac558)) + (pin "6" (uuid 8439ba08-cf8f-46b9-97a3-bee8b8140101)) + (pin "10" (uuid 0da0253b-2d8e-4be8-89c3-d91561e68264)) + (pin "8" (uuid 2cccba94-6af0-4db6-9859-9c6d8766db42)) + (pin "9" (uuid 632c7690-294f-4f86-874a-68cdd78546fc)) (pin "11" (uuid 94a1c51b-a034-4b45-9e36-ba1013a3987a)) (pin "12" (uuid 203c9db7-77c7-46e3-a0b2-661683ca12ae)) (pin "13" (uuid 14c0c4df-db41-4e93-b67d-f5abc3579115)) + (pin "14" (uuid 2530330e-6f34-4a7d-96c2-412c7f6ba5a0)) + (pin "7" (uuid cd76d690-4a74-415f-98a3-e347bab9112f)) ) (symbol (lib_id "74xx:74LS245") (at 280.67 143.51 0) (unit 1) @@ -5722,6 +5809,18 @@ (property "Datasheet" "http://www.ti.com/lit/gpn/sn74ls00" (id 3) (at 349.25 205.74 0) (effects (font (size 1.27 1.27)) hide) ) + (pin "1" (uuid 0af3f124-b086-4e09-8910-867a54fb902e)) + (pin "2" (uuid 36481291-c445-4b6e-a0f5-4b847e913cc2)) + (pin "3" (uuid 06879bef-7dca-4c07-8423-61e400b818d1)) + (pin "4" (uuid b1ebe26b-706c-4647-a118-dd9e69ab3dcd)) + (pin "5" (uuid 8c974c5d-de55-4739-812c-e8c86779636d)) + (pin "6" (uuid 1db1348d-3a28-408b-9a6a-17d88088093e)) + (pin "10" (uuid 422b8b8b-73c3-442c-9f0e-50e3358cafc2)) + (pin "8" (uuid d059b2fe-df4b-4abe-aadf-3d7556a7a4c5)) + (pin "9" (uuid eebf3a91-ed09-4598-923d-0b9b08a601de)) + (pin "11" (uuid dcfc1971-7ca9-421c-a4a6-5b6591e1dbd6)) + (pin "12" (uuid 22b98e35-08c1-4501-a2b9-8bc8ab2275d9)) + (pin "13" (uuid 2b53118c-2082-4f55-ae49-9f37e43af075)) (pin "14" (uuid 86095ba6-cf04-49c5-ad87-9313ad0c0254)) (pin "7" (uuid 848470c0-08b9-4de1-9d57-0deb204c083d)) ) @@ -5741,6 +5840,18 @@ (property "Datasheet" "http://www.ti.com/lit/gpn/sn74LS32" (id 3) (at 368.3 205.74 0) (effects (font (size 1.27 1.27)) hide) ) + (pin "1" (uuid c0f1c945-6874-4014-a83d-0f6b6946c10d)) + (pin "2" (uuid c922b84c-fdae-4822-bc74-51e2f0091599)) + (pin "3" (uuid 013ba537-0898-41c0-ab98-f571839324a5)) + (pin "4" (uuid b425d8be-6f1f-42bf-aba9-0485beb0893a)) + (pin "5" (uuid 1ec025a8-272d-4aaf-8873-7ee352a7601b)) + (pin "6" (uuid d66853de-cdae-44f9-a7b7-f6fae7089b01)) + (pin "10" (uuid 69211dfd-08b1-4298-86f6-6c1c7028c2c1)) + (pin "8" (uuid d0a3dc94-fe74-4e63-a3f4-b7d8ea3146ca)) + (pin "9" (uuid 531b09b0-b58f-43ef-b797-6771a3678427)) + (pin "11" (uuid 57890c2e-f822-4e96-9441-8d5554ddcb7d)) + (pin "12" (uuid 564e2c18-086d-4c75-8c16-6524598c7a20)) + (pin "13" (uuid 065dcee7-58ad-4d5b-9d41-dfa23110c919)) (pin "14" (uuid 6de5780e-d3a1-4f4a-bcab-bc01cd2647d6)) (pin "7" (uuid 0a541000-633e-4d44-83c4-a3e87d3866a2)) ) @@ -5751,7 +5862,7 @@ (property "Reference" "C8" (id 0) (at 391.541 163.9316 0) (effects (font (size 1.27 1.27)) (justify left)) ) - (property "Value" "100n" (id 1) (at 391.541 166.243 0) + (property "Value" "0.1 µF" (id 1) (at 391.541 166.243 0) (effects (font (size 1.27 1.27)) (justify left)) ) (property "Footprint" "Apple2:Capacitor" (id 2) (at 389.5852 168.91 0) @@ -5770,7 +5881,7 @@ (property "Reference" "C7" (id 0) (at 382.651 163.9316 0) (effects (font (size 1.27 1.27)) (justify left)) ) - (property "Value" "100n" (id 1) (at 382.651 166.243 0) + (property "Value" "0.1 µF" (id 1) (at 382.651 166.243 0) (effects (font (size 1.27 1.27)) (justify left)) ) (property "Footprint" "Apple2:Capacitor" (id 2) (at 380.6952 168.91 0) @@ -5798,6 +5909,18 @@ (property "Datasheet" "http://www.ti.com/lit/gpn/sn74LS32" (id 3) (at 387.35 205.74 0) (effects (font (size 1.27 1.27)) hide) ) + (pin "1" (uuid c5143a00-e900-48a2-a82d-8db4bfd865a0)) + (pin "2" (uuid ebfee597-bd5a-4ffb-89b9-587f48338994)) + (pin "3" (uuid 09c79adc-28a8-4e51-8128-d754716a170e)) + (pin "4" (uuid b2fdd67a-60fd-4990-9077-d1b55326bdee)) + (pin "5" (uuid 827e2adc-b461-42c3-af09-816ee467a3bd)) + (pin "6" (uuid 298ce0ee-439b-4e8d-bc30-aa5fb9e369c3)) + (pin "10" (uuid 8beaf6c8-70da-4e34-a8d9-c19984e365e6)) + (pin "8" (uuid d7944521-3d5e-49c8-a8dd-41ddb103e3c7)) + (pin "9" (uuid ed7ec5e0-772b-4067-a0dd-9d4aaace7bde)) + (pin "11" (uuid bb590ecc-1d81-4a92-9ffa-f97f4e946635)) + (pin "12" (uuid eba9f422-9820-4127-8838-e1aa945452a0)) + (pin "13" (uuid aa74d806-1e5e-43f8-985e-a85442e69653)) (pin "14" (uuid 299dfa84-9cf0-4f6a-9013-42286bd3c900)) (pin "7" (uuid c2b1410a-a360-4692-88f0-3a5b1b0dcdef)) ) @@ -5808,7 +5931,7 @@ (property "Reference" "C9" (id 0) (at 381.381 213.4616 0) (effects (font (size 1.27 1.27)) (justify left)) ) - (property "Value" "C" (id 1) (at 381.381 215.773 0) + (property "Value" "0.1 µF" (id 1) (at 381.381 215.773 0) (effects (font (size 1.27 1.27)) (justify left)) ) (property "Footprint" "Apple2:Capacitor" (id 2) (at 379.4252 218.44 0) @@ -5835,6 +5958,17 @@ (pin "1" (uuid 84871e25-7c51-4425-803d-10248cf5465a)) (pin "2" (uuid 685bb84c-eae4-40c2-9c2f-cba074809328)) (pin "3" (uuid 78634ab1-d719-4068-a89b-45f47e2076c3)) + (pin "4" (uuid 567f7042-d9fb-4361-bf03-6483971112c6)) + (pin "5" (uuid 1bc6b6dc-ee63-4354-b489-92c7d6bb4211)) + (pin "6" (uuid 3f215145-bfe7-4a68-ad90-8cbdda2580bc)) + (pin "10" (uuid 95de4035-6921-4bb6-840b-8e36a0528adc)) + (pin "8" (uuid 063d5f8b-a783-4436-b79b-5b06b508d557)) + (pin "9" (uuid af14cbc5-ee2e-4b16-b94d-e470cd3e7de9)) + (pin "11" (uuid 1c3fae3d-ee70-4956-bc9d-df2fd97dff76)) + (pin "12" (uuid 92555cb8-91aa-45fb-b36e-3f927632fcd0)) + (pin "13" (uuid 623569cf-093e-4ba0-8c9c-d119eab4db50)) + (pin "14" (uuid 84d3ab77-db52-435a-a10e-c64a356624a5)) + (pin "7" (uuid e6691274-2384-4c5c-a526-e73d660c8a76)) ) (symbol (lib_id "74xx:74LS32") (at 166.37 173.99 0) (unit 2) @@ -5848,9 +5982,20 @@ (property "Datasheet" "http://www.ti.com/lit/gpn/sn74LS32" (id 3) (at 166.37 173.99 0) (effects (font (size 1.27 1.27)) hide) ) + (pin "1" (uuid 86b9f6f8-30f6-4109-b9f2-05502cabf2d1)) + (pin "2" (uuid 30f58a07-5295-444c-b944-00c318261c71)) + (pin "3" (uuid b90fac15-f593-430d-986d-f94f4f25b5e6)) (pin "4" (uuid d62e9911-44e3-43f2-a3c8-820f8a779b1b)) (pin "5" (uuid 98ce6dcc-02a8-4aac-9f23-0d5ec09c4a8b)) (pin "6" (uuid 554b12f8-26e8-4f25-90de-cda584823f93)) + (pin "10" (uuid ba25ed3c-4fad-4d9a-9150-a2a0c6b0f6ac)) + (pin "8" (uuid 64ce92d3-36ca-41fe-81f0-888ab6024bb2)) + (pin "9" (uuid 5fc6acc2-0a13-4d3e-886f-7fff983e203c)) + (pin "11" (uuid 0de695a5-ba13-49f1-b412-7b224e80c525)) + (pin "12" (uuid d41e1d4a-5bb4-4dc2-84cf-37f242167dae)) + (pin "13" (uuid 8ef92343-2136-44d8-9781-a6ea74675f54)) + (pin "14" (uuid 5894e791-846d-49cc-93b9-4235860a1728)) + (pin "7" (uuid 28015c5a-9751-45f3-a262-39894bf94f5e)) ) (symbol (lib_id "74xx:74LS32") (at 116.84 161.29 0) (unit 3) @@ -5864,9 +6009,20 @@ (property "Datasheet" "http://www.ti.com/lit/gpn/sn74LS32" (id 3) (at 116.84 161.29 0) (effects (font (size 1.27 1.27)) hide) ) + (pin "1" (uuid 5e1ada16-d441-4bb1-9830-6feb5505fa37)) + (pin "2" (uuid 73ee99cb-5d2b-42cb-a871-58c6d5ae1c45)) + (pin "3" (uuid a4d49be3-7c4d-4703-806b-3f833e5f4813)) + (pin "4" (uuid 881294d0-a3bc-4b96-bd86-02d283f0f9e7)) + (pin "5" (uuid b2d75c93-4786-4ff5-b6d7-be8255674889)) + (pin "6" (uuid a8674c98-f340-420f-a76d-5e5c09b947c2)) (pin "10" (uuid f97b357c-8f2f-40ec-95c1-e90493fbe567)) (pin "8" (uuid 0ad8c54b-ca57-4539-9f6e-a4a9cfb1c85d)) (pin "9" (uuid f9e83731-f733-40e4-9c7f-6906aaf7d750)) + (pin "11" (uuid f268e04d-92b2-479f-823d-01b8c7150451)) + (pin "12" (uuid 152af408-bc70-4346-b666-adb4ff286957)) + (pin "13" (uuid 04db0548-1aea-4ef1-87ff-7133ec0b3e85)) + (pin "14" (uuid 402cce49-a56b-47df-8c2d-3be1e145d710)) + (pin "7" (uuid aadabbc7-d36f-45be-84e6-732196d89054)) ) (symbol (lib_id "74xx:74LS32") (at 116.84 176.53 0) (unit 4) @@ -5880,9 +6036,20 @@ (property "Datasheet" "http://www.ti.com/lit/gpn/sn74LS32" (id 3) (at 116.84 176.53 0) (effects (font (size 1.27 1.27)) hide) ) + (pin "1" (uuid 22238ad7-3b76-4dd8-8931-ed0c96e725d4)) + (pin "2" (uuid 7541e0c2-4634-4e24-8a00-2661ddd213be)) + (pin "3" (uuid 6def11f1-0cee-42b0-8cf0-b29618f38d71)) + (pin "4" (uuid d0e18661-bc79-4ba2-b3db-e6c62bb2b9ff)) + (pin "5" (uuid 519f749d-7093-4709-9035-d64cf025eade)) + (pin "6" (uuid 8c9432db-4bdc-4e35-a29a-0527bb21fa1e)) + (pin "10" (uuid 60afb76b-d313-4f08-ae1e-4f0b1ccaa3d9)) + (pin "8" (uuid 611a300a-c234-4dcf-abe4-3d5788490b07)) + (pin "9" (uuid 224a70ee-268f-4d96-babe-de78686ad59b)) (pin "11" (uuid c40f273a-9dba-43e0-822d-6ff127715a8a)) (pin "12" (uuid bf19533b-16de-47f5-a9b4-645f328f4dfe)) (pin "13" (uuid 55488c96-5c7c-42e8-84b2-a8e477480d1b)) + (pin "14" (uuid 15a47401-5c1b-4090-850f-5a486fc4248e)) + (pin "7" (uuid 066f5967-c4fb-4809-9a8c-87bedb61ee98)) ) (symbol (lib_id "Jumper:Jumper_2_Bridged") (at 170.18 27.94 0) (unit 1) @@ -6324,31 +6491,31 @@ (reference "#PWR0103") (unit 1) (value "GND") (footprint "") ) (path "/00000000-0000-0000-0000-00005fb85911" - (reference "C1") (unit 1) (value "100n") (footprint "Apple2:Capacitor") + (reference "C1") (unit 1) (value "0.1 µF") (footprint "Apple2:Capacitor") ) (path "/00000000-0000-0000-0000-00005fb849d8" - (reference "C2") (unit 1) (value "100n") (footprint "Apple2:Capacitor") + (reference "C2") (unit 1) (value "0.1 µF") (footprint "Apple2:Capacitor") ) (path "/00000000-0000-0000-0000-00005fb81404" - (reference "C3") (unit 1) (value "C") (footprint "Apple2:Capacitor") + (reference "C3") (unit 1) (value "0.1 µF") (footprint "Apple2:Capacitor") ) (path "/00000000-0000-0000-0000-00005fb82906" - (reference "C4") (unit 1) (value "C") (footprint "Apple2:Capacitor") + (reference "C4") (unit 1) (value "0.1 µF") (footprint "Apple2:Capacitor") ) (path "/00000000-0000-0000-0000-00005fb8694d" - (reference "C5") (unit 1) (value "100n") (footprint "Apple2:Capacitor") + (reference "C5") (unit 1) (value "0.1 µF") (footprint "Apple2:Capacitor") ) (path "/00000000-0000-0000-0000-00005fb87862" - (reference "C6") (unit 1) (value "100n") (footprint "Apple2:Capacitor") + (reference "C6") (unit 1) (value "0.1 µF") (footprint "Apple2:Capacitor") ) (path "/00000000-0000-0000-0000-000060a87587" - (reference "C7") (unit 1) (value "100n") (footprint "Apple2:Capacitor") + (reference "C7") (unit 1) (value "0.1 µF") (footprint "Apple2:Capacitor") ) (path "/00000000-0000-0000-0000-000060a58951" - (reference "C8") (unit 1) (value "100n") (footprint "Apple2:Capacitor") + (reference "C8") (unit 1) (value "0.1 µF") (footprint "Apple2:Capacitor") ) (path "/00000000-0000-0000-0000-000060c3a67b" - (reference "C9") (unit 1) (value "C") (footprint "Apple2:Capacitor") + (reference "C9") (unit 1) (value "0.1 µF") (footprint "Apple2:Capacitor") ) (path "/00000000-0000-0000-0000-00005fa0a8c3" (reference "J0") (unit 1) (value "Apple II Expansion Bus") (footprint "Apple2:Apple II Expansion Edge Connector") diff --git a/Hardware/Apple2IORPi.pdf b/Hardware/Apple2IORPi.pdf index d144617..93b3b3c 100644 Binary files a/Hardware/Apple2IORPi.pdf and b/Hardware/Apple2IORPi.pdf differ diff --git a/Hardware/BOM.csv b/Hardware/BOM.csv new file mode 100644 index 0000000..513882a --- /dev/null +++ b/Hardware/BOM.csv @@ -0,0 +1,12 @@ +Part,Quantity,Supplier Part #,Supplier +74LS32,2,595-SN74LS32N,Mouser +74LS00,1,595-SN74LS00N,Mouser +74LS245,1,595-SN74LS245N,Mouser +74LVC245,2,595-SN74LVC245AN,Mouser +74LVC374,2,595-SN74LVC374AN,Mouser +28C64B,1,556-AT28C64B15PU,Mouser +0.1µF Capacitor,9,594-K104K15X7RF5TH5,Mouser +2x20 GPIO Female Header,1,2222,Adafruit +14 Pin DIP Socket,3,571-1-2199298-3,Mouser +20 Pin DIP Socket,5,571-1-2199298-6,Mouser +28 Pin DIP Socket,1,571-1-2199299-2,Mouser \ No newline at end of file diff --git a/Hardware/BOM.pdf b/Hardware/BOM.pdf new file mode 100644 index 0000000..fd22027 Binary files /dev/null and b/Hardware/BOM.pdf differ diff --git a/LICENSE b/LICENSE index 31ffda1..3d7f409 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2020-2022 Terence J. Boldt +Copyright (c) 2020-2024 Terence J. Boldt Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index d59e97a..59417b1 100644 --- a/README.md +++ b/README.md @@ -1,25 +1,56 @@ # Apple2-IO-RPi +Apple II expansion card using a Raspberry Pi for I/O -1. See the [upstream repo](https://github.com/tjboldt/Apple2-IO-RPi) for the original, full info. +![Image of Board](/Hardware/Apple2IORPi.jpg) -2. This fork is based on [A2Pico](https://github.com/oliverschmidt/a2pico). +## Purpose +The purpose of this project is to provide I/O for an Apple II series 8 bit computer via a Raspberry Pi Zero 2 W which is powered by the Apple II expansion bus. This includes using the attached RPi Zero 2 W for it's storage, network and processor to provide new functionality for the Apple II. -## Installing +## Features +1. Boot message which waits for RPi to be ready +2. ProDOS bootable drive from image stored on RPi +3. Linux bash shell to the RPi from the Apple II including some VT100 support via `-SHELL` from ProDOS +4. Load binary files directly from the RPi to the II (via dynamic virtual drive of current working directory on the RPi) +5. Update Apple II firmware in place from image on RPi (note, this is done per slot) +6. Supports two drive images at the same time +7. Supports "RPI" command from BASIC to execute Linux commands from the command prompt or inside BASIC programs: `10 PRINT CHR$(4);"RPI ls -al /"` -1. Flash [Apple2-IO-RPi.uf2](https://github.com/oliverschmidt/apple2-io-rpi/releases/latest/download/Apple2-IO-RPi.uf2) to the Raspberry Pi Pico. +## Project Status -2. Execute steps __5.)__ - __8.)__ and __10.)__ on [Setup new card from scratch](https://github.com/tjboldt/Apple2-IO-RPi/discussions/63). +### Classic Hardware +So far, this is still a project and not a finished product. The current prototype is on the sixth revision. I have sold about 60 boards including previous prototypes. There are more than 100 in the wild between self made and ones purchased in places like eBay that were made by others. The sixth prototype is functionally equivalent to the fifth, other than a new jumper to select internal/external power. -3. Execute `wget --no-cache -O - https://raw.githubusercontent.com/oliverschmidt/apple2-io-rpi/main/RaspberryPi/setup.sh | bash` +The card enables the Apple II to boot from and write to virtual hard drive images stored on the RPi in any slot (except slot 3), execute Linux commands from Applesoft BASIC and run a bash shell with VT100 emulation. The code has very few tests and is incomplete. Note that currently the firmware assumes an 80 column card is in slot 3 and than you have lowercase support. Most development has been done with an enhanced Apple //e with the card in slot 7. If you have other drive controllers earlier in the boot cycle, you can still boot from the Apple2-IO-RPi. For example, if the card was in slot 4, you could type `PR#4` from the BASIC prompt to boot the card. Note that the Raspberry Pi Zero W (and W 2) consume 170 - 250 mA and there is only 500 mA available to all expansion slots according to Apple. It is not recommended to have a lot of other cards in the system at the same time. With the sixth revision of the prototype, it is possible to remove the power jumper and run the RPi on an external USB power source. If configured for external power, note that the card's firmware will hang on boot without USB power on as the latch chips are powered by the 3.3V output of the RPi. -## Using +If you have a problem or idea for enhancement, log an issue [here](https://github.com/tjboldt/Apple2-IO-RPi/issues) or start a [discussion](https://github.com/tjboldt/Apple2-IO-RPi/discussions/categories/general). I recommend starring/watching the project for updates on GitHub. You are welcome to fork the project and submit pull requests which I will review. The latest version has an in-memory virtual drive representing current working directory in Linux for ease of copying files between Linux and ProDOS when the drive 1 is not specified as a file. -1. Access the two ProDOS 8 drives either via cold boot or `PR#n`. +### Pico Hardware +Ralle Palaveev has a version of the hardware that uses a RPi Pico to handle firmware and communications to the host over USB. -2. Make sure to check out `SHELL` and `RPI.COMMAND` in drive 1. +## Roadmap +See [List of issues tagged roadmap](https://github.com/tjboldt/Apple2-IO-RPi/issues?q=is%3Aissue+is%3Aopen+label%3Aroadmap+author%3Atjboldt) -## Building +## Setup on classic hardware +[Setup card from scratch](https://github.com/tjboldt/Apple2-IO-RPi/discussions/63) -1. Build the project in `/RaspberryPiPico` (requires the [Raspberry Pico C/C++ SDK](https://www.raspberrypi.com/documentation/microcontrollers/c_sdk.html)). +[Setup if you received a complete board from me](https://github.com/tjboldt/Apple2-IO-RPi/discussions/64) -2. Execute `go build` in `/RaspberryPi/apple2driver` (requires [Go](https://go.dev/)). +[Update to latest](https://github.com/tjboldt/Apple2-IO-RPi/discussions/65) + +## Setup on Pico based hardware +[Setup card with Pico hardware](https://github.com/tjboldt/Apple2-IO-RPi/discussions/162) + +## Contributions/Thanks +- Hans Hübner ([@hanshuebner](https://github.com/hanshuebner)) for help cleaning up schematics +- Scott ([@figital](https://github.com/figital)) for assembling early prototypes and recommending the AT28C64B chip +- Brokencodez for help with 3.3V conversion +- David Schmenk ([@dschmenk](https://github.com/dschmenk)) for creating his Apple2Pi project, proving that Raspberry Pi can be powered by the Apple II expansion bus +- Wyatt Wong ([@wyatt-wong](https://github.com/wyatt-wong)) for testing with multiple cards +- ([@Abysmal](https://github.com/Abysmal)) for shell and rpi.command testing +- ([@bfranske](https://github.com/bfranske)) for suggesting adding the 5V jumper +- Tim Boldt ([@timboldt](https://github.com/timboldt)) for recommending removing sysfs based GPIO code +- Oliver Schmidt ([@oliverschmidt])(https://github.com/oliverschmidt/apple2-io-rpi/)) for writing the Pico PIO and firmware +- Ralle Palaveev ([@rallepalaveev](https://github.com/rallepalaveev/a2pico)) for Pico hardware design + +## Similar Project +If you prefer having Apple II peripherals control a Raspberry Pi rather than simply using the Raspberry Pi to provide storage, network access and processing to the Apple II, have a look at David Schmenk's excellent [Apple2Pi](https://github.com/dschmenk/apple2pi) project. I am often asked about differences between these two projects. They are similar in some ways but essentially opposite. The Apple2Pi is meant for the primary machine to be the RPi, using the Apple II for it's peripherals. The Apple2-IO-RPi is meant to have the Apple II as the primary machine and just use the RPi for its processing, storage and network. \ No newline at end of file diff --git a/RaspberryPi/Apple2-IO-RPi.hdv b/RaspberryPi/Apple2-IO-RPi.hdv deleted file mode 100644 index 178550d..0000000 Binary files a/RaspberryPi/Apple2-IO-RPi.hdv and /dev/null differ diff --git a/RaspberryPi/apple2driver/a2io/communication.go b/RaspberryPi/apple2driver/a2io/communication.go index 056b0b8..c078b7d 100644 --- a/RaspberryPi/apple2driver/a2io/communication.go +++ b/RaspberryPi/apple2driver/a2io/communication.go @@ -1,4 +1,4 @@ -// Copyright Terence J. Boldt (c)2021-2022 +// Copyright Terence J. Boldt (c)2021-2024 // Use of this source code is governed by an MIT // license that can be found in the LICENSE file. @@ -15,7 +15,7 @@ type A2Io interface { WriteString(outString string) error WriteBlock(buffer []byte) error WriteBuffer(buffer []byte) error - ReadByte() (byte, error) + ReadByte(noDelay ...bool) (byte, error) ReadString() (string, error) ReadBlock(buffer []byte) error SendCharacter(character byte) diff --git a/RaspberryPi/apple2driver/a2io/gpio.go b/RaspberryPi/apple2driver/a2io/gpio.go index 09d6bd6..12db887 100644 --- a/RaspberryPi/apple2driver/a2io/gpio.go +++ b/RaspberryPi/apple2driver/a2io/gpio.go @@ -1,4 +1,4 @@ -// Copyright Terence J. Boldt (c)2020-2022 +// Copyright Terence J. Boldt (c)2020-2024 // Use of this source code is governed by an MIT // license that can be found in the LICENSE file. @@ -154,17 +154,26 @@ func (a2 A2Gpio) WriteString(outString string) error { } // ReadByte reads a byte from the Apple II via Raspberry Pi's GPIO ports -func (a2 A2Gpio) ReadByte() (byte, error) { +func (a2 A2Gpio) ReadByte(noDelay ...bool) (byte, error) { // let the Apple II know we are ready to read outRead.Low() // wait for the Apple II to write startTime := time.Now() + lastSleepTime := time.Now() + sleepDuration := 10 for inWrite.Read() == 1 { if time.Since(startTime) > edgeTimeout { outRead.High() return 0, errors.New("timed out reading byte -- write stuck high") } + if time.Since(lastSleepTime) > edgeTimeout/10 { + if len(noDelay) == 0 || !noDelay[0] { + sleepDuration *= 3; + } + time.Sleep(time.Millisecond * time.Duration(sleepDuration)); + lastSleepTime = time.Now() + } } // get a nibble of data @@ -211,10 +220,19 @@ func (a2 A2Gpio) ReadByte() (byte, error) { // wait for the Apple II to finish writing //fmt.Printf("wait for the Apple II to finish writing\n") startTime = time.Now() + lastSleepTime = time.Now() + sleepDuration = 10 for inWrite.Read() == 0 { if time.Since(startTime) > edgeTimeout { return 0, errors.New("timed out reading byte -- write stuck low") } + if time.Since(lastSleepTime) > edgeTimeout/10 { + if len(noDelay) == 0 || !noDelay[0] { + sleepDuration *= 3; + } + time.Sleep(time.Millisecond * time.Duration(sleepDuration)); + lastSleepTime = time.Now() + } } return data, nil @@ -230,11 +248,18 @@ func (a2 A2Gpio) WriteByte(data byte) error { // wait for the Apple II to be ready to read startTime := time.Now() + lastSleepTime := time.Now() + sleepDuration := 10 for inRead.Read() == 1 { if time.Since(startTime) > edgeTimeout { outWrite.High() return errors.New("timed out writing byte -- read stuck high") } + if time.Since(lastSleepTime) > edgeTimeout/10 { + sleepDuration *= 3; + time.Sleep(time.Millisecond * time.Duration(sleepDuration)); + lastSleepTime = time.Now() + } } if ((data & 128) >> 7) == 1 { @@ -291,11 +316,18 @@ func (a2 A2Gpio) WriteByte(data byte) error { // wait for the Apple II to finsih reading //fmt.Printf("wait for the Apple II to finsih reading\n") startTime = time.Now() + lastSleepTime = time.Now() + sleepDuration = 10 for inRead.Read() == 0 { if time.Since(startTime) > edgeTimeout { outWrite.High() return errors.New("timed out writing byte -- read stuck low") } + if time.Since(lastSleepTime) > edgeTimeout/10 { + sleepDuration *= 3; + time.Sleep(time.Millisecond * time.Duration(sleepDuration)); + lastSleepTime = time.Now() + } } // let the Apple II know we are done writing diff --git a/RaspberryPi/apple2driver/a2io/mockio.go b/RaspberryPi/apple2driver/a2io/mockio.go index fed6172..1edaa72 100644 --- a/RaspberryPi/apple2driver/a2io/mockio.go +++ b/RaspberryPi/apple2driver/a2io/mockio.go @@ -1,4 +1,4 @@ -// Copyright Terence J. Boldt (c)2021-2022 +// Copyright Terence J. Boldt (c)2021-2024 // Use of this source code is governed by an MIT // license that can be found in the LICENSE file. @@ -66,7 +66,7 @@ func (mockIo MockIo) WriteBuffer(buffer []byte) error { } // ReadByte mocks reading a byte from the Apple II -func (mockIo MockIo) ReadByte() (byte, error) { +func (mockIo MockIo) ReadByte(noDelay ...bool) (byte, error) { b := mockIo.Data.BytesToRead[mockIo.Data.NumberBytesRead] mockIo.Data.NumberBytesRead++ return b, mockIo.Data.ErrorToThrow diff --git a/RaspberryPi/apple2driver/a2io/userio.go b/RaspberryPi/apple2driver/a2io/userio.go index d590125..c0fdfcc 100644 --- a/RaspberryPi/apple2driver/a2io/userio.go +++ b/RaspberryPi/apple2driver/a2io/userio.go @@ -1,4 +1,4 @@ -// Copyright Terence J. Boldt (c)2021-2022 +// Copyright Terence J. Boldt (c)2021-2024 // Use of this source code is governed by an MIT // license that can be found in the LICENSE file. @@ -55,7 +55,7 @@ func (userIo UserIo) WriteBuffer(buffer []byte) error { } // ReadByte simulates reading to the Apple II but uses stdin instead -func (userIo UserIo) ReadByte() (byte, error) { +func (userIo UserIo) ReadByte(noDelay ...bool) (byte, error) { fmt.Printf("ReadByte: ") var b byte fmt.Scanf("%x", &b) diff --git a/RaspberryPi/apple2driver/a2io/vt100.go b/RaspberryPi/apple2driver/a2io/vt100.go index 51c4693..b64e5e7 100644 --- a/RaspberryPi/apple2driver/a2io/vt100.go +++ b/RaspberryPi/apple2driver/a2io/vt100.go @@ -1,4 +1,4 @@ -// Copyright Terence J. Boldt (c)2021-2022 +// Copyright Terence J. Boldt (c)2021-2024 // Use of this source code is governed by an MIT // license that can be found in the LICENSE file. @@ -220,7 +220,7 @@ func sendCharacter(comm A2Io, b byte) { } func readCharacter(comm A2Io) (string, error) { - b, err := comm.ReadByte() + b, err := comm.ReadByte(true) var s = string(b) if err == nil { if applicationMode { @@ -234,7 +234,7 @@ func readCharacter(comm A2Io) (string, error) { case 0x08: // left s = "\033OD" case 0x0d: // return - s = string(byte(0x0a)) + s = string(byte(0x0d)) } } else { switch b { @@ -247,7 +247,7 @@ func readCharacter(comm A2Io) (string, error) { case 0x08: // left s = "\033[D" case 0x0d: // return - s = string(byte(0x0a)) + s = string(byte(0x0d)) } } } diff --git a/RaspberryPi/apple2driver/drive/drive.go b/RaspberryPi/apple2driver/drive/drive.go new file mode 100644 index 0000000..e7f637e --- /dev/null +++ b/RaspberryPi/apple2driver/drive/drive.go @@ -0,0 +1,36 @@ +// Copyright Terence J. Boldt (c)2023-2024 +// Use of this source code is governed by an MIT +// license that can be found in the LICENSE file. + +// This file is used for handling ProDOS image generation + +package drive + +import ( + "fmt" + "os" + "path/filepath" + + "github.com/tjboldt/ProDOS-Utilities/prodos" +) + +// GetDriveImageDirectory gets the default directory for driveimage +func GetDriveImageDirectory() (string, error) { + exec, err := os.Executable() + if err != nil { + fmt.Printf("ERROR: %s", err.Error()) + return "", err + } + driveImageDirectory := filepath.Join(filepath.Dir(filepath.Dir(exec)), "driveimage") + + return driveImageDirectory, nil +} + +// GenerateDriveFromDirectory regenerates a ProDOS drive from a host directory +func GenerateDriveFromDirectory(volumeName string, directory string) (prodos.ReaderWriterAt, error) { + drive := prodos.NewMemoryFile(0x2000000) + fmt.Printf("Generating Drive in memory from: %s\n", directory) + prodos.CreateVolume(drive, volumeName, 65535) + err := prodos.AddFilesFromHostDirectory(drive, directory, "/"+volumeName+"/", true) + return drive, err +} diff --git a/RaspberryPi/apple2driver/driver.go b/RaspberryPi/apple2driver/driver.go index 7640b9e..0a4aa92 100644 --- a/RaspberryPi/apple2driver/driver.go +++ b/RaspberryPi/apple2driver/driver.go @@ -1,4 +1,4 @@ -// Copyright Terence J. Boldt (c)2020-2022 +// Copyright Terence J. Boldt (c)2020-2024 // Use of this source code is governed by an MIT // license that can be found in the LICENSE file. @@ -19,8 +19,10 @@ import ( "go.bug.st/serial" "github.com/tjboldt/Apple2-IO-RPi/RaspberryPi/apple2driver/a2io" + "github.com/tjboldt/Apple2-IO-RPi/RaspberryPi/apple2driver/drive" "github.com/tjboldt/Apple2-IO-RPi/RaspberryPi/apple2driver/handlers" "github.com/tjboldt/Apple2-IO-RPi/RaspberryPi/apple2driver/info" + "github.com/tjboldt/ProDOS-Utilities/prodos" ) const resetCommand = 0 @@ -35,7 +37,13 @@ const menuCommand = 8 const shellCommand = 9 func main() { - drive1, drive2, cdc := getFlags() + drive1Name, drive2Name, cdc := getFlags() + drive1, drive2 := getDriveFiles(drive1Name, drive2Name) + + driveImageDir, err := drive.GetDriveImageDirectory() + if err == nil { + os.Chdir(driveImageDir) + } fmt.Printf("Starting Apple II RPi v%s...\n", info.Version) @@ -49,15 +57,12 @@ func main() { handlers.SetCommunication(comm) comm.Init() - lastCommandTime := time.Now() - // In case Apple II is waiting, send 0 byte to start comm.WriteByte(0) for { command, err := comm.ReadByte() if err == nil { - lastCommandTime = time.Now() switch command { case resetCommand: handlers.ResetCommand() @@ -68,7 +73,7 @@ func main() { case getTimeCommand: handlers.GetTimeCommand() case execCommand: - handlers.ExecCommand() + handlers.ExecCommand(&drive1, &drive2) case loadFileCommand: handlers.LoadFileCommand() case menuCommand: @@ -77,20 +82,20 @@ func main() { handlers.ShellCommand() } // the A2Io interface should be extended in one way or another - // to encapsulate this, e.g. by a ReadByte variant / parameter + // to encapsulate this, e.g. by a ReadByte variant / parameter } else if cdc { var portErr *serial.PortError if errors.As(err, &portErr) && portErr.Code() == serial.PortClosed { comm.Init() } // temporary workaround for busy wait loop heating up the RPi - } else if time.Since(lastCommandTime) > time.Millisecond*100 { - time.Sleep(time.Millisecond * 100) + } else { + time.Sleep(time.Millisecond * 200) } } } -func getFlags() (*os.File, *os.File, bool) { +func getFlags() (string, string, bool) { var drive1Name string var drive2Name string var cdc bool @@ -99,48 +104,43 @@ func getFlags() (*os.File, *os.File, bool) { path := filepath.Dir(execName) path = filepath.Join(path, "..") path, _ = filepath.EvalSymlinks(path) - defaultFileName := filepath.Join(path, "Apple2-IO-RPi.hdv") flag.StringVar(&drive1Name, "d1", "", "A ProDOS format drive image for drive 1") - flag.StringVar(&drive2Name, "d2", defaultFileName, "A ProDOS format drive image for drive 2 and will be used for drive 1 if drive 1 empty") + flag.StringVar(&drive2Name, "d2", "", "A ProDOS format drive image for drive 2 and will be used for drive 1 if drive 1 empty") flag.BoolVar(&cdc, "cdc", false, "Use ACM CDC serial device") flag.Parse() - var drive1 *os.File - var drive2 *os.File + return drive1Name, drive2Name, cdc +} + +func getDriveFiles(drive1Name string, drive2Name string) (prodos.ReaderWriterAt, prodos.ReaderWriterAt) { + var drive1 prodos.ReaderWriterAt + var drive2 prodos.ReaderWriterAt var err error if len(drive1Name) > 0 { fmt.Printf("Opening Drive 1 as: %s\n", drive1Name) drive1, err = os.OpenFile(drive1Name, os.O_RDWR, 0755) - if err != nil { - fmt.Printf("ERROR: %s", err.Error()) - os.Exit(1) - } + logAndExitOnErr(err) + } else { + directory, err := drive.GetDriveImageDirectory() + logAndExitOnErr(err) + drive1, err = drive.GenerateDriveFromDirectory("APPLE2.IO.RPI", directory) + logAndExitOnErr(err) } if len(drive2Name) > 0 { - if drive1 == nil { - fmt.Printf("Opening Drive 1 as: %s because Drive 1 was empty\n", drive2Name) - drive1, err = os.OpenFile(drive2Name, os.O_RDWR, 0755) - if err != nil { - fmt.Printf("ERROR: %s", err.Error()) - os.Exit(1) - } - } else { - fmt.Printf("Opening Drive 2 as: %s\n", drive2Name) - drive2, err = os.OpenFile(drive2Name, os.O_RDWR, 0755) - if err != nil { - fmt.Printf("ERROR: %s", err.Error()) - os.Exit(1) - } - } - } - - if drive1 == nil { - flag.PrintDefaults() - os.Exit(1) + fmt.Printf("Opening Drive 2 as: %s\n", drive2Name) + drive2, err = os.OpenFile(drive2Name, os.O_RDWR, 0755) + logAndExitOnErr(err) } return drive1, drive2, cdc } + +func logAndExitOnErr(err error) { + if err != nil { + fmt.Printf("ERROR: %s", err.Error()) + os.Exit(1) + } +} diff --git a/RaspberryPi/apple2driver/go.mod b/RaspberryPi/apple2driver/go.mod index 132cc51..47b195f 100644 --- a/RaspberryPi/apple2driver/go.mod +++ b/RaspberryPi/apple2driver/go.mod @@ -3,8 +3,9 @@ module github.com/tjboldt/Apple2-IO-RPi/RaspberryPi/apple2driver go 1.16 require ( - github.com/creack/pty v1.1.18 + github.com/creack/pty v1.1.21 github.com/stianeikeland/go-rpio/v4 v4.6.0 - github.com/tjboldt/ProDOS-Utilities v0.3.0 + github.com/tjboldt/ProDOS-Utilities v0.4.8 + golang.org/x/image v0.14.0 // indirect go.bug.st/serial v1.3.5 ) diff --git a/RaspberryPi/apple2driver/go.sum b/RaspberryPi/apple2driver/go.sum index 1648788..aa982fe 100644 --- a/RaspberryPi/apple2driver/go.sum +++ b/RaspberryPi/apple2driver/go.sum @@ -1,6 +1,41 @@ -github.com/creack/pty v1.1.17 h1:QeVUsEDNrLBW4tMgZHvxy18sKtr6VI492kBhUfhDJNI= -github.com/creack/pty v1.1.17/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= +github.com/creack/pty v1.1.21 h1:1/QdRyBaHHJP61QkWMXlOIBfsgdDeeKfK8SYVUWJKf0= +github.com/creack/pty v1.1.21/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= github.com/stianeikeland/go-rpio/v4 v4.6.0 h1:eAJgtw3jTtvn/CqwbC82ntcS+dtzUTgo5qlZKe677EY= github.com/stianeikeland/go-rpio/v4 v4.6.0/go.mod h1:A3GvHxC1Om5zaId+HqB3HKqx4K/AqeckxB7qRjxMK7o= -github.com/tjboldt/ProDOS-Utilities v0.3.0 h1:nlBvrGtvAV7KBfxiSkXHdosmDLEYAXMq955P8NL0qiE= -github.com/tjboldt/ProDOS-Utilities v0.3.0/go.mod h1:eBQRf0U+goRbBOxzFCwRW+FZmALC8dfYaqCwcqwzi74= +github.com/tjboldt/ProDOS-Utilities v0.4.8 h1:hW4gHliqTjKCep6jXX4Z59pkVhB+OyVJPWM5X3N+ybs= +github.com/tjboldt/ProDOS-Utilities v0.4.8/go.mod h1:tk5Cd5WSoogNF+XRMjEPuWeU1vVuqdJexn23s5ev/fU= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/image v0.13.0/go.mod h1:6mmbMOeV28HuMTgA6OSRkdXKYw/t5W9Uwn2Yv1r3Yxk= +golang.org/x/image v0.14.0 h1:tNgSxAFe3jC4uYqvZdTr84SZoM1KfwdC9SKIFrLjFn4= +golang.org/x/image v0.14.0/go.mod h1:HUYqC05R2ZcZ3ejNQsIHQDQiwWM4JBqmm6MKANTp4LE= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/RaspberryPi/apple2driver/handlers/block.go b/RaspberryPi/apple2driver/handlers/block.go index 2989699..0ee8414 100644 --- a/RaspberryPi/apple2driver/handlers/block.go +++ b/RaspberryPi/apple2driver/handlers/block.go @@ -1,4 +1,4 @@ -// Copyright Terence J. Boldt (c)2020-2022 +// Copyright Terence J. Boldt (c)2020-2024 // Use of this source code is governed by an MIT // license that can be found in the LICENSE file. @@ -8,13 +8,12 @@ package handlers import ( "fmt" - "os" "github.com/tjboldt/ProDOS-Utilities/prodos" ) // ReadBlockCommand handles requests to read ProDOS blocks -func ReadBlockCommand(drive1 *os.File, drive2 *os.File) { +func ReadBlockCommand(drive1 prodos.ReaderWriterAt, drive2 prodos.ReaderWriterAt) (int, error) { blockLow, _ := comm.ReadByte() blockHigh, _ := comm.ReadByte() var driveUnit byte @@ -24,7 +23,7 @@ func ReadBlockCommand(drive1 *os.File, drive2 *os.File) { if err != nil { fmt.Printf("Failed to read block") - return + return 0, err } file := drive1 @@ -35,28 +34,30 @@ func ReadBlockCommand(drive1 *os.File, drive2 *os.File) { driveNumber = 2 } - slotNumber := driveUnit &0x7F >> 4 + slotNumber := driveUnit & 0x7F >> 4 block := int(blockHigh)*256 + int(blockLow) fmt.Printf("Read block %04X in slot %d, drive %d...", block, slotNumber, driveNumber) - buffer,err := prodos.ReadBlock(file, block) + buffer, err := prodos.ReadBlock(file, block) if err != nil { - fmt.Printf("failed %s\n",err) - return + fmt.Printf("failed %s\n", err) + return 0, err } err = comm.WriteBlock(buffer) if err == nil { fmt.Printf("succeeded\n") } else { - fmt.Printf("failed %s\n",err) + fmt.Printf("failed %s\n", err) } + + return block, nil } // WriteBlockCommand handles requests to write ProDOS blocks -func WriteBlockCommand(drive1 *os.File, drive2 *os.File) { +func WriteBlockCommand(drive1 prodos.ReaderWriterAt, drive2 prodos.ReaderWriterAt) error { blockLow, _ := comm.ReadByte() blockHigh, _ := comm.ReadByte() @@ -66,7 +67,7 @@ func WriteBlockCommand(drive1 *os.File, drive2 *os.File) { driveUnit, err = comm.ReadByte() if err != nil { fmt.Printf("Failed to write block") - return + return err } file := drive1 @@ -81,14 +82,14 @@ func WriteBlockCommand(drive1 *os.File, drive2 *os.File) { block := int(blockHigh)*256 + int(blockLow) - slotNumber := driveUnit &0x7F >> 4 + slotNumber := driveUnit & 0x7F >> 4 fmt.Printf("Write block %04X in slot %d, drive %d...", block, slotNumber, driveNumber) err = comm.ReadBlock(buffer) if err != nil { - fmt.Printf("failed %s\n",err) - return + fmt.Printf("failed %s\n", err) + return err } fmt.Printf("...") @@ -98,4 +99,6 @@ func WriteBlockCommand(drive1 *os.File, drive2 *os.File) { } else { fmt.Printf("failed\n") } + + return nil } diff --git a/RaspberryPi/apple2driver/handlers/communication.go b/RaspberryPi/apple2driver/handlers/communication.go index e1ea36b..d237191 100644 --- a/RaspberryPi/apple2driver/handlers/communication.go +++ b/RaspberryPi/apple2driver/handlers/communication.go @@ -1,4 +1,4 @@ -// Copyright Terence J. Boldt (c)2021-2022 +// Copyright Terence J. Boldt (c)2021-2024 // Use of this source code is governed by an MIT // license that can be found in the LICENSE file. diff --git a/RaspberryPi/apple2driver/handlers/exec.go b/RaspberryPi/apple2driver/handlers/exec.go index 3bc69d5..11bd591 100644 --- a/RaspberryPi/apple2driver/handlers/exec.go +++ b/RaspberryPi/apple2driver/handlers/exec.go @@ -1,4 +1,4 @@ -// Copyright Terence J. Boldt (c)2020-2022 +// Copyright Terence J. Boldt (c)2020-2024 // Use of this source code is governed by an MIT // license that can be found in the LICENSE file. @@ -16,14 +16,16 @@ import ( "strings" "time" + "github.com/tjboldt/Apple2-IO-RPi/RaspberryPi/apple2driver/drive" "github.com/tjboldt/Apple2-IO-RPi/RaspberryPi/apple2driver/info" + "github.com/tjboldt/ProDOS-Utilities/prodos" ) var forceLowercase = false var execTimeoutSeconds = int(10) // ExecCommand handles requests for the Apple II executing Linux commands -func ExecCommand() { +func ExecCommand(drive1 *prodos.ReaderWriterAt, drive2 *prodos.ReaderWriterAt) { workingDirectory, err := os.Getwd() if err != nil { workingDirectory = "/home" @@ -74,6 +76,10 @@ func ExecCommand() { a2timeout(linuxCommand) return } + if strings.HasPrefix(linuxCommand, "a2drive") { + a2drive(linuxCommand, drive1, drive2) + return + } if linuxCommand == "a2prompt" { prompt := fmt.Sprintf("A2IO:%s ", workingDirectory) comm.WriteString(prompt) @@ -160,6 +166,7 @@ func a2help() { "a2timeout - seconds to timeout commands\r" + "A2LOWER - force lowercase for II+\r" + "a2lower - disable force lowercase\r" + + "a2drive - change drive images\r" + "\r") } @@ -182,6 +189,89 @@ func a2timeout(linuxCommand string) { } } +func a2drive(linuxCommand string, drive1 *prodos.ReaderWriterAt, drive2 *prodos.ReaderWriterAt) { + params := strings.Fields(linuxCommand) + + if len(params) < 3 { + showa2DriveUsage() + return + } + + driveNumber, err := strconv.ParseInt(params[1], 10, 32) + if err != nil { + comm.WriteString("\rFailed to parse drive number\r") + showa2DriveUsage() + return + } + + if params[2] == "regen" { + directory, err := drive.GetDriveImageDirectory() + if err != nil { + comm.WriteString("\rFailed to parse source directory\r") + return + } + if len(params) > 3 { + directory = params[3] + } + switch driveNumber { + case 1: + *drive1, err = drive.GenerateDriveFromDirectory("APPLE2.IO.RPI", directory) + if err != nil { + comm.WriteString("\rFailed to regenerate drive 1\r") + return + } + comm.WriteString("\rDrive 1 regenerated\r") + case 2: + *drive2, err = drive.GenerateDriveFromDirectory("APPLE2.IO.RPI2", directory) + if err != nil { + comm.WriteString("\rFailed to regenerate drive 2\r") + return + } + comm.WriteString("\rDrive 2 regenerated\r") + default: + comm.WriteString("\rOnly drives 1 or 2 are supported\r") + showa2DriveUsage() + return + } + } + + if params[2] == "load" { + + if len(params) != 4 { + comm.WriteString("\rMust specify a drive image to load\r") + showa2DriveUsage() + return + } + + imageFileName := params[3] + + switch driveNumber { + case 1: + *drive1, err = os.OpenFile(imageFileName, os.O_RDWR, 0755) + if err != nil { + comm.WriteString("\rFailed to load drive 1\r") + return + } + comm.WriteString("\rDrive 1 loaded\r") + case 2: + *drive2, err = os.OpenFile(imageFileName, os.O_RDWR, 0755) + if err != nil { + comm.WriteString("\rFailed to load drive 2\r") + return + } + comm.WriteString("\rDrive 2 loaded\r") + default: + comm.WriteString("\rOnly drives 1 or 2 are supported\r") + showa2DriveUsage() + return + } + } +} + +func showa2DriveUsage() { + comm.WriteString("\rUsage: a2drive DRIVENUMBER [regen [PATH] | load FILENAME]\rExamples: a2drive 1 regen ~/Apple2-IO-RPi/RaspberryPi/driveimage\r a2drive 2 load /home/pi/Games.hdv\r") +} + func a2lower(enable bool) { forceLowercase = enable comm.WriteString(fmt.Sprintf("All commands will be converted to lowercase: %t\r", forceLowercase)) diff --git a/RaspberryPi/apple2driver/handlers/getTime.go b/RaspberryPi/apple2driver/handlers/getTime.go index 9d82baa..b04d730 100644 --- a/RaspberryPi/apple2driver/handlers/getTime.go +++ b/RaspberryPi/apple2driver/handlers/getTime.go @@ -1,4 +1,4 @@ -// Copyright Terence J. Boldt (c)2020-2022 +// Copyright Terence J. Boldt (c)2020-2024 // Use of this source code is governed by an MIT // license that can be found in the LICENSE file. diff --git a/RaspberryPi/apple2driver/handlers/loadFile.go b/RaspberryPi/apple2driver/handlers/loadFile.go index 854bda5..9e2586f 100644 --- a/RaspberryPi/apple2driver/handlers/loadFile.go +++ b/RaspberryPi/apple2driver/handlers/loadFile.go @@ -1,4 +1,4 @@ -// Copyright Terence J. Boldt (c)2020-2022 +// Copyright Terence J. Boldt (c)2020-2024 // Use of this source code is governed by an MIT // license that can be found in the LICENSE file. diff --git a/RaspberryPi/apple2driver/handlers/loadFile_test.go b/RaspberryPi/apple2driver/handlers/loadFile_test.go index 1269282..7c12b96 100644 --- a/RaspberryPi/apple2driver/handlers/loadFile_test.go +++ b/RaspberryPi/apple2driver/handlers/loadFile_test.go @@ -1,4 +1,4 @@ -// Copyright Terence J. Boldt (c)2020-2022 +// Copyright Terence J. Boldt (c)2020-2024 // Use of this source code is governed by an MIT // license that can be found in the LICENSE file. diff --git a/RaspberryPi/apple2driver/handlers/menu.go b/RaspberryPi/apple2driver/handlers/menu.go index 64b7a0d..44769ed 100755 --- a/RaspberryPi/apple2driver/handlers/menu.go +++ b/RaspberryPi/apple2driver/handlers/menu.go @@ -1,4 +1,4 @@ -// Copyright Terence J. Boldt (c)2020-2022 +// Copyright Terence J. Boldt (c)2020-2024 // Use of this source code is governed by an MIT // license that can be found in the LICENSE file. @@ -15,7 +15,7 @@ import ( func MenuCommand() { fmt.Printf("Sending menu...\n") comm.WriteString("Apple2-IO-RPi\r" + - "(c)2020-2021 Terence J. Boldt\r" + + "(c)2020-2024 Terence J. Boldt\r" + "\r" + "Select an option:\r" + "\r" + diff --git a/RaspberryPi/apple2driver/handlers/menu_test.go b/RaspberryPi/apple2driver/handlers/menu_test.go index 7ada1f4..865af73 100644 --- a/RaspberryPi/apple2driver/handlers/menu_test.go +++ b/RaspberryPi/apple2driver/handlers/menu_test.go @@ -1,4 +1,4 @@ -// Copyright Terence J. Boldt (c)2020-2022 +// Copyright Terence J. Boldt (c)2020-2024 // Use of this source code is governed by an MIT // license that can be found in the LICENSE file. diff --git a/RaspberryPi/apple2driver/handlers/reset.go b/RaspberryPi/apple2driver/handlers/reset.go index 39788df..76e7b8e 100755 --- a/RaspberryPi/apple2driver/handlers/reset.go +++ b/RaspberryPi/apple2driver/handlers/reset.go @@ -1,4 +1,4 @@ -// Copyright Terence J. Boldt (c)2020-2022 +// Copyright Terence J. Boldt (c)2020-2024 // Use of this source code is governed by an MIT // license that can be found in the LICENSE file. diff --git a/RaspberryPi/apple2driver/handlers/shell.go b/RaspberryPi/apple2driver/handlers/shell.go index 1db501c..7139c9c 100755 --- a/RaspberryPi/apple2driver/handlers/shell.go +++ b/RaspberryPi/apple2driver/handlers/shell.go @@ -1,4 +1,4 @@ -// Copyright Terence J. Boldt (c)2020-2022 +// Copyright Terence J. Boldt (c)2020-2024 // Use of this source code is governed by an MIT // license that can be found in the LICENSE file. @@ -17,6 +17,7 @@ import ( // ShellCommand handles requests for the Apple II executing a Linux shell func ShellCommand() { + fmt.Printf("Shell started\n") cmd := exec.Command("bash", "-i") cmd.Env = append(os.Environ(), "TERM=vt100", @@ -43,7 +44,10 @@ func ShellCommand() { for { select { case <-outputComplete: + fmt.Printf("Shell output complete\n") + outputComplete <- true ptmx.Close() + cmd.Wait() comm.WriteByte(0) // return break @@ -54,6 +58,8 @@ func ShellCommand() { // comm.WriteByte(0) return case <-inputComplete: + fmt.Printf("Shell input complete\n") + ptmx.Close() cmd.Wait() comm.WriteByte(0) return diff --git a/RaspberryPi/apple2driver/info/version.go b/RaspberryPi/apple2driver/info/version.go index 4053d2d..3bcded3 100644 --- a/RaspberryPi/apple2driver/info/version.go +++ b/RaspberryPi/apple2driver/info/version.go @@ -1,4 +1,4 @@ -// Copyright Terence J. Boldt (c)2020-2022 +// Copyright Terence J. Boldt (c)2020-2024 // Use of this source code is governed by an MIT // license that can be found in the LICENSE file. @@ -8,4 +8,4 @@ package info // Version is the hexadecimal version number that // should be incremented with each driver update -const Version = "0026" +const Version = "002C" diff --git a/RaspberryPi/driveimage/BASIC.SYSTEM.SYS b/RaspberryPi/driveimage/BASIC.SYSTEM.SYS new file mode 100644 index 0000000..fd2c3f3 Binary files /dev/null and b/RaspberryPi/driveimage/BASIC.SYSTEM.SYS differ diff --git a/RaspberryPi/driveimage/PRODOS.SYS b/RaspberryPi/driveimage/PRODOS.SYS new file mode 100644 index 0000000..7760a27 Binary files /dev/null and b/RaspberryPi/driveimage/PRODOS.SYS differ diff --git a/RaspberryPi/driveimage/Shell.bin b/RaspberryPi/driveimage/Shell.bin new file mode 100644 index 0000000..07bb2f6 Binary files /dev/null and b/RaspberryPi/driveimage/Shell.bin differ diff --git a/RaspberryPi/driveimage/Startup.bas b/RaspberryPi/driveimage/Startup.bas new file mode 120000 index 0000000..46801de --- /dev/null +++ b/RaspberryPi/driveimage/Startup.bas @@ -0,0 +1 @@ +../../Apple2/Startup.bas \ No newline at end of file diff --git a/RaspberryPi/driveimage/Update.Firmware.bas b/RaspberryPi/driveimage/Update.Firmware.bas new file mode 120000 index 0000000..84b69c8 --- /dev/null +++ b/RaspberryPi/driveimage/Update.Firmware.bas @@ -0,0 +1 @@ +../../Apple2/Update.Firmware.bas \ No newline at end of file diff --git a/RaspberryPi/setup.sh b/RaspberryPi/setup.sh index 880a5e9..83247ae 100644 --- a/RaspberryPi/setup.sh +++ b/RaspberryPi/setup.sh @@ -1,34 +1,56 @@ #!/bin/sh +sudo apt update sudo apt install git -y -wget https://golang.org/dl/go1.19.linux-armv6l.tar.gz -sudo tar -C /usr/local -xzf go1.19.linux-armv6l.tar.gz +if [ "$(uname -m)" = 'aarch64' ]; then + if [ ! -f go1.21.3.linux-arm64.tar.gz ]; then + wget https://go.dev/dl/go1.21.3.linux-arm64.tar.gz + sudo tar -C /usr/local -xzf go1.21.3.linux-arm64.tar.gz + fi +else + if [ ! -f go1.21.3.linux-arm6l.tar.gz ]; then + wget https://golang.org/dl/go1.21.3.linux-armv6l.tar.gz + sudo tar -C /usr/local -xzf go1.21.3.linux-armv6l.tar.gz + fi +fi +if [ -f "/usr/bin/go" ]; then + sudo rm /usr/bin/go +fi sudo ln -s /usr/local/go/bin/go /usr/bin/go -git clone https://github.com/tjboldt/ProDOS-Utilities.git +if [ ! -d "ProDOS-Utilities" ]; then + git clone https://github.com/tjboldt/ProDOS-Utilities.git +fi cd ProDOS-Utilities || exit go mod tidy go build cd ~ || exit +if [ -L "/usr/bin/ProDOS-Utilities" ]; then + sudo rm /usr/bin/ProDOS-Utilities +fi sudo ln -s $HOME/ProDOS-Utilities/ProDOS-Utilities /usr/bin/ProDOS-Utilities -git clone https://github.com/oliverschmidt/Apple2-IO-RPi.git +if [ ! -d "Apple2-IO-RPi" ]; then + git clone https://github.com/tjboldt/Apple2-IO-RPi.git +fi cd Apple2-IO-RPi/RaspberryPi/apple2driver || exit go mod tidy go build sudo apt install cc65 vim -y cd ~ || exit + sudo bash -c 'cat > /boot/config.txt << EOF disable_splash=1 dtoverlay=disable-bt boot_delay=0 EOF' sudo bash -c 'echo " quiet" >> /boot/cmdline.txt' -wget https://github.com/a2-4am/4cade/releases/latest/download/Total.Replay.hdv -sudo --preserve-env=HOME --preserve-env=USER bash -c 'cat > /etc/systemd/system/apple2driver.service << EOF +sudo --preserve-env=HOME --preserve-env=USER bash -c 'cat > apple2driver.service << EOF [Unit] Description=Apple2-IO-RPi Driver [Service] -ExecStart=$HOME/Apple2-IO-RPi/RaspberryPi/apple2driver/apple2driver -cdc -d1 $HOME/Apple2-IO-RPi/RaspberryPi/Apple2-IO-RPi.hdv -d2 $HOME/Total.Replay.hdv +ExecStart=$HOME/Apple2-IO-RPi/RaspberryPi/apple2driver/apple2driver +StandardOutput=syslog +StandardError=syslog SyslogIdentifier=apple2driver User=$USER Group=$USER @@ -37,8 +59,11 @@ WorkingDirectory=$HOME/Apple2-IO-RPi/RaspberryPi/apple2driver [Install] WantedBy=basic.target EOF' +sudo mv apple2driver.service /etc/systemd/system/apple2driver.service +sudo chown root:root /etc/systemd/system/apple2driver.service sudo systemctl start apple2driver sudo systemctl enable apple2driver sudo systemctl disable avahi-daemon.service sudo systemctl disable triggerhappy.service sudo systemctl disable raspi-config.service +sudo systemctl daemon-reload