├── .gitmodules ├── LICENSE ├── README.md ├── aphid ├── Makefile ├── README.md ├── cameo-aphid.service ├── firmware │ ├── Makefile │ ├── PB-CAMEO-APHID.dts │ ├── aphd_pru0_datapump │ │ ├── AM335x_PRU.cmd │ │ ├── Makefile │ │ ├── aphd_pru0_datapump.asm │ │ └── aphd_pru0_resource_table.c │ ├── aphd_pru1_control │ │ ├── AM335x_PRU.cmd │ │ ├── Makefile │ │ ├── aphd_pru1_control.cc │ │ ├── aphd_pru1_data_bytes_with_parity.h │ │ ├── aphd_pru1_data_drive_sector.h │ │ ├── aphd_pru1_interrupt_and_buffer_handler.cc │ │ ├── aphd_pru1_interrupt_and_buffer_handler.h │ │ ├── aphd_pru1_resource_table.c │ │ ├── aphd_pru1_resource_table.h │ │ ├── aphd_pru1_rpmsg.c │ │ ├── aphd_pru1_rpmsg.h │ │ ├── aphd_pru1_shared_memory.cc │ │ ├── aphd_pru1_shared_memory.h │ │ └── shared_memory_snooper.py │ └── aphd_pru_common.h ├── pics │ ├── cameo-aphid.jpg │ ├── smd_layout.png │ ├── thumb_all_parts.jpg │ ├── thumb_frontback.jpg │ ├── thumb_profile.jpg │ ├── thumb_sideside.jpg │ └── ui.jpg ├── profile.py ├── profile_plugin_FFFEFC_selector_rescue.py ├── profile_plugin_FFFEFD_system_info.py ├── profile_plugin_FFFEFE_filesystem_ops.py ├── profile_plugin_FFFEFF_key_value_store.py ├── profile_plugins.py ├── selector │ ├── MANUAL.md │ ├── PROTOCOL.md │ ├── README.md │ ├── ask_ui.x68 │ ├── block.x68 │ ├── boot.x68 │ ├── catalogue.x68 │ ├── catalogue_ui.x68 │ ├── config.x68 │ ├── config_ui.x68 │ ├── drive.x68 │ ├── key_value.x68 │ ├── narrated.x68 │ ├── outro.x68 │ ├── screensaver.jpg │ ├── script.x68 │ ├── selector.3.5inch.dc42.zip │ ├── selector.image.zip │ ├── selector.jpg │ ├── selector.twiggy.dc42.zip │ ├── selector.x68 │ ├── selector_ui.x68 │ ├── ui_base.x68 │ ├── ui_macros.x68 │ ├── ui_psystem_menu.x68 │ ├── ui_screensaver.x68 │ ├── ui_scrolling_menu.x68 │ └── ui_textinput.x68 ├── setup_device_tree_overlay.sh ├── setup_dos_partition_part1.sh ├── setup_dos_partition_part2.sh ├── setup_os_config_changes.sh ├── setup_overlayroot.sh ├── setup_trim_misc.sh └── setup_trim_services.sh ├── hardware ├── arcanebyte_aphde │ ├── README.md │ ├── rev_a │ │ ├── cameo.brd │ │ ├── cameo.sch │ │ ├── cameo_top_bom.csv │ │ └── cameo_top_cpl.csv │ └── rev_b │ │ ├── cameo.brd │ │ ├── cameo.sch │ │ ├── cameo_top_bom.csv │ │ └── cameo_top_cpl.csv └── cameo_cape │ ├── cameo_cape-cache.dcm │ ├── cameo_cape-cache.lib │ ├── cameo_cape.dcm │ ├── cameo_cape.kicad_pcb │ ├── cameo_cape.net │ ├── cameo_cape.pro │ ├── cameo_cape.sch │ ├── components │ ├── symbols.dcm │ └── symbols.lib │ ├── gerber │ ├── cameo_cape-B.Paste.gbr │ ├── cameo_cape-B.SilkS.gbr │ ├── cameo_cape-Bottom.gbr │ ├── cameo_cape-DigitalGND.gbr │ ├── cameo_cape-Edge.Cuts.gbr │ ├── cameo_cape-F.Paste.gbr │ ├── cameo_cape-F.SilkS.gbr │ ├── cameo_cape-Top.gbr │ ├── cameo_cape-VDD.gbr │ └── cameo_cape.drl │ └── pdfs │ ├── layers │ ├── cameo_cape-B.Paste.pdf │ ├── cameo_cape-B.SilkS.pdf │ ├── cameo_cape-Bottom.pdf │ ├── cameo_cape-DigitalGND.pdf │ ├── cameo_cape-Edge.Cuts.pdf │ ├── cameo_cape-F.Paste.pdf │ ├── cameo_cape-F.SilkS.pdf │ ├── cameo_cape-Top.pdf │ └── cameo_cape-VDD.pdf │ └── schematic │ └── cameo_cape.pdf └── pics ├── cameo.jpg ├── installed.jpg ├── plugboard.jpg ├── plugboard_map.png ├── plugboard_pads.jpg ├── smd_layout.png └── thumb_aphid.jpg /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "aphid/selector/lisa_io"] 2 | path = aphid/selector/lisa_io 3 | url = https://github.com/stepleton/lisa_io.git 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | This is free and unencumbered software released into the public domain. 2 | 3 | Anyone is free to copy, modify, publish, use, compile, sell, or 4 | distribute this software, either in source code form or as a compiled 5 | binary, for any purpose, commercial or non-commercial, and by any 6 | means. 7 | 8 | In jurisdictions that recognize copyright laws, the author or authors 9 | of this software dedicate any and all copyright interest in the 10 | software to the public domain. We make this dedication for the benefit 11 | of the public at large and to the detriment of our heirs and 12 | successors. We intend this dedication to be an overt act of 13 | relinquishment in perpetuity of all present and future rights to this 14 | software under copyright law. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 20 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | OTHER DEALINGS IN THE SOFTWARE. 23 | 24 | For more information, please refer to 25 | -------------------------------------------------------------------------------- /aphid/Makefile: -------------------------------------------------------------------------------- 1 | # Apple parallel port storage emulator for Cameo 2 | # 3 | # Forfeited into the public domain with NO WARRANTY. Read LICENSE for details. 4 | # 5 | # This file: build and install Aphid firmware, Linux-side programs, startup 6 | # scripts, and a blank disk image. Installation locations: 7 | # Firmware: /lib/firmware 8 | # Disk emulator script and blank disk image: /usr/local/lib/cameo-aphid 9 | # systemd startup script: /lib/systemd/system 10 | 11 | 12 | INSTALL_DIR=/usr/local/lib/cameo-aphid 13 | SYSTEMD_DIR=/lib/systemd/system 14 | 15 | 16 | all: 17 | gunzip - < selector/selector.image.zip > profile.image 18 | $(MAKE) -C firmware 19 | 20 | 21 | clean: 22 | $(MAKE) -C firmware clean 23 | rm -f profile.image 24 | 25 | 26 | install: 27 | $(MAKE) -C firmware install 28 | mkdir -p $(INSTALL_DIR) 29 | install --mode=775 profile.py $(INSTALL_DIR) 30 | install --mode=664 profile_plugin_FFFEFC_selector_rescue.py $(INSTALL_DIR) 31 | install --mode=664 profile_plugin_FFFEFD_system_info.py $(INSTALL_DIR) 32 | install --mode=664 profile_plugin_FFFEFE_filesystem_ops.py $(INSTALL_DIR) 33 | install --mode=664 profile_plugin_FFFEFF_key_value_store.py $(INSTALL_DIR) 34 | install --mode=664 profile_plugins.py $(INSTALL_DIR) 35 | install --backup=numbered --mode=664 profile.image $(INSTALL_DIR) 36 | chown -R debian:debian $(INSTALL_DIR) | true # Ignore error: dir may be 37 | chmod -R ug+rw $(INSTALL_DIR) | true # on another filesystem. 38 | install --mode=644 cameo-aphid.service $(SYSTEMD_DIR) 39 | @echo 40 | @echo 'To start ProFile emulation on boot, execute:' 41 | @echo ' sudo systemctl enable cameo-aphid' 42 | 43 | 44 | 45 | .PHONY: all clean install 46 | -------------------------------------------------------------------------------- /aphid/cameo-aphid.service: -------------------------------------------------------------------------------- 1 | # Apple parallel port storage emulator for Cameo 2 | # 3 | # Forfeited into the public domain with NO WARRANTY. Read LICENSE for details. 4 | # 5 | # This systemd file starts the Aphid profile emulator software on an ordinary 6 | # multi-user boot. It expects the disk emulator script (profile.py) and a 7 | # disk image (profile.image) in the directory /usr/local/lib/cameo-aphid. 8 | # 9 | # Since this file is most useful for running the disk emulator in "headless" 10 | # mode, it's good to know the blinking patterns that the emulator flashes on 11 | # the user LEDs to communicate about its state. See profile.py for details. 12 | 13 | [Unit] 14 | Description=Cameo/Aphid parallel port hard drive emulator 15 | Requires=systemd-modules-load.service 16 | 17 | [Service] 18 | User=root 19 | WorkingDirectory=/usr/local/lib/cameo-aphid 20 | # With the --skip_load_pru_firmware and --skip_pin_setup flags, it's necessary 21 | # for the header pins to have been configured ahead of time by a device tree 22 | # overlay, and for the PRU firmware to have been pre-loaded by the kernel during 23 | # boot (accomplished by using the filenames am335x-pru0-fw and am335x-pru1-fw 24 | # in /lib/firmware/). The payoff for this extra trouble is faster boot times. 25 | ExecStart=/usr/local/lib/cameo-aphid/profile.py --skip_load_pru_firmware --skip_pin_setup profile.image 26 | # The first kill signal tells Cameo to flush all pending writes to the disk 27 | # image. The second tells Cameo to terminate. 28 | ExecStop=/bin/kill $MAINPID 29 | ExecStop=/bin/sleep 5 30 | ExecStop=-/bin/kill $MAINPID 31 | 32 | [Install] 33 | WantedBy=multi-user.target 34 | -------------------------------------------------------------------------------- /aphid/firmware/Makefile: -------------------------------------------------------------------------------- 1 | # Apple parallel port storage emulator for Cameo 2 | # 3 | # Forfeited into the public domain with NO WARRANTY. Read LICENSE for details. 4 | # 5 | # This file: build Aphid firmware for both PRUs. 6 | # 7 | # While it's recommended that you `make` the firmware as an ordinary user, 8 | # `make install` expects to run as root so that it can install the firmware 9 | # in /lib/firmware. 10 | 11 | 12 | INSTALL_DIR=/lib/firmware 13 | 14 | 15 | all: PB-CAMEO-APHID.dtbo 16 | $(MAKE) -C aphd_pru0_datapump 17 | $(MAKE) -C aphd_pru1_control 18 | 19 | 20 | clean: 21 | rm -f PB-CAMEO-APHID.dtbo PB-CAMEO-APHID.preprocessed.dts 22 | $(MAKE) -C aphd_pru0_datapump clean 23 | $(MAKE) -C aphd_pru1_control clean 24 | 25 | 26 | install: all 27 | install --mode=644 \ 28 | aphd_pru0_datapump/aphd_pru0_datapump.fw $(INSTALL_DIR) 29 | install --mode=644 \ 30 | aphd_pru1_control/aphd_pru1_control.fw $(INSTALL_DIR) 31 | install --mode=644 --backup=numbered -T \ 32 | aphd_pru0_datapump/aphd_pru0_datapump.fw \ 33 | $(INSTALL_DIR)/am335x-pru0-fw 34 | install --mode=644 --backup=numbered -T \ 35 | aphd_pru1_control/aphd_pru1_control.fw \ 36 | $(INSTALL_DIR)/am335x-pru1-fw 37 | install --mode=644 \ 38 | aphd_pru1_control/aphd_pru1_control.fw $(INSTALL_DIR) 39 | install --mode=644 \ 40 | PB-CAMEO-APHID.dtbo $(INSTALL_DIR) 41 | 42 | 43 | PB-CAMEO-APHID.preprocessed.dts: PB-CAMEO-APHID.dts 44 | cpp -I/opt/source/bb.org-overlays/include $< -P -o $@ 45 | 46 | 47 | PB-CAMEO-APHID.dtbo: PB-CAMEO-APHID.preprocessed.dts 48 | dtc -@ -I dts -O dtb -o $@ $< 49 | 50 | 51 | .PHONY: all clean install 52 | -------------------------------------------------------------------------------- /aphid/firmware/PB-CAMEO-APHID.dts: -------------------------------------------------------------------------------- 1 | /* Apple parallel port storage emulator for Cameo 2 | * 3 | * Forfeited into the public domain with NO WARRANTY. Read LICENSE for details. 4 | * 5 | * This file: a device tree overlay for Cameo/Aphid. 6 | * 7 | * When activated at boot, this device tree overlay reserves the header pins 8 | * that Cameo/Aphid uses, introduces a pinmux configuration for those pins, and 9 | * enables the PRUs. 10 | */ 11 | 12 | /dts-v1/; 13 | /plugin/; 14 | 15 | /* This header file doesn't exist on our pocketbeagle, so we replicate 16 | * necessary symbols manually. */ 17 | /* #include */ 18 | #define PB_P1_02 0x08e4 19 | #define PB_P1_29 0x09ac 20 | #define PB_P1_30 0x0974 21 | #define PB_P1_31 0x09a0 22 | #define PB_P1_33 0x0994 23 | #define PB_P1_36 0x0990 24 | #define PB_P2_09 0x0984 25 | #define PB_P2_24 0x0830 26 | #define PB_P2_28 0x09a8 27 | #define PB_P2_30 0x099c 28 | #define PB_P2_32 0x0998 29 | #define PB_P2_34 0x09a4 30 | #define PB_P2_35 0x08e0 31 | 32 | #include 33 | #include 34 | 35 | / { 36 | /* For showing loaded overlays at /proc/device-tree/chosen/overlays/ */ 37 | fragment@0 { 38 | target-path = "/"; 39 | __overlay__ { 40 | chosen { 41 | overlays { 42 | PB-CAMEO-APHID = __TIMESTAMP__; 43 | }; 44 | }; 45 | }; 46 | }; 47 | 48 | /* Reserve these header pins so the pinmux helpers don't claim them. */ 49 | fragment@1 { 50 | target = <&ocp>; 51 | __overlay__ { 52 | P1_02_pinmux { status = "disabled"; }; 53 | P1_29_pinmux { status = "disabled"; }; 54 | P1_30_pinmux { status = "disabled"; }; 55 | P1_31_pinmux { status = "disabled"; }; 56 | P1_33_pinmux { status = "disabled"; }; 57 | P1_36_pinmux { status = "disabled"; }; 58 | P2_09_pinmux { status = "disabled"; }; 59 | P2_24_pinmux { status = "disabled"; }; 60 | P2_28_pinmux { status = "disabled"; }; 61 | P2_30_pinmux { status = "disabled"; }; 62 | P2_32_pinmux { status = "disabled"; }; 63 | P2_34_pinmux { status = "disabled"; }; 64 | P2_35_pinmux { status = "disabled"; }; 65 | }; 66 | }; 67 | 68 | /* Introduce a pinmux configuration for Cameo/Aphid. */ 69 | fragment@2 { 70 | target = <&am33xx_pinmux>; 71 | __overlay__ { 72 | 73 | /* Here is our new pinmux configuration. It's called 74 | * "pinmux_aphd_pins", and you can find the files that 75 | * correspond to this declaration at 76 | * /sys/firmware/devicetree/base/ocp/l4_wkup@44c00000/ 77 | * scm@210000/pinmux@800/pinmux_aphd_pins 78 | * 79 | * The symbol "aphd_pins" can then be used to refer to 80 | * this configuration elsewhere in this overlay. */ 81 | aphd_pins: pinmux_aphd_pins { 82 | pinctrl-single,pins = < 83 | 84 | /* Ordinary GPIO pins. Even though these 85 | * pins are accessible to the ARM, the 86 | * only part of the Cameo/Aphid software 87 | * that touches them are the PRU 88 | * firmware programs. The ARM tells the 89 | * PRUs what to do over rpmsg. */ 90 | 91 | AM33XX_IOPAD(PB_P1_29, PIN_INPUT | MUX_MODE7 ) 92 | AM33XX_IOPAD(PB_P1_31, PIN_INPUT | MUX_MODE7 ) 93 | AM33XX_IOPAD(PB_P1_33, PIN_INPUT | MUX_MODE7 ) 94 | AM33XX_IOPAD(PB_P1_36, PIN_INPUT | MUX_MODE7 ) 95 | AM33XX_IOPAD(PB_P2_28, PIN_INPUT | MUX_MODE7 ) 96 | AM33XX_IOPAD(PB_P2_30, PIN_INPUT | MUX_MODE7 ) 97 | AM33XX_IOPAD(PB_P2_32, PIN_INPUT | MUX_MODE7 ) 98 | AM33XX_IOPAD(PB_P2_34, PIN_INPUT | MUX_MODE7 ) 99 | 100 | /* PRU-exclusive pins. Note that all are 101 | * declared "inputs" even though the 102 | * latter two are PRU outputs --- IIRC, 103 | * from the ARM's perspective, they're 104 | * inputs. */ 105 | 106 | /* Input pins */ 107 | AM33XX_IOPAD(PB_P1_02, PIN_INPUT | MUX_MODE6 ) 108 | AM33XX_IOPAD(PB_P1_30, PIN_INPUT | MUX_MODE6 ) 109 | AM33XX_IOPAD(PB_P2_09, PIN_INPUT | MUX_MODE6 ) 110 | /* Output pins: note 2.24 is unusual for 111 | * doing input in Mode 6. */ 112 | AM33XX_IOPAD(PB_P2_24, INPUT_EN | MUX_MODE6 ) 113 | AM33XX_IOPAD(PB_P2_35, INPUT_EN | MUX_MODE5 ) 114 | >; 115 | }; 116 | }; 117 | }; 118 | 119 | /* Required for use of the PRUs. */ 120 | fragment@3 { 121 | target = <&pruss>; 122 | __overlay__ { 123 | pinctrl-names = "default"; 124 | pinctrl-0 = <&aphd_pins>; 125 | status = "okay"; 126 | }; 127 | }; 128 | }; 129 | -------------------------------------------------------------------------------- /aphid/firmware/aphd_pru0_datapump/AM335x_PRU.cmd: -------------------------------------------------------------------------------- 1 | /****************************************************************************/ 2 | /* AM335x_PRU.cmd */ 3 | /* Copyright (c) 2015 Texas Instruments Incorporated */ 4 | /* */ 5 | /* Description: This file is a linker command file that can be used for */ 6 | /* linking PRU programs built with the C compiler and */ 7 | /* the resulting .out file on an AM335x device. */ 8 | /****************************************************************************/ 9 | 10 | -cr /* Link using C conventions */ 11 | --entry_point=INIT 12 | 13 | /* Specify the System Memory Map */ 14 | MEMORY 15 | { 16 | PAGE 0: 17 | PRU_IMEM : org = 0x00000000 len = 0x00002000 /* 8kB PRU0 Instruction RAM */ 18 | 19 | PAGE 1: 20 | 21 | /* RAM */ 22 | 23 | PRU_DMEM_0_1 : org = 0x00000000 len = 0x00002000 CREGISTER=24 /* 8kB PRU Data RAM 0_1 */ 24 | PRU_DMEM_1_0 : org = 0x00002000 len = 0x00002000 CREGISTER=25 /* 8kB PRU Data RAM 1_0 */ 25 | 26 | PAGE 2: 27 | PRU_SHAREDMEM : org = 0x00010000 len = 0x00003000 CREGISTER=28 /* 12kB Shared RAM */ 28 | 29 | DDR : org = 0x80000000 len = 0x00000100 CREGISTER=31 30 | L3OCMC : org = 0x40000000 len = 0x00010000 CREGISTER=30 31 | 32 | 33 | /* Peripherals */ 34 | 35 | PRU_CFG : org = 0x00026000 len = 0x00000044 CREGISTER=4 36 | PRU_ECAP : org = 0x00030000 len = 0x00000060 CREGISTER=3 37 | PRU_IEP : org = 0x0002E000 len = 0x0000031C CREGISTER=26 38 | PRU_INTC : org = 0x00020000 len = 0x00001504 CREGISTER=0 39 | PRU_UART : org = 0x00028000 len = 0x00000038 CREGISTER=7 40 | 41 | DCAN0 : org = 0x481CC000 len = 0x000001E8 CREGISTER=14 42 | DCAN1 : org = 0x481D0000 len = 0x000001E8 CREGISTER=15 43 | DMTIMER2 : org = 0x48040000 len = 0x0000005C CREGISTER=1 44 | PWMSS0 : org = 0x48300000 len = 0x000002C4 CREGISTER=18 45 | PWMSS1 : org = 0x48302000 len = 0x000002C4 CREGISTER=19 46 | PWMSS2 : org = 0x48304000 len = 0x000002C4 CREGISTER=20 47 | GEMAC : org = 0x4A100000 len = 0x0000128C CREGISTER=9 48 | I2C1 : org = 0x4802A000 len = 0x000000D8 CREGISTER=2 49 | I2C2 : org = 0x4819C000 len = 0x000000D8 CREGISTER=17 50 | MBX0 : org = 0x480C8000 len = 0x00000140 CREGISTER=22 51 | MCASP0_DMA : org = 0x46000000 len = 0x00000100 CREGISTER=8 52 | MCSPI0 : org = 0x48030000 len = 0x000001A4 CREGISTER=6 53 | MCSPI1 : org = 0x481A0000 len = 0x000001A4 CREGISTER=16 54 | MMCHS0 : org = 0x48060000 len = 0x00000300 CREGISTER=5 55 | SPINLOCK : org = 0x480CA000 len = 0x00000880 CREGISTER=23 56 | TPCC : org = 0x49000000 len = 0x00001098 CREGISTER=29 57 | UART1 : org = 0x48022000 len = 0x00000088 CREGISTER=11 58 | UART2 : org = 0x48024000 len = 0x00000088 CREGISTER=12 59 | 60 | RSVD10 : org = 0x48318000 len = 0x00000100 CREGISTER=10 61 | RSVD13 : org = 0x48310000 len = 0x00000100 CREGISTER=13 62 | RSVD21 : org = 0x00032400 len = 0x00000100 CREGISTER=21 63 | RSVD27 : org = 0x00032000 len = 0x00000100 CREGISTER=27 64 | 65 | } 66 | 67 | /* Specify the sections allocation into memory */ 68 | SECTIONS { 69 | 70 | /* Forces _c_int00 to the start of PRU IRAM. Not necessary when */ 71 | /* loading an ELF file, but useful when loading a binary */ 72 | 73 | .text:_c_int00* > 0x0, PAGE 0 74 | .text > PRU_IMEM, PAGE 0 75 | .stack > PRU_DMEM_0_1, PAGE 1 76 | .bss > PRU_DMEM_0_1, PAGE 1 77 | .cio > PRU_DMEM_0_1, PAGE 1 78 | .data > PRU_DMEM_0_1, PAGE 1 79 | .switch > PRU_DMEM_0_1, PAGE 1 80 | .sysmem > PRU_DMEM_0_1, PAGE 1 81 | .cinit > PRU_DMEM_0_1, PAGE 1 82 | .rodata > PRU_DMEM_0_1, PAGE 1 83 | .rofardata > PRU_DMEM_0_1, PAGE 1 84 | .farbss > PRU_DMEM_0_1, PAGE 1 85 | .fardata > PRU_DMEM_0_1, PAGE 1 86 | .resource_table > PRU_DMEM_0_1, PAGE 1 87 | } 88 | -------------------------------------------------------------------------------- /aphid/firmware/aphd_pru0_datapump/Makefile: -------------------------------------------------------------------------------- 1 | # Apple parallel port storage emulator for Cameo 2 | # 3 | # Forfeited into the public domain with NO WARRANTY. Read LICENSE for details. 4 | # 5 | # This file: build "data pump" Aphid firmware for PRU 0. 6 | 7 | CC=clpru 8 | CFLAGS=-I.. \ 9 | -I/usr/lib/ti/pru-software-support-package/include \ 10 | -I/usr/lib/ti/pru-software-support-package/include/am335x \ 11 | --endian=little --hardware_mac=on --define=am3358 --define=pru0 \ 12 | -v3 -O2 13 | 14 | LD=clpru 15 | LDFLAGS=-i/usr/lib/ti/pru-software-support-package/lib \ 16 | --define=am3358 --define=pru0 \ 17 | --heap_size=0 --stack_size=0 --reread_libs --warn_sections 18 | 19 | 20 | DEPS=../aphd_pru_common.h 21 | 22 | 23 | all: aphd_pru0_datapump.fw 24 | 25 | 26 | aphd_pru0_datapump.obj: aphd_pru0_datapump.asm $(DEPS) 27 | $(CC) -c $< $(CFLAGS) 28 | 29 | 30 | aphd_pru0_resource_table.obj: aphd_pru0_resource_table.c $(DEPS) 31 | $(CC) -c $< $(CFLAGS) 32 | 33 | 34 | aphd_pru0_datapump.fw: aphd_pru0_resource_table.obj aphd_pru0_datapump.obj AM335x_PRU.cmd 35 | $(LD) -z -o $@ $(LDFLAGS) \ 36 | aphd_pru0_resource_table.obj aphd_pru0_datapump.obj \ 37 | AM335x_PRU.cmd -llibc.a 38 | 39 | 40 | clean: 41 | rm -f *.obj aphd_pru0_datapump.fw 42 | 43 | 44 | .PHONY: clean all 45 | -------------------------------------------------------------------------------- /aphid/firmware/aphd_pru0_datapump/aphd_pru0_resource_table.c: -------------------------------------------------------------------------------- 1 | /* Apple parallel port storage emulator for Cameo 2 | * 3 | * Forfeited into the public domain with NO WARRANTY. Read LICENSE for details. 4 | * 5 | * This file: the remoteproc resource table for PRU 0. 6 | */ 7 | 8 | 9 | #include 10 | #include 11 | 12 | #include 13 | #include 14 | 15 | #include "aphd_pru_common.h" 16 | 17 | 18 | /* Define this symbol to embed a resource table that configures the interrupt 19 | * controller to match the resources that PRU 0 uses. Ordinarily we leave this 20 | * undefined and use an empty resource table in the expectation that the PRU 1 21 | * resource table will configure the interrupt controller appropriately. */ 22 | #undef PRU_0_STANDALONE 23 | 24 | 25 | #ifdef PRU_0_STANDALONE 26 | /* Define a resource table that configures the interrupt controller to support 27 | * the interrupts that PRU 0 will use. */ 28 | 29 | 30 | struct pru0_resource_table { 31 | struct resource_table resources; 32 | uint32_t offsets[1]; /* Size should match the value in resources.num. */ 33 | struct fw_rsc_custom intc; /* PRU intc. */ 34 | }; 35 | 36 | 37 | struct ch_map PRU0_INTC_SYSEVENT_TO_CHANNEL[] = { 38 | {ePRU0to1, 1U}, 39 | {ePRU1to0, 0U}, 40 | }; 41 | 42 | 43 | #pragma DATA_SECTION(PRU0_RESOURCE_TABLE, ".resource_table") 44 | #pragma RETAIN(PRU0_RESOURCE_TABLE) 45 | struct pru0_resource_table PRU0_RESOURCE_TABLE = { 46 | .resources = { 47 | .ver = 1U, 48 | .num = 1U, 49 | .reserved = {0U, 0U}, 50 | }, 51 | 52 | .offsets = { 53 | offsetof(struct pru0_resource_table, intc), 54 | }, 55 | 56 | .intc = { 57 | .type = TYPE_CUSTOM, 58 | .sub_type = TYPE_PRU_INTS, 59 | .rsc_size = sizeof(struct fw_rsc_custom_ints), 60 | .rsc = { 61 | .pru_ints = { 62 | .version = 0U, 63 | .channel_host = { 64 | 0U, /* Channel 0 (ePRU1to0): host interrupt 0, so r31 bit 30. */ 65 | 1U, /* Channel 1 (ePRU0to1): host interrupt 1, so r31 bit 31. */ 66 | 255U, 255U, 255U, 255U, 255U, 255U, 255U, 255U, /* 4-9: unused. */ 67 | }, 68 | .num_evts = (sizeof(PRU0_INTC_SYSEVENT_TO_CHANNEL) / 69 | sizeof(struct ch_map)), 70 | .event_channel = PRU0_INTC_SYSEVENT_TO_CHANNEL, 71 | }, 72 | }, 73 | }, 74 | }; 75 | 76 | 77 | #else /* PRU_0_STANDALONE */ 78 | /* Define an empty resource table. */ 79 | 80 | 81 | struct pru0_resource_table { 82 | struct resource_table resources; 83 | }; 84 | 85 | 86 | #pragma DATA_SECTION(PRU0_RESOURCE_TABLE, ".resource_table") 87 | #pragma RETAIN(PRU0_RESOURCE_TABLE) 88 | struct pru0_resource_table PRU0_RESOURCE_TABLE = { 89 | .resources = { 90 | .ver = 1U, 91 | .num = 0U, 92 | .reserved = {0U, 0U}, 93 | }, 94 | }; 95 | 96 | 97 | #endif /* PRU_0_STANDALONE */ 98 | -------------------------------------------------------------------------------- /aphid/firmware/aphd_pru1_control/AM335x_PRU.cmd: -------------------------------------------------------------------------------- 1 | /****************************************************************************/ 2 | /* AM335x_PRU.cmd */ 3 | /* Copyright (c) 2015 Texas Instruments Incorporated */ 4 | /* */ 5 | /* Description: This file is a linker command file that can be used for */ 6 | /* linking PRU programs built with the C compiler and */ 7 | /* the resulting .out file on an AM335x device. */ 8 | /****************************************************************************/ 9 | 10 | -cr /* Link using C conventions */ 11 | -stack 0x100 /* Either or both of these options are required ... */ 12 | -heap 0x100 /* ...in order for RPMsg to work. */ 13 | 14 | /* Specify the System Memory Map */ 15 | MEMORY 16 | { 17 | PAGE 0: 18 | PRU_IMEM : org = 0x00000000 len = 0x00002000 /* 8kB PRU0 Instruction RAM */ 19 | 20 | PAGE 1: 21 | 22 | /* RAM */ 23 | 24 | PRU_DMEM_0_1 : org = 0x00000000 len = 0x00002000 CREGISTER=24 /* 8kB PRU Data RAM 0_1 */ 25 | PRU_DMEM_1_0 : org = 0x00002000 len = 0x00002000 CREGISTER=25 /* 8kB PRU Data RAM 1_0 */ 26 | 27 | PAGE 2: 28 | PRU_SHAREDMEM : org = 0x00010000 len = 0x00003000 CREGISTER=28 /* 12kB Shared RAM */ 29 | 30 | DDR : org = 0x80000000 len = 0x00000100 CREGISTER=31 31 | L3OCMC : org = 0x40000000 len = 0x00010000 CREGISTER=30 32 | 33 | 34 | /* Peripherals */ 35 | 36 | PRU_CFG : org = 0x00026000 len = 0x00000044 CREGISTER=4 37 | PRU_ECAP : org = 0x00030000 len = 0x00000060 CREGISTER=3 38 | PRU_IEP : org = 0x0002E000 len = 0x0000031C CREGISTER=26 39 | PRU_INTC : org = 0x00020000 len = 0x00001504 CREGISTER=0 40 | PRU_UART : org = 0x00028000 len = 0x00000038 CREGISTER=7 41 | 42 | DCAN0 : org = 0x481CC000 len = 0x000001E8 CREGISTER=14 43 | DCAN1 : org = 0x481D0000 len = 0x000001E8 CREGISTER=15 44 | DMTIMER2 : org = 0x48040000 len = 0x0000005C CREGISTER=1 45 | PWMSS0 : org = 0x48300000 len = 0x000002C4 CREGISTER=18 46 | PWMSS1 : org = 0x48302000 len = 0x000002C4 CREGISTER=19 47 | PWMSS2 : org = 0x48304000 len = 0x000002C4 CREGISTER=20 48 | GEMAC : org = 0x4A100000 len = 0x0000128C CREGISTER=9 49 | I2C1 : org = 0x4802A000 len = 0x000000D8 CREGISTER=2 50 | I2C2 : org = 0x4819C000 len = 0x000000D8 CREGISTER=17 51 | MBX0 : org = 0x480C8000 len = 0x00000140 CREGISTER=22 52 | MCASP0_DMA : org = 0x46000000 len = 0x00000100 CREGISTER=8 53 | MCSPI0 : org = 0x48030000 len = 0x000001A4 CREGISTER=6 54 | MCSPI1 : org = 0x481A0000 len = 0x000001A4 CREGISTER=16 55 | MMCHS0 : org = 0x48060000 len = 0x00000300 CREGISTER=5 56 | SPINLOCK : org = 0x480CA000 len = 0x00000880 CREGISTER=23 57 | TPCC : org = 0x49000000 len = 0x00001098 CREGISTER=29 58 | UART1 : org = 0x48022000 len = 0x00000088 CREGISTER=11 59 | UART2 : org = 0x48024000 len = 0x00000088 CREGISTER=12 60 | 61 | RSVD10 : org = 0x48318000 len = 0x00000100 CREGISTER=10 62 | RSVD13 : org = 0x48310000 len = 0x00000100 CREGISTER=13 63 | RSVD21 : org = 0x00032400 len = 0x00000100 CREGISTER=21 64 | RSVD27 : org = 0x00032000 len = 0x00000100 CREGISTER=27 65 | 66 | } 67 | 68 | /* Specify the sections allocation into memory */ 69 | SECTIONS { 70 | 71 | /* Forces _c_int00 to the start of PRU IRAM. Not necessary when */ 72 | /* loading an ELF file, but useful when loading a binary */ 73 | 74 | .text:_c_int00* > 0x0, PAGE 0 75 | .text > PRU_IMEM, PAGE 0 76 | .stack > PRU_DMEM_0_1, PAGE 1 77 | .bss > PRU_DMEM_0_1, PAGE 1 78 | .cio > PRU_DMEM_0_1, PAGE 1 79 | .data > PRU_DMEM_0_1, PAGE 1 80 | .switch > PRU_DMEM_0_1, PAGE 1 81 | .sysmem > PRU_DMEM_0_1, PAGE 1 82 | .cinit > PRU_DMEM_0_1, PAGE 1 83 | .rodata > PRU_DMEM_0_1, PAGE 1 84 | .rofardata > PRU_DMEM_0_1, PAGE 1 85 | .farbss > PRU_DMEM_0_1, PAGE 1 86 | .fardata > PRU_DMEM_0_1, PAGE 1 87 | .resource_table > PRU_DMEM_0_1, PAGE 1 88 | 89 | .shmem > PRU_SHAREDMEM, PAGE 2 90 | } 91 | -------------------------------------------------------------------------------- /aphid/firmware/aphd_pru1_control/Makefile: -------------------------------------------------------------------------------- 1 | # Apple parallel port storage emulator for Cameo 2 | # 3 | # Forfeited into the public domain with NO WARRANTY. Read LICENSE for details. 4 | # 5 | # This file: build "control" Aphid firmware for PRU 1. 6 | 7 | CC=clpru 8 | 9 | CC=clpru 10 | CFLAGS=-I. -I.. \ 11 | -I/usr/lib/ti/pru-software-support-package/include \ 12 | -I/usr/lib/ti/pru-software-support-package/include/am335x \ 13 | --endian=little --hardware_mac=on --define=am3358 --define=pru0 \ 14 | -v3 -O2 15 | 16 | LD=clpru 17 | LDFLAGS=-i/usr/lib/ti/pru-software-support-package/lib \ 18 | --define=am3358 --define=pru0 \ 19 | --heap_size=0 --stack_size=0 --reread_libs --warn_sections 20 | 21 | 22 | DEPS=../aphd_pru_common.h \ 23 | aphd_pru1_data_bytes_with_parity.h \ 24 | aphd_pru1_data_drive_sector.h \ 25 | aphd_pru1_interrupt_and_buffer_handler.h \ 26 | aphd_pru1_resource_table.h \ 27 | aphd_pru1_rpmsg.h \ 28 | aphd_pru1_shared_memory.h 29 | 30 | 31 | all: aphd_pru1_control.fw 32 | 33 | 34 | aphd_pru1_control.obj: aphd_pru1_control.cc $(DEPS) 35 | $(CC) -c $< $(CFLAGS) 36 | 37 | 38 | aphd_pru1_interrupt_and_buffer_handler.obj: aphd_pru1_interrupt_and_buffer_handler.cc $(DEPS) 39 | $(CC) -c $< $(CFLAGS) 40 | 41 | 42 | aphd_pru1_resource_table.obj: aphd_pru1_resource_table.c $(DEPS) 43 | $(CC) -c $< $(CFLAGS) 44 | 45 | 46 | aphd_pru1_rpmsg.obj: aphd_pru1_rpmsg.c $(DEPS) 47 | $(CC) -c $< $(CFLAGS) 48 | 49 | 50 | aphd_pru1_shared_memory.obj: aphd_pru1_shared_memory.cc $(DEPS) 51 | $(CC) -c $< $(CFLAGS) 52 | 53 | 54 | aphd_pru1_control.fw: aphd_pru1_control.obj aphd_pru1_interrupt_and_buffer_handler.obj aphd_pru1_resource_table.obj aphd_pru1_rpmsg.obj aphd_pru1_shared_memory.obj 55 | $(LD) -z -o $@ $(LDFLAGS) \ 56 | aphd_pru1_control.obj \ 57 | aphd_pru1_interrupt_and_buffer_handler.obj \ 58 | aphd_pru1_resource_table.obj \ 59 | aphd_pru1_rpmsg.obj \ 60 | aphd_pru1_shared_memory.obj \ 61 | AM335x_PRU.cmd -llibc.a -lrpmsg_lib.lib 62 | 63 | 64 | clean: 65 | rm -f *.obj aphd_pru1_control.fw 66 | 67 | 68 | .PHONY: clean all 69 | -------------------------------------------------------------------------------- /aphid/firmware/aphd_pru1_control/aphd_pru1_data_bytes_with_parity.h: -------------------------------------------------------------------------------- 1 | /* Apple parallel port storage emulator for Cameo 2 | * 3 | * Forfeited into the public domain with NO WARRANTY. Read LICENSE for details. 4 | * 5 | * This file: parity table to fill the bytes_with_parity shared memory region. 6 | */ 7 | 8 | 9 | {0x00, 0xff}, {0x01, 0x00}, {0x02, 0x00}, {0x03, 0xff}, 10 | {0x04, 0x00}, {0x05, 0xff}, {0x06, 0xff}, {0x07, 0x00}, 11 | {0x08, 0x00}, {0x09, 0xff}, {0x0a, 0xff}, {0x0b, 0x00}, 12 | {0x0c, 0xff}, {0x0d, 0x00}, {0x0e, 0x00}, {0x0f, 0xff}, 13 | 14 | {0x10, 0x00}, {0x11, 0xff}, {0x12, 0xff}, {0x13, 0x00}, 15 | {0x14, 0xff}, {0x15, 0x00}, {0x16, 0x00}, {0x17, 0xff}, 16 | {0x18, 0xff}, {0x19, 0x00}, {0x1a, 0x00}, {0x1b, 0xff}, 17 | {0x1c, 0x00}, {0x1d, 0xff}, {0x1e, 0xff}, {0x1f, 0x00}, 18 | 19 | {0x20, 0x00}, {0x21, 0xff}, {0x22, 0xff}, {0x23, 0x00}, 20 | {0x24, 0xff}, {0x25, 0x00}, {0x26, 0x00}, {0x27, 0xff}, 21 | {0x28, 0xff}, {0x29, 0x00}, {0x2a, 0x00}, {0x2b, 0xff}, 22 | {0x2c, 0x00}, {0x2d, 0xff}, {0x2e, 0xff}, {0x2f, 0x00}, 23 | 24 | {0x30, 0xff}, {0x31, 0x00}, {0x32, 0x00}, {0x33, 0xff}, 25 | {0x34, 0x00}, {0x35, 0xff}, {0x36, 0xff}, {0x37, 0x00}, 26 | {0x38, 0x00}, {0x39, 0xff}, {0x3a, 0xff}, {0x3b, 0x00}, 27 | {0x3c, 0xff}, {0x3d, 0x00}, {0x3e, 0x00}, {0x3f, 0xff}, 28 | 29 | {0x40, 0x00}, {0x41, 0xff}, {0x42, 0xff}, {0x43, 0x00}, 30 | {0x44, 0xff}, {0x45, 0x00}, {0x46, 0x00}, {0x47, 0xff}, 31 | {0x48, 0xff}, {0x49, 0x00}, {0x4a, 0x00}, {0x4b, 0xff}, 32 | {0x4c, 0x00}, {0x4d, 0xff}, {0x4e, 0xff}, {0x4f, 0x00}, 33 | 34 | {0x50, 0xff}, {0x51, 0x00}, {0x52, 0x00}, {0x53, 0xff}, 35 | {0x54, 0x00}, {0x55, 0xff}, {0x56, 0xff}, {0x57, 0x00}, 36 | {0x58, 0x00}, {0x59, 0xff}, {0x5a, 0xff}, {0x5b, 0x00}, 37 | {0x5c, 0xff}, {0x5d, 0x00}, {0x5e, 0x00}, {0x5f, 0xff}, 38 | 39 | {0x60, 0xff}, {0x61, 0x00}, {0x62, 0x00}, {0x63, 0xff}, 40 | {0x64, 0x00}, {0x65, 0xff}, {0x66, 0xff}, {0x67, 0x00}, 41 | {0x68, 0x00}, {0x69, 0xff}, {0x6a, 0xff}, {0x6b, 0x00}, 42 | {0x6c, 0xff}, {0x6d, 0x00}, {0x6e, 0x00}, {0x6f, 0xff}, 43 | 44 | {0x70, 0x00}, {0x71, 0xff}, {0x72, 0xff}, {0x73, 0x00}, 45 | {0x74, 0xff}, {0x75, 0x00}, {0x76, 0x00}, {0x77, 0xff}, 46 | {0x78, 0xff}, {0x79, 0x00}, {0x7a, 0x00}, {0x7b, 0xff}, 47 | {0x7c, 0x00}, {0x7d, 0xff}, {0x7e, 0xff}, {0x7f, 0x00}, 48 | 49 | {0x80, 0x00}, {0x81, 0xff}, {0x82, 0xff}, {0x83, 0x00}, 50 | {0x84, 0xff}, {0x85, 0x00}, {0x86, 0x00}, {0x87, 0xff}, 51 | {0x88, 0xff}, {0x89, 0x00}, {0x8a, 0x00}, {0x8b, 0xff}, 52 | {0x8c, 0x00}, {0x8d, 0xff}, {0x8e, 0xff}, {0x8f, 0x00}, 53 | 54 | {0x90, 0xff}, {0x91, 0x00}, {0x92, 0x00}, {0x93, 0xff}, 55 | {0x94, 0x00}, {0x95, 0xff}, {0x96, 0xff}, {0x97, 0x00}, 56 | {0x98, 0x00}, {0x99, 0xff}, {0x9a, 0xff}, {0x9b, 0x00}, 57 | {0x9c, 0xff}, {0x9d, 0x00}, {0x9e, 0x00}, {0x9f, 0xff}, 58 | 59 | {0xa0, 0xff}, {0xa1, 0x00}, {0xa2, 0x00}, {0xa3, 0xff}, 60 | {0xa4, 0x00}, {0xa5, 0xff}, {0xa6, 0xff}, {0xa7, 0x00}, 61 | {0xa8, 0x00}, {0xa9, 0xff}, {0xaa, 0xff}, {0xab, 0x00}, 62 | {0xac, 0xff}, {0xad, 0x00}, {0xae, 0x00}, {0xaf, 0xff}, 63 | 64 | {0xb0, 0x00}, {0xb1, 0xff}, {0xb2, 0xff}, {0xb3, 0x00}, 65 | {0xb4, 0xff}, {0xb5, 0x00}, {0xb6, 0x00}, {0xb7, 0xff}, 66 | {0xb8, 0xff}, {0xb9, 0x00}, {0xba, 0x00}, {0xbb, 0xff}, 67 | {0xbc, 0x00}, {0xbd, 0xff}, {0xbe, 0xff}, {0xbf, 0x00}, 68 | 69 | {0xc0, 0xff}, {0xc1, 0x00}, {0xc2, 0x00}, {0xc3, 0xff}, 70 | {0xc4, 0x00}, {0xc5, 0xff}, {0xc6, 0xff}, {0xc7, 0x00}, 71 | {0xc8, 0x00}, {0xc9, 0xff}, {0xca, 0xff}, {0xcb, 0x00}, 72 | {0xcc, 0xff}, {0xcd, 0x00}, {0xce, 0x00}, {0xcf, 0xff}, 73 | 74 | {0xd0, 0x00}, {0xd1, 0xff}, {0xd2, 0xff}, {0xd3, 0x00}, 75 | {0xd4, 0xff}, {0xd5, 0x00}, {0xd6, 0x00}, {0xd7, 0xff}, 76 | {0xd8, 0xff}, {0xd9, 0x00}, {0xda, 0x00}, {0xdb, 0xff}, 77 | {0xdc, 0x00}, {0xdd, 0xff}, {0xde, 0xff}, {0xdf, 0x00}, 78 | 79 | {0xe0, 0x00}, {0xe1, 0xff}, {0xe2, 0xff}, {0xe3, 0x00}, 80 | {0xe4, 0xff}, {0xe5, 0x00}, {0xe6, 0x00}, {0xe7, 0xff}, 81 | {0xe8, 0xff}, {0xe9, 0x00}, {0xea, 0x00}, {0xeb, 0xff}, 82 | {0xec, 0x00}, {0xed, 0xff}, {0xee, 0xff}, {0xef, 0x00}, 83 | 84 | {0xf0, 0xff}, {0xf1, 0x00}, {0xf2, 0x00}, {0xf3, 0xff}, 85 | {0xf4, 0x00}, {0xf5, 0xff}, {0xf6, 0xff}, {0xf7, 0x00}, 86 | {0xf8, 0x00}, {0xf9, 0xff}, {0xfa, 0xff}, {0xfb, 0x00}, 87 | {0xfc, 0xff}, {0xfd, 0x00}, {0xfe, 0x00}, {0xff, 0xff}, 88 | -------------------------------------------------------------------------------- /aphid/firmware/aphd_pru1_control/aphd_pru1_data_drive_sector.h: -------------------------------------------------------------------------------- 1 | /* Apple parallel port storage emulator for Cameo 2 | * 3 | * Forfeited into the public domain with NO WARRANTY. Read LICENSE for details. 4 | * 5 | * This file: generic data to fill out the drive_sector shared memory region. 6 | * (Specifically: Article 2 of the UN's Universal Declaration of Human Rights.) 7 | */ 8 | 9 | 10 | {'[', 0x00}, {'[', 0x00}, {'A', 0xff}, {'r', 0xff}, {'t', 0xff}, {'i', 0xff}, 11 | {'c', 0xff}, {'l', 0xff}, {'e', 0xff}, {' ', 0x00}, {'2', 0x00}, {':', 0xff}, 12 | {' ', 0x00}, {'E', 0x00}, {'v', 0x00}, {'e', 0xff}, {'r', 0xff}, {'y', 0x00}, 13 | {'o', 0xff}, {'n', 0x00}, {'e', 0xff}, {' ', 0x00}, {'i', 0xff}, {'s', 0x00}, 14 | {' ', 0x00}, {'e', 0xff}, {'n', 0x00}, {'t', 0xff}, {'i', 0xff}, {'t', 0xff}, 15 | {'l', 0xff}, {'e', 0xff}, {'d', 0x00}, {' ', 0x00}, {'t', 0xff}, {'o', 0xff}, 16 | {' ', 0x00}, {'a', 0x00}, {'l', 0xff}, {'l', 0xff}, {' ', 0x00}, {'t', 0xff}, 17 | {'h', 0x00}, {'e', 0xff}, {' ', 0x00}, {'r', 0xff}, {'i', 0xff}, {'g', 0x00}, 18 | {'h', 0x00}, {'t', 0xff}, {'s', 0x00}, {' ', 0x00}, {'a', 0x00}, {'n', 0x00}, 19 | {'d', 0x00}, {' ', 0x00}, {'f', 0xff}, {'r', 0xff}, {'e', 0xff}, {'e', 0xff}, 20 | {'d', 0x00}, {'o', 0xff}, {'m', 0x00}, {'s', 0x00}, {' ', 0x00}, {'s', 0x00}, 21 | {'e', 0xff}, {'t', 0xff}, {' ', 0x00}, {'f', 0xff}, {'o', 0xff}, {'r', 0xff}, 22 | {'t', 0xff}, {'h', 0x00}, {' ', 0x00}, {'i', 0xff}, {'n', 0x00}, {' ', 0x00}, 23 | {'t', 0xff}, {'h', 0x00}, {'i', 0xff}, {'s', 0x00}, {' ', 0x00}, {'D', 0xff}, 24 | {'e', 0xff}, {'c', 0xff}, {'l', 0xff}, {'a', 0x00}, {'r', 0xff}, {'a', 0x00}, 25 | {'t', 0xff}, {'i', 0xff}, {'o', 0xff}, {'n', 0x00}, {',', 0x00}, {' ', 0x00}, 26 | {'w', 0xff}, {'i', 0xff}, {'t', 0xff}, {'h', 0x00}, {'o', 0xff}, {'u', 0x00}, 27 | {'t', 0xff}, {' ', 0x00}, {'d', 0x00}, {'i', 0xff}, {'s', 0x00}, {'t', 0xff}, 28 | {'i', 0xff}, {'n', 0x00}, {'c', 0xff}, {'t', 0xff}, {'i', 0xff}, {'o', 0xff}, 29 | {'n', 0x00}, {' ', 0x00}, {'o', 0xff}, {'f', 0xff}, {' ', 0x00}, {'a', 0x00}, 30 | {'n', 0x00}, {'y', 0x00}, {' ', 0x00}, {'k', 0x00}, {'i', 0xff}, {'n', 0x00}, 31 | {'d', 0x00}, {',', 0x00}, {' ', 0x00}, {'s', 0x00}, {'u', 0x00}, {'c', 0xff}, 32 | {'h', 0x00}, {' ', 0x00}, {'a', 0x00}, {'s', 0x00}, {' ', 0x00}, {'r', 0xff}, 33 | {'a', 0x00}, {'c', 0xff}, {'e', 0xff}, {',', 0x00}, {' ', 0x00}, {'c', 0xff}, 34 | {'o', 0xff}, {'l', 0xff}, {'o', 0xff}, {'u', 0x00}, {'r', 0xff}, {',', 0x00}, 35 | {' ', 0x00}, {'s', 0x00}, {'e', 0xff}, {'x', 0xff}, {',', 0x00}, {' ', 0x00}, 36 | {'l', 0xff}, {'a', 0x00}, {'n', 0x00}, {'g', 0x00}, {'u', 0x00}, {'a', 0x00}, 37 | {'g', 0x00}, {'e', 0xff}, {',', 0x00}, {' ', 0x00}, {'r', 0xff}, {'e', 0xff}, 38 | {'l', 0xff}, {'i', 0xff}, {'g', 0x00}, {'i', 0xff}, {'o', 0xff}, {'n', 0x00}, 39 | {',', 0x00}, {' ', 0x00}, {'p', 0x00}, {'o', 0xff}, {'l', 0xff}, {'i', 0xff}, 40 | {'t', 0xff}, {'i', 0xff}, {'c', 0xff}, {'a', 0x00}, {'l', 0xff}, {' ', 0x00}, 41 | {'o', 0xff}, {'r', 0xff}, {' ', 0x00}, {'o', 0xff}, {'t', 0xff}, {'h', 0x00}, 42 | {'e', 0xff}, {'r', 0xff}, {' ', 0x00}, {'o', 0xff}, {'p', 0x00}, {'i', 0xff}, 43 | {'n', 0x00}, {'i', 0xff}, {'o', 0xff}, {'n', 0x00}, {',', 0x00}, {' ', 0x00}, 44 | {'n', 0x00}, {'a', 0x00}, {'t', 0xff}, {'i', 0xff}, {'o', 0xff}, {'n', 0x00}, 45 | {'a', 0x00}, {'l', 0xff}, {' ', 0x00}, {'o', 0xff}, {'r', 0xff}, {' ', 0x00}, 46 | {'s', 0x00}, {'o', 0xff}, {'c', 0xff}, {'i', 0xff}, {'a', 0x00}, {'l', 0xff}, 47 | {' ', 0x00}, {'o', 0xff}, {'r', 0xff}, {'i', 0xff}, {'g', 0x00}, {'i', 0xff}, 48 | {'n', 0x00}, {',', 0x00}, {' ', 0x00}, {'p', 0x00}, {'r', 0xff}, {'o', 0xff}, 49 | {'p', 0x00}, {'e', 0xff}, {'r', 0xff}, {'t', 0xff}, {'y', 0x00}, {',', 0x00}, 50 | {' ', 0x00}, {'b', 0x00}, {'i', 0xff}, {'r', 0xff}, {'t', 0xff}, {'h', 0x00}, 51 | {' ', 0x00}, {'o', 0xff}, {'r', 0xff}, {' ', 0x00}, {'o', 0xff}, {'t', 0xff}, 52 | {'h', 0x00}, {'e', 0xff}, {'r', 0xff}, {' ', 0x00}, {'s', 0x00}, {'t', 0xff}, 53 | {'a', 0x00}, {'t', 0xff}, {'u', 0x00}, {'s', 0x00}, {'.', 0xff}, {' ', 0x00}, 54 | {'F', 0x00}, {'u', 0x00}, {'r', 0xff}, {'t', 0xff}, {'h', 0x00}, {'e', 0xff}, 55 | {'r', 0xff}, {'m', 0x00}, {'o', 0xff}, {'r', 0xff}, {'e', 0xff}, {',', 0x00}, 56 | {' ', 0x00}, {'n', 0x00}, {'o', 0xff}, {' ', 0x00}, {'d', 0x00}, {'i', 0xff}, 57 | {'s', 0x00}, {'t', 0xff}, {'i', 0xff}, {'n', 0x00}, {'c', 0xff}, {'t', 0xff}, 58 | {'i', 0xff}, {'o', 0xff}, {'n', 0x00}, {' ', 0x00}, {'s', 0x00}, {'h', 0x00}, 59 | {'a', 0x00}, {'l', 0xff}, {'l', 0xff}, {' ', 0x00}, {'b', 0x00}, {'e', 0xff}, 60 | {' ', 0x00}, {'m', 0x00}, {'a', 0x00}, {'d', 0x00}, {'e', 0xff}, {' ', 0x00}, 61 | {'o', 0xff}, {'n', 0x00}, {' ', 0x00}, {'t', 0xff}, {'h', 0x00}, {'e', 0xff}, 62 | {' ', 0x00}, {'b', 0x00}, {'a', 0x00}, {'s', 0x00}, {'i', 0xff}, {'s', 0x00}, 63 | {' ', 0x00}, {'o', 0xff}, {'f', 0xff}, {' ', 0x00}, {'t', 0xff}, {'h', 0x00}, 64 | {'e', 0xff}, {' ', 0x00}, {'p', 0x00}, {'o', 0xff}, {'l', 0xff}, {'i', 0xff}, 65 | {'t', 0xff}, {'i', 0xff}, {'c', 0xff}, {'a', 0x00}, {'l', 0xff}, {',', 0x00}, 66 | {' ', 0x00}, {'j', 0xff}, {'u', 0x00}, {'r', 0xff}, {'i', 0xff}, {'s', 0x00}, 67 | {'d', 0x00}, {'i', 0xff}, {'c', 0xff}, {'t', 0xff}, {'i', 0xff}, {'o', 0xff}, 68 | {'n', 0x00}, {'a', 0x00}, {'l', 0xff}, {' ', 0x00}, {'o', 0xff}, {'r', 0xff}, 69 | {' ', 0x00}, {'i', 0xff}, {'n', 0x00}, {'t', 0xff}, {'e', 0xff}, {'r', 0xff}, 70 | {'n', 0x00}, {'a', 0x00}, {'t', 0xff}, {'i', 0xff}, {'o', 0xff}, {'n', 0x00}, 71 | {'a', 0x00}, {'l', 0xff}, {' ', 0x00}, {'s', 0x00}, {'t', 0xff}, {'a', 0x00}, 72 | {'t', 0xff}, {'u', 0x00}, {'s', 0x00}, {' ', 0x00}, {'o', 0xff}, {'f', 0xff}, 73 | {' ', 0x00}, {'t', 0xff}, {'h', 0x00}, {'e', 0xff}, {' ', 0x00}, {'c', 0xff}, 74 | {'o', 0xff}, {'u', 0x00}, {'n', 0x00}, {'t', 0xff}, {'r', 0xff}, {'y', 0x00}, 75 | {' ', 0x00}, {'o', 0xff}, {'r', 0xff}, {' ', 0x00}, {'t', 0xff}, {'e', 0xff}, 76 | {'r', 0xff}, {'r', 0xff}, {'i', 0xff}, {'t', 0xff}, {'o', 0xff}, {'r', 0xff}, 77 | {'y', 0x00}, {' ', 0x00}, {'t', 0xff}, {'o', 0xff}, {' ', 0x00}, {'w', 0xff}, 78 | {'h', 0x00}, {'i', 0xff}, {'c', 0xff}, {'h', 0x00}, {' ', 0x00}, {'a', 0x00}, 79 | {' ', 0x00}, {'p', 0x00}, {'e', 0xff}, {'r', 0xff}, {'s', 0x00}, {'o', 0xff}, 80 | {'n', 0x00}, {' ', 0x00}, {'b', 0x00}, {'e', 0xff}, {'l', 0xff}, {'o', 0xff}, 81 | {'n', 0x00}, {'g', 0x00}, {'s', 0x00}, {',', 0x00}, {' ', 0x00}, {'w', 0xff}, 82 | {'h', 0x00}, {'e', 0xff}, {'t', 0xff}, {'h', 0x00}, {'e', 0xff}, {'r', 0xff}, 83 | {' ', 0x00}, {'i', 0xff}, {'t', 0xff}, {' ', 0x00}, {'b', 0x00}, {'e', 0xff}, 84 | {' ', 0x00}, {'i', 0xff}, {'n', 0x00}, {'d', 0x00}, {'e', 0xff}, {'p', 0x00}, 85 | {'e', 0xff}, {'n', 0x00}, {'d', 0x00}, {'e', 0xff}, {'n', 0x00}, {'t', 0xff}, 86 | {',', 0x00}, {' ', 0x00}, {'t', 0xff}, {'r', 0xff}, {'u', 0x00}, {'s', 0x00}, 87 | {'t', 0xff}, {',', 0x00}, {' ', 0x00}, {'n', 0x00}, {'o', 0xff}, {'n', 0x00}, 88 | {'-', 0xff}, {'s', 0x00}, {'e', 0xff}, {'l', 0xff}, {'f', 0xff}, {'-', 0xff}, 89 | {'g', 0x00}, {'o', 0xff}, {'v', 0x00}, {'e', 0xff}, {'r', 0xff}, {'n', 0x00}, 90 | {'i', 0xff}, {'n', 0x00}, {'g', 0x00}, {' ', 0x00}, {'o', 0xff}, {'r', 0xff}, 91 | {' ', 0x00}, {'u', 0x00}, {'n', 0x00}, {'d', 0x00}, {'e', 0xff}, {'r', 0xff}, 92 | {' ', 0x00}, {'a', 0x00}, {'n', 0x00}, {'y', 0x00}, {' ', 0x00}, {'o', 0xff}, 93 | {'t', 0xff}, {'h', 0x00}, {'e', 0xff}, {'r', 0xff}, {' ', 0x00}, {'l', 0xff}, 94 | {'i', 0xff}, {'m', 0x00}, {'i', 0xff}, {'t', 0xff}, {'a', 0x00}, {'t', 0xff}, 95 | {'i', 0xff}, {'o', 0xff}, {'n', 0x00}, {' ', 0x00}, {'o', 0xff}, {'f', 0xff}, 96 | {' ', 0x00}, {'s', 0x00}, {'o', 0xff}, {'v', 0x00}, {'e', 0xff}, {'r', 0xff}, 97 | {'e', 0xff}, {'i', 0xff}, {'g', 0x00}, {'n', 0x00}, {'t', 0xff}, {'y', 0x00}, 98 | {'.', 0xff}, {']', 0x00}, {']', 0x00}, {'\n', 0xff}, 99 | -------------------------------------------------------------------------------- /aphid/firmware/aphd_pru1_control/aphd_pru1_interrupt_and_buffer_handler.h: -------------------------------------------------------------------------------- 1 | // Aphid: Apple parallel port hard drive emulator for Cameo 2 | // 3 | // Forfeited into the public domain with NO WARRANTY. Read LICENSE for details. 4 | // 5 | // This file: firmware for PRU 1; interrupt and RPMsg buffer handling. 6 | // 7 | // Although this unit contains routines for servicing all kinds of interrupts 8 | // encountered by PRU1, most of the code is for dealing with RPMsg messages 9 | // from the ARM. Some interrupts (particularly those from PRU 0 data pump 10 | // routines) are handled by aphd_pru1_control.cc code directly to minimise 11 | // latency. 12 | 13 | #ifndef APHD_PRU1_INTERRUPT_AND_BUFFER_HANDLER_H_ 14 | #define APHD_PRU1_INTERRUPT_AND_BUFFER_HANDLER_H_ 15 | 16 | 17 | // Interpretations for R31 bit 31 interrupts to PRU1. These serve as return 18 | // values for `handle_interrupt()`. 19 | enum InterruptMeaning { 20 | // There was no interrupt, as best we can tell, at least not one that we 21 | // were equipped to handle. Note that it's preferable to call 22 | // handle_interrupt() only when there is an interrupt, i.e. R31 bit 31 is 23 | // actually set. 24 | kImNone = 0, 25 | 26 | // The interrupt originated from PRU0. It's up to the caller to determine 27 | // what to do about that. 28 | kImPru0 = 1, 29 | 30 | // The interrupt came from the ARM sending a message over RPMsg, but it was 31 | // a buffer-handling request that the interrupt handler serviced on its own. 32 | // No action is required. 33 | kImArmHandled = 2, 34 | 35 | // The interrupt came from the ARM sending a message over RPMSG, and although 36 | // it was a buffer-handling request that the interrupt handler could service 37 | // on its own, its attempt to do so failed. 38 | kImArmFailedToHandle = 3, 39 | 40 | // The interrupt came from the ARM sending a message over RPMsg, and it was 41 | // the ARM advising PRU1 that the ARM has completed all of the buffer 42 | // operations that PRU1 was waiting on the ARM to complete. 43 | kImArmProceed = 4, 44 | }; 45 | 46 | 47 | // Handle an R31 bit 31 interrupt. 48 | // 49 | // There are two sources of bit-31 ("for PRU1") interrupts: the ARM and PRU0. 50 | // 51 | // An interrupt from PRU0 is essentially up to the caller to handle---usually 52 | // it means that a data transfer to the Apple has completed, and so the 53 | // controller can go on with the rest of the protocol. 54 | // 55 | // Interrupts from the ARM mainly concern memory that the ARM would like to read 56 | // into or out of sector buffers. The interrupt handler takes care of these on 57 | // its own. Occasionally an ARM interrupt tells PRU1 that the ARM is finished 58 | // with certain critical buffer operations (it's written a sector to the disk 59 | // image, for example) and that the rest of the read or write can continue. 60 | // 61 | // This routine should be called only when PRU1 finds that R31 bit 31 is set. 62 | // It will investigate the interrupt, handle it appropriately, **and finally, 63 | // clear it.** 64 | // 65 | // Returns: 66 | // an `InterruptMeaning` value indicating the importance (and in some cases, 67 | // resolution) of the interrupt. See `InterruptMeaning` for details. 68 | InterruptMeaning handle_interrupt(); 69 | 70 | 71 | #endif // APHD_PRU1_INTERRUPT_AND_BUFFER_HANDLER_H_ 72 | -------------------------------------------------------------------------------- /aphid/firmware/aphd_pru1_control/aphd_pru1_resource_table.c: -------------------------------------------------------------------------------- 1 | /* Apple parallel port storage emulator for Cameo 2 | * 3 | * Forfeited into the public domain with NO WARRANTY. Read LICENSE for details. 4 | * 5 | * This file: the remoteproc resource table for PRU 1. 6 | */ 7 | 8 | 9 | #include "aphd_pru_common.h" 10 | #include "aphd_pru1_resource_table.h" 11 | 12 | 13 | struct ch_map PRU1_INTC_SYSEVENT_TO_CHANNEL[] = { 14 | {ePRU0to1, 1U}, 15 | {ePRU1to0, 0U}, 16 | {ePRU1toARM, 2U}, 17 | {eARMtoPRU1, 3U}, 18 | }; 19 | 20 | 21 | #pragma DATA_SECTION(PRU1_RESOURCE_TABLE, ".resource_table") 22 | #pragma RETAIN(PRU1_RESOURCE_TABLE) 23 | struct pru1_resource_table PRU1_RESOURCE_TABLE = { 24 | .resources = { 25 | .ver = 1U, 26 | .num = 2U, 27 | .reserved = {0U, 0U}, 28 | }, 29 | 30 | .offsets = { 31 | offsetof(struct pru1_resource_table, rpmsg), 32 | offsetof(struct pru1_resource_table, intc), 33 | }, 34 | 35 | .rpmsg = { 36 | .vdev = { 37 | .type = TYPE_VDEV, 38 | .id = VIRTIO_ID_RPMSG, 39 | .notifyid = 0U, /* Host populates this notify ID. */ 40 | .dfeatures = 0x00000001U, /* Supports name service notifications. */ 41 | .gfeatures = 0U, /* Host populates with its own features. */ 42 | .config_len = 0U, 43 | .status = 0U, /* Host populates this status byte. */ 44 | .num_of_vrings = 2U, /* For RX and TX (not sure which is which). */ 45 | .reserved = {0U, 0U}, 46 | }, 47 | .vring0 = { 48 | .da = 0U, /* Host populates this device address. */ 49 | .align = 16U, 50 | .num = 16U, /* Number of buffers must be a power of 2. */ 51 | .notifyid = 0U, /* Host populates this notify ID. */ 52 | .reserved = 0U, 53 | }, 54 | .vring1 = { 55 | .da = 0U, /* Host populates this device address. */ 56 | .align = 16U, 57 | .num = 16U, /* Number of buffers must be a power of 2. */ 58 | .notifyid = 0U, /* Host populates this notify ID. */ 59 | .reserved = 0U, 60 | }, 61 | }, 62 | 63 | .intc = { 64 | .type = TYPE_CUSTOM, 65 | /* The rsc_types.h header changed between versions 9.4 and 9.5 of the OS to 66 | * provide two ways to specify the custom resource sub-type. The change also 67 | * defined the macro TYPE_PRELOAD_VENDOR, which was undefined before. We use 68 | * this macro to identify which version of rsc_types.h we're using. */ 69 | #ifdef TYPE_PRELOAD_VENDOR 70 | .u = { 71 | .sub_type = TYPE_PRU_INTS, 72 | }, 73 | #else 74 | .sub_type = TYPE_PRU_INTS, 75 | #endif 76 | .rsc_size = sizeof(struct fw_rsc_custom_ints), 77 | .rsc = { 78 | .pru_ints = { 79 | /* The pru_types.h header changed between versions 9.4 and 9.5 of the OS 80 | * to deprecate the version field of fw_rsc_custom_ints. The change also 81 | * defined the macro PRU_INTS_VER0, which was undefined before. We use 82 | * this macro to identify which version of pru_types.h we're using. */ 83 | #ifdef PRU_INTS_VER0 84 | .reserved = 0U, 85 | #else 86 | .version = 0U, 87 | #endif 88 | .channel_host = { 89 | 0U, /* Channel 0 (ePRU1to0): host interrupt 0, so r31 bit 30. */ 90 | 1U, /* Channel 1 (ePRU0to1): host interrupt 1, so r31 bit 31. */ 91 | 2U, /* Channel 2 (ePRU1toARM): host interrupt 2. */ 92 | 1U, /* Channel 3 (eARMtoPRU1): host interrupt 1, so r31 bit 31. */ 93 | 255U, 255U, 255U, 255U, 255U, 255U, /* Channels 4-9: unused. */ 94 | }, 95 | .num_evts = (sizeof(PRU1_INTC_SYSEVENT_TO_CHANNEL) / 96 | sizeof(struct ch_map)), 97 | .event_channel = PRU1_INTC_SYSEVENT_TO_CHANNEL, 98 | }, 99 | }, 100 | }, 101 | }; 102 | -------------------------------------------------------------------------------- /aphid/firmware/aphd_pru1_control/aphd_pru1_resource_table.h: -------------------------------------------------------------------------------- 1 | /* Apple parallel port storage emulator for Cameo 2 | * 3 | * Forfeited into the public domain with NO WARRANTY. Read LICENSE for details. 4 | * 5 | * This file: the remoteproc resource table for PRU 1. 6 | */ 7 | 8 | #ifndef APHD_PRU1_RESOURCE_TABLE_H_ 9 | #define APHD_PRU1_RESOURCE_TABLE_H_ 10 | 11 | 12 | #include 13 | #include 14 | 15 | #include 16 | #include 17 | #include 18 | 19 | 20 | #ifdef __cplusplus 21 | #extern "C" { 22 | #endif /* __cplusplus */ 23 | 24 | 25 | struct pru1_resource_table { 26 | struct resource_table resources; 27 | uint32_t offsets[2]; /* Size should match the value in resources.num. */ 28 | 29 | /* RPMsg configuration; a vdev with two vrings. */ 30 | struct { 31 | struct fw_rsc_vdev vdev; 32 | struct fw_rsc_vdev_vring vring0; 33 | struct fw_rsc_vdev_vring vring1; 34 | } rpmsg; 35 | 36 | /* PRU INTC configuration. */ 37 | struct fw_rsc_custom intc; 38 | }; 39 | 40 | 41 | extern struct pru1_resource_table PRU1_RESOURCE_TABLE; 42 | 43 | 44 | #ifdef __cplusplus 45 | } 46 | #endif /* __cplusplus */ 47 | 48 | #endif /* APHD_PRU1_RESOURCE_TABLE_H_ */ 49 | -------------------------------------------------------------------------------- /aphid/firmware/aphd_pru1_control/aphd_pru1_rpmsg.c: -------------------------------------------------------------------------------- 1 | /* Apple parallel port storage emulator for Cameo 2 | * 3 | * Forfeited into the public domain with NO WARRANTY. Read LICENSE for details. 4 | * 5 | * This file: firmware for PRU1; RPMsg I/O routines. 6 | */ 7 | 8 | 9 | #include 10 | 11 | #include 12 | #include 13 | 14 | #include "aphd_pru_common.h" 15 | #include "aphd_pru1_resource_table.h" 16 | #include "aphd_pru1_rpmsg.h" 17 | 18 | 19 | /* For reasons elaborated in aphd_pru1_rpmsg.h, we define our own "copy" of the 20 | * RPMSG_BUF_SIZE value called RPMSG_BUFFER_SIZE. It's essential that our copy 21 | * track the original, so this type definition will cause a compile failure if 22 | * RPMSG_BUF_SIZE ever changes from its current value. To fix, all that's likely 23 | * to be necessary is to change RPMSG_BUFFER_SIZE to the correct value. */ 24 | typedef char ______RPMSG_BUF_SIZE_and_RPMSG_BUFFER_SIZE_are_not_the_same______[ 25 | (RPMSG_BUF_SIZE == RPMSG_BUFFER_SIZE) ? 1 : -1]; 26 | 27 | 28 | /* TI RPMsg API data structure for RPMsg communication. */ 29 | static struct pru_rpmsg_transport RPMSG_TRANSPORT; 30 | 31 | /* RPMsg uses these dynamically-assigned addresses to specify the senders and 32 | * recipients of messages. */ 33 | static uint16_t RPMSG_ARM_ADDRESS; 34 | static uint16_t RPMSG_PRU_ADDRESS; 35 | 36 | /* Data buffer mainly for incoming messages. Details in header. */ 37 | uint8_t RPMSG_BUFFER[RPMSG_BUFFER_SIZE + RPMSG_BUFFER_SIZE]; 38 | 39 | 40 | /* Built-in symbols used for PRU GPIO pin access and interrupt handling. */ 41 | volatile register uint32_t __R30; 42 | volatile register uint32_t __R31; 43 | 44 | 45 | /* Helper: calls pru_rpmsg_receive with the state variables internal to this 46 | * module as parameters. */ 47 | inline int _receive(uint8_t* buffer, uint16_t* length) { 48 | return pru_rpmsg_receive( 49 | &RPMSG_TRANSPORT, 50 | &RPMSG_ARM_ADDRESS, 51 | &RPMSG_PRU_ADDRESS, 52 | buffer, 53 | length); 54 | } 55 | 56 | 57 | void aphd_pru1_rpmsg_init() { 58 | uint16_t received; 59 | 60 | /* Wait until the Linux driver has updated the status byte in the vdev struct 61 | * inside our resource table. 0x4 is the correct bit to look out for as per 62 | * virtio_config.h in the Linux kernel source. */ 63 | const uint8_t kVirtioConfigSDriverOk = 0x4; 64 | volatile uint8_t* status = &PRU1_RESOURCE_TABLE.rpmsg.vdev.status; 65 | while (!(*status & kVirtioConfigSDriverOk)); 66 | 67 | /* Initialise the RPMSG_TRANSPORT structure. */ 68 | pru_rpmsg_init( 69 | &RPMSG_TRANSPORT, /* Initialise this transport structure */ 70 | &PRU1_RESOURCE_TABLE.rpmsg.vring0, /* One of the input/output vrings */ 71 | &PRU1_RESOURCE_TABLE.rpmsg.vring1, /* The other input/output vring */ 72 | ePRU1toARM, 73 | eARMtoPRU1); 74 | 75 | /* With that structure, create an RPMsg channel between ARM and the PRU. */ 76 | while (pru_rpmsg_channel( 77 | RPMSG_NS_CREATE, 78 | &RPMSG_TRANSPORT, 79 | "rpmsg-pru", /* Channel name---loads corresp. kernel module */ 80 | "Channel 31", /* Channel description */ 81 | 31 /* Channel port */ 82 | ) != PRU_RPMSG_SUCCESS); 83 | 84 | /* Await a dummy message from the ARM to populate src and dst addresses. We 85 | * are hoping at this early stage not to receive any interrupts from PRU0, 86 | * but if we do, we will just ignore them and let PRU0 time out. */ 87 | CT_INTC.SICR = eARMtoPRU1; /* Clear ARM to PRU1 interrupt */ 88 | for(;;) { 89 | if (__R31 & (1U << iAnyToPRU1)) { /* If we got an interrupt... */ 90 | if (CT_INTC.SECR0 & (1 << eARMtoPRU1)) { /* ...from the ARM, then... */ 91 | /* ...throw away data from the ARM and clear ARM to PRU1 interrupt. */ 92 | if (_receive(RPMSG_BUFFER, &received) == PRU_RPMSG_SUCCESS) { 93 | while(_receive(RPMSG_BUFFER, &received) == PRU_RPMSG_SUCCESS); 94 | CT_INTC.SICR = eARMtoPRU1; 95 | break; 96 | } 97 | 98 | } else { /* But if the interrupt wasn't from the ARM, then... */ 99 | CT_INTC.SICR = ePRU0to1; /* ...clear PRU0 to PRU1 interrupt... */ 100 | } /* ...and keep waiting for the ARM */ 101 | } 102 | } 103 | } 104 | 105 | 106 | int16_t aphd_pru1_rpmsg_send(void* buffer, uint16_t length) { 107 | return pru_rpmsg_send( 108 | &RPMSG_TRANSPORT, 109 | RPMSG_PRU_ADDRESS, 110 | RPMSG_ARM_ADDRESS, 111 | buffer, 112 | length); 113 | } 114 | 115 | 116 | uint16_t aphd_pru1_rpmsg_receive() { 117 | uint16_t total_received = 0; 118 | uint16_t received; 119 | uint8_t* buf = RPMSG_BUFFER; 120 | 121 | /* Messages can be broken into smaller chunks, so we continue pulling in data 122 | * until there isn't any left. */ 123 | for (;;) { 124 | if (_receive(buf, &received) != PRU_RPMSG_SUCCESS) break; 125 | 126 | total_received += received; 127 | buf += received; 128 | 129 | /* If we've received more than RPMSG_BUFFER_SIZE bytes, we toss any 130 | * remaining data into the bit bucket until we've exhausted all input. */ 131 | if (total_received > RPMSG_BUFFER_SIZE) { 132 | for (;;) { 133 | if (_receive(RPMSG_BUFFER + 134 | RPMSG_BUFFER_SIZE, &received) != PRU_RPMSG_SUCCESS) break; 135 | } 136 | break; 137 | } 138 | } 139 | 140 | return total_received; 141 | } 142 | -------------------------------------------------------------------------------- /aphid/firmware/aphd_pru1_control/aphd_pru1_rpmsg.h: -------------------------------------------------------------------------------- 1 | /* Apple parallel port storage emulator for Cameo 2 | * 3 | * Forfeited into the public domain with NO WARRANTY. Read LICENSE for details. 4 | * 5 | * This file: firmware for PRU1; RPMsg I/O routines 6 | * 7 | * RPMsg is the communication mechanism for transferring data to and from the 8 | * ARM. Once initialised, ARM programs will be able to send and receive data 9 | * to and from PRU1 by writing to/reading from /dev/rpmsg_pru31, a character 10 | * device. 11 | * 12 | * All individual data transactions should be limited to 512 - 16 = 496 bytes: 13 | * the empty space in RPMsg message buffers once the TI RPMsg libraries claim 14 | * part of it for a header. When sending, the ARM program should probably use 15 | * `select()` or `poll()` to make sure that PRU1 is ready for new data. 16 | */ 17 | 18 | #ifndef APHD_PRU1_RPMSG_H_ 19 | #define APHD_PRU1_RPMSG_H_ 20 | 21 | 22 | #include 23 | 24 | 25 | #ifdef __cplusplus 26 | extern "C" { 27 | #endif /* __cplusplus */ 28 | 29 | 30 | /* This symbol has the exact same meaning and value as RPMSG_BUF_SIZE from 31 | * pru_rpmsg.h, but since C++ code can have a hard time including that file, we 32 | * redefine that number here. There is a "static assert" of sorts at the 33 | * beginning of aphd_pru1_rpmsg.c that will cause a compilation failure if the 34 | * value of this symbol no longer matches the value of RPMSG_BUF_SIZE. */ 35 | #define RPMSG_BUFFER_SIZE 512 36 | 37 | 38 | /* A buffer for RPMsg messages. All inbound messages land here; outbound 39 | * messages can originate from anywhere in RAM. 40 | * 41 | * (This buffer is twice the size of the largest RPMsg message in the spirit of 42 | * "defensive programming". RPMsg provides no way to know how big a message is 43 | * before you receive it. Since `aphd_pru1_rpmsg_receive()` flushes all pending 44 | * incoming messages each time it's called, but promises to keep the first 45 | * RPMSG_BUFFER_SIZE bytes it loads, it needs room for the messages to overflow 46 | * this limit before it knows to throw the extra information into the void.) */ 47 | extern uint8_t RPMSG_BUFFER[RPMSG_BUFFER_SIZE + RPMSG_BUFFER_SIZE]; 48 | 49 | 50 | /* Initialise internal RPMsg I/O control state. 51 | * 52 | * This function must be called before calling any of the other functions in 53 | * this file---ideally right when the firmware starts running. Loops forever if 54 | * certain initialisation conditions on the Linux side are not met; since the 55 | * PRU1 firmware is not much use without being able to talk to the ARM, this 56 | * seems like a reasonable simplification. */ 57 | void aphd_pru1_rpmsg_init(); 58 | 59 | 60 | /* Send data to the ARM via RPMsg. 61 | * 62 | * Args: 63 | * buffer: starting address of data to send. 64 | * length: amount of data to send in bytes. Successful sends require this 65 | * value to be no larger than 496. 66 | * 67 | * Returns: 68 | * See return value documentation for `pru_rpmsg_send()` in the TI RPMsg API's 69 | * pru_rpmsg.h. Success causes a return value of 0. */ 70 | int16_t aphd_pru1_rpmsg_send(void* buffer, uint16_t length); 71 | 72 | 73 | /* Receive data from the ARM via RPMsg. 74 | * 75 | * Retrieves all inbound RPMsg messages waiting to be delivered to PRU1 from the 76 | * ARM. Up to the first RPMSG_BUFFER_SIZE bytes of data in these messages will 77 | * be stored in RPMSG_BUFFER. (Occasionally a bit more may be retrieved if there 78 | * is more than that amount waiting, but only the first RPMSG_BUFFER_SIZE are 79 | * guaranteed to be saved; the rest may be discarded.) 80 | * 81 | * Returns: 82 | * Amount of data received in bytes. 83 | */ 84 | uint16_t aphd_pru1_rpmsg_receive(); 85 | 86 | 87 | #ifdef __cplusplus 88 | } 89 | #endif /* __cplusplus */ 90 | 91 | #endif /* APHD_PRU1_RPMSG_H_ */ 92 | -------------------------------------------------------------------------------- /aphid/firmware/aphd_pru1_control/aphd_pru1_shared_memory.cc: -------------------------------------------------------------------------------- 1 | // Aphid: Apple parallel port hard drive emulator for Cameo 2 | // 3 | // Forfeited into the public domain with NO WARRANTY. Read LICENSE for details. 4 | // 5 | // This file: firmware for PRU 1; shared memory setup. 6 | 7 | 8 | #include "aphd_pru1_shared_memory.h" 9 | 10 | // This defines a shared memory structure that starts at the beginning of the 11 | // PRU shared memory space. We also initialise the bytes_with_parity table that 12 | // it holds, as well as the drive_sector table (originally for testing, but it 13 | // can't hurt to have something besides zeros there regardless) and the debug 14 | // word. The other elements are basically left uninitialised. 15 | #pragma DATA_SECTION(".shmem") 16 | volatile __far SharedMemory SHMEM = { 17 | /* data_pump_command: */ { 18 | /* return_code: */ 0xff, 19 | /* command (invalid on purpose): */ 0x80, 20 | /* size */ 0x0, 21 | /* address */ 0x0, 22 | }, 23 | /* data_pump_statistics: */ {}, 24 | /* apple_handshake: */ {}, 25 | /* apple_command: */ {}, 26 | /* drive_status: */ {}, 27 | /* drive_sector: */ { 28 | #include 29 | }, 30 | /* apple_sector: */ {}, 31 | /* bytes_with_parity: */ { 32 | #include 33 | }, 34 | /* control_debug_word: */ 0xffff, 35 | /* last_control_debug_word: */ 0xfdfd, 36 | /* rpmsg_debug_word: */ 0xffff, 37 | /* last_rpmsg_debug_word: */ 0xfdfd, 38 | }; 39 | -------------------------------------------------------------------------------- /aphid/firmware/aphd_pru1_control/aphd_pru1_shared_memory.h: -------------------------------------------------------------------------------- 1 | // Aphid: Apple parallel port hard drive emulator for Cameo 2 | // 3 | // Forfeited into the public domain with NO WARRANTY. Read LICENSE for details. 4 | // 5 | // This file: firmware for PRU 1; shared memory setup. 6 | 7 | #ifndef APHD_PRU1_SHARED_MEMORY_H_ 8 | #define APHD_PRU1_SHARED_MEMORY_H_ 9 | 10 | 11 | #include 12 | 13 | 14 | // The data pump command structure sits at the base of the shared memory region. 15 | // PRU 1 can invoke the data pump (i.e. PRU 0) by placing values in this 16 | // structure and sending PRU 0 an interrupt. PRU 0 will perform the operation, 17 | // deposit a return value in the return_code field, and send an interrupt 18 | // back to PRU 1. This invocation mechanism is automated by functions in the 19 | // "LOW LEVEL I/O" section of aphd_pru1_control.cc. 20 | // 21 | // Note: for details on .command values besides 0x00 and 0x01, see documentation 22 | // in aphd_pru0_datapump/aphd_pru0_datapump.asm. 23 | struct __attribute__((packed)) DataPumpCommand { 24 | uint8_t return_code; // Return code for the data pump operation 25 | uint8_t command; // Command: 0x0: read, 0x1: write, other: see above 26 | uint16_t size; // Number of bytes/words affected by the operation 27 | uint32_t address; // Location of bytes/words affected by the operation 28 | }; 29 | 30 | 31 | // After each I/O operation, PRU 0 copies updated versions of several 32 | // accumulated performance statistics into shared memory. 33 | struct __attribute__((packed)) DataPumpStatistics { 34 | // These four values total the number of bytes/words requested and 35 | // successfully received/emitted for reading/writing operations. 36 | uint32_t data_pump_read_bytes_requested; 37 | uint32_t data_pump_read_bytes_succeeded; 38 | uint32_t data_pump_write_words_requested; 39 | uint32_t data_pump_write_words_succeeded; 40 | }; 41 | 42 | 43 | // When the data pump (PRU 0) sends data from shared memory to the Apple, the 44 | // odd parity bit for each data byte must be precomputed. Data bytes and parity 45 | // bits sit side-by-side in RAM in pairs described by this data structure. The 46 | // sixth bit of the parity member of ByteParityPair supplies the actual value 47 | // assigned to the \PPARITY line, but since all other bits are ignored, it's 48 | // fine to use values like 0x00 and 0xff. 49 | struct __attribute__((packed)) ByteParityPair { 50 | uint8_t data; 51 | uint8_t parity; 52 | 53 | // We need to define this in order to enable copies between ByteParityPair 54 | // values in shared memory. 55 | volatile ByteParityPair& operator=(volatile ByteParityPair& other) volatile { 56 | this->data = other.data; 57 | this->parity = other.parity; 58 | return *this; 59 | } 60 | }; 61 | 62 | 63 | // This structure defines the layout of the shared memory space. 64 | struct __attribute__((packed)) SharedMemory { 65 | // The data pump command structure; see DataPumpCommand for details. 66 | DataPumpCommand data_pump_command; 67 | 68 | // Data pump usage statistics; see DataPumpStatistics for details. 69 | DataPumpStatistics data_pump_statistics; 70 | 71 | // The most recent handshake byte from the Apple. We only need a single byte, 72 | // but we use two for the sake of (not strictly necessary) 16-bit alignment. 73 | // It just feels tidier. 74 | uint8_t apple_handshake[2]; 75 | 76 | // The most recent six command bytes from the Apple. 77 | uint8_t apple_command[6]; 78 | 79 | // The most recent four byte-parity pairs that encode the status information 80 | // that the drive returns to the Apple. 81 | ByteParityPair drive_status[4]; 82 | 83 | // Whole disk sector data that the drive sends to the Apple. It's important 84 | // that this immediately follows drive_status. 85 | ByteParityPair drive_sector[532]; 86 | 87 | // Whole disk sector data that the Apple sends to the drive. 88 | uint8_t apple_sector[532]; 89 | 90 | // Often we may need to send single bytes to the Apple, or assemble short 91 | // sequences to send to the Apple. For this we make use of a big precomputed 92 | // table of bytes and parity values. 93 | ByteParityPair bytes_with_parity[256]; 94 | 95 | // The remaining shared memory items are supplemental debugging data items. 96 | // There is no standard means of exporting these items from PRU1 to the ARM; 97 | // if you'd like to do it yourself, I recommend writing a program that mmaps 98 | // /dev/mem and starts reading from address 0x4a310000... 99 | 100 | // If kDebug in aphd_pru1_control.cc is true, then this word will be updated 101 | // with various symbols that indicate the control state machine's state. 102 | uint16_t control_debug_word; 103 | 104 | // If kDebug in aphd_pru1_control.cc is true, then this word will contain the 105 | // value of control_debug_word just before it was last reset at the top of the 106 | // state machine outer loop. 107 | uint16_t last_control_debug_word; 108 | 109 | // If kDebug in aphd_pru1_interrupt_and_buffer_handler.cc is true, then this 110 | // word will be updated with various symbols that indicate progress through 111 | // RPMsg transactions with the ARM. 112 | uint16_t rpmsg_debug_word; 113 | 114 | // If kDebug in aphd_pru1_interrupt_and_buffer_handler.cc is true, then this 115 | // word will contain the value of rpmsg_debug_word just before it was last 116 | // reset in the interrupt handler. 117 | uint16_t last_rpmsg_debug_word; 118 | }; 119 | 120 | 121 | // Declare the shared memory itself. 122 | extern volatile __far SharedMemory SHMEM; 123 | 124 | 125 | #endif // APHD_PRU0_SHARED_MEMORY_H_ 126 | -------------------------------------------------------------------------------- /aphid/firmware/aphd_pru_common.h: -------------------------------------------------------------------------------- 1 | /* Apple parallel port storage emulator for Cameo 2 | * 3 | * Forfeited into the public domain with NO WARRANTY. Read LICENSE for details. 4 | * 5 | * This file: constants and other shared information for both PRU programs. 6 | * 7 | * Comments may refer to various manuals by abbreviations: 8 | * TRM: AM335x Technical Reference Manual 9 | * PRG: AM335x PRU Reference Guide 10 | */ 11 | 12 | #ifndef APHD_PRU_COMMON_H_ 13 | #define APHD_PRU_COMMON_H_ 14 | 15 | 16 | /* ////////////////////// 17 | //// I/O PIN ALIASES //// 18 | ////////////////////// */ 19 | 20 | /* Control lines are unidirectional, so we can refer to them via constants 21 | * whether we are retrieving or sending data. */ 22 | 23 | #define pBSY r30.t8 24 | #define psBSY "r30.t8" 25 | #define ppBSY 8 26 | 27 | #define pCMD r31.t9 28 | #define psCMD "r31.t9" 29 | #define ppCMD 9 30 | 31 | #define pPARITY r30.t14 32 | #define psPARITY "r30.t14" 33 | #define ppPARITY 14 34 | 35 | #define pRW r31.t15 /* NOTE: This signal is PEX2 on the schematic, */ 36 | #define psRW "r31.t15" /* not PR/\W. */ 37 | #define ppRW 15 38 | 39 | #define pSTRB r31.t16 40 | #define psSTRB "r31.t16" 41 | #define ppSTRB 16 42 | 43 | 44 | /* ///////////////////////// 45 | //// INTERRUPT HANDLING //// 46 | ///////////////////////// */ 47 | 48 | #define ePRU0to1 16U /* System event for interrupts from PRU0 to PRU1 */ 49 | #define ePRU1to0 17U /* System event for interrupts from PRU1 to PRU0 */ 50 | #define ePRU1toARM 18U /* System event for interrupts from PRU1 to ARM */ 51 | #define eARMtoPRU1 19U /* System event for interrputs from ARM to PRU1 */ 52 | /* Note: The Linux kernel device tree for the Beagles specify system events 53 | * 16 and 17 for RPMsg kicks between PRU0 and the ARM, and system events 54 | * 18 and 19 for RPMsg kicks between PRU1 and the ARM. Events 16 and 18 go 55 | * to the ARM; events 17 and 19 go to the PRU. */ 56 | 57 | #define sPRU0to1 16U + ePRU0to1 /* For raising a PRU0 to PRU1 system event */ 58 | #define sPRU1to0 16U + ePRU1to0 /* For raising a PRU1 to PRU0 system event */ 59 | #define sARMtoPRU1 16U + eARMtoPRU1 /* For raising an ARM to PRU1 sysevent */ 60 | 61 | #define iAnyToPRU1 31U /* R31 bit indicating any interrupt to PRU1 */ 62 | #define iPRU1to0 30U /* R31 bit indicating an interrupt from PRU1 to PRU0 */ 63 | /* Note: The resource table must ultimately map: 64 | * system event ePRU0to1 to host interrupt (iAnyToPRU1 - 30), 65 | * system event ePRU1to0 to host interrupt (iPRU1to0 - 30), and 66 | * system event eARMtoPRU1 to host interrupt (iAnyToPRU1 - 30) 67 | * for these definitions to be correct. */ 68 | 69 | 70 | /* //////////////////// 71 | //// CONST ALIASES //// 72 | //////////////////// */ 73 | 74 | /* Aliases for various const registers (PRG 5.2.1). */ 75 | 76 | #define cINTC c0 /* Pointer to PRU INTC */ 77 | #define cCONFIG c4 /* Pointer to PRU_SYSCFG */ 78 | #define cSHARED c28 /* Pointer to shared PRU RAM */ 79 | 80 | /* Aliases for offsets from various const registers. */ 81 | 82 | #define oINTC_SICR 0x24 /* cINTC offset to SICR register */ 83 | 84 | 85 | /* ///////////////////////// 86 | //// DATA PUMP COMMANDS //// 87 | ///////////////////////// */ 88 | 89 | #define dREAD 0x00 /* Read a block of data from the data lines */ 90 | #define dWRITE 0x01 /* Write a block of data to the data lines */ 91 | #define dINVALID 0x80 /* An intentional nonsense command, used for resets */ 92 | 93 | 94 | #endif /* APHD_PRU_COMMON_H_ */ 95 | -------------------------------------------------------------------------------- /aphid/pics/cameo-aphid.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stepleton/cameo/ca64ef0f286fabcdfb018684bf078709f3188b11/aphid/pics/cameo-aphid.jpg -------------------------------------------------------------------------------- /aphid/pics/smd_layout.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stepleton/cameo/ca64ef0f286fabcdfb018684bf078709f3188b11/aphid/pics/smd_layout.png -------------------------------------------------------------------------------- /aphid/pics/thumb_all_parts.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stepleton/cameo/ca64ef0f286fabcdfb018684bf078709f3188b11/aphid/pics/thumb_all_parts.jpg -------------------------------------------------------------------------------- /aphid/pics/thumb_frontback.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stepleton/cameo/ca64ef0f286fabcdfb018684bf078709f3188b11/aphid/pics/thumb_frontback.jpg -------------------------------------------------------------------------------- /aphid/pics/thumb_profile.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stepleton/cameo/ca64ef0f286fabcdfb018684bf078709f3188b11/aphid/pics/thumb_profile.jpg -------------------------------------------------------------------------------- /aphid/pics/thumb_sideside.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stepleton/cameo/ca64ef0f286fabcdfb018684bf078709f3188b11/aphid/pics/thumb_sideside.jpg -------------------------------------------------------------------------------- /aphid/pics/ui.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stepleton/cameo/ca64ef0f286fabcdfb018684bf078709f3188b11/aphid/pics/ui.jpg -------------------------------------------------------------------------------- /aphid/profile_plugin_FFFEFC_selector_rescue.py: -------------------------------------------------------------------------------- 1 | """A ProFile "magic block" plugin for reinstalling the Cameo/Aphid Selector. 2 | 3 | Forfeited into the public domain with NO WARRANTY. Read LICENSE for details. 4 | 5 | This plugin makes it easier to recover an installation of the Selector to the 6 | current working directory. It also "serves" the contents of complete Selector 7 | hard drive image files. The data for both operations come from (what in most 8 | Cameo/Aphid installations is) read-only storage, which may make it more robust 9 | to whatever mischief the user might inflict on their .image files. 10 | 11 | Note that if the user upgrades the Selector in the current working directory by 12 | hand (as they might do by copying a new Selector drive image onto the 13 | CAMEO_APHID microSD card partition), it still won't change the Selector copies 14 | that this plugin uses, and a restoration of an older version could feel like a 15 | downgrade. 16 | 17 | By convention, this plugin is associated with block $FFFEFC. There's no reason 18 | it can't be attached to different blocks, but for the following $FFFEFC will be 19 | used as a shorthand for whatever "magic block" is in use. 20 | 21 | - ProFile reads to $FFFEFC: have effects that depend on the 16-bit 22 | concatenation of the read's retry count and sparing threshold parameters. 23 | These are: 24 | 25 | - $FFFF: copy the contents of `selector.image` from the Zip archive 26 | `/home/debian/aphid/selector/selector.image.zip` to `profile.image` in 27 | the current working directory, then trigger the start of a new emulation 28 | session using `profile.image` as the current hard drive image. If a file 29 | called `profile.image` already exists, it will be renamed to 30 | `profile.backup-X.image`, where `X` is the first number counting up from 31 | 0 that yields an unused filename. The block contents retrieved by this 32 | read are unspecified. 33 | 34 | - $0XXX: retrieve the $XXXth 532-byte block of `selector.image` from the 35 | Zip archive `/home/debian/aphid/selector/selector.image.zip`, or, if 36 | `selector.image` is less than ($XXX - 1) * 532 bytes long, a block of 37 | 532 $00 bytes. 38 | 39 | - $1XXX: retrieve the $XXXth 532-byte block of `selector.3.5inch.dc42` from 40 | the Zip archive `/home/debian/aphid/selector/selector.3.5inch.dc42.zip`, 41 | or, if `selector.3.5inch.dc42` is less than ($XXX - 1) * 532 bytes long, 42 | a block of 532 $00 bytes. 43 | 44 | - $2XXX: retrieve the $XXXth 532-byte block of `selector.twiggy.dc42` from 45 | the Zip archive `/home/debian/aphid/selector/selector.twiggy.dc42.zip`, 46 | or, if `selector.twiggy.dc42` is less than ($XXX - 1) * 532 bytes long, 47 | a block of 532 $00 bytes. 48 | 49 | - ProFile writes to $FFFEFC: do nothing at all. 50 | 51 | This plugin may be convenient for Lisa users who have accidentally overwritten 52 | the Selector hard drive image that's usually distribted with Cameo/Aphid: 53 | instead of shutting down their device and using a modern computer to manage 54 | drive image files on the microSD card's CAMEO_APHID partition, the user can 55 | type a brief program into the Lisa's memory via the boot ROM's Service Mode, 56 | then execute it. An example of such a program (which can be placed in RAM at 57 | any valid address at or above $800) is: 58 | 59 | 223C 00FF FEFC 227C 00FE 0090 50C2 50C3 50C4 4ED1 60 | 61 | This program will only affect a Cameo/Aphid that's plugged into the built-in 62 | parallel port. It's intentionally designed to cause the Lisa to crash or 63 | reboot, but this is harmless and gets you booting into the Selector faster. 64 | The assembly code for this program is: 65 | 66 | MOVE.L #$FFFEFC,D1 ; Read from block $FFFEFC 67 | MOVEA.L #$FE0090,A1 ; Point A1 at the boot ROM ProFile read routine 68 | ST.B D2 ; Set a timeout count of $??FF 69 | ST.B D3 ; Set a retry count parameter of $FF 70 | ST.B D3 ; Set a sparing threshold parameter of $FF 71 | JMP (A1) ; Invoke the ProFile read routine 72 | 73 | You might be able to tell that this code attempts to load the contents of block 74 | $FFFEFC into the boot ROM, which the Lisa doesn't care for. Even though this 75 | loading cannot succeed, the attempt will still do enough communication with the 76 | drive to trigger the Selector drive image restoration process. 77 | """ 78 | 79 | import itertools 80 | import logging 81 | import os 82 | import pathlib 83 | 84 | from typing import Dict, Optional 85 | 86 | import profile_plugins 87 | 88 | 89 | PROFILE_READ = 0x00 # The ProFile protocol op byte that means "read a block" 90 | SECTOR_SIZE = 532 # Sector size in bytes. Cf. "block size" in spare tables. 91 | 92 | IMAGE_PROFILE = '/home/debian/aphid/selector/selector.image.zip' 93 | IMAGE_3_5INCH = '/home/debian/aphid/selector/selector.3.5inch.dc42.zip' 94 | IMAGE_TWIGGY = '/home/debian/aphid/selector/selector.twiggy.zip' 95 | 96 | 97 | class SelectorRescuePlugin(profile_plugins.Plugin): 98 | """'Selector rescue' plugin. 99 | 100 | See the file header comment for usage details. 101 | """ 102 | 103 | def __init__(self) -> None: 104 | """Initialise a SelectorRescuePlugin""" 105 | self._image_cache = {} # type: Dict[str, bytes] 106 | 107 | def __call__( 108 | self, 109 | op: int, 110 | block: int, 111 | retry_count: int, 112 | sparing_threshold: int, 113 | data: Optional[bytes], 114 | ) -> Optional[bytes]: 115 | """Implements the protocol described in the file header comment.""" 116 | # We simply log and ignore non-reads. 117 | if op != PROFILE_READ: 118 | logging.warning( 119 | 'System info plugin: ignoring non-read operation %02X', op) 120 | return None 121 | 122 | # Collect and interpret the command. 123 | command = (retry_count << 8) + sparing_threshold 124 | 125 | if command == 0xffff: 126 | return self._restore_selector() 127 | elif command < 0x1000: 128 | return self._image_data(IMAGE_PROFILE, command) 129 | elif command < 0x2000: 130 | return self._image_data(IMAGE_3_5INCH, command - 0x1000) 131 | elif command < 0x3000: 132 | return self._image_data(IMAGE_TWIGGY, command - 0x2000) 133 | else: 134 | return bytes(SECTOR_SIZE) # Return zero blocks for 0x3000 and higher 135 | 136 | def _restore_selector(self): 137 | """Restore `profile.image` as described in the file header comment.""" 138 | import zipfile # Import here to avoid delaying initial emulator start-up. 139 | 140 | # Load the disk image into memory; nevermind the cache. If it doesn't 141 | # exist, just return a zero block. 142 | if os.path.exists(IMAGE_PROFILE): 143 | with zipfile.ZipFile(IMAGE_PROFILE) as zf: 144 | data = zf.read(zf.namelist()[0]) 145 | else: 146 | logging.warning('Selector restore abandoned: %s missing', IMAGE_PROFILE) 147 | return bytes(SECTOR_SIZE) 148 | 149 | # Deal with any existing profile.image file. 150 | old_name = pathlib.Path('profile.image') 151 | if old_name.exists(): # It'd be weird if it didn't... 152 | # Check that there's enough free space for another disk image. 153 | st_statvfs = os.statvfs('.') 154 | if len(data) > (st_statvfs.f_bsize * st_statvfs.f_bavail): 155 | logging.warning('Selector restore abandoned: insufficient drive space') 156 | return bytes(SECTOR_SIZE) # Give up if there isn't enough room. 157 | 158 | # Identify the safe new name for the current profile.image, and rename it. 159 | for i in itertools.count(): 160 | new_name = f'profile.backup-{i}.image' 161 | if not os.path.exists(new_name): 162 | logging.info('Selector restore: moving %s to %s', old_name, new_name) 163 | old_name.rename(new_name) 164 | break 165 | 166 | # Write the new profile.image. 167 | with open(old_name, 'wb') as f: 168 | f.write(data) 169 | logging.info('Selector restore: wrote %s from %s', old_name, IMAGE_PROFILE) 170 | 171 | # Now raise the Conclusion exception that will start a new emulator 172 | # session that reads 'profile.image'. 173 | logging.info('Selector restore: triggering a new emulation session') 174 | raise profile_plugins.Conclusion(b'IMAGE:' + bytes(old_name)) 175 | 176 | def _image_data(self, path: str, block: int) -> bytes: 177 | """Retrieve a block from a disk image stored in a Zip archive. 178 | 179 | Args: 180 | path: Full path to a Zip file whose only (or at least first) archived 181 | file is a disk image. 182 | block: Which 532-byte block to retrieve from the disk image. 183 | 184 | Returns: 185 | The specified 532-byte block from the disk image, or a block of 0x00 186 | bytes if the disk image can't be opened or has fewer than `block` blocks. 187 | """ 188 | import zipfile # Import here to avoid delaying initial emulator start-up. 189 | 190 | # Load the disk image into cache if it isn't there already. If the image 191 | # archive doesn't exist, just return zeros. 192 | if path not in self._image_cache: 193 | if os.path.exists(path): 194 | with zipfile.ZipFile(path) as zf: 195 | self._image_cache[path] = zf.read(zf.namelist()[0]) 196 | logging.info('Selector rescue plugin: loaded %s', path) 197 | else: 198 | logging.warning('Selector rescue plugin: failed to read %s', path) 199 | return bytes(SECTOR_SIZE) 200 | 201 | # Retrieve the specified block from the disk image. 202 | start = block * SECTOR_SIZE 203 | end = start + SECTOR_SIZE 204 | data = self._image_cache[path][start:end] 205 | return data + bytes(SECTOR_SIZE - len(data)) 206 | 207 | 208 | # By calling plugin() within this module, the plugin service instantiates a 209 | # new SelectorRescuePlugin. 210 | plugin = SelectorRescuePlugin 211 | -------------------------------------------------------------------------------- /aphid/profile_plugin_FFFEFD_system_info.py: -------------------------------------------------------------------------------- 1 | """A ProFile "magic block" plugin for Cameo/Aphid system information. 2 | 3 | Forfeited into the public domain with NO WARRANTY. Read LICENSE for details. 4 | 5 | This plugin allows the Apple to obtain some basic system information from a 6 | Cameo/Aphid. 7 | 8 | By convention, this plugin is associated with block $FFFEFD. There's no reason 9 | it can't be attached to different blocks, but for the following $FFFEFD will be 10 | used as a shorthand for whatever "magic block" is in use. 11 | 12 | Operations: 13 | 14 | - ProFile reads to $FFFEFD: Retrieve information about the Cameo/Aphid. The 15 | data returned by this plugin has the following format: 16 | 17 | Bytes 0-9: DDDDHHMMSS ASCII uptime; days right-justified space padded 18 | Bytes 10-24: ASCII right-aligned space-padded filesystem bytes free 19 | Bytes 25-31: ASCII null-terminated 1-minute load average 20 | Bytes 32-38: ASCII null-terminated 5-minute load average 21 | Bytes 39-45: ASCII null-terminated 15-minute load average 22 | Bytes 46-50: ASCII null-terminated number of processes running 23 | Bytes 51-55: ASCII null-terminated number of total processes 24 | 25 | - ProFile writes to $FFFEFD: do nothing at all. 26 | """ 27 | 28 | import logging 29 | import os 30 | 31 | from typing import Optional 32 | 33 | import profile_plugins 34 | 35 | 36 | PROFILE_READ = 0x00 # The ProFile protocol op byte that means "read a block" 37 | 38 | 39 | class SystemInfoPlugin(profile_plugins.Plugin): 40 | """System information plugin. 41 | 42 | See the file header comment for usage details. 43 | """ 44 | 45 | def __call__( 46 | self, 47 | op: int, 48 | block: int, 49 | retry_count: int, 50 | sparing_threshold: int, 51 | data: Optional[bytes], 52 | ) -> Optional[bytes]: 53 | """Implements the protocol described in the file header comment.""" 54 | # We simply log and ignore non-reads. 55 | if op != PROFILE_READ: 56 | logging.warning( 57 | 'System info plugin: ignoring non-read operation %02X', op) 58 | return None 59 | 60 | # Collect the information that this plugin returns. First, system uptime: 61 | with open('/proc/uptime', 'r') as f: 62 | seconds_left = round(float(f.read().split(' ')[0])) 63 | u_days, seconds_left = divmod(seconds_left, 86400) 64 | u_hours, seconds_left = divmod(seconds_left, 3600) 65 | u_minutes, seconds_left = divmod(seconds_left, 60) 66 | uptime = '{:4d}{:02d}{:02d}{:02d}'.format( 67 | u_days, u_hours, u_minutes, seconds_left) 68 | 69 | # Filesystem bytes free. 70 | st_statvfs = os.statvfs('.') 71 | bytes_free = '{:15d}'.format(st_statvfs.f_bsize * st_statvfs.f_bavail) 72 | 73 | # System load. 74 | with open('/proc/loadavg', 'r') as f: 75 | l_1min, l_5min, l_15min, l_processes, _ = f.read().split(' ') 76 | l_running, l_total = l_processes.split('/') 77 | 78 | # Helper: convert to binary and zero-pad to the right. 79 | def encode_and_pad(s: str, l: int) -> bytes: 80 | se = s.encode()[:l-1] 81 | return se + bytes(l - len(se)) 82 | 83 | data = b''.join([ 84 | uptime.encode(), 85 | bytes_free.encode(), 86 | encode_and_pad(l_1min, 7), 87 | encode_and_pad(l_5min, 7), 88 | encode_and_pad(l_15min, 7), 89 | encode_and_pad(l_running, 5), 90 | encode_and_pad(l_total, 5), 91 | ]) 92 | return data[:532] + bytes(max(0, 532 - len(data))) 93 | 94 | 95 | # By calling plugin() within this module, the plugin service instantiates a 96 | # new FilesystemOpsPlugin. 97 | plugin = SystemInfoPlugin 98 | -------------------------------------------------------------------------------- /aphid/profile_plugin_FFFEFF_key_value_store.py: -------------------------------------------------------------------------------- 1 | """A ProFile "magic block" plugin providing a permanent key/value store. 2 | 3 | Forfeited into the public domain with NO WARRANTY. Read LICENSE for details. 4 | 5 | This plugin allows the Apple to read from and write to a durable key/value 6 | store through ordinary ProFile disk I/O. This store is accessible no matter 7 | which disk image is being served to the Apple. Keys are 20 bytes long; values 8 | are 512 bytes long. 9 | 10 | The facility presents as having a kind of volatile (that is, not retained 11 | through system reboots) write-through cache where the 65,535 cache entries are 12 | controllable by the Apple (as opposed to being controlled automatically, as 13 | with a CPU cache for example). Cache keys are 16-bit values formed by the 14 | concatenation of the retry count and the sparing threshold that the Apple 15 | specifies during a ProFile read or a write. During reads, the Apple can only 16 | request items from the cache, so it must have earlier directed the store to 17 | have loaded data there from the durable key/value store. For writes, the Apple 18 | specifies both a cache key and the 20-byte store key; the data will be saved in 19 | both the cache and the durable store automatically. 20 | 21 | By convention, this plugin is associated with block $FFFEFF. There's no reason 22 | it can't be attached to different blocks, but for the following $FFFEFF will be 23 | used as a shorthand for whatever "magic block" is in use. 24 | 25 | Operations: 26 | 27 | - ProFile reads to $FFFEFF: Retrieve the cache entry assocated with the 28 | 16-bit concatenation of the retry count and sparing threshold parameters 29 | specified in the read. The store key will be the first 20 bytes of the 30 | returned data; the value is the remaining 512 bytes. 31 | 32 | - ProFile writes to $FFFEFF with retry count and sparing threshold both set 33 | to $FF: Order the store to load key/value pairs into the cache. The data 34 | in the write has the following format: 35 | 36 | Byte 0: Number of key/value pairs to load (up to 24) 37 | 38 | Bytes 1-2: 2-byte key for the cache entry receiving the first value 39 | Bytes 3-22: 20-byte key of the value to load into that cache entry 40 | 41 | Bytes 23-24: 2-byte key for the cache entry receiving the second value 42 | Bytes 25-44: 20-byte key of the value to load into that cache entry 43 | 44 | And so on. 45 | 46 | - ProFile writes to $FFFEFF with any other retry count and sparing threshold 47 | parameters: Write data to the cache entry specified by the parameters and 48 | to the key/value store. The store key is the first 20 bytes of the data, 49 | and the value is the remaining 512 bytes. 50 | 51 | From a logical perspective, any store keys not yet associated with any data are 52 | paired with 512 $00 bytes, and any cache keys not yet associated with any data 53 | are associated with 532 $00 bytes (in other words, an all-$00 20-byte key and 54 | 512 bytes of all-$00 data). 55 | 56 | See the class comment at `KeyValueStore` for implementation details. 57 | """ 58 | 59 | import collections 60 | import logging 61 | import dbm 62 | 63 | from typing import Dict, MutableMapping, Optional 64 | 65 | import profile_plugins 66 | 67 | 68 | PROFILE_READ = 0x00 69 | 70 | _512_NULS = bytes(512) # The data portion of an empty block. 71 | _532_NULS = bytes(532) # An entire empty block's worth of NULs. 72 | 73 | 74 | class KeyValueStorePlugin(profile_plugins.FlushingPlugin): 75 | """DBM-backed key/value store plugin. 76 | 77 | See the file header comment for usage details. 78 | 79 | Durable storage for the key/value store makes use of the `dbm` library for 80 | I/O to a "DBM" database. The `dbm` library is a generic interface, so the 81 | actual library used for reads and writes and the format of the database file 82 | may vary. 83 | """ 84 | 85 | def __init__( 86 | self, 87 | filename: str = 'profile_key_value_store.db', 88 | delay: float = 4.0, 89 | ) -> None: 90 | """Inititalises a KeyValueStorePlugin. 91 | 92 | Opens the DBM database file backing the durable key/value store and 93 | initialises an empty cache. 94 | 95 | Args: 96 | filename: Database file backing the durable key/value store. 97 | delay: How long to wait after writes to the database before syncing it 98 | to disk. 99 | """ 100 | super().__init__(default_delay=delay) 101 | logging.info('Key/value store plugin: opening database at %s...', filename) 102 | self._db = dbm.open(filename, 'c') # type: MutableMapping[bytes, bytes] 103 | self._cache = {} # type: Dict[int, bytes] 104 | 105 | def __call__( 106 | self, 107 | op: int, 108 | block: int, 109 | retry_count: int, 110 | sparing_threshold: int, 111 | data: Optional[bytes], 112 | ) -> Optional[bytes]: 113 | """Implements the protocol described in the file header comment.""" 114 | cache_key = (retry_count << 8) + sparing_threshold 115 | 116 | # Operation is a read: withdraw an item from cache. 117 | if op == PROFILE_READ: 118 | return self._cache.setdefault(cache_key, _532_NULS) 119 | 120 | # Operation is a write, with data. 121 | elif data is not None: 122 | if len(data) != 532: data = data[:532] + bytes(max(0, 532 - len(data))) 123 | 124 | if cache_key == 0xffff: # Operation wants us to move data into the cache 125 | for i in range(min(24, data[0])): # Only 24 cache requests fit 126 | req = data[(1 + i * 22):(23 + i * 22)] # Retrieve the i'th request 127 | req_cache_key = (req[0] << 8) + req[1] # Which cache entry to fill 128 | req_store_key = req[2:] # What to fill it with 129 | self._cache[req_cache_key] = ( # Pull in the data 130 | req_store_key + self._db.setdefault(req_store_key, _512_NULS)) 131 | return None 132 | else: # Operation just wants us to write 133 | self._cache[cache_key] = data # Store data in the cache 134 | self._db[data[:20]] = data[20:] # Store data in the store; TODO: lock? 135 | self.dirty() # Flush the data to disk eventually 136 | return None 137 | 138 | # Operation is something weird or malformed. Just return NULs. 139 | else: 140 | logging.warning( 141 | 'Key/value store plugin: ignoring operation %02X with no data', op) 142 | return _532_NULS 143 | 144 | def flush(self) -> None: 145 | """Flush: save pending permanent key/value store changes to disk.""" 146 | self._db.sync() # type: ignore 147 | 148 | def close(self) -> None: 149 | """Close: close the permanent key/value store.""" 150 | self.cancel() 151 | logging.info('Key/value store plugin: closing database') 152 | self._db.close() # type: ignore 153 | 154 | 155 | # By calling plugin() within this module, the plugin service instantiates a 156 | # new KeyValueStorePlugin. 157 | plugin = KeyValueStorePlugin 158 | -------------------------------------------------------------------------------- /aphid/profile_plugins.py: -------------------------------------------------------------------------------- 1 | r"""ProFile "magic block" plugins library for the Cameo/Aphid ProFile emulator. 2 | 3 | The ProFile hard drive protocol allows the computer to read and write to 4 | logical blocks identified by 24-bit numbers in the range $000000..$FFFFFD. 5 | A hard drive providing storage for that many distinct block would store over 6 | 8 TiB of data, which would have been impressive to see in 1983. 7 | 8 | Since no ordinary Apple II, Apple III, or Lisa software expects to access disk 9 | blocks beyond 10 or so MiB, we can safely use larger block numbers for other 10 | data transactions with the Cameo/Aphid emulator---including ones unrelated to 11 | data storage altogether. For example, we could have successive reads from 12 | $314159 supply us with 1,064 more BCD digits of pi---surely the ARM core on 13 | the Cameo/Aphid would compute them much faster than the Lisa could. 14 | 15 | A plugin system allows us to avoid hard-coding such "magic" features into 16 | `profile.py`. A plugin is a Python single-file module whose name "fullmatches" 17 | the regex 18 | 19 | profile_plugin_[0-9A-F]{6}.*\.py 20 | 21 | where the six **uppercase** hexadecimal digits after `profile_plugin_` are the 22 | block that the plugin will "enchant" with its own special handling of reads and 23 | writes. The module should contain a zero-argument callable called `plugin` that 24 | will return an instance of `Plugin` (defined below). See the definition of 25 | `Plugin` to understand what methods in this instance must do. 26 | 27 | For now, only logical blocks $FF0000..$FFFEFF can be handled by plugins. If 28 | the Cameo/Aphid plugin ecosystem ever requires more than 65,519 distinct block 29 | addresses, the lower bound may be adjusted downward. 30 | 31 | (As a final note, Cameo/Aphid does implement a few "magic" blocks natively. 32 | $FFFFFF and $FFFFFE were already magical for the ProFile: they retrieve the 33 | spare table and the ProFile's memory buffer respectively. Writes to $FFFFFD 34 | can be used to restart or end ProFile emulation: see README.md for details.) 35 | """ 36 | 37 | import abc 38 | import contextlib 39 | import importlib.util 40 | import logging 41 | import pathlib 42 | import threading 43 | 44 | from typing import Dict, Generator, Optional 45 | 46 | 47 | SECTOR_SIZE = 532 # Sector size in bytes. Cf. "block size" in spare tables. 48 | 49 | 50 | class Plugin(abc.ABC): 51 | """Cameo/Aphid "magic block" plugin abstract base class. 52 | 53 | All plugins for the Profile emulator should subclass this class. Any resource 54 | allocation required for the plugin's operation (e.g. opening a file) should 55 | probably take place in its `__init__`. 56 | """ 57 | 58 | @abc.abstractmethod 59 | def __call__( 60 | self, 61 | op: int, 62 | block: int, 63 | retry_count: int, 64 | sparing_threshold: int, 65 | data: Optional[bytes], 66 | ) -> Optional[bytes]: 67 | """Handle a ProFile I/O command from the Apple. 68 | 69 | Args: 70 | op: Operation requested by the Apple. $00 is a block read, and $01..$03 71 | are different kinds of writes (a plugin can treat all of these the 72 | same). This argument will take on no other values. 73 | block: Block requested by the Apple. This will always be the block 74 | selected by the module's filename. 75 | retry_count: Operation retry count specified by the Apple, a value in 76 | $00..$FF. The plugin can use this value as a parameter if desired. 77 | sparing_threshold: Operation sparing threshold specified by the Apple, a 78 | value in $00..$FF. The plugin can use this value as a parameter, too. 79 | data: If `op == $00`, then None. Otherwise, 532 bytes of data that the 80 | Apple expects to "write" to the block selected by `block`. 81 | 82 | Returns: 83 | If `op == $00`, then the return value should be 532 bytes of data "read" 84 | from the block. Otherwise any return value is ignored. 85 | """ 86 | pass 87 | 88 | def close(self) -> None: 89 | """Cease operation of the plugin. 90 | 91 | This method will be called prior to emulator shutdown. Plugins should 92 | perform whatever operations here are necessary to ensure that essential 93 | data is saved and that other resources are gracefully retired. If no such 94 | operations are required, there's no need to implement this method. 95 | 96 | Remember that Cameo/Aphid is often shut down by cutting the power. Plugins 97 | that should be robust to sudden power cuts may benefit from inheriting 98 | from `FlushingPlugin`. 99 | """ 100 | pass 101 | 102 | 103 | class FlushingPlugin(Plugin): 104 | """A `Plugin` subclass for plugins that wish to "flush" after a time delay. 105 | 106 | This subclass simplifies the implementation of plugins that will want to 107 | perform some kind of delayed cleanup operation, such as saving information 108 | to the filesystem. Plugins can call the `dirty` method in their `__call__`, 109 | which will asynchronously call the `flush` method after a preset interval. 110 | 111 | If `dirty` is called again during the interval, the delay will be pushed 112 | back---reset to its original duration (unless a different delay is specified, 113 | in which case it is reset to that duration). 114 | 115 | The motivating circumstance is a plugin that commits changes to the 116 | filesystem. A write after every change would be slow and may risk wearing the 117 | solid-state storage media, so instead the plugin can call `dirty` after 118 | accumulating writes in a buffer. Once there is a period of low activity, the 119 | `flush` method will be called and buffered writes can be written all at once. 120 | """ 121 | 122 | def __init__(self, default_delay: float = 4.0) -> None: 123 | """Initialise a FlushingPlugin. 124 | 125 | Args: 126 | default_delay: Default interval between the last call to `dirty` and 127 | a subsequent call to the `flush` method. 128 | """ 129 | self._delay = default_delay 130 | self._timer = None # type: Optional[threading.Timer] 131 | self._rlock = threading.RLock() 132 | self._abort = False 133 | 134 | @abc.abstractmethod 135 | def flush(self) -> None: 136 | """A method that is called some time after the last call to `dirty`.""" 137 | pass 138 | 139 | def dirty(self, delay: Optional[float] = None) -> None: 140 | """Schedule a call to `flush` after some delay. 141 | 142 | Args: 143 | delay: The delay after which `flush` will be called, unless `dirty` is 144 | called again in the meantime. If unspecified, the `default_delay` 145 | parameter passed to the constructor is used. 146 | """ 147 | with self._rlock: 148 | self.cancel() 149 | self._abort = False 150 | self._timer = threading.Timer( 151 | delay if delay is not None else self._delay, 152 | self._flush) 153 | 154 | def cancel(self) -> None: 155 | """Cancels a pending call to `flush`.""" 156 | with self._rlock: 157 | self._abort = True 158 | if self._timer: self._timer.cancel() 159 | self._timer = None 160 | 161 | def _flush(self) -> None: 162 | """Helper for calling the user-implemented `flush` method.""" 163 | with self._rlock: 164 | if self._abort: return 165 | self._timer = None 166 | self.flush() 167 | 168 | 169 | def load_plugins(directory: str = '.') -> Dict[int, Plugin]: 170 | """Collect instantiated plugins from the specified directory. 171 | 172 | This function will attempt to load plugins from all files whose name 173 | "fullmatches" the regex 174 | 175 | profile_plugin_[0-9A-F]{6}.*\.py 176 | 177 | It will attempt to load these files as python modules and invoke a callable 178 | called `plugin` inside with no arguments. Exceptions that occur at any point 179 | when trying to load a module are logged and ignored. 180 | 181 | It us up to the caller to call these plugins' `close` methods when the 182 | plugins are no longer required. The `plugins` context manager in this module 183 | automates this process. 184 | 185 | Args: 186 | directory: Directory to load plugins from. 187 | 188 | Returns: 189 | All plugins loaded from the directory, keyed by the block number specified 190 | in their filenames. 191 | 192 | Raises: 193 | ValueError: `directory` was not a directory. 194 | """ 195 | path = pathlib.Path(directory) 196 | if not path.is_dir(): raise ValueError( 197 | '{} is not a directory'.format(directory)) 198 | 199 | plugins = {} # type: Dict[int, Plugin] 200 | for item in path.glob('profile_plugin_??????*.py'): 201 | # Get block number for the plugin---again, all hex digits must be uppercase. 202 | hex_digits = item.name[15:21] 203 | if not all(d in '0123456789ABCDEF' for d in hex_digits): continue 204 | block = int(hex_digits, 16) 205 | 206 | # Try to load and instantiate the plugin. We log and ignore any exception. 207 | try: 208 | logging.info('Plugins: loading %s...', item.stem) 209 | module_spec = importlib.util.spec_from_file_location(item.stem, str(item)) 210 | module = importlib.util.module_from_spec(module_spec) 211 | module_spec.loader.exec_module(module) # type: ignore 212 | plugin = module.plugin() # type: ignore 213 | plugins[block] = plugin 214 | except Exception: 215 | logging.exception('While attempting to load the plugin for block $%06X ' 216 | 'from %s', block, item.name) 217 | 218 | return plugins 219 | 220 | 221 | @contextlib.contextmanager 222 | def plugins(directory: str = '.') -> Generator[Dict[int, Plugin], None, None]: 223 | """A context manager that loads and automatically closes plugins. 224 | 225 | Wraps `load_plugins` in a context manager that calls the `close` method on 226 | all loaded plugins at context exit. Exceptions raised by any `close` method 227 | are logged and ignored. 228 | 229 | Args: 230 | directory: Directory to load plugins from. 231 | 232 | Yields: 233 | The plugins dict returned by `load_plugins(directory)`. 234 | 235 | Raises: 236 | ValueError: `directory` was not a directory. 237 | """ 238 | plugins = load_plugins(directory) 239 | try: 240 | yield plugins 241 | finally: 242 | for block, plugin in plugins.items(): 243 | try: 244 | plugin.close() 245 | except Exception: 246 | logging.exception('While closing the plugin for block $%06X:', block) 247 | 248 | 249 | class Conclusion(Exception): 250 | """An exception that concludes the current emulation session. 251 | 252 | A plugin that raises this exception in its __call__ method will cause the 253 | current emulation session to end, with the "conclusion" to the session being 254 | the result of truncating or zero-padding the `conclusion` bytes argument to 255 | the constructor to exactly 532 bytes. 256 | 257 | Study `process_conclusion` in `profile.py` to learn more about how data in 258 | these conclusions are interpreted by the emulator. 259 | 260 | The 532-byte read data provided to the Apple if a Conclusion is raised during 261 | a read is not specified. Cameo/Aphid may also not do anything at all with 262 | data it receives during a write operation that raises a Conclusion. 263 | 264 | Attributes: 265 | conclusion: A 532-byte value indicating what should happen when the current 266 | emulation session is ended. 267 | """ 268 | conclusion: bytes 269 | 270 | def __init__(self, conclusion: bytes) -> None: 271 | """Initialise a Conclusion exception. 272 | 273 | Args: 274 | message: 275 | """ 276 | super().__init__() 277 | self.conclusion = ( 278 | conclusion[:SECTOR_SIZE] + bytes(max(0, SECTOR_SIZE - len(conclusion)))) 279 | -------------------------------------------------------------------------------- /aphid/selector/README.md: -------------------------------------------------------------------------------- 1 | # Cameo/Aphid Selector 2 | 3 | ![The Selector running on a Lisa 1](selector.jpg "The Selector in real life") 4 | 5 | The Cameo/Aphid drive image selector program ("the Selector" for short) is a 6 | program for Apple Lisa computers that controls a [Cameo/Aphid ProFile hard 7 | drive emulator](https://github.com/stepleton/cameo/tree/master/aphid). Most 8 | Selector users will use the Selector to create, manange, and boot hard drive 9 | images that belong to a catalogue of hard drive images on their Cameo/Aphid 10 | devices. 11 | 12 | ## Installation 13 | 14 | This README file is a placeholder; before long, additional information and 15 | installation instructions will be provided here. For now, if you have a 16 | Cameo/Aphid running the most current version of the Cameo/Aphid software 17 | listed [in the Cameo/Aphid README](../README.md#software-installation), you 18 | may do the following: 19 | 20 | 1. Back up your Cameo/Aphid microSD card. 21 | 22 | 2. On a modern computer, copy these files into the microSD card's FAT 23 | partition (called `CAMEO_APHID`): `profile.py`, 24 | `profile_plugin_FFFEFC_selector_rescue.py`, 25 | `profile_plugin_FFFEFD_system_info.py`, 26 | `profile_plugin_FFFEFE_filesystem_ops.py`, 27 | `profile_plugin_FFFEFF_key_value_store.py`, and `profile_plugins.py`. Note 28 | that you will overwrite the existing `profile.py`. 29 | 30 | 3. Rename any existing file on the FAT partition called `profile.image` to 31 | something else. 32 | 33 | 4. Download `selector.image.zip`, unpack `selector.image` and copy it to the 34 | microSD card's FAT partition, and rename it `profile.image`. 35 | 36 | ## Manual and more 37 | 38 | There is a detailed [user's manual](MANUAL.md) and a document that describes 39 | [the protocol the Selector uses](PROTOCOL.md) to control the Cameo/Aphid. 40 | 41 | -- _[Tom Stepleton](mailto:stepleton@gmail.com), 17 January 2021, London_ 42 | -------------------------------------------------------------------------------- /aphid/selector/ask_ui.x68: -------------------------------------------------------------------------------- 1 | * Cameo/Aphid disk image selector: resources for asking the user a question 2 | * ========================================================================= 3 | * 4 | * Forfeited into the public domain with NO WARRANTY. Read LICENSE for details. 5 | * 6 | * Routines and definitions for asking the user for some input, and also for 7 | * showing the user the result of attempting to carry out some kind of operation. 8 | * Some data definitions are not used by routines in this file. 9 | * 10 | * These routines make use of routines defined in 11 | * lisa_ui/lisa_console_screen.x68 and ui_base.x68. They also invoke macros 12 | * defined in ui_macros.x68. 13 | * 14 | * Public procedures: 15 | * - AskVerdict -- Present final operation's result and await keypress 16 | * - AskVerdictByZ -- Present verdict depending on Z, await keypress 17 | * - AskOpResultByZ -- Present an operation result depending on Z 18 | 19 | 20 | * ask_ui Code ----------------------------------- 21 | 22 | 23 | SECTION kSecCode 24 | 25 | 26 | ; AskVerdict -- Present final operation's result and await keypress 27 | ; Args: 28 | ; SP+$4: l. Address of a "verdict" string, e.g. "succeeded" 29 | ; Notes: 30 | ; At the bottom of the screen (row 34), prints "Operation" followed by the 31 | ; verdict string, then ". Press any key to continue." 32 | ; Prior contents of row 34 are not cleared 33 | ; Will show the screensaver after a delay, then reprints the verdict even 34 | ; though it's probably gonna look weird; we still want the user who 35 | ; went off to the toilet to know whether something succeeded or failed 36 | ; when they come back 37 | ; Trashes D0-D1/A0-A1 38 | AskVerdict: 39 | mUiGotoRC #$22,#$1 ; Jump to the bottom of the screen 40 | MOVE.L $4(SP),-(SP) ; Duplicate verdict address on stack 41 | mUiPrint <'Operation '>,s,<'. Press any key to continue.'> 42 | BSR UiScreensaverWaitForKb ; Await a keypress 43 | BNE.S AskVerdict ; Go back to the top if it wasn't a keypress 44 | RTS 45 | 46 | 47 | ; AskVerdictByZ -- Present verdict depending on Z, await keypress 48 | ; Args: 49 | ; CCR: If Z=1, say "Operation succeeded", if Z=0, say it failed 50 | ; Notes: 51 | ; Leaves Z unchanged 52 | ; Unlike AskOpResultByZ, awaits a keypress 53 | ; Trashes D0-D1/A0-A1 54 | AskVerdictByZ: 55 | SNE.B -(SP) ; If Z push $00, otherwise push $FF 56 | BNE.S .fa ; If ~Z, announce failure 57 | PEA.L sAskVerdictSucceeded(PC) ; Success verdict address on the stack 58 | BRA.S .pr ; Jump ahead to print the verdict 59 | .fa PEA.L sAskVerdictFailed(PC) ; Failure verdict on the stack 60 | .pr BSR.S AskVerdict ; Print the verdict and await a keypress 61 | ADDQ.L #$4,SP ; Pop verdict address off the stack 62 | TST.B (SP)+ ; Recover original Z from stack 63 | RTS 64 | 65 | 66 | ; AskOpResultByZ -- Present an operation result depending on Z 67 | ; Args: 68 | ; CCR: If Z=1, say "OK\n\n", if Z=0, say "FAILED\n\n" 69 | ; Notes: 70 | ; Leaves Z unchanged 71 | ; Trashes D0-D1/A0-A1 72 | AskOpResultByZ: 73 | SNE.B -(SP) ; If Z push $00, otherwise push $FF 74 | BNE.S .fa ; If ~Z, announce failure 75 | PEA.L sAskOpOk(PC) ; "OK" address on the stack 76 | BRA.S .pr ; Jump ahead to print the verdict 77 | .fa PEA.L sAskOpFailed(PC) ; "failed" address on the stack 78 | .pr mUiPrint s ; Print the result 79 | TST.B (SP)+ ; Recover original Z from stack 80 | RTS 81 | 82 | 83 | * ask_ui Data ----------------------------------- 84 | 85 | 86 | SECTION kSecData 87 | 88 | 89 | sAskVerdictCancelled: 90 | DC.B 'cancelled',$0 91 | sAskVerdictSucceeded: 92 | DC.B 'succeeded',$0 93 | sAskVerdictFailed: 94 | sAskOpFailed: 95 | DC.B 'failed',$0 96 | 97 | sAskIssuing: 98 | DC.B $0A,$0A,$0A,$0A,$0A,' Issuing command... ',$0 99 | sAskOpOk: 100 | DC.B 'OK',$0 101 | 102 | sAskReturnCancel: 103 | DC.B ' Return (',$85,') to proceed, Clear (',$98,') to cancel.',$0 104 | -------------------------------------------------------------------------------- /aphid/selector/block.x68: -------------------------------------------------------------------------------- 1 | * Cameo/Aphid disk image selector: memory block utilities 2 | * ======================================================= 3 | * 4 | * Forfeited into the public domain with NO WARRANTY. Read LICENSE for details. 5 | * 6 | * Generic utilities for working with blocks of memory. 7 | * 8 | * Public procedures: 9 | * - Copy -- Copy a block of memory 10 | * - Zero -- Fill a block of memory with $00 bytes 11 | * - BlockZero -- Zero a 512-byte block 12 | * - BlockCsumCheck -- Check the trailing checksum of a 512-byte block 13 | * - BlockCsumSet -- Set the trailing checksum of a 512-byte block 14 | * - StrNCmp -- Compare null-terminated strings 15 | * - StrCpy255 -- Copy strings of up to 255 characters (plus terminator) 16 | 17 | 18 | 19 | * block Code ------------------------------------ 20 | 21 | 22 | SECTION kSecCode 23 | 24 | 25 | ; Copy -- Copy a block of memory 26 | ; Args: 27 | ; SP+$A: l. Start address for the source of the copied data 28 | ; SP+$6: l. Start address for the destination of the copied data 29 | ; SP+$4: w. Size of the block to copy, in bytes 30 | ; Notes: 31 | ; Will behave correctly if the source and destination overlap 32 | ; Copies data byte-by-byte; could be faster if it copied words when able 33 | ; Word-alignment not required 34 | ; Use 32-bit clean addresses 35 | ; Trashes D0-D1/A0-A1 36 | Copy: 37 | CLR.L D0 ; Clear all of D0 so that it can take... 38 | MOVE.W $4(SP),D0 ; ...the copy count, extended to a longword 39 | BEQ.S .rt ; If block size is 0, quit early 40 | MOVEA.L $A(SP),A0 ; Copy source address to A0 41 | MOVEA.L $6(SP),A1 ; Copy destination address to A1 42 | MOVE.L A1,D1 ; Subtract source from... 43 | SUB.L A0,D1 ; ...destination address... 44 | BEQ.S .rt ; ...(quit early if they were the same)... 45 | BPL.S .ck ; ...and take its... 46 | NEG.L D1 ; ...absolute value 47 | .ck CMP.L D0,D1 ; Difference >= the count? 48 | BGE.S .cf ; No interference; do a forward copy 49 | CMPA.L A0,A1 ; Destination precedes the source? 50 | BLT.S .cf ; If so, we need a forward copy 51 | 52 | ; Backward copy from source to destination 53 | ADDA.L D0,A0 ; Point A0 just beyond end of source 54 | ADDA.L D0,A1 ; Point A1 just beyond end of source 55 | SUBQ.W #$1,D0 ; Turn D0 into a loop counter 56 | .lb MOVE.B -(A0),-(A1) ; Copy a byte 57 | DBRA D0,.lb ; Decrement counter and loop 58 | BRA.S .rt ; Skip ahead to quit 59 | 60 | ; Ordinary forward copy from source to destination 61 | .cf SUBQ.W #$1,D0 ; Turn D0 into a loop counter 62 | .lf MOVE.B (A0)+,(A1)+ ; Copy a byte 63 | DBRA D0,.lf ; Decrement counter and loop 64 | 65 | .rt RTS 66 | 67 | 68 | ; Zero -- Fill a block of memory with $00 bytes 69 | ; Args: 70 | ; SP+$6: l. Start address of block to zero 71 | ; SP+$4: w. Size of the block to zero, in bytes 72 | ; Notes: 73 | ; Zeros data byte-by-byte; could be faster if it zeroed words when able 74 | ; Word-alignment not required 75 | ; Trashes D0/A0 76 | Zero: 77 | MOVE.W $4(SP),D0 ; Copy block size to D0 78 | BEQ.S .rt ; If block size is 0, quit early 79 | MOVEA.L $6(SP),A0 ; Copy block start address to A0 80 | SUBQ.W #$1,D0 ; Turn D0 into a loop counter 81 | .lp CLR.B (A0)+ ; Clear a byte 82 | DBRA.W D0,.lp ; Loop to clear the next byte 83 | .rt RTS 84 | 85 | 86 | ; BlockZero -- Zero a 512-byte block 87 | ; Args: 88 | ; SP+$4: l. Start address of block to zero 89 | ; Notes: 90 | ; Zeros data byte-by-byte; could be faster if it zeroed words when able 91 | ; Trashes D0/A0 92 | BlockZero: 93 | MOVE.L $4(SP),-(SP) ; Duplicate address argument on stack 94 | MOVE.W #$100,-(SP) ; We need to copy 512 bytes 95 | BSR.S Zero ; Jump to copy 96 | ADDQ.L #$6,SP ; Pop arguments to Zero off the stack 97 | RTS 98 | 99 | 100 | ; BlockCsumCheck -- Check the trailing checksum of a 512-byte block 101 | ; Args: 102 | ; SP+$4: l. Address of a 512-byte block to check 103 | ; Notes: 104 | ; Address must be word-aligned 105 | ; Final word in the block should be the checksum 106 | ; Sets Z if the checksum is a match 107 | ; Uses the checksum algorithm from the Lisa Boot ROM (reimplemented) 108 | ; Trashes D0-D1/A0 109 | BlockCsumCheck: 110 | MOVEA.L $4(SP),A0 ; Copy block address to A0 111 | MOVE.W #$00FF,D0 ; Check 256 words 112 | CLR.W D1 ; Clear the accumulator 113 | .lp ADD.W (A0)+,D1 ; Add the next word to the accumulator 114 | ROL.W #$1,D1 ; Rotate the accumulator left one bit 115 | DBRA D0,.lp ; Loop if there are more words to go 116 | RTS 117 | 118 | 119 | ; BlockCsumSet -- Set the trailing checksum of a 512-byte block 120 | ; Args: 121 | ; SP+$4: l. Address of a 512-byte block receiving a new checksum 122 | ; Notes: 123 | ; Final word in block will be overwritten with the checksum 124 | ; Uses the checksum algorithm from the Lisa Boot ROM (reimplemented) 125 | ; Trashes D0-D1/A0 126 | BlockCsumSet: 127 | MOVEA.L $4(SP),A0 ; Copy block address to A0 128 | MOVE.W #$00FE,D0 ; Sum 255 words 129 | CLR.W D1 ; Clear the accumulator 130 | .lp ADD.W (A0)+,D1 ; Add the next word to the accumulator 131 | ROL.W #$1,D1 ; Rotate the accumulator left one bit 132 | DBRA D0,.lp ; Loop if there are more words to go 133 | NEG.W D1 ; Compute checksum's additive inverse 134 | MOVE.W D1,(A0) ; And store it at the end of the block 135 | RTS 136 | 137 | 138 | ; StrNCmp -- Compare null-terminated strings 139 | ; Args: 140 | ; SP+$C: w. Maximum number of bytes to compare 141 | ; SP+$8: l. Address of the first of the null-terminated strings 142 | ; SP+$4: l. Address of the second null-terminated string 143 | ; Notes: 144 | ; Could be faster; lots of memory accesses 145 | ; Sets flags in the manner of strncmp(3) from C; if Z is set, then the 146 | ; strings are equal up through the terminator or (SP+$C-1) characters 147 | ; (both inclusive, whichever comes first) 148 | ; Flags are not dependable if the number of bytes to compare is 0 149 | ; Trashes D0-D1/A0-A1 150 | StrNCmp: 151 | MOVE.W $C(SP),D0 ; Copy character count to D0 152 | BEQ.S .rt ; No characters? Return with Z set 153 | MOVEA.L $8(SP),A0 ; Point A0 at the first string 154 | MOVEA.L $4(SP),A1 ; Point A1 at the second string 155 | SUBQ.W #$1,D0 ; Convert D0 to a loop iterator 156 | MOVE.W D2,-(SP) ; Save D2 on the stack 157 | 158 | .lp MOVE.B (A0)+,D1 ; Next A0 byte into D1 159 | MOVE.B (A1)+,D2 ; Next A1 byte into D2 160 | BEQ.S .fc ; Skip ahead if A1 byte was the terminator 161 | TST.B D1 ; Was A0 byte the terminator? 162 | BEQ.S .fc ; Skip ahead if so 163 | CMP.B D2,D1 ; Are the two bytes the same, though? 164 | DBNE D0,.lp ; Loop again if they are 165 | 166 | .fc CMP.B D2,D1 ; Set flags from comparing final bytes 167 | MOVEM.W (SP)+,D2 ; Recover D2 without changing flags 168 | .rt RTS 169 | 170 | 171 | ; StrCpy255 -- Copy strings of up to 255 characters (plus terminator) 172 | ; Args: 173 | ; SP+$8: l. Address of the string to copy from 174 | ; SP+$4: l. Address of the string to copy to 175 | ; Notes: 176 | ; Copies byte-wise---could be faster I guess 177 | ; String source and destination must not overlap in a way where the 178 | ; destination address comes after the source address, but it's okay if 179 | ; the destination address precedes the source address or if they're 180 | ; both the same 181 | ; Sets Z iff the string to copy was 255 or fewer characters long (not 182 | ; counting the null terminator), or if the two addresses were the same 183 | ; Longer strings are truncated at the destination 184 | ; On return, A0 points just past the copied string's terminator 185 | ; Trashes D0/A0-A1 186 | StrCpy255: 187 | MOVE.L $8(SP),A1 ; A1 gets the source address 188 | MOVE.L $4(SP),A0 ; A0 gets the destination address 189 | CMP.L A0,A1 ; Are they the same? 190 | BEQ.S .si ; Simulate a copy if so by advancing A0 191 | CLR.W D0 ; We've copied 0 characters so far 192 | 193 | .lp ADDQ.L #$1,D0 ; Increment number of bytes copied 194 | MOVE.B (A1)+,(A0)+ ; Copy a byte 195 | BEQ.S .rt ; Hit the terminator? Done. 196 | CMPI.W #$100,D0 ; Have we copied 256 bytes 197 | BLO.S .lp ; No, copy another byte 198 | 199 | ; If we fall out of the loop, we haven't finished copying and need to 200 | ; cut bait, null-terminate, and clear Z 201 | CLR.B -1(A0) ; Null-terminate 202 | ANDI.B #$FB,CCR ; Clear Z marking a copy failure 203 | BRA.S .rt ; Jump ahead to return 204 | 205 | ; If here, the source and destination pointers were the same, but we still 206 | ; have to advance A0 to point just past the string's terminator 207 | .si TST.B (A0)+ ; Test here for the terminator and advance 208 | BNE.S .si ; Keep going if not NULL; otherwise, set Z 209 | 210 | .rt RTS 211 | -------------------------------------------------------------------------------- /aphid/selector/boot.x68: -------------------------------------------------------------------------------- 1 | * Cameo/Aphid disk image selector: boot routines 2 | * ============================================== 3 | * 4 | * Forfeited into the public domain with NO WARRANTY. Read LICENSE for details. 5 | * 6 | * Routines (well, just one for now) that load the first block or sector from 7 | * a drive and call it. 8 | * 9 | * The routines in this file attempt to set up conditions that mimic what 10 | * happens when the boot ROM boots from a drive. For the internal parallel port, 11 | * it's straightforward: the first hard drive block is loaded to $20000 and the 12 | * boot ROM (or our own code) jumps there. A boot from a drive attached to a 13 | * parallel port expansion card is more complex: the boot ROM loads the parallel 14 | * port card ROM's boot program to $20000 and runs it, then that program loads 15 | * the boot program to $20810 and jumps there. For this latter case, our code 16 | * loads the card's boot program into ROM for verisimilitude, but it never calls 17 | * it; we load the first drive block ourselves. 18 | * 19 | * Unlike the boot ROM, we don't worry about whether the tag data for boot blocks 20 | * mark the drive as bootable --- we jump to the code no matter what. 21 | * 22 | * These routines make use of data definitions set forth in selector.x68 and 23 | * routines defined in block.x68. They also require that the lisa_profile_io 24 | * library from the lisa_io collection be memory-resident. 25 | * 26 | * Public procedures: 27 | * - BootHd -- Load and execute a hard drive's boot block (block $000000) 28 | 29 | 30 | * boot Defines ---------------------------------- 31 | 32 | 33 | kBoot_Intnl EQU $20000 ; Where to load boot code for the internal port 34 | kBoot_Pcard EQU $20810 ; Where to load boot code for parallel cards 35 | kBoot_Slot1 EQU $FC0001 ; Memory address for first I/O slot 36 | 37 | 38 | 39 | * boot Code ------------------------------------- 40 | 41 | 42 | SECTION kSecCode 43 | 44 | 45 | ; BootHd -- Load and execute a hard drive's boot block (block $000000) 46 | ; Args: 47 | ; (none) 48 | ; Notes: 49 | ; Jumps to offset $14 in the boot block when booting -- that is, past the 50 | ; the 20 "tag" bytes and at the beginning of the 512 "data" bytes 51 | ; Does not check whether the drive is marked as bootable (that is, it 52 | ; doesn't bother looking for $AAAA at tag bytes $8 and $9) 53 | ; Attempts to replicate some ordinary Lisa booting behaviour: 54 | ; - When booting from the internal parallel port, the data block 55 | ; is positioned at $20000 56 | ; - When booting from a parallel port card, the contents of the 57 | ; parallel port's boot ROM are loaded to $1FFFC, and the data block 58 | ; is positioned at $20810 59 | ; If booting fails for some reason, returns with Z clear; if the booted 60 | ; program returns for some reason without destroying the memory 61 | ; occupied by the selector program, returns with Z set 62 | ; Trashes D0-D1/A0-A1, plus whatever the booted program destroys (which 63 | ; could be everything, really) 64 | BootHd: 65 | ; Load the first block from the current hard drive to the location where we 66 | ; we load boot blocks for internal drives (we'll move it later if we're 67 | ; loading from a parallel card) 68 | CLR.L D1 ; $00000000: we want to read block $000000 69 | MOVE.W #$0A03,D2 ; Standard retry count/sparing threshold params 70 | MOVEA.L #(kBoot_Intnl-$14),A0 ; Here's where we want to load the block 71 | MOVEA.L zProFileIoPtr(PC),A1 ; Copy ProFile I/O routine address to A1 72 | JSR (A1) ; Call it 73 | BNE .rt ; Failure? Jump ahead to return 74 | MOVE.B zCurrentDrive(PC),D1 ; Load current device ID into D1 75 | CMPI.B #$02,D1 ; Is it the internal drive? 76 | BEQ.S .bt ; Yes, go straight ahead and boot it 77 | 78 | ; If we're loading from a parallel port card, move the data we've loaded to 79 | ; the location where the parallel card's boot program would have put it, 80 | ; then load the parallel card's boot program to $20000 81 | MOVE.L #(kBoot_Intnl-$14),-(SP) ; Here's where we loaded block $000000 82 | MOVE.L #(kBoot_Pcard-$14),-(SP) ; Here's where it needs to move 83 | MOVE.W #$214,-(SP) ; We'll move the entire block, 532 bytes 84 | BSR Copy ; Here we go 85 | ADDQ.L #$8,SP ; Pop Copy arguments off the stack, part 1 86 | ADDQ.L #$2,SP ; Pop Copy arguments off the stack, part 2 87 | 88 | ; Now replicate the behaviour of the boot ROM and copy the parallel port ROM 89 | ; to location $20000 --- it's not clear that the program we're loading needs 90 | ; to see it there, but we love verisimilitude... 91 | MOVE.B zCurrentDrive(PC),D0 ; Copy current drive ID to D0 92 | MOVEA.L #kBoot_Slot1,A0 ; Point A0 at slot 1 93 | CMPI.B #$05,D0 ; Are we booting from a card in that slot? 94 | BLO.S .lr ; Yes, jump to load the ROM 95 | ADDA.W #$4000,A0 ; No, point A0 at slot 2 96 | CMPI.B #$08,D0 ; Are we booting from a card in that slot? 97 | BLO.S .lr ; Yes, jump to load the ROM 98 | ADDA.W #$4000,A0 ; No, point A0 at slot 3 99 | 100 | .lr MOVEA.L #(kBoot_Intnl-$4),A1 ; Card ROM data loads to $1FFFC 101 | MOVEP.L $0(A0),D1 ; Load card ID and word count to D1 102 | MOVE.L D1,(A1)+ ; Save it to memory as well 103 | ADDQ.L #$8,A0 ; And move A0 ahead to ROM data that follows 104 | SUBQ.W #$1,D1 ; Word count to loop iterator, but limit to... 105 | ANDI.W #$3FF,D1 ; ...1024 words to avoid clobbering block data 106 | .lp MOVEP.W $0(A0),D0 ; Read the next word from the ROM 107 | ADDQ.W #$4,A0 ; Advance ROM data pointer 108 | MOVE.W D0,(A1)+ ; Copy the ROM word to RAM 109 | DBRA.W D1,.lp ; And loop to get the next word 110 | 111 | ; At last, boot the boot block --- unlike the boot ROM, we use a JSR just 112 | ; in case someone feels like returning to us... 113 | .bt BSR LisaConsolePollKbMouse ; Flush the COPS: poll it for any input 114 | BCS.S .bt ; Keep looping if there was any 115 | MOVE.B $1B3,-(SP) ; Save the ROM's boot device ID on the stack 116 | MOVE.B zCurrentDrive(PC),D0 ; Put current parallel port ID into D0 117 | MOVE.B D0,$1B3 ; Substitute it atop the ROM's boot device ID 118 | 119 | MOVE.L #kBoot_Intnl,A2 ; Boot address for internal port data into A2 120 | CMPI.B #$02,D0 ; But are we booting from the internal port? 121 | BEQ.S .go ; Yes, go do it 122 | ADDA.W #(kBoot_Pcard-kBoot_Intnl),A2 ; No, boot addr for par. card data 123 | 124 | .go JSR (A2) ; And awaaaay we go! 125 | 126 | MOVE.B (SP)+,$1B3 ; (We're back?!) Restore ROM boot device ID 127 | ORI.B #$04,CCR ; Then clear Z to mark success, I guess 128 | 129 | .rt RTS 130 | -------------------------------------------------------------------------------- /aphid/selector/screensaver.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stepleton/cameo/ca64ef0f286fabcdfb018684bf078709f3188b11/aphid/selector/screensaver.jpg -------------------------------------------------------------------------------- /aphid/selector/selector.3.5inch.dc42.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stepleton/cameo/ca64ef0f286fabcdfb018684bf078709f3188b11/aphid/selector/selector.3.5inch.dc42.zip -------------------------------------------------------------------------------- /aphid/selector/selector.image.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stepleton/cameo/ca64ef0f286fabcdfb018684bf078709f3188b11/aphid/selector/selector.image.zip -------------------------------------------------------------------------------- /aphid/selector/selector.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stepleton/cameo/ca64ef0f286fabcdfb018684bf078709f3188b11/aphid/selector/selector.jpg -------------------------------------------------------------------------------- /aphid/selector/selector.twiggy.dc42.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stepleton/cameo/ca64ef0f286fabcdfb018684bf078709f3188b11/aphid/selector/selector.twiggy.dc42.zip -------------------------------------------------------------------------------- /aphid/selector/ui_macros.x68: -------------------------------------------------------------------------------- 1 | * Cameo/Aphid disk image selector: UI library macros 2 | * ================================================== 3 | * 4 | * Forfeited into the public domain with NO WARRANTY. Read LICENSE for details. 5 | * 6 | * Macros for invoking various procedures in our UI library. We have: 7 | * 8 | * For `ui_base.x68`, macros for directly invoking the procedures: 9 | * 10 | * - mUiInvertBox -- Invert a rectangle of characters 11 | * - mUiClearBox -- Clear a rectangle of characters 12 | * - mUiScrollBox -- Vertical scroll within a rectangle of characters 13 | * - mUiShiftLine -- Horizontal shift part of a character line 14 | * - mUiPrintStr -- Print a null-terminated string 15 | * - mUiPrintStrN -- Print up to N characters of a null-terminated string 16 | * - mUiPutc -- Print a single character and advance the cursor horizontally 17 | * 18 | * and additional convenience macros: 19 | * 20 | * - mUiPrintLit -- Print a literal string 21 | * - mUiPrint -- Print multiple items 22 | * - mUiGotoRC -- Designate the screen position for the next print operation 23 | * - mUiGotoR -- Designate the screen row for the next print operation 24 | * - mUiGotoC -- Designate the screen column for the next print operation 25 | 26 | 27 | * ui_base Macros -------------------------------- 28 | 29 | 30 | ; mUiInvertBox -- Invert a rectangle of characters 31 | ; Args: 32 | ; \1: w. Top-left corner of the rectangle, in rows 33 | ; \2: w. Top-left corner of the rectangle, in columns 34 | ; \3: w. Height of the rectangle, in rows 35 | ; \4: w. Width of the rectangle, in columns 36 | ; Notes: 37 | ; Boxes that overlap screen boundaries cause undefined behaviour 38 | ; Pushes items onto the stack while processing arguments 39 | ; Trashes D0-D1/A0-A1 40 | mUiInvertBox MACRO 41 | MOVE.W \4,-(SP) 42 | MOVE.W \3,-(SP) 43 | MOVE.W \2,-(SP) 44 | MOVE.W \1,-(SP) 45 | BSR UiInvertBox 46 | ADDQ.L #$8,SP ; Pop arguments off of the stack 47 | ENDM 48 | 49 | 50 | ; mUiClearBox -- Clear a rectangle of characters 51 | ; Args: 52 | ; \1: w. Top-left corner of the rectangle, in rows 53 | ; \2: w. Top-left corner of the rectangle, in columns 54 | ; \3: w. Height of the rectangle, in rows 55 | ; \4: w. Width of the rectangle, in columns 56 | ; Notes: 57 | ; Boxes that overlap screen boundaries cause undefined behaviour 58 | ; Pushes items onto the stack while processing arguments 59 | ; Trashes D0-D1/A0-A1 60 | mUiClearBox MACRO 61 | MOVE.W \4,-(SP) 62 | MOVE.W \3,-(SP) 63 | MOVE.W \2,-(SP) 64 | MOVE.W \1,-(SP) 65 | BSR UiClearBox 66 | ADDQ.L #$8,SP ; Pop arguments off of the stack 67 | ENDM 68 | 69 | 70 | ; mUiScrollBox -- Scroll vertically within a rectangle of characters 71 | ; Args: 72 | ; \1: w. Top-left corner of the rectangle, in rows 73 | ; \2: w. Top-left corner of the rectangle, in columns 74 | ; \3: w. Height of the rectangle, in rows 75 | ; \4: w. Width of the rectangle, in columns 76 | ; \5: w. Number of rows to scroll; can be negative 77 | ; Notes: 78 | ; Region that new text would scroll into is left blank 79 | ; Boxes that overlap screen boundaries cause undefined behaviour 80 | ; Scrolling more rows than the box contains causes undefined behaviour 81 | ; Pushes items onto the stack while processing arguments 82 | ; Trashes D0-D1/A0-A1 83 | mUiScrollBox MACRO 84 | MOVE.W \5,-(SP) 85 | MOVE.W \4,-(SP) 86 | MOVE.W \3,-(SP) 87 | MOVE.W \2,-(SP) 88 | MOVE.W \1,-(SP) 89 | BSR UiScrollBox 90 | ADDA.W #$A,SP ; Pop arguments off of the stack 91 | ENDM 92 | 93 | 94 | ; mUiShiftLine -- Horizontal shift part of a character line 95 | ; Args: 96 | ; \1: w. Which row to apply the shift to 97 | ; \2: w. Leftmost column of the shift region 98 | ; \3: w. Number of columns to shift 99 | ; \4: w. Width of the shift region 100 | ; Notes: 101 | ; Region that new text would scroll into is left blank 102 | ; Lines that extend beyond screen boundaries cause undefined behaviour 103 | ; Shifting more columns than the region holds causes undefined behaviour 104 | ; Pushes items onto the stack while processing arguments 105 | ; Trashes D0-D1/A0-A1 106 | mUiShiftLine MACRO 107 | MOVE.W \4,-(SP) 108 | MOVE.W \3,-(SP) 109 | MOVE.W \2,-(SP) 110 | MOVE.W \1,-(SP) 111 | BSR UiShiftLine 112 | ADDQ.L #$8,SP ; Pop arguments off of the stack 113 | ENDM 114 | 115 | 116 | ; mUiPrintStr -- Print a null-terminated string 117 | ; Args: 118 | ; \1: l. Address of a null-terminated string to print 119 | ; Notes: 120 | ; Notes for Print\1 of lisa_console_screen.x68 apply here as well 121 | ; Trashes D0-D1/A0-A1 122 | mUiPrintStr MACRO 123 | MOVE.L \1,-(SP) 124 | BSR UiPrintStr 125 | ADDQ.L #$4,SP ; Pop argument off of the stack 126 | ENDM 127 | 128 | 129 | ; mUiPrintStrN -- Print up to N characters of a null-terminated string 130 | ; Args: 131 | ; \1: w. Maximum number of characters to print 132 | ; \2: l. Address of a null-terminated string to print 133 | ; Notes: 134 | ; Notes for Print\1 of lisa_console_screen.x68 apply here as well 135 | ; Modifies the string to print (temporarily) --- not thread safe! 136 | ; Trashes D0-D1/A0-A1 137 | mUiPrintStrN MACRO 138 | MOVE.L \2,-(SP) 139 | MOVE.W \1,-(SP) 140 | BSR UiPrintStrN 141 | ADDQ.L #$6,SP ; Pop arguments off of the stack 142 | ENDM 143 | 144 | 145 | ; mUiPutc -- Print a single character and advance the cursor horizontally 146 | ; Args: 147 | ; \1: b. Character to print 148 | ; Notes: 149 | ; Notes for Putc\1 of lisa_console_screen.x68 apply here as well 150 | ; DOES NOT ADVANCE TO THE NEXT LINE IF A NEWLINE CHARACTER IS ENCOUNTERED 151 | ; DOES NOT ADVANCE TO THE NEXT LINE IF THE CURSOR IS AT THE LAST COLUMN 152 | ; Trashes A0-A1/D0-D1 153 | mUiPutc MACRO 154 | MOVE.B \1,-(SP) 155 | BSR UiPutc 156 | ADDQ.L #$2,SP ; Pop arguments off of the stack 157 | ENDM 158 | 159 | 160 | ; mUiPrintLit -- Print a literal string 161 | ; Args: 162 | ; \1: Literal string to print 163 | ; Notes: 164 | ; Notes for Print\1 of lisa_console_screen.x68 apply here as well 165 | ; The literal is embedded in the code at the site of macro invocation 166 | ; Trashes D0-D1/A0-A1 167 | mUiPrintLit MACRO 168 | BRA.S .p\@ ; Jump past string constant 169 | .s\@ DC.B \1,$00 ; Null-terminated string literal 170 | DS.W 0 ; Force even word alignment 171 | .p\@ PEA.L .s\@(PC) ; Push string literal address onto the stack 172 | BSR UiPrintStr ; Print the string literal 173 | ADDQ.L #$4,SP ; Pop argument off of the stack 174 | ENDM 175 | 176 | 177 | ; mUiGotoRC -- Designate the screen position for the next print operation 178 | ; Args: 179 | ; \1: w. Row for the next print operation 180 | ; \2: w. Column for the next print operation (cannot be D1) 181 | ; Notes: 182 | ; Out-of-bounds screen positions cause undefined behaviour 183 | ; Trashes D0-D1 184 | mUiGotoRC MACRO 185 | IFC '\2','D1' 186 | FAIL Second argument to mUiGotoRC cannot be D1 187 | ENDC 188 | IFNC '\1','D1' 189 | MOVE.W \1,D1 190 | ENDC 191 | IFNC '\2','D0' 192 | MOVE.W \2,D0 193 | ENDC 194 | BSR GotoXYLisaConsole 195 | ENDM 196 | 197 | 198 | ; mUiGotoR -- Designate the screen row for the next print operation 199 | ; Args: 200 | ; \1: w. Row for the next print operation 201 | ; Notes: 202 | ; Out-of-bounds screen rows cause undefined behaviour 203 | ; Trashes D0 204 | mUiGotoR MACRO 205 | IFNC '\1','D0' 206 | MOVE.W \1,D0 207 | ENDC 208 | BSR GotoYLisaConsole 209 | ENDM 210 | 211 | 212 | ; mUiGotoC -- Designate the screen column for the next print operation 213 | ; Args: 214 | ; \1: w. Column for the next print operation 215 | ; Notes: 216 | ; Out-of-bounds screen columns cause undefined behaviour 217 | ; Trashes D0 218 | mUiGotoC MACRO 219 | IFNC '\1','D0' 220 | MOVE.W \1,D0 221 | ENDC 222 | BSR GotoXLisaConsole 223 | ENDM 224 | 225 | 226 | ; mUiPrintX -- Perform a variety of print operations 227 | ; Args: 228 | ; \1: What to print (see notes) 229 | ; Notes: 230 | ; Notes for Print\1 of lisa_console_screen.x68 apply here as well 231 | ; \1 can be any of the following: 232 | ; - <'A literal string'> - print this string 233 | ; - s - pop an address and print the null-terminated string there 234 | ; - r1c0 - the next print operation will start at row 1, column 0 235 | ; - r1c1 - the next print operation will start at row 1, column 1 236 | ; - r1c2 - the next print operation will start at row 1, column 2 237 | ; - c3 - the next print operation will start at column 3 238 | ; Some arguments, but not all, can trash D0-D1/A0-A1 239 | mUiPrintX MACRO 240 | IFC <'\1'>,<'s'> 241 | BSR UiPrintStr ; Print a string at an address on the stack 242 | ADDQ.L #$4,SP ; Pop address off of the stack 243 | ENDC 244 | IFC <'\1'>,<'r1c0'> 245 | mUiGotoRC #$1,#$0 ; Next print operation at row 1, column 0 246 | ENDC 247 | IFC <'\1'>,<'r1c1'> 248 | mUiGotoRC #$1,#$1 ; Next print operation at row 1, column 1 249 | ENDC 250 | IFC <'\1'>,<'r1c2'> 251 | mUiGotoRC #$1,#$2 ; Next print operation at row 1, column 2 252 | ENDC 253 | IFC <'\1'>,<'c3'> 254 | mUiGotoC #$3 ; Next print operation at column 3 255 | ENDC 256 | 257 | IFNC <'\1'>,<'s'> ; A proper else clause would be nice... 258 | IFNC <'\1'>,<'r1c0'> 259 | IFNC <'\1'>,<'r1c1'> 260 | IFNC <'\1'>,<'r1c2'> 261 | IFNC <'\1'>,<'c3'> 262 | mUiPrintLit <\1> ; Print a literal string 263 | ENDC 264 | ENDC 265 | ENDC 266 | ENDC 267 | ENDC 268 | ENDM 269 | 270 | 271 | ; mUiPrint -- Print multiple items 272 | ; Args: 273 | ; \1 and optionally up to \9: What to print (see notes) 274 | ; Notes: 275 | ; Notes for Print\1 of lisa_console_screen.x68 apply here as well 276 | ; See argument notes for mUiPrintX for what \1 can be 277 | ; Some arguments, but not all, can trash D0-D1/A0-A1 278 | mUiPrint MACRO 279 | IFARG 1 280 | mUiPrintX <\1> 281 | ENDC 282 | IFARG 2 283 | mUiPrintX <\2> 284 | ENDC 285 | IFARG 3 286 | mUiPrintX <\3> 287 | ENDC 288 | IFARG 4 289 | mUiPrintX <\4> 290 | ENDC 291 | IFARG 5 292 | mUiPrintX <\5> 293 | ENDC 294 | IFARG 6 295 | mUiPrintX <\6> 296 | ENDC 297 | IFARG 7 298 | mUiPrintX <\7> 299 | ENDC 300 | IFARG 8 301 | mUiPrintX <\8> 302 | ENDC 303 | IFARG 9 304 | mUiPrintX <\9> 305 | ENDC 306 | ENDM 307 | -------------------------------------------------------------------------------- /aphid/selector/ui_psystem_menu.x68: -------------------------------------------------------------------------------- 1 | * Cameo/Aphid disk image selector: UCSD p-System-style menus 2 | * ========================================================== 3 | * 4 | * Forfeited into the public domain with NO WARRANTY. Read LICENSE for details. 5 | * 6 | * Displays a menu at the top of the screen that resembles the menus used by the 7 | * UCSD p-System (and systems it inspired, like the Monitor and the Pascal 8 | * Workshop). Uses the `ui_base.x68` library. 9 | * 10 | * [Title] Command: Y(odel, W(arble, U(lulate, C(aterwaul, ? [1.2] 11 | * 12 | * The "[Title]" prefix is novel to this library, and optional. The version 13 | * string "[1.2]" is common to several p-System implementations, and also 14 | * optional. The text in between usually presents several single-letter menu 15 | * options in the style shown, although the library will accept any string for 16 | * this region. 17 | * 18 | * By convention, the ? command displays more options that would not fit in the 19 | * menu, often without the version string: 20 | * 21 | * [Title] Command: B(ellow, S(hriek 22 | * 23 | * In either menu, all of the commands are usually available, including ?, which 24 | * has the effect of toggling back and forth between the menus. 25 | * 26 | * Identifying commands that all start with different letters is a challenge for 27 | * the menu designer. 28 | * 29 | * Public procedures: 30 | * - UiPSystemShow -- Show a UCSD p-System style menu 31 | * - UiPSystemKey -- Interpret a keypress 32 | * 33 | * All public procedures have convenience macros in `ui_macros.x68`. 34 | * 35 | * There's not much to this component. Typical applications will display a menu 36 | * with UiPSystemShow, collect a key input through some I/O library, then 37 | * attempt to interpret the keypress with UiPSystemKey. 38 | 39 | 40 | * ui_psystem_menu Code -------------------------- 41 | 42 | 43 | SECTION kSecCode 44 | 45 | 46 | ; UiPSystemShow -- Show a UCSD p-System style menu 47 | ; Args: 48 | ; SP+$C: l. Address of the version string, or $0 to show no version string 49 | ; SP+$8: l. Address of the command text, or $0 to show no command text 50 | ; SP+$4: l. Address of the title string, or $0 to show no title 51 | ; Notes: 52 | ; Menus that extend beyond one row of text cause undefined behaviour 53 | ; Trashes D0-D1/A0-A1 54 | UiPSystemShow: 55 | ; First, clear the row where the menu line displays, and indent two spaces 56 | mUiClearBox #$1,#$0,#$1,#$5A 57 | mUiPrint r1c2 ; Ready to go at row 1 column 2 58 | ; Print the title if supplied 59 | TST.L $4(SP) ; Is there a title string? 60 | BEQ.S .co ; No, skip to the command string 61 | MOVE.L $4(SP),-(SP) ; Yes, duplicate its pointer on the stack 62 | mUiPutc #'[' 63 | mUiPrint s,<'] '> ; Print the title string in square brackets 64 | ; Print the command text if supplied 65 | .co TST.L $8(SP) ; Is there command text? 66 | BEQ.S .ve ; No, skip to the version string 67 | MOVE.L $8(SP),-(SP) ; Yes, duplicate its pointer on the stack 68 | mUiPrint s ; Print the command text by itself 69 | mUiPutc #$20 ; Trailing space after command text 70 | ; Print the version string if supplied 71 | .ve TST.L $C(SP) ; Is there a version string? 72 | BEQ.S .rt ; No, skip to return 73 | MOVE.L $C(SP),-(SP) ; Yes, duplicate its pointer on the stack 74 | mUiPutc #'[' 75 | mUiPrint s ; Print the version string in square brackets 76 | mUiPutc #']' 77 | 78 | .rt RTS 79 | 80 | 81 | ; UiPSystemKey -- Interpret a keypress 82 | ; Args: 83 | ; SP+$6: l. Address of the "menu list" data structure (see notes) 84 | ; SP+$4: b. ISO 8859-1 character byte from the keypress 85 | ; Notes: 86 | ; The word-aligned "menu list" repeats: 87 | ; - a padding byte which is either $00 (requiring an exact match) or 88 | ; $01 (case-insensitive matches OK); use no other padding byte 89 | ; - an ISO 8859-1 character byte; if you've specified a $01 padding 90 | ; byte for case-insensitve matching, this must be an uppercase letter 91 | ; - a 16-bit signed offset from the "menu list" address in SP+$4 92 | ; The menu list is terminated with a $0000 word 93 | ; This routine attempts to match the SP+$6 argument with a menu list entry 94 | ; If a match is found, a full address is computed in A0 and Z is set 95 | ; Otherwise Z is cleared 96 | ; Trashes D0,A0 97 | UiPSystemKey: 98 | MOVEA.L $6(SP),A0 ; Point A0 at the menu list 99 | .lo TST.W (A0) ; Have we reached the end of the menu list? 100 | BEQ.S .no ; Yes, quit empty-handed 101 | MOVE.B $4(SP),D0 ; (Re)copy the character byte to D0 102 | BTST.B #$0,(A0)+ ; Is this entry's case-insensitive flag set? 103 | BEQ.S .cp ; If not, skip ahead to compare 104 | ANDI.B #$DF,D0 ; If so, make the character byte uppercase 105 | .cp CMP.B (A0)+,D0 ; Does the key match the list entry? 106 | BEQ.S .ok ; Yes, construct the jump address and return 107 | ADDQ.L #$2,A0 ; No, move to the next menu list entry 108 | BRA.S .lo ; Loop again to process it 109 | 110 | .no ANDI.B #$FB,CCR ; Clear the Z flag 111 | BRA.S .rt ; Jump to exit 112 | 113 | .ok MOVE.W (A0),D0 ; Copy address offset to D0 114 | MOVEA.L $6(SP),A0 ; Point A0 back at the menu list 115 | ADDA.W D0,A0 ; Add the address offset 116 | ORI.B #$04,CCR ; Set the Z flag 117 | 118 | .rt RTS 119 | -------------------------------------------------------------------------------- /aphid/selector/ui_screensaver.x68: -------------------------------------------------------------------------------- 1 | * Cameo/Aphid disk image selector: Screensaver 2 | * ============================================ 3 | * 4 | * Forfeited into the public domain with NO WARRANTY. Read LICENSE for details. 5 | * 6 | * A compact implementation of Rule 30 that scrolls up the screen, hopefully 7 | * averting burn-in. 8 | * 9 | * These procedures make use of the `lisa_console_kbmouse.x68` and 10 | * `lisa_console_screen.x68` components from the `lisa_io` library. Before using 11 | * any routine defined below, both of those components must have been initialised 12 | * via the `InitLisaConsoleKbMouse` and `InitLisaConsoleScreen` procedures. 13 | * 14 | * Public procedures: 15 | * - UiScreensaver -- Display a pattern that occupies the screen 16 | * - UiScreensaverWaitForKb -- Await keypress or do screensaver after a delay 17 | 18 | 19 | * ui_screensaver Code --------------------------- 20 | 21 | 22 | SECTION kSecCode 23 | 24 | 25 | ; UiScreensaverWaitForKb -- Await keypress or do screensaver after a delay 26 | ; Args: 27 | ; (none) 28 | ; Notes: 29 | ; Flushes the COPS input buffer immediately after being called 30 | ; The delay to jump to the screensaver is fixed at about 90 seconds 31 | ; Z is set if the user pressed a glyph key; if clear, the screensaver ran 32 | ; instead and the user has interrupted it, so redraw and start over 33 | ; Note: this means the loops you build around this routine will differ 34 | ; from ones you make for the LisaConsole___KbMouse routines. 35 | ; Trashes D0-D1/A0-A1 36 | UiScreensaverWaitForKb: 37 | MOVEM.W D2-D3,-(SP) ; Save registers we use 38 | BSR FlushCops ; Dump out the COPS input buffer 39 | MOVE.W #$0059,D3 ; Repeat 90 times 40 | .pl MOVE.W #$FFFE,D2 ; Number of times to poll the COPS 41 | BSR LisaConsoleDelayForKbMouse ; Poll the COPS for input 42 | BEQ.S .rt ; Glyph key pressed? Jump to exit 43 | BCS.S .pl ; Other COPS byte? Restart this polling round 44 | DBRA D3,.pl ; Otherwise onto the next round of polling 45 | 46 | BSR.S UiScreensaver ; Timed out; run the screensaver 47 | ANDI.B #$FB,CCR ; Clear Z to tell the caller we timed out 48 | .rt MOVEM.W (SP)+,D2-D3 ; Restore saved registers 49 | RTS 50 | 51 | 52 | ; UiScreensaver -- Display a pattern that occupies the screen 53 | ; Args: 54 | ; (none) 55 | ; Notes: 56 | ; Press a key to exit the screensaver 57 | ; Trashes D0-D1/A0-A1 58 | UiScreensaver: 59 | MOVEM.L D2-D6/A2,-(SP) ; Save registers we use 60 | 61 | ; Hint that the Lisa isn't glitching out 62 | mUiGotoRc #$23,#$10 ; Jump to the bottom of the screen 63 | mUiPrint <'[Screensaver]'> ; Note no descenders to interfere with the FA 64 | 65 | ; Initialise constants and other state 66 | MOVE.L #$1E1E1E1E,D3 ; Repeated Rule 30 bitmap for BTST lookups 67 | LEA.L zLisaConsoleKbCode(PC),A2 ; Point A2 at the last raw keycode 68 | MOVE.W $1BE,D6 ; Seed RNG with bits from the boot time 69 | 70 | ; Initialise the bottom row of the display --- plus the last word of the row 71 | ; before that 72 | .in MOVEA.L zLisaConsoleScreenBase(PC),A0 ; Start of the display buffer into A0 73 | ADDA.W #$7F9C,A0 ; Advance to bottom line of the screen (almost) 74 | MOVEQ.L #$2D,D1 ; Prepare to clear 46 words 75 | .cl CLR.W (A0)+ ; Clear this word, advance the pointer 76 | DBRA D1,.cl ; Loop to clear the next word 77 | ADDQ.B #$1,-46(A0) ; Make the very tip of the Rule 30 pyramid 78 | 79 | ; Scroll the entire display up one pixel; leave bottom row unchanged 80 | ; This is the top of the outermost loop 81 | .lo MOVE.W SR,-(SP) ; Save current interrupt mask 82 | ORI.W #$700,SR ; Now disable interrupts for speed 83 | MOVEA.L zLisaConsoleScreenBase(PC),A0 ; Start of the display buffer into A0 84 | LEA.L $5A(A0),A1 ; Point A1 90 bytes ahead 85 | MOVE.W #$3FCE,D1 ; Prepare to move 16,635 words 86 | .sl MOVE.W (A1)+,(A0)+ ; Copy this word, advance pointers 87 | DBRA D1,.sl ; Loop to copy the next word 88 | 89 | ; Initialise the input sliding window for the rightmost edge, where we 90 | ; imagine the state of the bit just to the right of the edge of the screen 91 | ; to be 0 if the rightmost bit of the prior line is 0 and random if it is 1 92 | CLR.W D1 ; Clear bottom of the input sliding window 93 | BTST.B #$0,-1(A0) ; Should we inject randomness into this edge? 94 | BEQ.S .no ; No, the bit was 0 95 | MOVE.L D6,D1 ; Yes, put it in there 96 | .no SWAP.W D1 ; And move whatever out of the way of the... 97 | MOVE.W -(A0),D1 ; ...rightmost word of the prior line 98 | ROL.L #$2,D1 ; Now set it up for the loop 99 | 100 | ; The middle loop computes all 45 words of the current line 101 | MOVEQ.L #$2C,D5 ; Prepare to repeat 45 times 102 | .lm CLR.W D2 ; Clear the output sliding window 103 | 104 | ; First we compute just two of the bits of the output word 105 | MOVEQ.L #$1,D4 ; Prepare to repeat twice 106 | .l1 ROR.L #$1,D1 ; Advance the input sliding window one bit 107 | BTST.L D1,D3 ; Should we set this bit in the output window? 108 | BEQ.S .c1 ; No, leave it clear 109 | ADDQ.B #$1,D2 ; Yes, set the bit (short instruction) 110 | .c1 ROR.W #$1,D2 ; Advance the output sliding window one bit 111 | DBRA D4,.l1 ; Loop to do the second bit 112 | 113 | ; Load the next input word from the prior generation into the upper word 114 | SWAP.W D1 ; Move input window contents out of the way 115 | MOVE.W -(A0),D1 ; Copy in the next word from prior generation 116 | SWAP.W D1 ; Move input window contents back 117 | 118 | ; Now we compute the remaining 14 bits of the output word 119 | MOVEQ.L #$D,D4 ; Prepare to repeat 14 times 120 | .l2 ROR.L #$1,D1 ; Advance the input sliding window one bit 121 | BTST.L D1,D3 ; Should we set this bit in the output window? 122 | BEQ.S .c2 ; No, leave it clear 123 | ADDQ.B #$1,D2 ; Yes, set the bit (short instruction) 124 | .c2 ROR.W #$1,D2 ; Advance the output sliding window one bit 125 | DBRA D4,.l2 ; Loop to do another bit 126 | 127 | ; The output word is full; write it to the screen, start a new output word 128 | MOVE.W D2,-(A1) ; Commit the output sliding window 129 | DBRA D5,.lm ; Repeat middle loop 130 | 131 | ; Now that we're out of the loop, advance the Galois LFSR that gives us the 132 | ; randomness that we inject into the rightmost edge 133 | ROL.W #$1,D6 ; The LFSR's rotate step 134 | BCC.S .kb ; Skip ahead if the rotated bit was 0 135 | EORI.W #$002C,D6 ; Otherwise, flip certain bits 136 | 137 | ; See if there's a key-up event or if the mouse has moved 138 | .kb MOVE.W (SP)+,SR ; Restore interrupts 139 | .kp CLR.B (A2) ; Clear the last raw keycode 140 | BSR LisaConsolePollKbMouse ; Poll the COPS for events 141 | BCC.S .lo ; No byte at all? Another round please 142 | ROXR.W #$1,D4 ; Rotate the X bit into D4's MSBit 143 | BMI.S .kp ; If X had been set, we need to poll again 144 | TST.B (A2) ; Did we get a key event from the COPS? 145 | BLE.S .lo ; No, or it was a keydown, so one more round 146 | 147 | ; If the key-up was the Backspace key, then it's an easter egg: XOR the 148 | ; lower word of the Rule 30 bitmap in D3 with LFSR state, rotate it one bit 149 | ; left, and start all over; note that this results in an automaton that's 150 | ; different to an elementary cellular automaton, since a bits value depends 151 | ; on the value of itself, its right neighbour, and its *3* left neighbours. 152 | CMPI.B #$45,(A2) ; Was it key-up on the Backspace key? 153 | BNE.S .rt ; No, jump to return to the caller 154 | EOR.W D6,D3 ; XOR the LFSR state with the bitmap lower half 155 | ROL.L #$1,D3 ; Rotate the bitmap one bit left. 156 | 157 | ; Photosensitivity guard! Any D3 bitmap where the MSBit is 0 and the LSBit 158 | ; is 1 will make a pattern with a rapidly alternating black and white lines, 159 | ; and since this produces a flickering image that could be hazardous to some 160 | ; users, we edit the bitmap to make this condition impossible 161 | BMI .in ; If MSBit is 1, safe to start the pattern 162 | BCLR.L #$0,D3 ; Otherwise we force the LSBit to be 0 163 | BRA .in ; And then restart the pattern 164 | 165 | ; Got a key-up, so return to the caller 166 | .rt MOVEM.L (SP)+,D2-D6/A2 ; Restore registers we use 167 | RTS 168 | -------------------------------------------------------------------------------- /aphid/setup_device_tree_overlay.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Apple parallel port storage emulator for Cameo 3 | # 4 | # Forfeited into the public domain with NO WARRANTY. Read LICENSE for details. 5 | # 6 | # This shell script changes the boot configuration in /boot/uEnv.txt to load 7 | # the Cameo/Aphid device tree overlay, which should have been installed in 8 | # /lib/firmware when you ran `make install`. 9 | # 10 | # Bad modifications to /boot/uEnv.txt can result in an unbootable PocketBeagle 11 | # (although since the microSD card can be removed, it's not the worst thing in 12 | # the world). This script is therefore very conservative in making changes to 13 | # this file and will abort if it detects anything out of the ordinary. 14 | # 15 | # This script must be run with superuser privileges. 16 | 17 | # The file we're modifying 18 | UENV_FILE='/boot/uEnv.txt' 19 | # The device tree overlay file we'd like to load on boot 20 | DTBO_FILE='/lib/firmware/PB-CAMEO-APHID.dtbo' 21 | # The suffix for backups of $UENV_FILE 22 | BACKUP_SUFFIX='.bak.no_cameo_aphid_dtbo' 23 | 24 | # Here is the modification itself: we want to enable a specific key-value pair 25 | # in the file (but we want to be careful that the user hasn't already done it). 26 | TARGET_PARAMETER='uboot_overlay_addr4' 27 | TARGET_ORIGINAL="#${TARGET_PARAMETER}=/lib/firmware/.dtbo" 28 | TARGET_MODIFIED="${TARGET_PARAMETER}=${DTBO_FILE}" 29 | 30 | 31 | # Generic failure message. 32 | fail() 33 | { 34 | echo "Giving up on setting up the Cameo/Aphid device tree overlay." 35 | exit 1 36 | } 37 | 38 | 39 | # Make sure the files that are important to this script exist. 40 | if [ ! -f $UENV_FILE ]; then 41 | echo "The boot configuration file $UENV_FILE is missing." 42 | fail 43 | fi 44 | if [ ! -f $DTBO_FILE ]; then 45 | echo "The compiled device tree overlay file $DTBO_FILE is missing." 46 | fail 47 | fi 48 | 49 | # Make sure that the string we wish to modify can be found in the file. 50 | if ! grep -q "^${TARGET_ORIGINAL}$" $UENV_FILE; then 51 | echo "The boot configuration file $UENV_FILE doesn't contain the line we know" 52 | echo "how to modify." 53 | fail 54 | fi 55 | # But also make sure that the parameter hasn't already been specified in the 56 | # file for some other cape (and whoever did that is just leaving the original 57 | # commented line around). 58 | if grep -q "^${TARGET_PARAMETER}=" $UENV_FILE; then 59 | echo "The boot configuration file $UENV_FILE has a line that's already using" 60 | echo "the parameter we'd like to use: ${TARGET_PARAMETER}." 61 | fail 62 | fi 63 | 64 | # Okay, we're finally ready to give it a shot. 65 | echo -n "Modifying ${UENV_FILE}... " 66 | sed_command="s|^${TARGET_ORIGINAL}$|${TARGET_MODIFIED}|" 67 | if sed "-i${BACKUP_SUFFIX}" -e "${sed_command}" $UENV_FILE; then 68 | echo "success." 69 | else 70 | echo "failure." 71 | fi 72 | echo "Look for a backup of the original file in ${UENV_FILE}${BACKUP_SUFFIX}." 73 | -------------------------------------------------------------------------------- /aphid/setup_dos_partition_part1.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Apple parallel port storage emulator for Cameo 3 | # 4 | # Forfeited into the public domain with NO WARRANTY. Read LICENSE for details. 5 | # 6 | # Together with setup_dos_partition_part2.sh, this shell script puts a fat32 7 | # partition in spare space on your microSD card, establishes a mount point for 8 | # it, and modifies /etc/fstab to mount the partition automatically. Usage: 9 | # 10 | # setup_dos_partition_part1.sh 11 | # 12 | # where is an optional size in bytes. The actual partition size that 13 | # this script will use will be this value rounded down to the nearest multiple 14 | # of 512. If no size is specified, a 512 MB partition size is assumed. 15 | # 16 | # This script must be run with superuser privileges. 17 | # 18 | # XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX 19 | # THIS SCRIPT MODIFIES YOUR PARTITION TABLE. NO "UNDO" ACTION IS PROVIDED! 20 | # XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX 21 | 22 | #### CONFIGURATION #### 23 | 24 | DEVICE='/dev/mmcblk0' # Should be the SD card. 25 | PARTITION_SIZE=`expr "${1:-536870912}" / 512` # 512 MB by default; in sectors. 26 | MOUNT_POINT='/usr/local/lib/cameo-aphid' # The Aphid images directory. 27 | 28 | 29 | #### SAFETY CHECKS AND INFO GATHERING #### 30 | 31 | # Stop if we've already got this partition. 32 | if findmnt $MOUNT_POINT > /dev/null; then 33 | echo "It looks like $MOUNT_POINT is already a filesystem that this" 34 | echo 'PocketBeagle can mount. Giving up.' 35 | exit 1 36 | fi 37 | 38 | # Stop if we've already got a directory at $MOUNT_POINT. 39 | if [ -e $MOUNT_POINT ]; then 40 | echo "It looks like $MOUNT_POINT is already a file or directory. Giving up." 41 | exit 1 42 | fi 43 | 44 | # Stop if the device already has a second partition. Ths won't work if the user 45 | # hasn't got privileges, but the next check will fail in that case. 46 | if sfdisk -l "${DEVICE}p2" 2>/dev/null; then 47 | echo "A second partition already exists on $DEVICE; giving up." 48 | exit 1 49 | fi 50 | 51 | # Get the starting address and the amount of free space. All units are sectors. 52 | FREE_START=`sfdisk -F $DEVICE | awk 'END{print $1}'` 53 | FREE_SIZE=`sfdisk -F $DEVICE | awk 'END{print $3}'` 54 | if [ -z "$FREE_START" -o -z "$FREE_SIZE" ]; then 55 | echo "Couldn't find the start or size of free space beyond the last" 56 | echo "partition on $DEVICE; giving up. (Try again as root?)" 57 | exit 1 58 | fi 59 | 60 | # Quit if there isn't enough free space left. 61 | if [ "$PARTITION_SIZE" -gt "$FREE_SIZE" ]; then 62 | echo "Not enough room on $DEVICE to add a partition with $PARTITION_SIZE " 63 | echo "sectors; only $FREE_SIZE sectors remain beyond the last partition." 64 | echo "Giving up." 65 | exit 1 66 | fi 67 | 68 | 69 | #### MAKING CHANGES #### 70 | 71 | # Create the mount point. 72 | echo -n "Creating mount point at $MOUNT_POINT..." 73 | if mkdir -p $MOUNT_POINT; then 74 | chown debian:debian $MOUNT_POINT # While we're at it, let's assign friendly 75 | chmod ug+rw $MOUNT_POINT # ownership and permissions. 76 | echo ' done.' 77 | else 78 | echo ' FAILED. Giving up.' 79 | exit 1 80 | fi 81 | 82 | # Add the new partition. Hang on to your hat... 83 | echo 84 | echo "[[ Creating a new ${PARTITION_SIZE}-sector partition ]]" 85 | echo "------------------------------------------------------------------------" 86 | PARTITION="${DEVICE}p2 : start=$FREE_START, size=$PARTITION_SIZE, type=c" 87 | echo $PARTITION | sfdisk $DEVICE -a --no-reread 88 | SFDISK_RESULT="$?" 89 | # Now touch a file inside the mount point to indicate that we're ready to run 90 | # part 2 of the script. 91 | touch "$MOUNT_POINT/ready_to_run_setup_dos_partition_part2" 92 | echo "------------------------------------------------------------------------" 93 | if [ "$SFDISK_RESULT" -eq "0" ]; then 94 | echo '[[ Done ]]' 95 | echo 96 | echo 'Warnings about being unable to refresh the partition table are normal.' 97 | echo 'Please reboot the PocketBeagle and run setup_dos_partition_part2.sh' 98 | echo 'with superuser privileges.' 99 | else 100 | echo '[[ FAILED. Giving up. Apologies and best of luck. ]]' 101 | exit 1 102 | fi 103 | -------------------------------------------------------------------------------- /aphid/setup_dos_partition_part2.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Apple parallel port storage emulator for Cameo 3 | # 4 | # Forfeited into the public domain with NO WARRANTY. Read LICENSE for details. 5 | # 6 | # Together with setup_dos_partition_part1.sh, this shell script puts a fat32 7 | # partition in spare space on your microSD card, establishes a mount point for 8 | # it, and modifies /etc/fstab to mount the partition automatically. Usage: 9 | # 10 | # setup_dos_partition_part2.sh 11 | # 12 | # This script continues the setup process that setup_dos_partition_part1.sh 13 | # begins. Before running this script, you should have run that script and 14 | # rebooted your PocketBeagle. 15 | # 16 | # This script must be run with superuser privileges. 17 | 18 | #### CONFIGURATION #### 19 | 20 | DEVICE='/dev/mmcblk0' # Should be the SD card. 21 | MOUNT_POINT='/usr/local/lib/cameo-aphid' # The Aphid images directory. 22 | 23 | 24 | #### SAFETY CHECKS ##### 25 | 26 | # Check for the presence of the file that indicates that we're picking up where 27 | # we left off from the previous script. 28 | if [ ! -e "$MOUNT_POINT/ready_to_run_setup_dos_partition_part2" ]; then 29 | echo "It looks like setup_dos_partition_part1.sh wasn't run successfully" 30 | echo 'just before now. If you believe it was, and would like this script to' 31 | echo 'proceed as if it did, run the following command:' 32 | echo 33 | echo " touch $MOUNT_POINT/ready_to_run_setup_dos_partition_part2" 34 | echo 35 | echo 'then try this script again.' 36 | echo 'Giving up.' 37 | exit 1 38 | fi 39 | 40 | # Stop if the DOS partition is already mountable. 41 | if findmnt $MOUNT_POINT > /dev/null; then 42 | echo "It looks like $MOUNT_POINT is already a filesystem that this " 43 | echo 'PocketBeagle can mount. Giving up.' 44 | exit 1 45 | fi 46 | 47 | # Stop if the device already has a second partition. Ths won't work if the user 48 | # hasn't got privileges, but the next check will fail in that case. 49 | if ! sfdisk -l -q "${DEVICE}p2" 2>/dev/null; then 50 | echo 'The partition that setup_dos_partition_part1.sh should have made on' 51 | echo "$DEVICE does not appear to exist; giving up." 52 | exit 1 53 | fi 54 | 55 | 56 | #### MAKING CHANGES #### 57 | 58 | # Delete the sentinel file. 59 | rm -f "$MOUNT_POINT/ready_to_run_setup_dos_partition_part2" 60 | 61 | # Format the new partition. 62 | echo -n 'Formatting the new partition...' 63 | if mkfs.vfat -n 'CAMEO_APHID' "${DEVICE}p2" > /dev/null; then 64 | echo ' done.' 65 | else 66 | echo ' FAILED. Giving up.' 67 | exit 1 68 | fi 69 | 70 | # Add the partition to /etc/fstab. 71 | FSTAB="${DEVICE}p2\ 72 | $MOUNT_POINT\ 73 | vfat\ 74 | rw,exec,nodev,check=strict,flush,umask=000\ 75 | 0 2" 76 | echo -n 'Adding the new partition to /etc/fstab...' 77 | if echo "$FSTAB" >> /etc/fstab; then 78 | echo ' done.' 79 | else 80 | echo ' FAILED. Giving up.' 81 | exit 1 82 | fi 83 | 84 | # Lastly, mount the partition. 85 | echo -n "Mounting the new partition at $MOUNT_POINT..." 86 | if mount --target $MOUNT_POINT; then 87 | echo ' done.' 88 | echo 'Partition setup complete.' 89 | else 90 | echo ' FAILED. Giving up.' 91 | exit 1 92 | fi 93 | -------------------------------------------------------------------------------- /aphid/setup_os_config_changes.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Apple parallel port storage emulator for Cameo 3 | # 4 | # Forfeited into the public domain with NO WARRANTY. Read LICENSE for details. 5 | # 6 | # This shell script makes various changes to operating system configuration 7 | # files in order to improve Cameo/Aphid's compatibility and usefulness (it's 8 | # difficult to be more specific than this!). Note that most of the effort that 9 | # went into file has been focused on the most recent recommended OS image; some 10 | # changes applied to that image may be appropriate for other OS images too, but 11 | # are missing because they simply haven't been tested, 12 | # 13 | # This script must be run with superuser privileges. 14 | 15 | # File listing the BeagleBoard image we're using. 16 | ID_FILE='/ID.txt' 17 | 18 | # Make sure we can identify which system image we're running. 19 | if [ ! -f $ID_FILE ]; then 20 | echo "OS image ID file $ID_FILE is missing; giving up on trimming services." 21 | exit 1 22 | fi 23 | ID=`cat $ID_FILE` 24 | 25 | if [ "$ID" = 'BeagleBoard.org Debian Image 2019-07-07' ]; then 26 | file='/opt/scripts/boot/am335x_evm.sh' 27 | echo "Changing USB ethernet to use NCM instead of ECM (the same change as" 28 | echo -n "https://github.com/RobertCNelson/boot-scripts/pull/114/commits)... " 29 | sed -i.bak 's/ecm.usb0/ncm.usb0/g' $file && echo 'done.' || echo 'failed!' 30 | 31 | echo 32 | echo "All done." 33 | else 34 | echo "No configuration changes are specified for an OS with image ID" 35 | echo " \"$ID\"" 36 | echo "so, not making any." 37 | fi 38 | -------------------------------------------------------------------------------- /aphid/setup_overlayroot.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Apple parallel port storage emulator for Cameo 3 | # 4 | # Forfeited into the public domain with NO WARRANTY. Read LICENSE for details. 5 | # 6 | # This shell script enables overlayroot filesystem protection for the root 7 | # filesystem---the last step in setting up your Cameo/Aphid stack as an 8 | # embedded appliance. With this option enabled, no changes to the root 9 | # filesystem will be saved to the microSD card---instead, changes are only 10 | # saved to RAM and will be lost whenever the PocketBeagle is shut down or 11 | # rebooted. Cameo/Aphid drive images must reside on a second disk partition 12 | # that does not have overlayroot protection; the setup_dos_partition* scripts 13 | # prepare such a partition for you. 14 | # 15 | # Before running this script, you should have run all of the other setup 16 | # scripts and completed the installation of the Cameo/Aphid software. 17 | # 18 | # This script must be run with superuser privileges. 19 | # 20 | # XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX 21 | # THIS SCRIPT MAKES FURTHER CHANGES IMPOSSIBLE. NO "UNDO" ACTION IS PROVIDED! 22 | # XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX 23 | 24 | #### CONFIGURATION #### 25 | 26 | MOUNT_POINT='/usr/local/lib/cameo-aphid' # The Aphid images directory. 27 | OVERLAY_CONF='/etc/overlayroot.conf' # OverlayFS config file. 28 | 29 | 30 | #### SAFETY CHECKS #### 31 | 32 | # Stop if overlayfs isn't installed---it's only been available on the 33 | # BeagleBoard image since the 2018-08-30 release. 34 | if [ ! -e $OVERLAY_CONF ]; then 35 | echo "It looks like overlayfs capability isn't available on this " 36 | echo 'PocketBeagle system software image. Giving up.' 37 | exit 1 38 | fi 39 | 40 | # Stop if there's no secondary partition for Cameo/Aphid drive images. 41 | if ! findmnt $MOUNT_POINT > /dev/null; then 42 | echo "It looks like $MOUNT_POINT does not reside on a secondary" 43 | echo 'filesystem, which overlayfs requires (otherwise writes to an emulated ' 44 | echo 'ProFile will not be saved once Cameo/Aphid is powered down). Make sure ' 45 | echo 'to run the setup_dos_partition* scripts before running this script.' 46 | echo 'Giving up.' 47 | exit 1 48 | fi 49 | 50 | # Stop if no Cameo/Aphid software is installed 51 | if ! systemctl status cameo-aphid 2>/dev/null | grep -q active ; then 52 | echo 'It looks like the Cameo/Aphid system service is not enabled. Once' 53 | echo 'overlayfs is active, it will not be very easy to enable it. Please' 54 | echo "install the Cameo/Aphid system software if you haven't yet." 55 | echo 'Giving up.' 56 | exit 1 57 | fi 58 | 59 | # Stop if overlayfs is already enabled. 60 | if ! grep -v '^#' $OVERLAY_CONF | grep -q '^overlayroot=""$'; then 61 | echo 'It looks like overlayfs is already enabled on this PocketBeagle.' 62 | echo 'Giving up.' 63 | exit 1 64 | fi 65 | # At last. It looks like we're ready to go. 66 | 67 | 68 | #### MAKING CHANGES #### 69 | 70 | SED_COMMAND='s/^overlayroot=""$/overlayroot="tmpfs:recurse=0"/' 71 | echo -n "Modifying overlayfs configuration in ${OVERLAY_CONF}..." 72 | if sed -i.orig "$SED_COMMAND" $OVERLAY_CONF; then 73 | echo ' done.' 74 | echo 75 | echo 'NOTE: On the next boot, overlayfs will be enabled, with no easy way to' 76 | echo 'disable it. The root filesystem will be locked in its current state.' 77 | echo 'Your last chance to back out of this change is now, with this command:' 78 | echo 79 | echo " mv ${OVERLAY_CONF}.orig $OVERLAY_CONF" 80 | echo 81 | echo "Otherwise, if you're happy to enable overlayfs, reboot now." 82 | else 83 | echo ' FAILED.' 84 | echo 'Do you have superuser privileges? Giving up.' 85 | exit 1 86 | fi 87 | -------------------------------------------------------------------------------- /aphid/setup_trim_misc.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Apple parallel port storage emulator for Cameo 3 | # 4 | # Forfeited into the public domain with NO WARRANTY. Read LICENSE for details. 5 | # 6 | # This shell script disables miscellaneous bits of system functionality that 7 | # are enabled by default on PocketBeagle system images. Trimming these items 8 | # hastens the boot process and conserves system resources. 9 | # 10 | # This script must be run with superuser privileges. 11 | 12 | 13 | # Disable initramfs by moving initrd images aside. This operation renames the 14 | # initrd files by prepending their filenames with "DISABLED-". To re-enable 15 | # initramfs, simply rename the files by removing this prefix. 16 | echo -n 'Renaming initramfs images (if any) so they are not used...' 17 | for i in /boot/initrd.img-*; do 18 | mv $i `echo $i | sed 's|^/boot/|/boot/DISABLED-|'` 19 | done 20 | echo ' done' 21 | -------------------------------------------------------------------------------- /aphid/setup_trim_services.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Apple parallel port storage emulator for Cameo 3 | # 4 | # Forfeited into the public domain with NO WARRANTY. Read LICENSE for details. 5 | # 6 | # This shell script disables a variety of system services that are enabled 7 | # by default on PocketBeagle system images. Trimming these images shaves 8 | # around a dozen seconds off of the boot time and cuts back on the number of 9 | # processes that could be writing to disk---handy if we are keeping root 10 | # filesystem changes in RAM via overlayfs. 11 | # 12 | # This script must be run with superuser privileges. 13 | 14 | # File listing the BeagleBoard image we're using. 15 | ID_FILE='/ID.txt' 16 | 17 | # We disable these systemd entities for the 2020-04-06 image: 18 | DISABLE_20200406="\ 19 | avahi-daemon.service \ 20 | bb-wl18xx-bluetooth.service \ 21 | bb-wl18xx-wlan0.service \ 22 | bluetooth.service \ 23 | bonescript-autorun.service \ 24 | bonescript.service \ 25 | bonescript.socket \ 26 | cloud9.service \ 27 | cloud9.socket \ 28 | cron.service \ 29 | emergency.service \ 30 | fake-hwclock.service \ 31 | getty-static.service \ 32 | logrotate.service \ 33 | logrotate.timer \ 34 | nginx.service \ 35 | nodered.service \ 36 | nodered.socket \ 37 | rc-local.service \ 38 | remote-fs.target \ 39 | rescue.service \ 40 | rsync.service \ 41 | rsyslog.service \ 42 | systemd-machine-id-commit.service \ 43 | systemd-timesyncd.service" 44 | 45 | # We REALLY disable these systemd entities for the 2020-04-06 image: 46 | MASK_20200406="\ 47 | cryptsetup.target \ 48 | getty.target \ 49 | getty@tty1.service \ 50 | graphical.target \ 51 | proc-sys-fs-binfmt_misc.automount \ 52 | proc-sys-fs-binfmt_misc.mount \ 53 | serial-getty@ttyGS0.service \ 54 | serial-getty@ttyS0.service \ 55 | swap.target \ 56 | systemd-ask-password-console.service \ 57 | systemd-ask-password-wall.service \ 58 | systemd-binfmt.service \ 59 | systemd-initctl.service \ 60 | systemd-initctl.socket \ 61 | systemd-journal-flush.service \ 62 | systemd-journald.service \ 63 | systemd-rfkill.service \ 64 | systemd-rfkill.socket \ 65 | systemd-tmpfiles-clean.timer \ 66 | timers.target \ 67 | wpa_supplicant.service" 68 | 69 | # We disable these systemd entities for the 2019-08-03 image: 70 | DISABLE_20190803="\ 71 | atd.service \ 72 | avahi-daemon.service \ 73 | bb-bbai-tether.service \ 74 | bb-wl18xx-bluetooth.service \ 75 | bb-wl18xx-wlan0.service \ 76 | bluetooth.service \ 77 | bonescript-autorun.service \ 78 | console-setup.service \ 79 | cron.service \ 80 | hostapd.service \ 81 | keyboard-setup.service \ 82 | nginx.service \ 83 | pppd-dns.service \ 84 | rc_battery_monitor.service \ 85 | robotcontrol.service \ 86 | rsync.service \ 87 | rsyslog.service \ 88 | systemd-timesyncd.service \ 89 | ti-ipc-dra7xx.service \ 90 | ti-mct-daemon.service \ 91 | ti-sgx-ti33x-ddk-um.service \ 92 | bonescript.socket \ 93 | cloud9.socket \ 94 | node-red.socket \ 95 | graphical.target \ 96 | remote-fs.target \ 97 | apt-daily-upgrade.timer \ 98 | apt-daily.timer" 99 | 100 | # We REALLY disable these systemd entities for the 2019-08-03 image: 101 | MASK_20190803="\ 102 | alsa-restore.service \ 103 | alsa-state.service \ 104 | serial-getty@ttyGS0.service \ 105 | serial-getty@ttyS0.service \ 106 | wpa_supplicant.service" 107 | 108 | # We disable these systemd entities for the 2019-07-07 image: 109 | DISABLE_20190707="\ 110 | atd.service \ 111 | avahi-daemon.service \ 112 | avahi-daemon.socket\ 113 | bb-wl18xx-bluetooth.service \ 114 | bb-wl18xx-wlan0.service \ 115 | bluetooth.service \ 116 | bonescript-autorun.service \ 117 | bonescript.service \ 118 | bonescript.socket \ 119 | cloud9.service \ 120 | cloud9.socket \ 121 | console-setup.service \ 122 | cron.service \ 123 | emergency.service \ 124 | fake-hwclock.service \ 125 | getty-static.service \ 126 | keyboard-setup.service \ 127 | logrotate.service \ 128 | logrotate.timer \ 129 | nginx.service \ 130 | node-red.service \ 131 | node-red.socket \ 132 | rc-local.service \ 133 | remote-fs.target \ 134 | rescue.service \ 135 | rsync.service \ 136 | rsyslog.service \ 137 | systemd-machine-id-commit.service \ 138 | systemd-timesyncd.service" 139 | 140 | # We REALLY disable these systemd entities for the 2019-07-07 image: 141 | MASK_20190707="\ 142 | cryptsetup.target \ 143 | getty.target \ 144 | getty@tty1.service \ 145 | graphical.target \ 146 | proc-sys-fs-binfmt_misc.automount \ 147 | proc-sys-fs-binfmt_misc.mount \ 148 | serial-getty@ttyGS0.service \ 149 | serial-getty@ttyS0.service \ 150 | swap.target \ 151 | systemd-ask-password-console.service \ 152 | systemd-ask-password-wall.service \ 153 | systemd-binfmt.service \ 154 | systemd-initctl.service \ 155 | systemd-initctl.socket \ 156 | systemd-journal-flush.service \ 157 | systemd-journald.service \ 158 | systemd-rfkill.service \ 159 | systemd-rfkill.socket \ 160 | systemd-tmpfiles-clean.timer \ 161 | timers.target \ 162 | wpa_supplicant.service" 163 | 164 | # We disable these systemd entities for the 2018-10-07 image: 165 | DISABLE_20181007="\ 166 | apache2.service \ 167 | atd.service \ 168 | avahi-daemon.service \ 169 | bb-wl18xx-bluetooth.service \ 170 | bb-wl18xx-wlan0.service \ 171 | bluetooth.service \ 172 | bonescript-autorun.service \ 173 | console-setup.service \ 174 | cron.service \ 175 | getty@.service \ 176 | keyboard-setup.service \ 177 | pppd-dns.service \ 178 | rc_battery_monitor.service \ 179 | robotcontrol.service \ 180 | rsync.service \ 181 | rsyslog.service \ 182 | serial-getty@.service \ 183 | systemd-timesyncd.service \ 184 | bonescript.socket \ 185 | cloud9.socket \ 186 | node-red.socket \ 187 | remote-fs.target \ 188 | apt-daily-upgrade.timer \ 189 | apt-daily.timer" 190 | 191 | # We disable these systemd entities for the 2018-08-30 image: 192 | DISABLE_20180830="\ 193 | apache2.service \ 194 | atd.service \ 195 | avahi-daemon.service \ 196 | bb-wl18xx-bluetooth.service \ 197 | bb-wl18xx-wlan0.service \ 198 | bluetooth.service \ 199 | bonescript-autorun.service \ 200 | console-setup.service \ 201 | cron.service \ 202 | keyboard-setup.service \ 203 | pppd-dns.service \ 204 | rc_battery_monitor.service \ 205 | robotcontrol.service \ 206 | rsync.service \ 207 | rsyslog.service \ 208 | serial-getty@.service \ 209 | systemd-timesyncd.service \ 210 | apt-daily-upgrade.timer \ 211 | apt-daily.timer" 212 | 213 | # Lists of systemd entities to disable in other images should be placed here. 214 | 215 | 216 | # This function disables each systemd entity listed in its arguments, exiting 217 | # early if any entity is not successfully disabled. 218 | disable_systemd_entities() 219 | { 220 | for i in $@; do 221 | echo -n "Disabling $i..." 222 | if systemctl -q disable $i; then 223 | echo ' done.' 224 | else 225 | echo ' FAILED. Giving up.' 226 | exit 1 227 | fi 228 | done 229 | } 230 | 231 | 232 | # This function masks each systemd entity listed in its arguments, exiting 233 | # early if any entity is not successfully masked. 234 | mask_systemd_entities() 235 | { 236 | for i in $@; do 237 | echo -n "Masking $i..." 238 | if systemctl -q mask $i; then 239 | echo ' done.' 240 | else 241 | echo ' FAILED. Giving up.' 242 | exit 1 243 | fi 244 | done 245 | } 246 | 247 | 248 | # Make sure we can identify which system image we're running. 249 | if [ ! -f $ID_FILE ]; then 250 | echo "OS image ID file $ID_FILE is missing; giving up on trimming services." 251 | exit 1 252 | fi 253 | ID=`cat $ID_FILE` 254 | 255 | if [ "$ID" = 'BeagleBoard.org Debian Image 2018-10-07' ]; then 256 | disable_systemd_entities $DISABLE_20181007 257 | elif [ "$ID" = 'BeagleBoard.org Debian Image 2018-08-30' ]; then 258 | disable_systemd_entities $DISABLE_20180830 259 | elif [ "$ID" = 'BeagleBoard.org Debian Image 2019-07-07' ]; then 260 | disable_systemd_entities $DISABLE_20190707 261 | mask_systemd_entities $MASK_20190707 262 | elif [ "$ID" = 'BeagleBoard.org Debian Image 2019-08-03' ]; then 263 | disable_systemd_entities $DISABLE_20190803 264 | mask_systemd_entities $MASK_20190803 265 | elif [ "$ID" = 'BeagleBoard.org Debian Buster IoT Image 2020-04-06' ]; then 266 | disable_systemd_entities $DISABLE_20200406 267 | mask_systemd_entities $MASK_20200406 268 | # elif a different image... 269 | else 270 | echo "I don't know how to trim services for an OS with image ID" 271 | echo " \"$ID\"" 272 | echo "so, giving up." 273 | exit 1 274 | fi 275 | -------------------------------------------------------------------------------- /hardware/arcanebyte_aphde/README.md: -------------------------------------------------------------------------------- 1 | # Apple Parallel Hard Drive Emulator 2 | 3 | The Apple Parallel Hard Drive Emulator is derived from the Cameo/Aphid cape 4 | for the [PocketBeagle](http://beagleboard.org/pocket) single-board computer. 5 | It is intended as a modified form-factor with some enhancements over the 6 | cape design. 7 | 8 | ## Rev A 9 | 10 | The Rev A design uses the same components as the cape, including two Texas 11 | Instruments [TXS0108EPWR]( http://www.ti.com/product/TXS0108E) 8-bit bidirectional voltage 12 | level translator ICs. The 100ohm resistors are included for better 13 | compatibility with the Lisa 2/10, but YMMV. The board is designed to plug 14 | directly into the parallel port without a cable. 15 | 16 | ## Rev B 17 | 18 | The Rev B design forgoes the TXS0108 chips for BSS138 logic level converters. 19 | This design has shown to be more compatible with the Apple Lisa 2/10 using the 20 | internal widget cable. A small adapter can be used to convert from the 26-pin 21 | IDC cable to the DB25 interface provided on the board. 22 | 23 | ## Other notes 24 | 25 | In the spirit of Cameo, this modified design is released into the public domain. 26 | There is no warranty and any improvements are welcome. 27 | -------------------------------------------------------------------------------- /hardware/arcanebyte_aphde/rev_a/cameo_top_bom.csv: -------------------------------------------------------------------------------- 1 | Comment,Designator,Footprint,LCSC Part # 2 | 0.1uF,C1 C2 C3 C4,C0603, 3 | 100,R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16,R0603, 4 | 240k,R1,R0603, 5 | TXS0108EPWR,U1 U2,SOP65P640X120-20N,C17206 -------------------------------------------------------------------------------- /hardware/arcanebyte_aphde/rev_a/cameo_top_cpl.csv: -------------------------------------------------------------------------------- 1 | Designator,Mid X,Mid Y,Layer,Rotation 2 | C1, 6.35,11.18,Top,270.0 3 | C2, 5.84,18.80,Top,90.0 4 | C3,43.18,11.68,Top,270.0 5 | C4,40.64,20.32,Top,90.0 6 | R1,16.76,13.46,Top,90.0 7 | R4,18.80,25.65,Top,90.0 8 | R5,36.32,22.10,Top,270.0 9 | R6,33.27,22.10,Top,270.0 10 | R7,30.23,22.10,Top,270.0 11 | R8,41.66,25.40,Top,270.0 12 | R9,44.70,25.40,Top,270.0 13 | R10,47.75,25.40,Top,270.0 14 | R11, 9.65,25.65,Top,270.0 15 | R12,12.70,25.65,Top,270.0 16 | R13,15.75,25.65,Top,270.0 17 | R14, 6.60,25.65,Top,270.0 18 | R15,27.18,22.10,Top,270.0 19 | R16,38.61,25.40,Top,270.0 20 | U1,10.92,17.27,Top,90.0 21 | U2,45.47,18.03,Top,90.0 22 | -------------------------------------------------------------------------------- /hardware/arcanebyte_aphde/rev_b/cameo_top_bom.csv: -------------------------------------------------------------------------------- 1 | Comment,Designator,Footprint,LCSC Part # 2 | 10K,R2 R3 R14 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29 R30 R31 R32 R33 R34 R35 R36 R37 R38 R39,R0603, 3 | 120,R4,R0603, 4 | 240k,R1,R0603, 5 | BSS138,Q1 Q2 Q3 Q4 Q5 Q6 Q7 Q8 Q9 Q10 Q11 Q13 Q14,SOT95P240X111-3N, 6 | RED,D1,LED-0603,C72044 7 | -------------------------------------------------------------------------------- /hardware/arcanebyte_aphde/rev_b/cameo_top_cpl.csv: -------------------------------------------------------------------------------- 1 | Designator,Mid X,Mid Y,Layer,Rotation 2 | D1, 2.03,37.34,Top,270.0 3 | Q1,20.32,35.05,Top,90.0 4 | Q2,11.18,35.05,Top,90.0 5 | Q3,47.75,35.05,Top,90.0 6 | Q4, 5.84,11.68,Top,90.0 7 | Q5,34.80,14.48,Top,90.0 8 | Q6,47.75,11.68,Top,90.0 9 | Q7,43.43,11.68,Top,90.0 10 | Q8,37.85,23.88,Top,90.0 11 | Q9,39.62,35.05,Top,90.0 12 | Q10,39.12,11.68,Top,90.0 13 | Q11,43.43,23.88,Top,90.0 14 | Q13,34.04,35.05,Top,90.0 15 | Q14,30.48,11.68,Top,90.0 16 | R1,31.75,23.62,Top,0.0 17 | R2,23.37,34.80,Top,90.0 18 | R3,14.22,34.80,Top,90.0 19 | R4, 4.83,37.34,Top,90.0 20 | R14,50.55,34.54,Top,90.0 21 | R17, 5.84, 8.64,Top,180.0 22 | R18,34.80,11.43,Top,180.0 23 | R19,34.80,17.53,Top,0.0 24 | R20, 5.84,14.73,Top,180.0 25 | R21,47.75,38.10,Top,180.0 26 | R22,11.18,38.10,Top,180.0 27 | R23,20.32,38.10,Top,180.0 28 | R24,30.48, 8.64,Top,180.0 29 | R25,36.83,34.80,Top,90.0 30 | R26,43.43,20.83,Top,180.0 31 | R27,39.12, 8.64,Top,180.0 32 | R28,42.42,34.80,Top,90.0 33 | R29,37.85,20.83,Top,180.0 34 | R30,43.43, 8.64,Top,180.0 35 | R31,47.75, 8.64,Top,180.0 36 | R32,30.48,14.73,Top,0.0 37 | R33,34.04,38.10,Top,0.0 38 | R34,43.43,26.92,Top,180.0 39 | R35,39.12,14.73,Top,0.0 40 | R36,39.62,38.10,Top,0.0 41 | R37,37.85,26.92,Top,180.0 42 | R38,43.43,14.73,Top,0.0 43 | R39,47.75,14.73,Top,0.0 44 | -------------------------------------------------------------------------------- /hardware/cameo_cape/cameo_cape-cache.dcm: -------------------------------------------------------------------------------- 1 | EESchema-DOCLIB Version 2.0 2 | # 3 | #End Doc Library 4 | -------------------------------------------------------------------------------- /hardware/cameo_cape/cameo_cape-cache.lib: -------------------------------------------------------------------------------- 1 | EESchema-LIBRARY Version 2.3 2 | #encoding utf-8 3 | # 4 | # 2X18-_INCH_-0.1-TH-_35MIL-DIA_-W_O-SILK 5 | # 6 | DEF 2X18-_INCH_-0.1-TH-_35MIL-DIA_-W_O-SILK P 0 40 N Y 1 L N 7 | F0 "P" 0 1030 45 H V R TNN 8 | F1 "2X18-_INCH_-0.1-TH-_35MIL-DIA_-W_O-SILK" 850 -950 45 H V R TNN 9 | F2 "TH-2X18-_35MIL-DIA_-W_O-SILK" 30 150 20 H I C CNN 10 | F3 "" 0 0 60 H I C CNN 11 | $FPLIST 12 | *TH-2X18-(35MIL-DIA)-W_O-SILK* 13 | $ENDFPLIST 14 | DRAW 15 | P 2 1 0 0 -300 -900 -300 1000 N 16 | P 2 1 0 0 -300 1000 300 1000 N 17 | P 2 1 0 0 300 -900 -300 -900 N 18 | P 2 1 0 0 300 1000 300 -900 N 19 | X 1 1 -250 900 100 R 40 40 1 1 B I 20 | X 2 2 250 900 100 L 40 40 1 1 B I 21 | X 3 3 -250 800 100 R 40 40 1 1 B I 22 | X 4 4 250 800 100 L 40 40 1 1 B I 23 | X 5 5 -250 700 100 R 40 40 1 1 B I 24 | X 6 6 250 700 100 L 40 40 1 1 B I 25 | X 7 7 -250 600 100 R 40 40 1 1 B I 26 | X 8 8 250 600 100 L 40 40 1 1 B I 27 | X 9 9 -250 500 100 R 40 40 1 1 B I 28 | X 10 10 250 500 100 L 40 40 1 1 B I 29 | X 20 20 250 0 100 L 40 40 1 1 B I 30 | X 30 30 250 -500 100 L 40 40 1 1 B I 31 | X 11 11 -250 400 100 R 40 40 1 1 B I 32 | X 21 21 -250 -100 100 R 40 40 1 1 B I 33 | X 31 31 -250 -600 100 R 40 40 1 1 B I 34 | X 12 12 250 400 100 L 40 40 1 1 B I 35 | X 22 22 250 -100 100 L 40 40 1 1 B I 36 | X 32 32 250 -600 100 L 40 40 1 1 B I 37 | X 13 13 -250 300 100 R 40 40 1 1 B I 38 | X 23 23 -250 -200 100 R 40 40 1 1 B I 39 | X 33 33 -250 -700 100 R 40 40 1 1 B I 40 | X 14 14 250 300 100 L 40 40 1 1 B I 41 | X 24 24 250 -200 100 L 40 40 1 1 B I 42 | X 34 34 250 -700 100 L 40 40 1 1 B I 43 | X 15 15 -250 200 100 R 40 40 1 1 B I 44 | X 25 25 -250 -300 100 R 40 40 1 1 B I 45 | X 35 35 -250 -800 100 R 40 40 1 1 B I 46 | X 16 16 250 200 100 L 40 40 1 1 B I 47 | X 26 26 250 -300 100 L 40 40 1 1 B I 48 | X 36 36 250 -800 100 L 40 40 1 1 B I 49 | X 17 17 -250 100 100 R 40 40 1 1 B I 50 | X 27 27 -250 -400 100 R 40 40 1 1 B I 51 | X 18 18 250 100 100 L 40 40 1 1 B I 52 | X 28 28 250 -400 100 L 40 40 1 1 B I 53 | X 19 19 -250 0 100 R 40 40 1 1 B I 54 | X 29 29 -250 -500 100 R 40 40 1 1 B I 55 | ENDDRAW 56 | ENDDEF 57 | # 58 | # CONN_02X13 59 | # 60 | DEF CONN_02X13 P 0 1 Y N 1 F N 61 | F0 "P" 0 700 50 H V C CNN 62 | F1 "CONN_02X13" 0 0 50 V V C CNN 63 | F2 "" 0 -1150 50 H V C CNN 64 | F3 "" 0 -1150 50 H V C CNN 65 | $FPLIST 66 | Pin_Header_Straight_2X13 67 | Pin_Header_Angled_2X13 68 | Socket_Strip_Straight_2X13 69 | Socket_Strip_Angled_2X13 70 | $ENDFPLIST 71 | DRAW 72 | S -100 -595 -50 -605 0 1 0 N 73 | S -100 -495 -50 -505 0 1 0 N 74 | S -100 -395 -50 -405 0 1 0 N 75 | S -100 -295 -50 -305 0 1 0 N 76 | S -100 -195 -50 -205 0 1 0 N 77 | S -100 -95 -50 -105 0 1 0 N 78 | S -100 5 -50 -5 0 1 0 N 79 | S -100 105 -50 95 0 1 0 N 80 | S -100 205 -50 195 0 1 0 N 81 | S -100 305 -50 295 0 1 0 N 82 | S -100 405 -50 395 0 1 0 N 83 | S -100 505 -50 495 0 1 0 N 84 | S -100 605 -50 595 0 1 0 N 85 | S -100 650 100 -650 0 1 0 N 86 | S 50 -595 100 -605 0 1 0 N 87 | S 50 -495 100 -505 0 1 0 N 88 | S 50 -395 100 -405 0 1 0 N 89 | S 50 -295 100 -305 0 1 0 N 90 | S 50 -195 100 -205 0 1 0 N 91 | S 50 -95 100 -105 0 1 0 N 92 | S 50 5 100 -5 0 1 0 N 93 | S 50 105 100 95 0 1 0 N 94 | S 50 205 100 195 0 1 0 N 95 | S 50 305 100 295 0 1 0 N 96 | S 50 405 100 395 0 1 0 N 97 | S 50 505 100 495 0 1 0 N 98 | S 50 605 100 595 0 1 0 N 99 | X P1 1 -250 600 150 R 50 50 1 1 P 100 | X P2 2 250 600 150 L 50 50 1 1 P 101 | X P3 3 -250 500 150 R 50 50 1 1 P 102 | X P4 4 250 500 150 L 50 50 1 1 P 103 | X P5 5 -250 400 150 R 50 50 1 1 P 104 | X P6 6 250 400 150 L 50 50 1 1 P 105 | X P7 7 -250 300 150 R 50 50 1 1 P 106 | X P8 8 250 300 150 L 50 50 1 1 P 107 | X P9 9 -250 200 150 R 50 50 1 1 P 108 | X P10 10 250 200 150 L 50 50 1 1 P 109 | X P20 20 250 -300 150 L 50 50 1 1 P 110 | X P11 11 -250 100 150 R 50 50 1 1 P 111 | X P21 21 -250 -400 150 R 50 50 1 1 P 112 | X P12 12 250 100 150 L 50 50 1 1 P 113 | X P22 22 250 -400 150 L 50 50 1 1 P 114 | X P13 13 -250 0 150 R 50 50 1 1 P 115 | X P23 23 -250 -500 150 R 50 50 1 1 P 116 | X P14 14 250 0 150 L 50 50 1 1 P 117 | X P24 24 250 -500 150 L 50 50 1 1 P 118 | X P15 15 -250 -100 150 R 50 50 1 1 P 119 | X P25 25 -250 -600 150 R 50 50 1 1 P 120 | X P16 16 250 -100 150 L 50 50 1 1 P 121 | X P26 26 250 -600 150 L 50 50 1 1 P 122 | X P17 17 -250 -200 150 R 50 50 1 1 P 123 | X P18 18 250 -200 150 L 50 50 1 1 P 124 | X P19 19 -250 -300 150 R 50 50 1 1 P 125 | ENDDRAW 126 | ENDDEF 127 | # 128 | # C_Small 129 | # 130 | DEF C_Small C 0 10 N N 1 F N 131 | F0 "C" 10 70 50 H V L CNN 132 | F1 "C_Small" 10 -80 50 H V L CNN 133 | F2 "" 0 0 50 H V C CNN 134 | F3 "" 0 0 50 H V C CNN 135 | $FPLIST 136 | C? 137 | C_????_* 138 | C_???? 139 | SMD*_c 140 | Capacitor* 141 | $ENDFPLIST 142 | DRAW 143 | P 2 0 1 13 -60 -20 60 -20 N 144 | P 2 0 1 12 -60 20 60 20 N 145 | X ~ 1 0 100 75 D 40 40 1 1 P 146 | X ~ 2 0 -100 80 U 40 40 1 1 P 147 | ENDDRAW 148 | ENDDEF 149 | # 150 | # GND 151 | # 152 | DEF GND #PWR 0 0 Y Y 1 F P 153 | F0 "#PWR" 0 -250 50 H I C CNN 154 | F1 "GND" 0 -150 50 H V C CNN 155 | F2 "" 0 0 50 H I C CNN 156 | F3 "" 0 0 50 H I C CNN 157 | DRAW 158 | P 6 0 1 0 0 0 0 -50 50 -50 0 -100 -50 -50 0 -50 N 159 | X GND 1 0 0 0 D 50 50 1 1 W N 160 | ENDDRAW 161 | ENDDEF 162 | # 163 | # Jumper_NC_Small 164 | # 165 | DEF ~Jumper_NC_Small JP 0 30 N N 1 F N 166 | F0 "JP" 0 80 50 H V C CNN 167 | F1 "Jumper_NC_Small" 10 -60 50 H I C CNN 168 | F2 "" 0 0 50 H V C CNN 169 | F3 "" 0 0 50 H V C CNN 170 | DRAW 171 | A 0 -10 57 450 1350 0 1 0 N 40 30 -40 30 172 | C -40 0 20 0 1 0 N 173 | C 40 0 20 0 1 0 N 174 | X 1 1 -100 0 40 R 50 50 0 1 P 175 | X 2 2 100 0 40 L 50 50 0 1 P 176 | ENDDRAW 177 | ENDDEF 178 | # 179 | # Jumper_NO_Small 180 | # 181 | DEF ~Jumper_NO_Small JP 0 30 N N 1 F N 182 | F0 "JP" 0 80 50 H V C CNN 183 | F1 "Jumper_NO_Small" 10 -60 50 H I C CNN 184 | F2 "" 0 0 50 H V C CNN 185 | F3 "" 0 0 50 H V C CNN 186 | DRAW 187 | C -40 0 20 0 1 0 N 188 | C 40 0 20 0 1 0 N 189 | X 1 1 -100 0 40 R 50 50 0 1 P 190 | X 2 2 100 0 40 L 50 50 0 1 P 191 | ENDDRAW 192 | ENDDEF 193 | # 194 | # R 195 | # 196 | DEF R R 0 0 N Y 1 F N 197 | F0 "R" 80 0 50 V V C CNN 198 | F1 "R" 0 0 50 V V C CNN 199 | F2 "" -70 0 50 V V C CNN 200 | F3 "" 0 0 50 H V C CNN 201 | $FPLIST 202 | R_* 203 | Resistor_* 204 | $ENDFPLIST 205 | DRAW 206 | S -40 -100 40 100 0 1 10 N 207 | X ~ 1 0 150 50 D 50 50 1 1 P 208 | X ~ 2 0 -150 50 U 50 50 1 1 P 209 | ENDDRAW 210 | ENDDEF 211 | # 212 | # R_Small 213 | # 214 | DEF R_Small R 0 10 N N 1 F N 215 | F0 "R" 30 20 50 H V L CNN 216 | F1 "R_Small" 30 -40 50 H V L CNN 217 | F2 "" 0 0 50 H V C CNN 218 | F3 "" 0 0 50 H V C CNN 219 | $FPLIST 220 | Resistor_* 221 | R_* 222 | $ENDFPLIST 223 | DRAW 224 | S -30 70 30 -70 0 1 8 N 225 | X ~ 1 0 100 30 D 40 40 1 1 P 226 | X ~ 2 0 -100 30 U 40 40 1 1 P 227 | ENDDRAW 228 | ENDDEF 229 | # 230 | # SYS_5V 231 | # 232 | DEF SYS_5V #SUPPLY 0 40 N N 1 L P 233 | F0 "#SUPPLY" 0 0 45 H I L BNN 234 | F1 "SYS_5V" 0 160 45 H V L BNN 235 | F2 "" 0 0 60 H I C CNN 236 | F3 "" 0 0 60 H I C CNN 237 | DRAW 238 | P 2 1 0 0 0 -100 0 0 N 239 | C 0 50 50 1 1 0 N 240 | X SYS_5V ~ 0 -100 100 U 40 40 1 1 W N 241 | ENDDRAW 242 | ENDDEF 243 | # 244 | # TXS0108E_PW_20 245 | # 246 | DEF TXS0108E_PW_20 U 0 10 Y Y 1 F N 247 | F0 "U" 1100 400 60 H V C CNN 248 | F1 "TXS0108E_PW_20" 1100 300 60 H V C CNN 249 | F2 "PW20" 1100 240 60 H I C CNN 250 | F3 "" 0 0 60 H V C CNN 251 | $FPLIST 252 | PW20 253 | PW20-M 254 | PW20-L 255 | $ENDFPLIST 256 | DRAW 257 | P 2 1 0 5 300 -1100 1900 -1100 N 258 | P 2 1 0 5 300 200 300 -1100 N 259 | P 2 1 0 5 1900 -1100 1900 200 N 260 | P 2 1 0 5 1900 200 300 200 N 261 | X A1 1 0 0 300 R 59 59 1 0 B 262 | X VCCA 2 0 -100 300 R 59 59 1 0 W 263 | X A2 3 0 -200 300 R 59 59 1 0 B 264 | X A3 4 0 -300 300 R 59 59 1 0 B 265 | X A4 5 0 -400 300 R 59 59 1 0 B 266 | X A5 6 0 -500 300 R 59 59 1 0 B 267 | X A6 7 0 -600 300 R 59 59 1 0 B 268 | X A7 8 0 -700 300 R 59 59 1 0 B 269 | X A8 9 0 -800 300 R 59 59 1 0 B 270 | X OE 10 0 -900 300 R 59 59 1 0 I 271 | X B1 20 2200 0 300 L 59 59 1 0 B 272 | X GND 11 2200 -900 300 L 59 59 1 0 W 273 | X B8 12 2200 -800 300 L 59 59 1 0 B 274 | X B7 13 2200 -700 300 L 59 59 1 0 B 275 | X B6 14 2200 -600 300 L 59 59 1 0 B 276 | X B5 15 2200 -500 300 L 59 59 1 0 B 277 | X B4 16 2200 -400 300 L 59 59 1 0 B 278 | X B3 17 2200 -300 300 L 59 59 1 0 B 279 | X B2 18 2200 -200 300 L 59 59 1 0 B 280 | X V 19 2200 -100 300 L 59 59 1 0 W 281 | ENDDRAW 282 | ENDDEF 283 | # 284 | # USB_DC 285 | # 286 | DEF USB_DC #SUPPLY 0 40 N N 1 L P 287 | F0 "#SUPPLY" 0 0 45 H I L BNN 288 | F1 "USB_DC" 0 160 45 H V L BNN 289 | F2 "" 0 0 60 H I C CNN 290 | F3 "" 0 0 60 H I C CNN 291 | DRAW 292 | P 2 1 0 0 0 -100 0 0 N 293 | C 0 50 50 1 1 0 N 294 | X USB_DC ~ 0 -100 100 U 40 40 1 1 W N 295 | ENDDRAW 296 | ENDDEF 297 | # 298 | # VDD_3V3B 299 | # 300 | DEF VDD_3V3B #SUPPLY 0 40 N N 1 L P 301 | F0 "#SUPPLY" 0 0 45 H I L BNN 302 | F1 "VDD_3V3B" 0 160 45 H V L BNN 303 | F2 "" 0 0 60 H I C CNN 304 | F3 "" 0 0 60 H I C CNN 305 | DRAW 306 | P 2 1 0 0 0 -100 0 0 N 307 | C 0 50 50 1 1 0 N 308 | X VDD_3V3B ~ 0 -100 100 U 40 40 1 1 W N 309 | ENDDRAW 310 | ENDDEF 311 | # 312 | # VDD_5V 313 | # 314 | DEF VDD_5V #SUPPLY 0 40 N N 1 L P 315 | F0 "#SUPPLY" 0 0 45 H I L BNN 316 | F1 "VDD_5V" 0 160 45 H V L BNN 317 | F2 "" 0 0 60 H I C CNN 318 | F3 "" 0 0 60 H I C CNN 319 | DRAW 320 | P 2 1 0 0 0 -100 0 0 N 321 | C 0 50 50 1 1 0 N 322 | X VDD_5V ~ 0 -100 100 U 40 40 1 1 W N 323 | ENDDRAW 324 | ENDDEF 325 | # 326 | #End Library 327 | -------------------------------------------------------------------------------- /hardware/cameo_cape/cameo_cape.dcm: -------------------------------------------------------------------------------- 1 | EESchema-DOCLIB Version 2.0 2 | # 3 | #End Doc Library 4 | -------------------------------------------------------------------------------- /hardware/cameo_cape/cameo_cape.pro: -------------------------------------------------------------------------------- 1 | update=Wed 11 Apr 2018 01:00:45 BST 2 | version=1 3 | last_client=kicad 4 | [pcbnew] 5 | version=1 6 | LastNetListRead=PocketBeagle.net 7 | UseCmpFile=1 8 | PadDrill=0.600000000000 9 | PadDrillOvalY=0.600000000000 10 | PadSizeH=1.500000000000 11 | PadSizeV=1.500000000000 12 | PcbTextSizeV=1.500000000000 13 | PcbTextSizeH=1.500000000000 14 | PcbTextThickness=0.300000000000 15 | ModuleTextSizeV=1.000000000000 16 | ModuleTextSizeH=1.000000000000 17 | ModuleTextSizeThickness=0.150000000000 18 | SolderMaskClearance=0.000000000000 19 | SolderMaskMinWidth=0.000000000000 20 | DrawSegmentWidth=0.200000000000 21 | BoardOutlineThickness=0.100000000000 22 | ModuleOutlineThickness=0.150000000000 23 | [cvpcb] 24 | version=1 25 | NetIExt=net 26 | [general] 27 | version=1 28 | [eeschema] 29 | version=1 30 | LibDir=components 31 | [eeschema/libraries] 32 | LibName1=components/symbols 33 | LibName2=conn 34 | LibName3=device 35 | [schematic_editor] 36 | version=1 37 | PageLayoutDescrFile= 38 | PlotDirectoryName= 39 | SubpartIdSeparator=0 40 | SubpartFirstId=65 41 | NetFmtName= 42 | SpiceForceRefPrefix=0 43 | SpiceUseNetNumbers=0 44 | LabSize=60 45 | -------------------------------------------------------------------------------- /hardware/cameo_cape/components/symbols.dcm: -------------------------------------------------------------------------------- 1 | EESchema-DOCLIB Version 2.0 2 | # 3 | #End Doc Library 4 | -------------------------------------------------------------------------------- /hardware/cameo_cape/components/symbols.lib: -------------------------------------------------------------------------------- 1 | EESchema-LIBRARY Version 2.3 2 | #encoding utf-8 3 | # 4 | # TXS0108E_PW_20 5 | # 6 | DEF TXS0108E_PW_20 U 0 10 Y Y 1 F N 7 | F0 "U" 1100 400 60 H V C CNN 8 | F1 "TXS0108E_PW_20" 1100 300 60 H V C CNN 9 | F2 "PW20" 1100 240 60 H I C CNN 10 | F3 "" 0 0 60 H V C CNN 11 | $FPLIST 12 | PW20 13 | PW20-M 14 | PW20-L 15 | $ENDFPLIST 16 | DRAW 17 | P 2 1 0 5 300 -1100 1900 -1100 N 18 | P 2 1 0 5 300 200 300 -1100 N 19 | P 2 1 0 5 1900 -1100 1900 200 N 20 | P 2 1 0 5 1900 200 300 200 N 21 | X A1 1 0 0 300 R 59 59 1 0 B 22 | X VCCA 2 0 -100 300 R 59 59 1 0 W 23 | X A2 3 0 -200 300 R 59 59 1 0 B 24 | X A3 4 0 -300 300 R 59 59 1 0 B 25 | X A4 5 0 -400 300 R 59 59 1 0 B 26 | X A5 6 0 -500 300 R 59 59 1 0 B 27 | X A6 7 0 -600 300 R 59 59 1 0 B 28 | X A7 8 0 -700 300 R 59 59 1 0 B 29 | X A8 9 0 -800 300 R 59 59 1 0 B 30 | X OE 10 0 -900 300 R 59 59 1 0 I 31 | X B1 20 2200 0 300 L 59 59 1 0 B 32 | X GND 11 2200 -900 300 L 59 59 1 0 W 33 | X B8 12 2200 -800 300 L 59 59 1 0 B 34 | X B7 13 2200 -700 300 L 59 59 1 0 B 35 | X B6 14 2200 -600 300 L 59 59 1 0 B 36 | X B5 15 2200 -500 300 L 59 59 1 0 B 37 | X B4 16 2200 -400 300 L 59 59 1 0 B 38 | X B3 17 2200 -300 300 L 59 59 1 0 B 39 | X B2 18 2200 -200 300 L 59 59 1 0 B 40 | X V 19 2200 -100 300 L 59 59 1 0 W 41 | ENDDRAW 42 | ENDDEF 43 | # 44 | #End Library 45 | -------------------------------------------------------------------------------- /hardware/cameo_cape/gerber/cameo_cape-B.Paste.gbr: -------------------------------------------------------------------------------- 1 | G04 #@! TF.FileFunction,Paste,Bot* 2 | %FSLAX46Y46*% 3 | G04 Gerber Fmt 4.6, Leading zero omitted, Abs format (unit mm)* 4 | G04 Created by KiCad (PCBNEW 4.0.2+dfsg1-stable) date Thu 26 Jul 2018 23:23:47 BST* 5 | %MOMM*% 6 | G01* 7 | G04 APERTURE LIST* 8 | %ADD10C,0.100000*% 9 | G04 APERTURE END LIST* 10 | D10* 11 | M02* 12 | -------------------------------------------------------------------------------- /hardware/cameo_cape/gerber/cameo_cape-B.SilkS.gbr: -------------------------------------------------------------------------------- 1 | G04 #@! TF.FileFunction,Legend,Bot* 2 | %FSLAX46Y46*% 3 | G04 Gerber Fmt 4.6, Leading zero omitted, Abs format (unit mm)* 4 | G04 Created by KiCad (PCBNEW 4.0.2+dfsg1-stable) date Thu 26 Jul 2018 23:23:47 BST* 5 | %MOMM*% 6 | G01* 7 | G04 APERTURE LIST* 8 | %ADD10C,0.100000*% 9 | %ADD11C,0.150000*% 10 | G04 APERTURE END LIST* 11 | D10* 12 | D11* 13 | X132588000Y-107569000D02* 14 | X165608000Y-107569000D01* 15 | X135128000Y-102489000D02* 16 | X165608000Y-102489000D01* 17 | X165608000Y-107569000D02* 18 | X165608000Y-102489000D01* 19 | X132588000Y-107569000D02* 20 | X132588000Y-105029000D01* 21 | X132308000Y-103759000D02* 22 | X132308000Y-102209000D01* 23 | X132588000Y-105029000D02* 24 | X135128000Y-105029000D01* 25 | X135128000Y-105029000D02* 26 | X135128000Y-102489000D01* 27 | X132308000Y-102209000D02* 28 | X133858000Y-102209000D01* 29 | X129210381Y-103020905D02* 30 | X128210381Y-103020905D01* 31 | X128210381Y-103401858D01* 32 | X128258000Y-103497096D01* 33 | X128305619Y-103544715D01* 34 | X128400857Y-103592334D01* 35 | X128543714Y-103592334D01* 36 | X128638952Y-103544715D01* 37 | X128686571Y-103497096D01* 38 | X128734190Y-103401858D01* 39 | X128734190Y-103020905D01* 40 | X128210381Y-103925667D02* 41 | X128210381Y-104544715D01* 42 | X128591333Y-104211381D01* 43 | X128591333Y-104354239D01* 44 | X128638952Y-104449477D01* 45 | X128686571Y-104497096D01* 46 | X128781810Y-104544715D01* 47 | X129019905Y-104544715D01* 48 | X129115143Y-104497096D01* 49 | X129162762Y-104449477D01* 50 | X129210381Y-104354239D01* 51 | X129210381Y-104068524D01* 52 | X129162762Y-103973286D01* 53 | X129115143Y-103925667D01* 54 | M02* 55 | -------------------------------------------------------------------------------- /hardware/cameo_cape/gerber/cameo_cape-Bottom.gbr: -------------------------------------------------------------------------------- 1 | G04 #@! TF.FileFunction,Copper,L4,Bot,Signal* 2 | %FSLAX46Y46*% 3 | G04 Gerber Fmt 4.6, Leading zero omitted, Abs format (unit mm)* 4 | G04 Created by KiCad (PCBNEW 4.0.2+dfsg1-stable) date Thu 26 Jul 2018 23:23:47 BST* 5 | %MOMM*% 6 | G01* 7 | G04 APERTURE LIST* 8 | %ADD10C,0.100000*% 9 | %ADD11C,1.524000*% 10 | %ADD12R,1.524000X1.524000*% 11 | %ADD13R,1.727200X1.727200*% 12 | %ADD14O,1.727200X1.727200*% 13 | %ADD15C,0.800000*% 14 | %ADD16C,0.254000*% 15 | G04 APERTURE END LIST* 16 | D10* 17 | D11* 18 | X170091100Y-116433600D03* 19 | X170091100Y-118973600D03* 20 | X167551100Y-116433600D03* 21 | X167551100Y-118973600D03* 22 | X165011100Y-116433600D03* 23 | X165011100Y-118973600D03* 24 | X162471100Y-116433600D03* 25 | X162471100Y-118973600D03* 26 | X159931100Y-116433600D03* 27 | X159931100Y-118973600D03* 28 | X157391100Y-116433600D03* 29 | X157391100Y-118973600D03* 30 | X154851100Y-116433600D03* 31 | X154851100Y-118973600D03* 32 | X152311100Y-116433600D03* 33 | X152311100Y-118973600D03* 34 | X149771100Y-116433600D03* 35 | X149771100Y-118973600D03* 36 | X147231100Y-116433600D03* 37 | X147231100Y-118973600D03* 38 | X144691100Y-116433600D03* 39 | X144691100Y-118973600D03* 40 | X142151100Y-116433600D03* 41 | X142151100Y-118973600D03* 42 | X139611100Y-116433600D03* 43 | X139611100Y-118973600D03* 44 | X137071100Y-116433600D03* 45 | X137071100Y-118973600D03* 46 | X134531100Y-116433600D03* 47 | X134531100Y-118973600D03* 48 | X131991100Y-116433600D03* 49 | X131991100Y-118973600D03* 50 | X129451100Y-116433600D03* 51 | X129451100Y-118973600D03* 52 | X126911100Y-116433600D03* 53 | D12* 54 | X126911100Y-118973600D03* 55 | D11* 56 | X170091100Y-91033600D03* 57 | X170091100Y-93573600D03* 58 | X167551100Y-91033600D03* 59 | X167551100Y-93573600D03* 60 | X165011100Y-91033600D03* 61 | X165011100Y-93573600D03* 62 | X162471100Y-91033600D03* 63 | X162471100Y-93573600D03* 64 | X159931100Y-91033600D03* 65 | X159931100Y-93573600D03* 66 | X157391100Y-91033600D03* 67 | X157391100Y-93573600D03* 68 | X154851100Y-91033600D03* 69 | X154851100Y-93573600D03* 70 | X152311100Y-91033600D03* 71 | X152311100Y-93573600D03* 72 | X149771100Y-91033600D03* 73 | X149771100Y-93573600D03* 74 | X147231100Y-91033600D03* 75 | X147231100Y-93573600D03* 76 | X144691100Y-91033600D03* 77 | X144691100Y-93573600D03* 78 | X142151100Y-91033600D03* 79 | X142151100Y-93573600D03* 80 | X139611100Y-91033600D03* 81 | X139611100Y-93573600D03* 82 | X137071100Y-91033600D03* 83 | X137071100Y-93573600D03* 84 | X134531100Y-91033600D03* 85 | X134531100Y-93573600D03* 86 | X131991100Y-91033600D03* 87 | X131991100Y-93573600D03* 88 | X129451100Y-91033600D03* 89 | X129451100Y-93573600D03* 90 | X126911100Y-91033600D03* 91 | D12* 92 | X126911100Y-93573600D03* 93 | D13* 94 | X133858000Y-103759000D03* 95 | D14* 96 | X133858000Y-106299000D03* 97 | X136398000Y-103759000D03* 98 | X136398000Y-106299000D03* 99 | X138938000Y-103759000D03* 100 | X138938000Y-106299000D03* 101 | X141478000Y-103759000D03* 102 | X141478000Y-106299000D03* 103 | X144018000Y-103759000D03* 104 | X144018000Y-106299000D03* 105 | X146558000Y-103759000D03* 106 | X146558000Y-106299000D03* 107 | X149098000Y-103759000D03* 108 | X149098000Y-106299000D03* 109 | X151638000Y-103759000D03* 110 | X151638000Y-106299000D03* 111 | X154178000Y-103759000D03* 112 | X154178000Y-106299000D03* 113 | X156718000Y-103759000D03* 114 | X156718000Y-106299000D03* 115 | X159258000Y-103759000D03* 116 | X159258000Y-106299000D03* 117 | X161798000Y-103759000D03* 118 | X161798000Y-106299000D03* 119 | X164338000Y-103759000D03* 120 | X164338000Y-106299000D03* 121 | D15* 122 | X167259000Y-114808000D03* 123 | X131191000Y-113411000D03* 124 | X129032000Y-101600000D03* 125 | X166751000Y-109728000D03* 126 | X173863000Y-103886000D03* 127 | X170053000Y-101600000D03* 128 | X145923000Y-109728000D03* 129 | X140716000Y-109728000D03* 130 | X160655000Y-101600000D03* 131 | X151130000Y-109728000D03* 132 | X156337000Y-109728000D03* 133 | X161544000Y-109728000D03* 134 | X135382000Y-100330000D03* 135 | X123444000Y-100203000D03* 136 | X165862000Y-101600000D03* 137 | X155321000Y-101600000D03* 138 | X149987000Y-101600000D03* 139 | X144653000Y-101600000D03* 140 | X139446000Y-101600000D03* 141 | X123190000Y-115951000D03* 142 | X134239000Y-108458000D03* 143 | X167259000Y-112395000D03* 144 | X124587000Y-106807000D03* 145 | X168275000Y-106680000D03* 146 | X170561000Y-102616000D03* 147 | X172339000Y-95885000D03* 148 | X130048000Y-95885000D03* 149 | X164592000Y-95885000D03* 150 | X159385000Y-95885000D03* 151 | X154051000Y-95885000D03* 152 | X148717000Y-95885000D03* 153 | X143383000Y-95885000D03* 154 | X138176000Y-95885000D03* 155 | X132842000Y-95885000D03* 156 | X132969000Y-114173000D03* 157 | X138176000Y-114173000D03* 158 | X143383000Y-114173000D03* 159 | X148590000Y-114173000D03* 160 | X153797000Y-114173000D03* 161 | X159004000Y-114173000D03* 162 | X164211000Y-114173000D03* 163 | X124333000Y-112395000D03* 164 | X173863000Y-112268000D03* 165 | X131191000Y-110998000D03* 166 | X172212000Y-113665000D03* 167 | X170434000Y-108839000D03* 168 | X169545000Y-109474000D03* 169 | X173863000Y-109474000D03* 170 | X148590000Y-89535000D03* 171 | X131445000Y-96774000D03* 172 | X123063000Y-109474000D03* 173 | X169545000Y-113665000D03* 174 | X167259000Y-113665000D03* 175 | X128651000Y-112522000D03* 176 | X131572000Y-120523000D03* 177 | X169545000Y-112395000D03* 178 | X126619000Y-108966000D03* 179 | X171069000Y-113665000D03* 180 | X162433000Y-112395000D03* 181 | X128270000Y-108331000D03* 182 | X127762000Y-102235000D03* 183 | X131191000Y-99949000D03* 184 | X137795000Y-101600000D03* 185 | X125857000Y-98806000D03* 186 | X167640000Y-103886000D03* 187 | X143002000Y-101600000D03* 188 | X169418000Y-106680000D03* 189 | X148336000Y-101600000D03* 190 | X146558000Y-98806000D03* 191 | X153670000Y-101600000D03* 192 | X169926000Y-103886000D03* 193 | X151511000Y-98933000D03* 194 | X159004000Y-101600000D03* 195 | X171958000Y-107315000D03* 196 | X157734000Y-98171000D03* 197 | X172212000Y-101727000D03* 198 | X162941000Y-97409000D03* 199 | X164211000Y-101600000D03* 200 | X163068000Y-105029000D03* 201 | X158623000Y-108077000D03* 202 | X153416000Y-108458000D03* 203 | X123825000Y-108077000D03* 204 | X148209000Y-108458000D03* 205 | X126111000Y-106807000D03* 206 | X125095000Y-101981000D03* 207 | X143002000Y-108458000D03* 208 | X124714000Y-99822000D03* 209 | X130302000Y-102743000D03* 210 | D16* 211 | X137071100Y-93573600D02* 212 | X137071100Y-94703900D01* 213 | X122174000Y-110236000D02* 214 | X124333000Y-112395000D01* 215 | X122174000Y-99314000D02* 216 | X122174000Y-110236000D01* 217 | X123825000Y-97663000D02* 218 | X122174000Y-99314000D01* 219 | X128651000Y-97663000D02* 220 | X123825000Y-97663000D01* 221 | X129032000Y-98044000D02* 222 | X128651000Y-97663000D01* 223 | X133731000Y-98044000D02* 224 | X129032000Y-98044000D01* 225 | X137071100Y-94703900D02* 226 | X133731000Y-98044000D01* 227 | X147231100Y-91033600D02* 228 | X147231100Y-90589100D01* 229 | X173863000Y-112268000D02* 230 | X172593000Y-110998000D01* 231 | X172593000Y-110998000D02* 232 | X131191000Y-110998000D01* 233 | X168148000Y-89535000D02* 234 | X161417000Y-89535000D01* 235 | X161417000Y-89535000D02* 236 | X159931100Y-91033600D01* 237 | X168783000Y-90170000D02* 238 | X168148000Y-89535000D01* 239 | X173990000Y-95631000D02* 240 | X170688000Y-92329000D01* 241 | X170688000Y-92329000D02* 242 | X169545000Y-92329000D01* 243 | X169545000Y-92329000D02* 244 | X168783000Y-91567000D01* 245 | X168783000Y-91567000D02* 246 | X168783000Y-90170000D01* 247 | X174752000Y-103378000D02* 248 | X174752000Y-98806000D01* 249 | X173990000Y-113665000D02* 250 | X174752000Y-112903000D01* 251 | X174752000Y-112903000D02* 252 | X174752000Y-103378000D01* 253 | X172212000Y-113665000D02* 254 | X173990000Y-113665000D01* 255 | X174752000Y-98806000D02* 256 | X173990000Y-98044000D01* 257 | X173990000Y-98044000D02* 258 | X173990000Y-95631000D01* 259 | X170434000Y-108839000D02* 260 | X169672000Y-108077000D01* 261 | X163766500Y-92329000D02* 262 | X162471100Y-91033600D01* 263 | X165608000Y-92329000D02* 264 | X163766500Y-92329000D01* 265 | X166243000Y-92964000D02* 266 | X165608000Y-92329000D01* 267 | X166243000Y-94107000D02* 268 | X166243000Y-92964000D01* 269 | X167132000Y-94996000D02* 270 | X166243000Y-94107000D01* 271 | X167132000Y-102489000D02* 272 | X167132000Y-94996000D01* 273 | X166116000Y-103505000D02* 274 | X167132000Y-102489000D01* 275 | X166116000Y-107061000D02* 276 | X166116000Y-103505000D01* 277 | X167132000Y-108077000D02* 278 | X166116000Y-107061000D01* 279 | X169672000Y-108077000D02* 280 | X167132000Y-108077000D01* 281 | X131445000Y-95250000D02* 282 | X130683000Y-94488000D01* 283 | X130683000Y-94488000D02* 284 | X130683000Y-90424000D01* 285 | X131572000Y-89535000D02* 286 | X130683000Y-90424000D01* 287 | X131445000Y-95250000D02* 288 | X131445000Y-96774000D01* 289 | X131572000Y-89535000D02* 290 | X148590000Y-89535000D01* 291 | X131699000Y-96520000D02* 292 | X131445000Y-96774000D01* 293 | X169545000Y-113665000D02* 294 | X167259000Y-113665000D01* 295 | X128651000Y-112522000D02* 296 | X130683000Y-114554000D01* 297 | X130683000Y-114554000D02* 298 | X130683000Y-119634000D01* 299 | X130683000Y-119634000D02* 300 | X131572000Y-120523000D01* 301 | X161099500Y-112522000D02* 302 | X165011100Y-116433600D01* 303 | X130175000Y-112522000D02* 304 | X161099500Y-112522000D01* 305 | X126619000Y-108966000D02* 306 | X130175000Y-112522000D01* 307 | X171069000Y-113665000D02* 308 | X170053000Y-114681000D01* 309 | X170053000Y-114681000D02* 310 | X169418000Y-114681000D01* 311 | X169418000Y-114681000D02* 312 | X168783000Y-115316000D01* 313 | X168783000Y-115316000D02* 314 | X168783000Y-117094000D01* 315 | X168783000Y-117094000D02* 316 | X168148000Y-117729000D01* 317 | X168148000Y-117729000D02* 318 | X166255700Y-117729000D01* 319 | X166255700Y-117729000D02* 320 | X165011100Y-118973600D01* 321 | X161925000Y-111887000D02* 322 | X162433000Y-112395000D01* 323 | X130683000Y-111887000D02* 324 | X161925000Y-111887000D01* 325 | X130048000Y-111252000D02* 326 | X130683000Y-111887000D01* 327 | X130048000Y-110109000D02* 328 | X130048000Y-111252000D01* 329 | X128270000Y-108331000D02* 330 | X130048000Y-110109000D01* 331 | X127762000Y-102235000D02* 332 | X127762000Y-100330000D01* 333 | X127762000Y-100330000D02* 334 | X128143000Y-99949000D01* 335 | X128143000Y-99949000D02* 336 | X131191000Y-99949000D01* 337 | X148336000Y-100584000D02* 338 | X148336000Y-101600000D01* 339 | X146558000Y-98806000D02* 340 | X148336000Y-100584000D01* 341 | X153670000Y-101092000D02* 342 | X153670000Y-101600000D01* 343 | X151511000Y-98933000D02* 344 | X153670000Y-101092000D01* 345 | X159004000Y-101600000D02* 346 | X159004000Y-99441000D01* 347 | X159004000Y-99441000D02* 348 | X157734000Y-98171000D01* 349 | X164211000Y-101473000D02* 350 | X162941000Y-100203000D01* 351 | X162941000Y-100203000D02* 352 | X162941000Y-97409000D01* 353 | X163068000Y-105029000D02* 354 | X161036000Y-105029000D01* 355 | X161036000Y-105029000D02* 356 | X160528000Y-105537000D01* 357 | X160528000Y-105537000D02* 358 | X160528000Y-107569000D01* 359 | X160528000Y-107569000D02* 360 | X160020000Y-108077000D01* 361 | X160020000Y-108077000D02* 362 | X158623000Y-108077000D01* 363 | X125349000Y-101981000D02* 364 | X125095000Y-101981000D01* 365 | X127000000Y-103632000D02* 366 | X125349000Y-101981000D01* 367 | X130048000Y-103632000D02* 368 | X127000000Y-103632000D01* 369 | X131445000Y-105029000D02* 370 | X130048000Y-103632000D01* 371 | X142113000Y-105029000D02* 372 | X131445000Y-105029000D01* 373 | X142748000Y-105664000D02* 374 | X142113000Y-105029000D01* 375 | X142748000Y-108204000D02* 376 | X142748000Y-105664000D01* 377 | X143002000Y-108458000D02* 378 | X142748000Y-108204000D01* 379 | X125476000Y-99822000D02* 380 | X124714000Y-99822000D01* 381 | X126873000Y-101219000D02* 382 | X125476000Y-99822000D01* 383 | X126873000Y-102743000D02* 384 | X126873000Y-101219000D01* 385 | X127254000Y-103124000D02* 386 | X126873000Y-102743000D01* 387 | X128270000Y-103124000D02* 388 | X127254000Y-103124000D01* 389 | X128651000Y-102743000D02* 390 | X128270000Y-103124000D01* 391 | X130302000Y-102743000D02* 392 | X128651000Y-102743000D01* 393 | M02* 394 | -------------------------------------------------------------------------------- /hardware/cameo_cape/gerber/cameo_cape-Edge.Cuts.gbr: -------------------------------------------------------------------------------- 1 | G04 #@! TF.FileFunction,Profile,NP* 2 | %FSLAX46Y46*% 3 | G04 Gerber Fmt 4.6, Leading zero omitted, Abs format (unit mm)* 4 | G04 Created by KiCad (PCBNEW 4.0.2+dfsg1-stable) date Thu 26 Jul 2018 23:23:47 BST* 5 | %MOMM*% 6 | G01* 7 | G04 APERTURE LIST* 8 | %ADD10C,0.100000*% 9 | %ADD11C,0.150000*% 10 | G04 APERTURE END LIST* 11 | D10* 12 | D11* 13 | X131001100Y-122503600D02* 14 | X166001100Y-122503600D01* 15 | X166001100Y-87503600D02* 16 | X131001100Y-87503600D01* 17 | X121001100Y-97503600D02* 18 | G75* 19 | G02X131001100Y-87503600I10000000J0D01* 20 | G01* 21 | X121001100Y-97503600D02* 22 | X121001100Y-112503600D01* 23 | X131001100Y-122503600D02* 24 | G75* 25 | G02X121001100Y-112503600I0J10000000D01* 26 | G01* 27 | X176001100Y-112503600D02* 28 | G75* 29 | G02X166001100Y-122503600I-10000000J0D01* 30 | G01* 31 | X176001100Y-112503600D02* 32 | X176001100Y-97503600D01* 33 | X166001100Y-87503600D02* 34 | G75* 35 | G02X176001100Y-97503600I0J-10000000D01* 36 | G01* 37 | M02* 38 | -------------------------------------------------------------------------------- /hardware/cameo_cape/gerber/cameo_cape-F.Paste.gbr: -------------------------------------------------------------------------------- 1 | G04 #@! TF.FileFunction,Paste,Top* 2 | %FSLAX46Y46*% 3 | G04 Gerber Fmt 4.6, Leading zero omitted, Abs format (unit mm)* 4 | G04 Created by KiCad (PCBNEW 4.0.2+dfsg1-stable) date Thu 26 Jul 2018 23:23:47 BST* 5 | %MOMM*% 6 | G01* 7 | G04 APERTURE LIST* 8 | %ADD10C,0.100000*% 9 | %ADD11R,0.750000X1.200000*% 10 | %ADD12R,0.900000X1.200000*% 11 | %ADD13R,0.355600X1.676400*% 12 | G04 APERTURE END LIST* 13 | D10* 14 | D11* 15 | X123190000Y-112715000D03* 16 | X123190000Y-114615000D03* 17 | X123444000Y-103439000D03* 18 | X123444000Y-101539000D03* 19 | X168402000Y-112715000D03* 20 | X168402000Y-114615000D03* 21 | X168783000Y-103439000D03* 22 | X168783000Y-101539000D03* 23 | D12* 24 | X127127000Y-100287000D03* 25 | X127127000Y-98087000D03* 26 | X132461000Y-100287000D03* 27 | X132461000Y-98087000D03* 28 | X137795000Y-100287000D03* 29 | X137795000Y-98087000D03* 30 | X143002000Y-100287000D03* 31 | X143002000Y-98087000D03* 32 | X148336000Y-100287000D03* 33 | X148336000Y-98087000D03* 34 | X153670000Y-100287000D03* 35 | X153670000Y-98087000D03* 36 | X159004000Y-100287000D03* 37 | X159004000Y-98087000D03* 38 | X164211000Y-100287000D03* 39 | X164211000Y-98087000D03* 40 | X172720000Y-100287000D03* 41 | X172720000Y-98087000D03* 42 | X163830000Y-111971000D03* 43 | X163830000Y-109771000D03* 44 | X158623000Y-111971000D03* 45 | X158623000Y-109771000D03* 46 | X153416000Y-111971000D03* 47 | X153416000Y-109771000D03* 48 | X148209000Y-111971000D03* 49 | X148209000Y-109771000D03* 50 | X143002000Y-111971000D03* 51 | X143002000Y-109771000D03* 52 | X137795000Y-111971000D03* 53 | X137795000Y-109771000D03* 54 | X132588000Y-111971000D03* 55 | X132588000Y-109771000D03* 56 | X128778000Y-100287000D03* 57 | X128778000Y-98087000D03* 58 | X134112000Y-100287000D03* 59 | X134112000Y-98087000D03* 60 | X139446000Y-100287000D03* 61 | X139446000Y-98087000D03* 62 | X144653000Y-100287000D03* 63 | X144653000Y-98087000D03* 64 | X149987000Y-100287000D03* 65 | X149987000Y-98087000D03* 66 | X155321000Y-100287000D03* 67 | X155321000Y-98087000D03* 68 | X160655000Y-100287000D03* 69 | X160655000Y-98087000D03* 70 | X165862000Y-100287000D03* 71 | X165862000Y-98087000D03* 72 | X171069000Y-100287000D03* 73 | X171069000Y-98087000D03* 74 | X165481000Y-109771000D03* 75 | X165481000Y-111971000D03* 76 | X160274000Y-109771000D03* 77 | X160274000Y-111971000D03* 78 | X155067000Y-109771000D03* 79 | X155067000Y-111971000D03* 80 | X149860000Y-109771000D03* 81 | X149860000Y-111971000D03* 82 | X144653000Y-109771000D03* 83 | X144653000Y-111971000D03* 84 | X139446000Y-109771000D03* 85 | X139446000Y-111971000D03* 86 | X134239000Y-109771000D03* 87 | X134239000Y-111971000D03* 88 | X129921000Y-111168000D03* 89 | X129921000Y-113368000D03* 90 | X128778000Y-95928000D03* 91 | X128778000Y-98128000D03* 92 | X134112000Y-95928000D03* 93 | X134112000Y-98128000D03* 94 | X139446000Y-95928000D03* 95 | X139446000Y-98128000D03* 96 | X144653000Y-95928000D03* 97 | X144653000Y-98128000D03* 98 | X149987000Y-95928000D03* 99 | X149987000Y-98128000D03* 100 | X155321000Y-95928000D03* 101 | X155321000Y-98128000D03* 102 | X160655000Y-95928000D03* 103 | X160655000Y-98128000D03* 104 | X165862000Y-95928000D03* 105 | X165862000Y-98128000D03* 106 | X171069000Y-95928000D03* 107 | X171069000Y-98128000D03* 108 | X165481000Y-114130000D03* 109 | X165481000Y-111930000D03* 110 | X160274000Y-114130000D03* 111 | X160274000Y-111930000D03* 112 | X155067000Y-114130000D03* 113 | X155067000Y-111930000D03* 114 | X149860000Y-114130000D03* 115 | X149860000Y-111930000D03* 116 | X144653000Y-114130000D03* 117 | X144653000Y-111930000D03* 118 | X139446000Y-114130000D03* 119 | X139446000Y-111930000D03* 120 | X134239000Y-114130000D03* 121 | X134239000Y-111930000D03* 122 | D13* 123 | X122932000Y-110896400D03* 124 | X123582001Y-110896400D03* 125 | X124231999Y-110896400D03* 126 | X124882001Y-110896400D03* 127 | X125531999Y-110896400D03* 128 | X126181998Y-110896400D03* 129 | X126831999Y-110896400D03* 130 | X127481998Y-110896400D03* 131 | X128131999Y-110896400D03* 132 | X128781998Y-110896400D03* 133 | X128782000Y-105257600D03* 134 | X128132002Y-105257600D03* 135 | X127482001Y-105257600D03* 136 | X126832002Y-105257600D03* 137 | X126182001Y-105257600D03* 138 | X125532002Y-105257600D03* 139 | X124882001Y-105257600D03* 140 | X124232002Y-105257600D03* 141 | X123582001Y-105257600D03* 142 | X122932002Y-105257600D03* 143 | X167890000Y-110896400D03* 144 | X168540001Y-110896400D03* 145 | X169189999Y-110896400D03* 146 | X169840001Y-110896400D03* 147 | X170489999Y-110896400D03* 148 | X171139998Y-110896400D03* 149 | X171789999Y-110896400D03* 150 | X172439998Y-110896400D03* 151 | X173089999Y-110896400D03* 152 | X173739998Y-110896400D03* 153 | X173740000Y-105257600D03* 154 | X173090002Y-105257600D03* 155 | X172440001Y-105257600D03* 156 | X171790002Y-105257600D03* 157 | X171140001Y-105257600D03* 158 | X170490002Y-105257600D03* 159 | X169840001Y-105257600D03* 160 | X169190002Y-105257600D03* 161 | X168540001Y-105257600D03* 162 | X167890002Y-105257600D03* 163 | M02* 164 | -------------------------------------------------------------------------------- /hardware/cameo_cape/gerber/cameo_cape.drl: -------------------------------------------------------------------------------- 1 | M48 2 | ;DRILL file {KiCad 4.0.2+dfsg1-stable} date Thu 26 Jul 2018 23:23:59 BST 3 | ;FORMAT={-:-/ absolute / inch / decimal} 4 | FMAT,2 5 | INCH,TZ 6 | T1C0.016 7 | T2C0.035 8 | T3C0.040 9 | % 10 | G90 11 | G05 12 | M72 13 | T1 14 | X4.845Y-4.31 15 | X4.85Y-4.565 16 | X4.86Y-3.945 17 | X4.875Y-4.255 18 | X4.895Y-4.425 19 | X4.905Y-4.205 20 | X4.91Y-3.93 21 | X4.925Y-4.015 22 | X4.955Y-3.89 23 | X4.965Y-4.205 24 | X4.985Y-4.29 25 | X5.03Y-4.025 26 | X5.05Y-4.265 27 | X5.065Y-4.43 28 | X5.08Y-4. 29 | X5.12Y-3.775 30 | X5.13Y-4.045 31 | X5.165Y-3.935 32 | X5.165Y-4.37 33 | X5.165Y-4.465 34 | X5.175Y-3.81 35 | X5.18Y-4.745 36 | X5.23Y-3.775 37 | X5.235Y-4.495 38 | X5.285Y-4.27 39 | X5.33Y-3.95 40 | X5.425Y-4. 41 | X5.44Y-3.775 42 | X5.44Y-4.495 43 | X5.49Y-4. 44 | X5.54Y-4.32 45 | X5.63Y-4. 46 | X5.63Y-4.27 47 | X5.645Y-3.775 48 | X5.645Y-4.495 49 | X5.695Y-4. 50 | X5.745Y-4.32 51 | X5.77Y-3.89 52 | X5.835Y-4.27 53 | X5.84Y-4. 54 | X5.85Y-3.525 55 | X5.85Y-4.495 56 | X5.855Y-3.775 57 | X5.905Y-4. 58 | X5.95Y-4.32 59 | X5.965Y-3.895 60 | X6.04Y-4.27 61 | X6.05Y-4. 62 | X6.055Y-4.495 63 | X6.065Y-3.775 64 | X6.115Y-4. 65 | X6.155Y-4.32 66 | X6.21Y-3.865 67 | X6.245Y-4.255 68 | X6.26Y-4. 69 | X6.26Y-4.495 70 | X6.275Y-3.775 71 | X6.325Y-4. 72 | X6.36Y-4.32 73 | X6.395Y-4.425 74 | X6.415Y-3.835 75 | X6.42Y-4.135 76 | X6.465Y-4. 77 | X6.465Y-4.495 78 | X6.48Y-3.775 79 | X6.53Y-4. 80 | X6.565Y-4.32 81 | X6.585Y-4.425 82 | X6.585Y-4.475 83 | X6.585Y-4.52 84 | X6.6Y-4.09 85 | X6.625Y-4.2 86 | X6.67Y-4.2 87 | X6.675Y-4.31 88 | X6.675Y-4.425 89 | X6.675Y-4.475 90 | X6.69Y-4.09 91 | X6.695Y-4. 92 | X6.71Y-4.285 93 | X6.715Y-4.04 94 | X6.735Y-4.475 95 | X6.77Y-4.225 96 | X6.78Y-4.005 97 | X6.78Y-4.475 98 | X6.785Y-3.775 99 | X6.845Y-4.09 100 | X6.845Y-4.31 101 | X6.845Y-4.42 102 | T2 103 | X4.9965Y-3.584 104 | X4.9965Y-3.684 105 | X4.9965Y-4.584 106 | X4.9965Y-4.684 107 | X5.0965Y-3.584 108 | X5.0965Y-3.684 109 | X5.0965Y-4.584 110 | X5.0965Y-4.684 111 | X5.1965Y-3.584 112 | X5.1965Y-3.684 113 | X5.1965Y-4.584 114 | X5.1965Y-4.684 115 | X5.2965Y-3.584 116 | X5.2965Y-3.684 117 | X5.2965Y-4.584 118 | X5.2965Y-4.684 119 | X5.3965Y-3.584 120 | X5.3965Y-3.684 121 | X5.3965Y-4.584 122 | X5.3965Y-4.684 123 | X5.4965Y-3.584 124 | X5.4965Y-3.684 125 | X5.4965Y-4.584 126 | X5.4965Y-4.684 127 | X5.5965Y-3.584 128 | X5.5965Y-3.684 129 | X5.5965Y-4.584 130 | X5.5965Y-4.684 131 | X5.6965Y-3.584 132 | X5.6965Y-3.684 133 | X5.6965Y-4.584 134 | X5.6965Y-4.684 135 | X5.7965Y-3.584 136 | X5.7965Y-3.684 137 | X5.7965Y-4.584 138 | X5.7965Y-4.684 139 | X5.8965Y-3.584 140 | X5.8965Y-3.684 141 | X5.8965Y-4.584 142 | X5.8965Y-4.684 143 | X5.9965Y-3.584 144 | X5.9965Y-3.684 145 | X5.9965Y-4.584 146 | X5.9965Y-4.684 147 | X6.0965Y-3.584 148 | X6.0965Y-3.684 149 | X6.0965Y-4.584 150 | X6.0965Y-4.684 151 | X6.1965Y-3.584 152 | X6.1965Y-3.684 153 | X6.1965Y-4.584 154 | X6.1965Y-4.684 155 | X6.2965Y-3.584 156 | X6.2965Y-3.684 157 | X6.2965Y-4.584 158 | X6.2965Y-4.684 159 | X6.3965Y-3.584 160 | X6.3965Y-3.684 161 | X6.3965Y-4.584 162 | X6.3965Y-4.684 163 | X6.4965Y-3.584 164 | X6.4965Y-3.684 165 | X6.4965Y-4.584 166 | X6.4965Y-4.684 167 | X6.5965Y-3.584 168 | X6.5965Y-3.684 169 | X6.5965Y-4.584 170 | X6.5965Y-4.684 171 | X6.6965Y-3.584 172 | X6.6965Y-3.684 173 | X6.6965Y-4.584 174 | X6.6965Y-4.684 175 | T3 176 | X5.27Y-4.085 177 | X5.27Y-4.185 178 | X5.37Y-4.085 179 | X5.37Y-4.185 180 | X5.47Y-4.085 181 | X5.47Y-4.185 182 | X5.57Y-4.085 183 | X5.57Y-4.185 184 | X5.67Y-4.085 185 | X5.67Y-4.185 186 | X5.77Y-4.085 187 | X5.77Y-4.185 188 | X5.87Y-4.085 189 | X5.87Y-4.185 190 | X5.97Y-4.085 191 | X5.97Y-4.185 192 | X6.07Y-4.085 193 | X6.07Y-4.185 194 | X6.17Y-4.085 195 | X6.17Y-4.185 196 | X6.27Y-4.085 197 | X6.27Y-4.185 198 | X6.37Y-4.085 199 | X6.37Y-4.185 200 | X6.47Y-4.085 201 | X6.47Y-4.185 202 | T0 203 | M30 204 | -------------------------------------------------------------------------------- /hardware/cameo_cape/pdfs/layers/cameo_cape-B.Paste.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stepleton/cameo/ca64ef0f286fabcdfb018684bf078709f3188b11/hardware/cameo_cape/pdfs/layers/cameo_cape-B.Paste.pdf -------------------------------------------------------------------------------- /hardware/cameo_cape/pdfs/layers/cameo_cape-B.SilkS.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stepleton/cameo/ca64ef0f286fabcdfb018684bf078709f3188b11/hardware/cameo_cape/pdfs/layers/cameo_cape-B.SilkS.pdf -------------------------------------------------------------------------------- /hardware/cameo_cape/pdfs/layers/cameo_cape-Bottom.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stepleton/cameo/ca64ef0f286fabcdfb018684bf078709f3188b11/hardware/cameo_cape/pdfs/layers/cameo_cape-Bottom.pdf -------------------------------------------------------------------------------- /hardware/cameo_cape/pdfs/layers/cameo_cape-DigitalGND.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stepleton/cameo/ca64ef0f286fabcdfb018684bf078709f3188b11/hardware/cameo_cape/pdfs/layers/cameo_cape-DigitalGND.pdf -------------------------------------------------------------------------------- /hardware/cameo_cape/pdfs/layers/cameo_cape-Edge.Cuts.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stepleton/cameo/ca64ef0f286fabcdfb018684bf078709f3188b11/hardware/cameo_cape/pdfs/layers/cameo_cape-Edge.Cuts.pdf -------------------------------------------------------------------------------- /hardware/cameo_cape/pdfs/layers/cameo_cape-F.Paste.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stepleton/cameo/ca64ef0f286fabcdfb018684bf078709f3188b11/hardware/cameo_cape/pdfs/layers/cameo_cape-F.Paste.pdf -------------------------------------------------------------------------------- /hardware/cameo_cape/pdfs/layers/cameo_cape-F.SilkS.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stepleton/cameo/ca64ef0f286fabcdfb018684bf078709f3188b11/hardware/cameo_cape/pdfs/layers/cameo_cape-F.SilkS.pdf -------------------------------------------------------------------------------- /hardware/cameo_cape/pdfs/layers/cameo_cape-Top.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stepleton/cameo/ca64ef0f286fabcdfb018684bf078709f3188b11/hardware/cameo_cape/pdfs/layers/cameo_cape-Top.pdf -------------------------------------------------------------------------------- /hardware/cameo_cape/pdfs/layers/cameo_cape-VDD.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stepleton/cameo/ca64ef0f286fabcdfb018684bf078709f3188b11/hardware/cameo_cape/pdfs/layers/cameo_cape-VDD.pdf -------------------------------------------------------------------------------- /hardware/cameo_cape/pdfs/schematic/cameo_cape.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stepleton/cameo/ca64ef0f286fabcdfb018684bf078709f3188b11/hardware/cameo_cape/pdfs/schematic/cameo_cape.pdf -------------------------------------------------------------------------------- /pics/cameo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stepleton/cameo/ca64ef0f286fabcdfb018684bf078709f3188b11/pics/cameo.jpg -------------------------------------------------------------------------------- /pics/installed.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stepleton/cameo/ca64ef0f286fabcdfb018684bf078709f3188b11/pics/installed.jpg -------------------------------------------------------------------------------- /pics/plugboard.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stepleton/cameo/ca64ef0f286fabcdfb018684bf078709f3188b11/pics/plugboard.jpg -------------------------------------------------------------------------------- /pics/plugboard_map.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stepleton/cameo/ca64ef0f286fabcdfb018684bf078709f3188b11/pics/plugboard_map.png -------------------------------------------------------------------------------- /pics/plugboard_pads.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stepleton/cameo/ca64ef0f286fabcdfb018684bf078709f3188b11/pics/plugboard_pads.jpg -------------------------------------------------------------------------------- /pics/smd_layout.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stepleton/cameo/ca64ef0f286fabcdfb018684bf078709f3188b11/pics/smd_layout.png -------------------------------------------------------------------------------- /pics/thumb_aphid.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stepleton/cameo/ca64ef0f286fabcdfb018684bf078709f3188b11/pics/thumb_aphid.jpg --------------------------------------------------------------------------------