Add files
|
@ -0,0 +1 @@
|
||||||
|
.wav
|
|
@ -0,0 +1,3 @@
|
||||||
|
[submodule "openscad/scad-utils"]
|
||||||
|
path = openscad/scad-utils
|
||||||
|
url = https://github.com/OskarLinde/scad-utils
|
99
README.md
|
@ -0,0 +1,99 @@
|
||||||
|
<p align="center">
|
||||||
|
<img align="center" width="300px" height="auto" src="./images/mm2_sd.gif">
|
||||||
|
</p>
|
||||||
|
|
||||||
|
# Mac(intosh) mini
|
||||||
|
|
||||||
|
## Build Instruction
|
||||||
|
- Print the outer shell.
|
||||||
|
- PLA, 0.2 mm, 180 ℃ (See also [./openscad/README.md](./openscad/README.md))
|
||||||
|
- `macintosh-mini-part-a.stl` ([stl](./openscad/macintosh-mini-part-a.stl))
|
||||||
|
- `macintosh-mini-part-b.stl` ([stl](./openscad/macintosh-mini-part-b.stl))
|
||||||
|
|
||||||
|
<img align="center" width="60%" height="auto" src="./openscad/images/models.png">
|
||||||
|
|
||||||
|
- Setup your Orange Pi Zero Plus 2 (H3)
|
||||||
|
- Install Armbian Bionic. https://www.armbian.com/orange-pi-zero-plus-2-h3/
|
||||||
|
- Then SSH into the device.
|
||||||
|
```bash
|
||||||
|
$ sudo apt install -y git xtightvncserver
|
||||||
|
|
||||||
|
# Install Node.js
|
||||||
|
$ git clone https://github.com/tj/n /tmp/n && cd /tmp/n && sudo make install
|
||||||
|
$ sudo n v10
|
||||||
|
|
||||||
|
# Install https://github.com/xpertsavenue/WiringOP-Zero
|
||||||
|
$ git clone https://github.com/xpertsavenue/WiringOP-Zero
|
||||||
|
## Please refer to https://github.com/xpertsavenue/WiringOP-Zero
|
||||||
|
|
||||||
|
# Setup vncserver
|
||||||
|
$ mkdir .vnc
|
||||||
|
$ vncpasswd .vnc/passwd
|
||||||
|
|
||||||
|
# Install the dependencies & config files
|
||||||
|
$ git clone https://github.com/likeablob/macmini ~/macmini
|
||||||
|
$ cd ~/macmini
|
||||||
|
$ sudo ./install.sh
|
||||||
|
|
||||||
|
# copy ypur assests
|
||||||
|
$ cp /path/to/vmac.rom ~/macmini/minivmac/vmac.rom # Mini vMac ROM file
|
||||||
|
$ cp /path/to/vmac.dsk ~/macmini/minivmac/system.dsk # Mini vMac disk file
|
||||||
|
$ cp /path/to/.basilisk_ii_prefs ~/.basilisk_ii_prefs # Basilisk II config file
|
||||||
|
$ cp /path/to/macboot.wav ~/macmini/macboot.wav # Boot sound (optional)
|
||||||
|
```
|
||||||
|
- [Tips]: Here is my working [.basilisk_ii_prefs](basilisk_ii_prefs.md).
|
||||||
|
|
||||||
|
- Wire the display & USB boards to the OPi
|
||||||
|
|
||||||
|
<img align="center" width="auto" height="400px" src="./images/mm_s_8.jpg">
|
||||||
|
|
||||||
|
| OPi | Peripherals |
|
||||||
|
| -------------- | -------------------- |
|
||||||
|
| PA15/SPI1_MOSI | LCD MOSI |
|
||||||
|
| PA16/SPI1_MISO | LCD MISO |
|
||||||
|
| PA14/SPI1_CLK | LCD CLK |
|
||||||
|
| PA13/SPI1_CS | LCD CS |
|
||||||
|
| PS12 | LCD RESET |
|
||||||
|
| PA11 | LCD DC |
|
||||||
|
| PA06 | Push Switch |
|
||||||
|
| USB-DP2 | USB (Front) Data+ |
|
||||||
|
| USB-DM2 | USB (Front) Data- |
|
||||||
|
| 5V | USB (Front/Rear) 5V |
|
||||||
|
| GND | USB (Front/Rear) GND |
|
||||||
|
|
||||||
|
## Basic Concepts
|
||||||
|
1. At system boot, [`fbtft_device`](./config/fbtft.conf) kernel module is loaded and it initializes the LCD as `/dev/fb0`.
|
||||||
|
2. `nodm` starts an X session and `~/.xinitrc` get executed.
|
||||||
|
3. `~/.xinitrc` launchs `matchbox-window-manager` and `~/macmini/switcher/*js`.
|
||||||
|
4. `~/macmini/switcher/index.js` reads the scripts [`~/macmini/switcher/sh.d/*sh`](./switcher/sh.d/) and spawns them one by one when there is a HTTP GET request at `localhost:5501/`.
|
||||||
|
5. `~/macmini/switcher/gpio-reader.js` watchs the push SW at GPIO7(PA06) and send a request to `localhost:5501/`.
|
||||||
|
|
||||||
|
### How does the low-res LCD(320x240) handle 512x384 resolution?
|
||||||
|
Internally `xthighvncserver` and `ssvncviewer` are used to scale the display.
|
||||||
|
- e.g. [`1_large_minimac.sh`]((./switcher/sh.d/1_large_minimac.sh)) launches:
|
||||||
|
- `xthighvncserver` to create a virtual display (512x384) at `DISPLAY=:1` (`:5901`)
|
||||||
|
- `minivmac` in `DISPLAY:1`
|
||||||
|
- `ssvncviewer -scale 0.625` in `DISPLAY:0` (By the `-scale` option, low-res LED get upscaled)
|
||||||
|
## Gallery
|
||||||
|
| <img align="center" width="auto" height="200px" src="./images/mm_s_5.jpg"> | <img align="center" width="auto" height="200px" src="./images/mm_s_7.jpg"> |
|
||||||
|
| :-------------------------------------------------------------------------: | :-------------------------------------------------------------------------: |
|
||||||
|
| <img align="center" width="auto" height="200px" src="./images/mm_s_20.jpg"> | <img align="center" width="auto" height="200px" src="./images/mm_s_14.jpg"> |
|
||||||
|
| <img align="center" width="auto" height="200px" src="./images/mm_s_10.jpg"> | <img align="center" width="auto" height="200px" src="./images/mm_s_23.jpg"> |
|
||||||
|
| <img align="center" width="auto" height="200px" src="./images/mm_s_9.jpg"> | <img align="center" width="auto" height="200px" src="./images/mm3_sd.gif"> |
|
||||||
|
|
||||||
|
|
||||||
|
## BOM
|
||||||
|
| Name | Quantity | Descriptions |
|
||||||
|
| ------------------------------------------------------- | :------: | ----------------------- |
|
||||||
|
| OrangePi Zero Plus 2 (H3) | 1 | H5 ver. might work too. |
|
||||||
|
| 2.4inch SPI Display (ili9340, 320x240, with flat cable) | 1 | |
|
||||||
|
| Generic micro-USB Breakout Board | 2 | |
|
||||||
|
| M2 x 6 mm Self Tapping Screw | 16 | |
|
||||||
|
| D10mm Rounding Magnet | 2 | |
|
||||||
|
| 7x7 mm Push Switch | 1 | |
|
||||||
|
|
||||||
|
## Acknowledgment
|
||||||
|
- Mini vMac https://www.gryphel.com/c/minivmac/
|
||||||
|
- Basilisk II https://basilisk.cebix.net/
|
||||||
|
- Kudos to all the devs!s
|
||||||
|
|
|
@ -0,0 +1,37 @@
|
||||||
|
~/.basilisk_ii_prefs
|
||||||
|
```bash
|
||||||
|
disk ${/path/to/disk1.dsk}
|
||||||
|
disk ${/path/to/disk2.dsk}
|
||||||
|
extfs ${/path/to/your/home/dir}
|
||||||
|
screen win/512/384
|
||||||
|
seriala /dev/ttyS5
|
||||||
|
serialb /dev/ttyS6
|
||||||
|
ether slirp
|
||||||
|
udptunnel false
|
||||||
|
udpport 6066
|
||||||
|
rom ${/path/to/mac.rom}
|
||||||
|
bootdrive 0
|
||||||
|
bootdriver 0
|
||||||
|
ramsize 33554432
|
||||||
|
frameskip 0
|
||||||
|
modelid 5
|
||||||
|
cpu 3
|
||||||
|
fpu false
|
||||||
|
nocdrom true
|
||||||
|
nosound false
|
||||||
|
noclipconversion false
|
||||||
|
nogui false
|
||||||
|
jit true
|
||||||
|
jitfpu true
|
||||||
|
jitdebug false
|
||||||
|
jitcachesize 2048
|
||||||
|
jitlazyflush true
|
||||||
|
jitinline true
|
||||||
|
keyboardtype 5
|
||||||
|
keycodes false
|
||||||
|
mousewheelmode 1
|
||||||
|
mousewheellines 3
|
||||||
|
dsp /dev/dsp
|
||||||
|
mixer /dev/mixer
|
||||||
|
idlewait true
|
||||||
|
```
|
|
@ -0,0 +1,12 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
MACMINI_DIR=~/macmini
|
||||||
|
xloadimage ${MACMINI_DIR}/images/macface.png -fullscreen -onroot
|
||||||
|
[ -e ${MACMINI_DIR}/macboot.wav ] && mplayer -af volume=10 ${MACMINI_DIR}/macboot.wav &
|
||||||
|
|
||||||
|
if [[ $DISPLAY == :0 ]];then
|
||||||
|
(cd ${MACMINI_DIR}/switcher && padsp npm start)&
|
||||||
|
(cd ${MACMINI_DIR}/switcher && gpio mode 7 up && npm run start:gpio)&
|
||||||
|
fi
|
||||||
|
|
||||||
|
matchbox-window-manager -use_titlebar no
|
|
@ -0,0 +1,6 @@
|
||||||
|
Section "Device"
|
||||||
|
Identifier "myfb"
|
||||||
|
Driver "fbdev"
|
||||||
|
Option "fbdev" "/dev/fb0"
|
||||||
|
EndSection
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
pcm.!default {
|
||||||
|
type hw
|
||||||
|
card 0
|
||||||
|
}
|
||||||
|
|
||||||
|
ctl.!default {
|
||||||
|
type hw
|
||||||
|
card 0
|
||||||
|
}
|
|
@ -0,0 +1 @@
|
||||||
|
options fbtft_device custom name=fb_ili9340 gpios=dc:11,reset:12 speed=64000000 busnum=1 rotate=270 bgr=1
|
|
@ -0,0 +1,14 @@
|
||||||
|
#!/bin/sh -e
|
||||||
|
#
|
||||||
|
# rc.local
|
||||||
|
#
|
||||||
|
# This script is executed at the end of each multiuser runlevel.
|
||||||
|
# Make sure that the script will "exit 0" on success or any other
|
||||||
|
# value on error.
|
||||||
|
#
|
||||||
|
# In order to enable or disable this script just change the execution
|
||||||
|
# bits.
|
||||||
|
#
|
||||||
|
# By default this script does nothing.
|
||||||
|
|
||||||
|
echo none | tee /sys/class/leds/orangepi\:red\:status/trigger # disable LED
|
|
@ -0,0 +1,5 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
# Fix to make GNOME work
|
||||||
|
export XKL_XMODMAP_DISABLE=1
|
||||||
|
/etc/X11/Xsession
|
After Width: | Height: | Size: 2.3 KiB |
After Width: | Height: | Size: 3.9 MiB |
After Width: | Height: | Size: 3.7 MiB |
After Width: | Height: | Size: 3.9 MiB |
After Width: | Height: | Size: 652 KiB |
After Width: | Height: | Size: 720 KiB |
After Width: | Height: | Size: 709 KiB |
After Width: | Height: | Size: 612 KiB |
After Width: | Height: | Size: 669 KiB |
After Width: | Height: | Size: 654 KiB |
After Width: | Height: | Size: 671 KiB |
After Width: | Height: | Size: 684 KiB |
After Width: | Height: | Size: 623 KiB |
|
@ -0,0 +1,32 @@
|
||||||
|
#! /bin/bash
|
||||||
|
|
||||||
|
[ $(id -u) -gt 0 ] && echo Please run as root! && exit 1
|
||||||
|
|
||||||
|
set +x
|
||||||
|
|
||||||
|
apt install -y -q \
|
||||||
|
bluez \
|
||||||
|
tightvncserver \
|
||||||
|
ssvnc \
|
||||||
|
mplayer \
|
||||||
|
chromium-browser \
|
||||||
|
basilisk2 \
|
||||||
|
matchbox-window-manager \
|
||||||
|
nodm \
|
||||||
|
xserver-xorg-input-libinput \
|
||||||
|
xloadimage \
|
||||||
|
pulseaudio \
|
||||||
|
pulseaudio-esound-compat \
|
||||||
|
pulseaudio-utils \
|
||||||
|
pavucontrol
|
||||||
|
|
||||||
|
cp -a config/.xinitrc ~/.xinitrc
|
||||||
|
cp -a config/xstartup ~/.vnc/
|
||||||
|
cp config/99-fbdev.conf /etc/X11/xorg.conf.d/
|
||||||
|
cp config/fbtft.conf /etc/modprobe.d/
|
||||||
|
cp config/asound.conf /etc/
|
||||||
|
cp config/rc.local /etc/
|
||||||
|
|
||||||
|
cd switcher && npm install
|
||||||
|
|
||||||
|
echo Done!
|
|
@ -0,0 +1,7 @@
|
||||||
|
*.dsk
|
||||||
|
*.DSK
|
||||||
|
*.zip
|
||||||
|
*.ZIP
|
||||||
|
*.rom
|
||||||
|
*.ROM
|
||||||
|
|
|
@ -0,0 +1,31 @@
|
||||||
|
OPENSCAD := openscad-nightly
|
||||||
|
MONTAGE := montage
|
||||||
|
targets := $(wildcard macintosh-mini-part*.scad)
|
||||||
|
stls := $(targets:.scad=.stl)
|
||||||
|
image_dir := images
|
||||||
|
thumbnails := $(targets:%.scad=${image_dir}/%_s.png)
|
||||||
|
img_models := ${image_dir}/models.png
|
||||||
|
|
||||||
|
.PHONY: all clean images
|
||||||
|
all: ${stls}
|
||||||
|
@echo done
|
||||||
|
|
||||||
|
${stls}: %.stl: %.scad
|
||||||
|
@echo Building $@ from $<
|
||||||
|
${OPENSCAD} -o $@ $<
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f ${stls}
|
||||||
|
|
||||||
|
images: $(thumbnails) ${img_models}
|
||||||
|
@echo done
|
||||||
|
|
||||||
|
$(thumbnails): ${image_dir}/%_s.png: %.scad
|
||||||
|
@echo Generating $@ from $<
|
||||||
|
${OPENSCAD} -o $@ \
|
||||||
|
--imgsize=640,480 --colorscheme=Tomorrow \
|
||||||
|
--projection o --camera -200,-200,280,0,0,40 $<
|
||||||
|
|
||||||
|
${img_models}: ${thumbnails}
|
||||||
|
@echo Generating $@ from $^
|
||||||
|
${MONTAGE} -label '%t' -geometry 320x240 $(sort $^) $@
|
|
@ -0,0 +1,21 @@
|
||||||
|
<p align="center">
|
||||||
|
<img align="center" width="80%" height="auto" src="./images/main.png">
|
||||||
|
</p>
|
||||||
|
|
||||||
|
## Print conditions
|
||||||
|
- PLA, 0.2 mm, 180 ℃
|
||||||
|
- `macintosh-mini-part-a`: Rotate so that the -X(front) side is facing down.
|
||||||
|
|
||||||
|
<img align="center" width="80%" height="auto" src="./images/models.png">
|
||||||
|
|
||||||
|
|
||||||
|
## Dependencies
|
||||||
|
- [OskarLinde]'s [scad-utils](https://github.com/OskarLinde/scad-utils)
|
||||||
|
- openscad-nightly (`20181009T230242.gitf3de0e27+2416.1`)
|
||||||
|
|
||||||
|
## Build
|
||||||
|
```sh
|
||||||
|
$ git submodule update --init --recursive # or git clone --recursive
|
||||||
|
$ make -j4
|
||||||
|
```
|
||||||
|
|
After Width: | Height: | Size: 14 KiB |
After Width: | Height: | Size: 16 KiB |
After Width: | Height: | Size: 14 KiB |
After Width: | Height: | Size: 127 KiB |
|
@ -0,0 +1,717 @@
|
||||||
|
$fn=40;
|
||||||
|
include <mylib.scad>
|
||||||
|
include <scad-utils/morphology.scad>
|
||||||
|
|
||||||
|
WH_RATIO = 22.7/29.2;
|
||||||
|
DH_RATIO = 46.0/63.4;
|
||||||
|
|
||||||
|
BODY_Z = 90;
|
||||||
|
BODY_X = BODY_Z * WH_RATIO;
|
||||||
|
BODY_Y = BODY_Z * DH_RATIO;
|
||||||
|
|
||||||
|
module copy_mirror(vec=[0,1,0]){
|
||||||
|
children();
|
||||||
|
mirror(vec) children();
|
||||||
|
}
|
||||||
|
|
||||||
|
module base(mscale=1) {
|
||||||
|
difference() {
|
||||||
|
hull() {
|
||||||
|
// upper
|
||||||
|
translate([0, 0, (BODY_X)/2 + (BODY_Z-BODY_X)/2])
|
||||||
|
rotate([0, 5, 0])
|
||||||
|
cube(size=[BODY_X, BODY_Y, BODY_X], center=true);
|
||||||
|
|
||||||
|
// lower
|
||||||
|
translate([0, 0, (BODY_Z-BODY_X)/2])
|
||||||
|
cube(size=[BODY_X, BODY_Y, BODY_Z-BODY_X], center=true);
|
||||||
|
|
||||||
|
// display
|
||||||
|
rotate([0, 5, 0])
|
||||||
|
translate([-BODY_X/2-6, 0, (BODY_Z-BODY_X)/2-1])
|
||||||
|
translate([0, 0, BODY_X/2])
|
||||||
|
cube(size=[0.1, BODY_Y*0.97, BODY_X*0.93], center=true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// under the display
|
||||||
|
minkowski() {
|
||||||
|
UD_Z = (BODY_Z-BODY_X)/2*0.6;
|
||||||
|
translate([-BODY_Y/2-10/2, 0, UD_Z-1.5])
|
||||||
|
hull() {
|
||||||
|
rotate([0, 5, 0])
|
||||||
|
cube(size=[BODY_Y*0.2+10, BODY_Y+1, UD_Z*2], center=true);
|
||||||
|
|
||||||
|
/* translate([BODY_Y*0.2/2+8, 0, -UD_Z])
|
||||||
|
rotate([90, 0, 0])
|
||||||
|
cylinder(d=0.01, h=BODY_Y+1, center=true); */
|
||||||
|
translate([BODY_Y*0.2/2+1, 0, -UD_Z])
|
||||||
|
rotate([90, 0, 0])
|
||||||
|
cylinder(d=0.01, h=BODY_Y+1, center=true);
|
||||||
|
}
|
||||||
|
|
||||||
|
rotate([90, 0, 0])
|
||||||
|
cylinder(d=1, h=10, center=true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// top mizo
|
||||||
|
translate([BODY_X*0.4, 0, BODY_Z-BODY_Z*0.27])
|
||||||
|
rotate([0, 5, 0])
|
||||||
|
scale([mscale, mscale, mscale])
|
||||||
|
linear_extrude(height=BODY_Z*0.3, scale=1.1, center=false, convexity=10, twist=0)
|
||||||
|
square(size=[BODY_X, BODY_Y/2], center=true);
|
||||||
|
|
||||||
|
// back edge
|
||||||
|
translate([BODY_Y, 0, BODY_X/2 + BODY_Z*0.5])
|
||||||
|
rotate([0, 60, 0])
|
||||||
|
cube(size=[BODY_X, BODY_Y+3, BODY_X], center=true);
|
||||||
|
|
||||||
|
// back
|
||||||
|
translate([BODY_X/2+BODY_X*0.1/2-1, 0, (BODY_Z)/2])
|
||||||
|
cube(size=[BODY_X*0.1, BODY_Y*1.2, BODY_Z], center=true);
|
||||||
|
|
||||||
|
// side edge
|
||||||
|
*copy_mirror([0,1,0])
|
||||||
|
translate([-BODY_X/2, BODY_Y/2, 0])
|
||||||
|
translate([0, 0, BODY_Z/2*1.1])
|
||||||
|
rotate([0, 5, 0])
|
||||||
|
rotate([0, 0, 60])
|
||||||
|
cube(size=[5, 5, BODY_Z], center=true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
THICK=-5;
|
||||||
|
|
||||||
|
// variables for partB
|
||||||
|
OPIZ_X = 48;
|
||||||
|
OPIZ_Y = 46;
|
||||||
|
OPIZ_Z = 10;
|
||||||
|
|
||||||
|
OPI_HOLE_POS = 2.8;
|
||||||
|
|
||||||
|
HDMI_Z=5.5;
|
||||||
|
HDMI_Y=15;
|
||||||
|
|
||||||
|
OPIZ_HLD_Z = BODY_Z*0.6;
|
||||||
|
OPIZ_HLD_Y = 5;
|
||||||
|
OPIZ_HLD_X = 10;
|
||||||
|
|
||||||
|
OPIZ_OFFSET_Z = 6;
|
||||||
|
OPIZ_OFFSET_X = -1.5;
|
||||||
|
|
||||||
|
BACKPANEL_X = 1.0;
|
||||||
|
|
||||||
|
module partB() {
|
||||||
|
difference() {
|
||||||
|
union() {
|
||||||
|
difference() {
|
||||||
|
intersection(){
|
||||||
|
difference(){
|
||||||
|
minkowski() {
|
||||||
|
base();
|
||||||
|
rotate([0, 90, 0])
|
||||||
|
cylinder(d=5, h=0.01, center=true);
|
||||||
|
}
|
||||||
|
// inner space
|
||||||
|
difference() {
|
||||||
|
translate([-0.5, 0, 0])
|
||||||
|
scale([0.95, 1, 1])
|
||||||
|
resize([BODY_X-THICK, 0, 0], auto=[false, true, true])
|
||||||
|
base(1.15);
|
||||||
|
|
||||||
|
translate([BODY_X/2+10/2-3, 0, 0])
|
||||||
|
cube(size=[10, BODY_Y*2, BODY_Z*2], center=true);
|
||||||
|
}
|
||||||
|
|
||||||
|
copy_mirror([0,1,0])
|
||||||
|
translate([BODY_X/2-10, BODY_Y*0.91/2, BODY_Z*0.68])
|
||||||
|
rotate([0, 90, 0]){
|
||||||
|
screw(2);
|
||||||
|
translate([0, 0, 8.5])
|
||||||
|
screw(4);
|
||||||
|
}
|
||||||
|
|
||||||
|
copy_mirror([0,1,0])
|
||||||
|
translate([BODY_X/2-10, BODY_Y*0.91/2, BODY_Z*0.1])
|
||||||
|
rotate([0, 90, 0]){
|
||||||
|
screw(2);
|
||||||
|
translate([0, 0, 8.5])
|
||||||
|
screw(4);
|
||||||
|
}
|
||||||
|
|
||||||
|
copy_mirror([0,1,0])
|
||||||
|
translate([-BODY_X*0.2, BODY_Y*0.91/2, BODY_Z*0.1/3])
|
||||||
|
union(){
|
||||||
|
screwB(3);
|
||||||
|
translate([0, 0, -15])
|
||||||
|
screwB(4);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// partB
|
||||||
|
|
||||||
|
union() {
|
||||||
|
H2 = (BODY_Z-BODY_X);
|
||||||
|
Y=BODY_Y-THICK-4-1;
|
||||||
|
// front
|
||||||
|
hull() {
|
||||||
|
translate([-(BODY_X/2 + BODY_Y*0.2)/2-1, 0, H2/2-2])
|
||||||
|
cube(size=[1, Y+8, 2], center=true);
|
||||||
|
|
||||||
|
translate([-(BODY_X/2 + BODY_Y*0.2)/2-1.3, 0, -2])
|
||||||
|
cube(size=[2, Y+8, 2], center=true);
|
||||||
|
|
||||||
|
translate([-(BODY_X/2)/2, 0, -4])
|
||||||
|
cube(size=[2, Y+8, 2], center=true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// bottom
|
||||||
|
cube(size=[BODY_X, Y, BODY_X*0.1], center=true);
|
||||||
|
|
||||||
|
// back
|
||||||
|
translate([(BODY_X/2), 0, BODY_Z*0.75/2-1-0.3])
|
||||||
|
cube(size=[BODY_X*0.2, Y, BODY_Z*0.70], center=true);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// hdmi
|
||||||
|
color("red")
|
||||||
|
translate([BODY_X/2-OPIZ_X/2-3, BODY_Y/3.5, OPIZ_Y/2 + OPIZ_OFFSET_Z])
|
||||||
|
rotate([90, 0, 0])
|
||||||
|
translate([OPIZ_X/2+3, OPIZ_Y/2-HDMI_Y/2-6.5, 2.5])
|
||||||
|
hdmi(0.3);
|
||||||
|
|
||||||
|
// micro usb for power
|
||||||
|
translate([BODY_X/2-USBM_BOARD[0]/2+OPIZ_OFFSET_X-1.1, -BODY_Y/4, 2])
|
||||||
|
rotate([0, 0, 180])
|
||||||
|
usbm_board(0.2);
|
||||||
|
|
||||||
|
// micro usb for keyboards
|
||||||
|
translate([-BODY_X*0.1-USBM_BOARD[0]/2-2, -BODY_Y/4,1])
|
||||||
|
usbm_board(0.2);
|
||||||
|
|
||||||
|
// switch
|
||||||
|
translate([BODY_X/2, -BODY_Y/4, BODY_Z*0.6])
|
||||||
|
rotate([0, 90, 0])
|
||||||
|
linear_extrude(height=10, center=true, convexity=10, twist=0)
|
||||||
|
circle(d=4);
|
||||||
|
|
||||||
|
} // diff
|
||||||
|
|
||||||
|
// opi holder
|
||||||
|
translate([OPIZ_OFFSET_X, 0, 0])
|
||||||
|
difference() {
|
||||||
|
union() {
|
||||||
|
translate([BODY_X/2-OPIZ_HLD_X/2-1, OPIZ_HLD_Y/2 + BODY_Y/3.5 + 1, OPIZ_HLD_Z/2])
|
||||||
|
cube(size=[OPIZ_HLD_X, OPIZ_HLD_Y, OPIZ_HLD_Z], center=true);
|
||||||
|
|
||||||
|
translate([BODY_X/2+OPIZ_HLD_X/2-5-OPIZ_X, OPIZ_HLD_Y/2 + BODY_Y/3.5 + 1, OPIZ_HLD_Z/4.5/2])
|
||||||
|
cube(size=[OPIZ_HLD_X, OPIZ_HLD_Y, OPIZ_HLD_Z/4], center=true);
|
||||||
|
|
||||||
|
// screw base A
|
||||||
|
translate([BODY_X/2-OPIZ_X/2-3, BODY_Y/3.5, OPIZ_Y/2 + OPIZ_OFFSET_Z])
|
||||||
|
rotate([90, 0, 0])
|
||||||
|
mirror_y()
|
||||||
|
translate([OPIZ_X/2-OPI_HOLE_POS, OPIZ_Y/2-OPI_HOLE_POS, -1])
|
||||||
|
cylinder(d=6, h=1, d2=5, center=!true);
|
||||||
|
|
||||||
|
// screw base B
|
||||||
|
translate([BODY_X/2-OPIZ_X/2-3, BODY_Y/3.5, OPIZ_Y/2 + OPIZ_OFFSET_Z])
|
||||||
|
rotate([90, 0, 0])
|
||||||
|
mirror([1, 0, 0])
|
||||||
|
mirror([0, 1, 0])
|
||||||
|
translate([OPIZ_X/2-OPI_HOLE_POS, OPIZ_Y/2-OPI_HOLE_POS, -1])
|
||||||
|
cylinder(d=6, h=1, d2=5, center=!true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// screws A
|
||||||
|
translate([BODY_X/2-OPIZ_X/2-3, BODY_Y/3.5, OPIZ_Y/2 + OPIZ_OFFSET_Z])
|
||||||
|
rotate([90, 0, 0])
|
||||||
|
mirror_y()
|
||||||
|
translate([OPIZ_X/2-OPI_HOLE_POS, OPIZ_Y/2-OPI_HOLE_POS, -1])
|
||||||
|
cylinder(d=2, h=10, center=true);
|
||||||
|
|
||||||
|
// screws B
|
||||||
|
translate([BODY_X/2-OPIZ_X/2-3, BODY_Y/3.5, OPIZ_Y/2 + OPIZ_OFFSET_Z])
|
||||||
|
rotate([90, 0, 0])
|
||||||
|
mirror([1, 0, 0])
|
||||||
|
mirror([0, 1, 0])
|
||||||
|
translate([OPIZ_X/2-OPI_HOLE_POS, OPIZ_Y/2-OPI_HOLE_POS, -1])
|
||||||
|
cylinder(d=2, h=10, center=true);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// micro usb for power - screws
|
||||||
|
translate([BODY_X/2-USBM_BOARD[0]/2+OPIZ_OFFSET_X-1.1, -BODY_Y/4, 0])
|
||||||
|
rotate([0, 0, 180])
|
||||||
|
usbm_board_screws(d=8, h=2, center=false);
|
||||||
|
|
||||||
|
// micro usb for keyboards - screws
|
||||||
|
translate([-BODY_X*0.1-USBM_BOARD[0]/2-2, -BODY_Y/4, 0])
|
||||||
|
usbm_board_screws(d=8, h=1, center=false);
|
||||||
|
|
||||||
|
// magnets - holder
|
||||||
|
mirror_y()
|
||||||
|
translate([7, BODY_Y/2.6, 0])
|
||||||
|
cylinder(d=12, h=4, center=!true);
|
||||||
|
} // union
|
||||||
|
|
||||||
|
// micro usb for power
|
||||||
|
translate([BODY_X/2-USBM_BOARD[0]/2+OPIZ_OFFSET_X-1.1, -BODY_Y/4, -2.2])
|
||||||
|
rotate([0, 0, 180])
|
||||||
|
usbm_board_screws(d=2, h=5, center=false);
|
||||||
|
|
||||||
|
// micro usb for keyboards
|
||||||
|
translate([-BODY_X*0.1-USBM_BOARD[0]/2-2, -BODY_Y/4, -2.2])
|
||||||
|
usbm_board_screws(d=2, h=5, center=false);
|
||||||
|
|
||||||
|
// magnets - holder
|
||||||
|
mirror_y()
|
||||||
|
translate([7, BODY_Y/2.6, -2.6]) {
|
||||||
|
cylinder(d=11, h=3+0.01, center=!true);
|
||||||
|
translate([0, 0, 3])
|
||||||
|
cylinder(d=11, d2=3, h=2, center=!true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// magnets - holder
|
||||||
|
mirror_y()
|
||||||
|
translate([7, BODY_Y/2.6, -2.6]) {
|
||||||
|
cylinder(d=1.5, h=10, center=!true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// back panel A
|
||||||
|
color("red")
|
||||||
|
translate([BODY_X/2+10/2-1-BACKPANEL_X, BODY_Y/3.5-5, OPIZ_Y/2+14])
|
||||||
|
rotate([0, 90, 0])
|
||||||
|
linear_extrude(height=10, center=true, convexity=10, twist=0)
|
||||||
|
rounding(0.8)
|
||||||
|
square(size=[35, 8], center=true);
|
||||||
|
|
||||||
|
// back panel B
|
||||||
|
color("red")
|
||||||
|
translate([BODY_X/2+10/2-1-BACKPANEL_X, 0, 2])
|
||||||
|
rotate([0, 90, 0])
|
||||||
|
linear_extrude(height=10, center=true, convexity=10, twist=0, scale=1.2)
|
||||||
|
rounding(0.8)
|
||||||
|
square(size=[20, 60], center=true);
|
||||||
|
|
||||||
|
// back panel C
|
||||||
|
color("red")
|
||||||
|
translate([BODY_X/2+10/2-1.5, -5, BODY_Z*0.35])
|
||||||
|
rotate([0, 90, 0])
|
||||||
|
linear_extrude(height=10, center=true, convexity=10, twist=0)
|
||||||
|
rounding(0.8)
|
||||||
|
square(size=[35, 25], center=true);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
module pport(y=10, z=3) {
|
||||||
|
rotate([0, 90, 0])
|
||||||
|
linear_extrude(height=1.0, center=true, convexity=10, twist=0)
|
||||||
|
|
||||||
|
difference() {
|
||||||
|
union() {
|
||||||
|
rounding(0.8)
|
||||||
|
hull() {
|
||||||
|
square(size=[0.1, y], center=true);
|
||||||
|
translate([z, 0, 0])
|
||||||
|
square(size=[0.1, y*0.85], center=true);
|
||||||
|
}
|
||||||
|
mirror_y()
|
||||||
|
translate([z/2, y/2+0.5, 0])
|
||||||
|
circle(d=1.9);
|
||||||
|
}
|
||||||
|
for (i=[-y/3:y/3]) {
|
||||||
|
translate([z/3, i*1.2, 0])
|
||||||
|
circle(d=1);
|
||||||
|
}
|
||||||
|
for (i=[-y/4:y/4+1]) {
|
||||||
|
translate([z/1.5, i*1.2-1.2/2, 0])
|
||||||
|
circle(d=1);
|
||||||
|
}
|
||||||
|
mirror_y()
|
||||||
|
translate([z/2, y/2+0.5, 0])
|
||||||
|
circle(d=1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// parallel port
|
||||||
|
color("green")
|
||||||
|
translate([BODY_X/2-1-BACKPANEL_X, 1, 7])
|
||||||
|
pport(14, 4);
|
||||||
|
|
||||||
|
// ps/2 port
|
||||||
|
color("green")
|
||||||
|
translate([BODY_X/2-1-BACKPANEL_X, BODY_Y/4, 5])
|
||||||
|
rotate([0, 90, 0])
|
||||||
|
linear_extrude(height=1, center=true, convexity=10, twist=0)
|
||||||
|
union() {
|
||||||
|
shell(0.3)
|
||||||
|
circle(d=3);
|
||||||
|
translate([-3/2+1/2, 0, 0])
|
||||||
|
square(size=[1, 1], center=true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ps/2 port
|
||||||
|
color("green")
|
||||||
|
translate([BODY_X/2-1-BACKPANEL_X, BODY_Y/4+6, 5])
|
||||||
|
rotate([0, 90, 0])
|
||||||
|
linear_extrude(height=1.0, center=true, convexity=10, twist=0)
|
||||||
|
union() {
|
||||||
|
shell(0.3)
|
||||||
|
circle(d=3);
|
||||||
|
translate([-3/2+1/2, 0, 0])
|
||||||
|
square(size=[1, 1], center=true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// display holder
|
||||||
|
difference() {
|
||||||
|
hull() {
|
||||||
|
translate([-(BODY_X-THICK)*0.9/2+3, 0, BODY_Z/1.6])
|
||||||
|
rotate([0, 5, 0])
|
||||||
|
cube(size=[1, 15, 15], center=true);
|
||||||
|
|
||||||
|
translate([-BODY_X*0.1, 0, 0])
|
||||||
|
rotate([90, 0, 0])
|
||||||
|
cylinder(d=1, h=15, center=true);
|
||||||
|
|
||||||
|
translate([-BODY_X*0.27, 0, 0])
|
||||||
|
rotate([90, 0, 0])
|
||||||
|
cylinder(d=1, h=12, center=true);
|
||||||
|
}
|
||||||
|
|
||||||
|
translate([2, 0, 0])
|
||||||
|
scale([1, 0.7, 1])
|
||||||
|
hull() {
|
||||||
|
translate([-(BODY_X-THICK)*0.9/2+3, 0, BODY_Z/1.6])
|
||||||
|
rotate([0, 5, 0])
|
||||||
|
cube(size=[1, 15, 15], center=true);
|
||||||
|
|
||||||
|
translate([-BODY_X*0.1, 0, 0])
|
||||||
|
rotate([90, 0, 0])
|
||||||
|
cylinder(d=1, h=15, center=true);
|
||||||
|
|
||||||
|
translate([-BODY_X*0.27, 0, 0])
|
||||||
|
rotate([90, 0, 0])
|
||||||
|
cylinder(d=1, h=12, center=true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// screw base
|
||||||
|
translate([BODY_X/2-OPIZ_X/2-3 + OPIZ_OFFSET_X, 0, OPIZ_Y/2 + OPIZ_OFFSET_Z])
|
||||||
|
rotate([90, 0, 0])
|
||||||
|
mirror([1, 0, 0])
|
||||||
|
mirror([0, 1, 0])
|
||||||
|
translate([OPIZ_X/2-OPI_HOLE_POS, OPIZ_Y/2-OPI_HOLE_POS, -1])
|
||||||
|
cylinder(d=6, h=20, center=true);
|
||||||
|
|
||||||
|
// pin header
|
||||||
|
translate([BODY_X/2-OPIZ_X/2-3 + OPIZ_OFFSET_X, 0, OPIZ_Y/2 + OPIZ_OFFSET_Z])
|
||||||
|
rotate([90, 0, 0])
|
||||||
|
translate([-OPIZ_X/2+33/2+7.7, -OPIZ_Y/2+5/2, -1])
|
||||||
|
cube(size=[33, 5, 20], center=true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// switch holder
|
||||||
|
translate([BODY_X/2-10/2-3, -BODY_Y/4, BODY_Z*0.6-5.5])
|
||||||
|
difference() {
|
||||||
|
cube(size=[10, 5, 15], center=true);
|
||||||
|
|
||||||
|
translate([0, 0, -10])
|
||||||
|
rotate([0, -60, 0])
|
||||||
|
cube(size=[10, 5+1, 25], center=true);
|
||||||
|
|
||||||
|
translate([-6/2+10/2, 0, 15-5])
|
||||||
|
cube(size=[6, 5+1, 15], center=true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module hdmi(offset=0.1) {
|
||||||
|
translate([0, 0, HDMI_Z]) {
|
||||||
|
rotate([-90, 0, 90])
|
||||||
|
linear_extrude(height=10, center=!true, convexity=10, twist=0)
|
||||||
|
outset(offset)
|
||||||
|
hull() {
|
||||||
|
translate([0, 4/2, 0])
|
||||||
|
square(size=[HDMI_Y, 4], center=true);
|
||||||
|
translate([0, HDMI_Z/2, 0])
|
||||||
|
square(size=[11, HDMI_Z], center=true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// opi
|
||||||
|
%translate([BODY_X/2-OPIZ_X/2-3+OPIZ_OFFSET_X, BODY_Y/3.5, OPIZ_Y/2 + OPIZ_OFFSET_Z])
|
||||||
|
rotate([90, 0, 0]){
|
||||||
|
translate([0, 0, OPIZ_Z/2])
|
||||||
|
cube(size=[OPIZ_X, OPIZ_Y, OPIZ_Z], center=true);
|
||||||
|
|
||||||
|
//screw
|
||||||
|
mirror_x()
|
||||||
|
mirror_y()
|
||||||
|
translate([OPIZ_X/2-OPI_HOLE_POS, OPIZ_Y/2-OPI_HOLE_POS, 0])
|
||||||
|
cylinder(d=3, h=10, center=true);
|
||||||
|
|
||||||
|
// hdmi
|
||||||
|
translate([OPIZ_X/2+3, OPIZ_Y/2-HDMI_Y/2-6.5, 2])
|
||||||
|
hdmi();
|
||||||
|
}
|
||||||
|
|
||||||
|
// partA
|
||||||
|
module partA() {
|
||||||
|
difference() {
|
||||||
|
minkowski() {
|
||||||
|
base();
|
||||||
|
rotate([0, 95, 0])
|
||||||
|
cylinder(d=5, h=0.01, center=true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// display
|
||||||
|
translate([0, 0, BODY_X/2 + (BODY_Z-BODY_X)/2*1.8])
|
||||||
|
rotate([0, 5, 0])
|
||||||
|
hull() {
|
||||||
|
DISP_Y = 72.6;
|
||||||
|
translate([-BODY_X/2-4, 0, 0])
|
||||||
|
cube(size=[0.1, DISP_Y*0.9, DISP_Y*0.9*0.75], center=true);
|
||||||
|
|
||||||
|
translate([-30, 0, 0])
|
||||||
|
sphere(d=20);
|
||||||
|
}
|
||||||
|
|
||||||
|
// inner space
|
||||||
|
scale([0.9, 1, 1])
|
||||||
|
resize([BODY_X-THICK, 0, 0], auto=[false, true, true])
|
||||||
|
base(1.15);
|
||||||
|
|
||||||
|
// floppy
|
||||||
|
floppy();
|
||||||
|
|
||||||
|
// partB
|
||||||
|
union() {
|
||||||
|
H2 = (BODY_Z-BODY_X);
|
||||||
|
Y=BODY_Y-THICK-4;
|
||||||
|
// front
|
||||||
|
hull() {
|
||||||
|
translate([-(BODY_X/2 + BODY_Y*0.2)/2-1, 0, H2/2-2])
|
||||||
|
cube(size=[2, Y+8, 2], center=true);
|
||||||
|
|
||||||
|
translate([-(BODY_X/2 + BODY_Y*0.2)/2-1.2, 0, -2])
|
||||||
|
cube(size=[2, Y+8, 2], center=true);
|
||||||
|
|
||||||
|
translate([-(BODY_X/2)/2, 0, -4])
|
||||||
|
cube(size=[2, Y+8, 2], center=true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// bottom
|
||||||
|
cube(size=[BODY_X, Y, BODY_X*0.1], center=true);
|
||||||
|
|
||||||
|
// back
|
||||||
|
translate([(BODY_X/2), 0, BODY_Z*0.75/2-1])
|
||||||
|
cube(size=[BODY_X*0.2, Y, BODY_Z*0.70], center=true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// air intake
|
||||||
|
copy_mirror([0,1,0])
|
||||||
|
translate([BODY_X/2-BODY_X*0.2/2, BODY_Y/2-BODY_Y/8.5, BODY_Z-BODY_Z*0.141])
|
||||||
|
for (i=[0:4]) {
|
||||||
|
translate([0, 0, -i*0.6*3])
|
||||||
|
cube(size=[BODY_X*0.2, BODY_Y/5, 0.9], center=true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// air intake
|
||||||
|
translate([-BODY_X*0.1, 0, BODY_Z-BODY_Z*0.175])
|
||||||
|
for (i=[-4:4]) {
|
||||||
|
translate([0, -i*0.8*3, 0])
|
||||||
|
rotate([90, 0, 0])
|
||||||
|
cube(size=[BODY_X*0.2, BODY_Y/12, 0.8], center=true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* translate([-BODY_X/2+4, 0, BODY_Z/2*0.88])
|
||||||
|
rotate([0, 5, 0])
|
||||||
|
rotate([90, 0, 90])
|
||||||
|
linear_extrude(height=0.5, center=true, convexity=10, twist=0)
|
||||||
|
shell(d=1)
|
||||||
|
square(size=[BODY_Y+4, BODY_Z], center=true); */
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// top cover
|
||||||
|
translate([-3, 0, BODY_Z-BODY_Z*0.105])
|
||||||
|
union() {
|
||||||
|
rotate([0, 5, 0])
|
||||||
|
cube(size=[BODY_X*0.18, BODY_Y/2, 2], center=true);
|
||||||
|
|
||||||
|
translate([0, 0, -1])
|
||||||
|
rotate([0, 5, 0])
|
||||||
|
hull() {
|
||||||
|
cube(size=[BODY_X*0.18, BODY_Y/3, 0.01], center=true);
|
||||||
|
translate([0, 0, -2])
|
||||||
|
cube(size=[BODY_X*0.18, BODY_Y/4, 0.01], center=true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
copy_mirror([0,1,0])
|
||||||
|
translate([BODY_X/2-10-3.5, BODY_Y*0.91/2, BODY_Z*0.68])
|
||||||
|
rotate([0, 90, 0])
|
||||||
|
screwBase();
|
||||||
|
|
||||||
|
copy_mirror([0,1,0])
|
||||||
|
translate([BODY_X/2-10-3.5, BODY_Y*0.91/2, BODY_Z*0.1])
|
||||||
|
rotate([0, 90, 0])
|
||||||
|
screwBase();
|
||||||
|
|
||||||
|
copy_mirror([0,1,0])
|
||||||
|
translate([-BODY_X*0.2, BODY_Y*0.91/2, BODY_Z*0.1/3])
|
||||||
|
screwBaseB();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
USBM_BOARD = [15, 14.3, 1.5];
|
||||||
|
module usbm_board(soffset=0.1) {
|
||||||
|
difference() {
|
||||||
|
translate([0, 0, USBM_BOARD[2]/2])
|
||||||
|
cube(size=USBM_BOARD, center=true);
|
||||||
|
|
||||||
|
// holes
|
||||||
|
mirror_y()
|
||||||
|
translate([USBM_BOARD[0]/2-5.5, USBM_BOARD[1]/2-2.5, 0])
|
||||||
|
cylinder(d=3, h=10, center=true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// socket
|
||||||
|
translate([0, 0, USBM_BOARD[2]+0.3])
|
||||||
|
rotate([90, 0, -90])
|
||||||
|
linear_extrude(height=10, center=!true, convexity=10, twist=0)
|
||||||
|
offset(soffset)
|
||||||
|
hull() {
|
||||||
|
translate([0, 2.7, 0])
|
||||||
|
square(size=[6.8, 0.1], center=true);
|
||||||
|
translate([0, 1.4, 0])
|
||||||
|
square(size=[7.8, 0.1], center=true);
|
||||||
|
square(size=[5.3, 0.1], center=true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module usbm_board_screws(d=3, h=10, center=true) {
|
||||||
|
USBM_BOARD = [15, 14.3, 1.5];
|
||||||
|
|
||||||
|
// holes
|
||||||
|
mirror_y()
|
||||||
|
translate([USBM_BOARD[0]/2-5.5, USBM_BOARD[1]/2-2.5, 0])
|
||||||
|
cylinder(d=d, h=h, center=center);
|
||||||
|
}
|
||||||
|
|
||||||
|
module floppy(args) {
|
||||||
|
// body...
|
||||||
|
module floppy_baseA() {
|
||||||
|
square(size=[BODY_Y/2.5, BODY_Z*0.01], center=true);
|
||||||
|
}
|
||||||
|
module floppy_baseB() {
|
||||||
|
translate([-BODY_Y/2.5/2+BODY_Y/9/2, -BODY_Z*0.01, 0])
|
||||||
|
square(size=[BODY_Y/9, BODY_Z*0.03], center=true);
|
||||||
|
}
|
||||||
|
module floppy_baseC() {
|
||||||
|
/* offset(r=2) */
|
||||||
|
translate([-BODY_Y/2.5/2+BODY_Y/9/2, BODY_Z*0.01, 0])
|
||||||
|
square(size=[BODY_Y/9, BODY_Z*0.02], center=true);
|
||||||
|
}
|
||||||
|
module floppy_baseD() {
|
||||||
|
translate([-BODY_Y/2.5/2+BODY_Y/9/2, 0, 0])
|
||||||
|
square(size=[BODY_Y/9, BODY_Z*0.02*2], center=true);
|
||||||
|
}
|
||||||
|
|
||||||
|
FLOPPY_Z = BODY_Z*0.26;
|
||||||
|
|
||||||
|
translate([-BODY_X/2, -BODY_Y*0.2, FLOPPY_Z])
|
||||||
|
rotate([0, 5, 0])
|
||||||
|
rotate([90, 0, 90])
|
||||||
|
linear_extrude(height=7, center=true, convexity=10, twist=0){
|
||||||
|
floppy_baseA();
|
||||||
|
floppy_baseB();
|
||||||
|
}
|
||||||
|
|
||||||
|
translate([-BODY_X/2-3, -BODY_Y*0.2, FLOPPY_Z])
|
||||||
|
rotate([0, 5, 0])
|
||||||
|
rotate([90, 0, 90])
|
||||||
|
offset(r=2)
|
||||||
|
linear_extrude(height=5, center=true, convexity=10, twist=0)
|
||||||
|
floppy_baseC();
|
||||||
|
|
||||||
|
// front
|
||||||
|
translate([-BODY_X/2-2, -BODY_Y*0.2, FLOPPY_Z])
|
||||||
|
rotate([0, 5, 0])
|
||||||
|
rotate([90, 0, 90]){
|
||||||
|
hull() {
|
||||||
|
linear_extrude(height=1, center=true, convexity=10, twist=0)
|
||||||
|
floppy_baseA();
|
||||||
|
|
||||||
|
translate([0, 0, -2])
|
||||||
|
linear_extrude(height=1, center=true, convexity=10, twist=0, scale=1.1)
|
||||||
|
offset(delta=1)
|
||||||
|
offset(r=0.1)
|
||||||
|
floppy_baseA();
|
||||||
|
}
|
||||||
|
hull() {
|
||||||
|
linear_extrude(height=1, center=true, convexity=10, twist=0)
|
||||||
|
offset(r=0.1)
|
||||||
|
floppy_baseD();
|
||||||
|
|
||||||
|
translate([0, 0, -2])
|
||||||
|
linear_extrude(height=1, center=true, convexity=10, twist=0, scale=1.1)
|
||||||
|
offset(delta=1)
|
||||||
|
offset(r=0.1)
|
||||||
|
floppy_baseD();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module screwBase() {
|
||||||
|
XY = 8;
|
||||||
|
Z = 10;
|
||||||
|
|
||||||
|
difference() {
|
||||||
|
translate([0, 0, Z/2])
|
||||||
|
cube(size=[XY, XY, 10], center=true);
|
||||||
|
|
||||||
|
cylinder(d=2, h=Z+1, center=!true);
|
||||||
|
|
||||||
|
rotate([-40, 0, 0])
|
||||||
|
translate([0, 0, -2])
|
||||||
|
cube(size=[XY*2, XY*3, XY], center=true);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module screwBaseB() {
|
||||||
|
XY = 8;
|
||||||
|
Z = 10;
|
||||||
|
translate([0, 0, -XY/2])
|
||||||
|
difference() {
|
||||||
|
translate([0, 0, Z/2])
|
||||||
|
cube(size=[XY*2, XY, XY], center=true);
|
||||||
|
|
||||||
|
translate([XY/2, 0, 0])
|
||||||
|
cylinder(d=2, h=Z+1, center=!true);
|
||||||
|
|
||||||
|
rotate([0, 0, -90-60])
|
||||||
|
translate([XY, 0, Z/2])
|
||||||
|
cube(size=[XY*2, XY*3, Z+1], center=true);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module screwB(d=2) {
|
||||||
|
XY = 8;
|
||||||
|
Z = 10;
|
||||||
|
translate([XY/2, 0, 0])
|
||||||
|
cylinder(d=d, h=Z*2, center=true);
|
||||||
|
}
|
||||||
|
|
||||||
|
module screw(d=2) {
|
||||||
|
XY = 8;
|
||||||
|
Z = 10;
|
||||||
|
|
||||||
|
cylinder(d=d, h=Z+1, center=!true);
|
||||||
|
}
|
|
@ -0,0 +1,3 @@
|
||||||
|
include <macintosh-mini-base.scad>
|
||||||
|
|
||||||
|
partA();
|
|
@ -0,0 +1,3 @@
|
||||||
|
include <macintosh-mini-base.scad>
|
||||||
|
|
||||||
|
partB();
|
|
@ -0,0 +1 @@
|
||||||
|
Subproject commit 484d39bc2fd19cf6903c8e92e01af40a77276e66
|
|
@ -0,0 +1,24 @@
|
||||||
|
module.exports = {
|
||||||
|
env: {
|
||||||
|
commonjs: true,
|
||||||
|
es6: true,
|
||||||
|
node: true
|
||||||
|
},
|
||||||
|
extends: ["eslint:recommended", "plugin:prettier/recommended"],
|
||||||
|
globals: {
|
||||||
|
Atomics: "readonly",
|
||||||
|
SharedArrayBuffer: "readonly"
|
||||||
|
},
|
||||||
|
parserOptions: {
|
||||||
|
ecmaVersion: 2018
|
||||||
|
},
|
||||||
|
rules: {
|
||||||
|
"prettier/prettier": [
|
||||||
|
"error",
|
||||||
|
{
|
||||||
|
singleQuote: true,
|
||||||
|
trailingComma: "es5"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
};
|
|
@ -0,0 +1,80 @@
|
||||||
|
|
||||||
|
# Created by https://www.gitignore.io/api/node
|
||||||
|
|
||||||
|
### Node ###
|
||||||
|
# Logs
|
||||||
|
logs
|
||||||
|
*.log
|
||||||
|
npm-debug.log*
|
||||||
|
yarn-debug.log*
|
||||||
|
yarn-error.log*
|
||||||
|
|
||||||
|
# Runtime data
|
||||||
|
pids
|
||||||
|
*.pid
|
||||||
|
*.seed
|
||||||
|
*.pid.lock
|
||||||
|
|
||||||
|
# Directory for instrumented libs generated by jscoverage/JSCover
|
||||||
|
lib-cov
|
||||||
|
|
||||||
|
# Coverage directory used by tools like istanbul
|
||||||
|
coverage
|
||||||
|
|
||||||
|
# nyc test coverage
|
||||||
|
.nyc_output
|
||||||
|
|
||||||
|
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
|
||||||
|
.grunt
|
||||||
|
|
||||||
|
# Bower dependency directory (https://bower.io/)
|
||||||
|
bower_components
|
||||||
|
|
||||||
|
# node-waf configuration
|
||||||
|
.lock-wscript
|
||||||
|
|
||||||
|
# Compiled binary addons (https://nodejs.org/api/addons.html)
|
||||||
|
build/Release
|
||||||
|
|
||||||
|
# Dependency directories
|
||||||
|
node_modules/
|
||||||
|
jspm_packages/
|
||||||
|
|
||||||
|
# TypeScript v1 declaration files
|
||||||
|
typings/
|
||||||
|
|
||||||
|
# Optional npm cache directory
|
||||||
|
.npm
|
||||||
|
|
||||||
|
# Optional eslint cache
|
||||||
|
.eslintcache
|
||||||
|
|
||||||
|
# Optional REPL history
|
||||||
|
.node_repl_history
|
||||||
|
|
||||||
|
# Output of 'npm pack'
|
||||||
|
*.tgz
|
||||||
|
|
||||||
|
# Yarn Integrity file
|
||||||
|
.yarn-integrity
|
||||||
|
|
||||||
|
# dotenv environment variables file
|
||||||
|
.env
|
||||||
|
|
||||||
|
# parcel-bundler cache (https://parceljs.org/)
|
||||||
|
.cache
|
||||||
|
|
||||||
|
# next.js build output
|
||||||
|
.next
|
||||||
|
|
||||||
|
# nuxt.js build output
|
||||||
|
.nuxt
|
||||||
|
|
||||||
|
# vuepress build output
|
||||||
|
.vuepress/dist
|
||||||
|
|
||||||
|
# Serverless directories
|
||||||
|
.serverless
|
||||||
|
|
||||||
|
|
||||||
|
# End of https://www.gitignore.io/api/node
|
|
@ -0,0 +1,17 @@
|
||||||
|
const Gpio = require('orange-pi-gpio');
|
||||||
|
const fetch = require('node-fetch')
|
||||||
|
|
||||||
|
let gpio5 = new Gpio({pin:7, mode: 'in'});
|
||||||
|
|
||||||
|
prev = 0
|
||||||
|
setInterval(function () {
|
||||||
|
gpio5.read()
|
||||||
|
.then((state)=>{
|
||||||
|
state = parseInt(state)
|
||||||
|
if (state !== prev && state === 0) {
|
||||||
|
console.log("push");
|
||||||
|
fetch("http://localhost:5501/").catch((err) => {console.log(err);})
|
||||||
|
}
|
||||||
|
prev = state
|
||||||
|
});
|
||||||
|
}, 100);
|
|
@ -0,0 +1,89 @@
|
||||||
|
const fs = require('fs');
|
||||||
|
const path = require('path');
|
||||||
|
const { spawn } = require('child_process');
|
||||||
|
const express = require('express');
|
||||||
|
const app = express();
|
||||||
|
|
||||||
|
const shPath = './sh.d';
|
||||||
|
|
||||||
|
class Runner {
|
||||||
|
constructor() {
|
||||||
|
this.files = fs
|
||||||
|
.readdirSync(shPath)
|
||||||
|
.filter(v => /.sh$/.test(v))
|
||||||
|
.map(v => path.join(shPath, v));
|
||||||
|
console.log('loaded scripts:', this.files);
|
||||||
|
this.currentTarget = null;
|
||||||
|
}
|
||||||
|
psleep(ms) {
|
||||||
|
return new Promise(resolve => {
|
||||||
|
setTimeout(resolve, ms);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
kill(sig = 'SIGINT') {
|
||||||
|
try {
|
||||||
|
process.kill(-this.currentTarget.pid, sig || 'SIGINT');
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
spawn(target) {
|
||||||
|
return new Promise(resolve => {
|
||||||
|
const child = spawn(target, {
|
||||||
|
sid: true,
|
||||||
|
detached: true,
|
||||||
|
});
|
||||||
|
const tag = `${target}:`;
|
||||||
|
child.stdout.on('data', data => {
|
||||||
|
console.log(tag, data.toString().trim());
|
||||||
|
});
|
||||||
|
child.stderr.on('data', data => {
|
||||||
|
console.log(tag, data.toString().trim());
|
||||||
|
});
|
||||||
|
child.on('close', code => {
|
||||||
|
console.log(tag, 'close');
|
||||||
|
resolve(code);
|
||||||
|
});
|
||||||
|
child.on('exit', code => {
|
||||||
|
console.log(tag, 'exit');
|
||||||
|
this.kill();
|
||||||
|
resolve(code);
|
||||||
|
});
|
||||||
|
this.currentTarget = child;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
async runner() {
|
||||||
|
let counter = 0;
|
||||||
|
while (true) {
|
||||||
|
const target = this.files[counter++ % this.files.length];
|
||||||
|
console.log('running', target);
|
||||||
|
await this.spawn(target).catch(err => {
|
||||||
|
console.error(err);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
start() {
|
||||||
|
this.runner();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const runner = new Runner();
|
||||||
|
runner.start();
|
||||||
|
|
||||||
|
const onExit = () => {
|
||||||
|
console.log('exitting');
|
||||||
|
runner.kill();
|
||||||
|
process.exit(0);
|
||||||
|
};
|
||||||
|
|
||||||
|
process.on('SIGTERM', onExit);
|
||||||
|
process.on('SIGINT', onExit);
|
||||||
|
|
||||||
|
app.get('/', (req, res) => {
|
||||||
|
const sig = req.query.force ? 'SIGKILL' : null;
|
||||||
|
runner.kill(sig);
|
||||||
|
res.sendStatus(200);
|
||||||
|
});
|
||||||
|
|
||||||
|
const port = process.env.PORT || 5501;
|
||||||
|
app.listen(port, 'localhost', () => console.log('listening on', port));
|
|
@ -0,0 +1,23 @@
|
||||||
|
{
|
||||||
|
"name": "mm-switcher",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "",
|
||||||
|
"main": "index.js",
|
||||||
|
"scripts": {
|
||||||
|
"start": "node index.js",
|
||||||
|
"start:gpio": "node gpio-reader.js",
|
||||||
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
|
},
|
||||||
|
"keywords": [],
|
||||||
|
"author": "",
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"express": "^4.16.3"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"eslint": "^6.5.1",
|
||||||
|
"eslint-config-prettier": "^6.3.0",
|
||||||
|
"eslint-plugin-prettier": "^3.1.1",
|
||||||
|
"prettier": "^1.18.2"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
vncserver -kill :1
|
||||||
|
vncserver -geometry 512x384
|
||||||
|
ssvncviewer -scale 0.625 :1 -fullscreen -passwd ~/.vnc/passwd &
|
||||||
|
DISPLAY=:1
|
||||||
|
cd ~/macmini/minivmac
|
||||||
|
./minivmac.512 vmac.rom system.dsk
|
|
@ -0,0 +1,8 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
vncserver -kill :1
|
||||||
|
vncserver -geometry 320x240
|
||||||
|
ssvncviewer -scale 1 :1 -fullscreen -passwd ~/.vnc/passwd &
|
||||||
|
DISPLAY=:1
|
||||||
|
cd ~/macmini/minivmac
|
||||||
|
./minivmac.320 vmac.rom system.dsk
|
|
@ -0,0 +1,6 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
vncserver -kill :1
|
||||||
|
vncserver -geometry 512x384
|
||||||
|
ssvncviewer -scale 0.625 :1 -fullscreen -passwd ~/.vnc/passwd &
|
||||||
|
DISPLAY=:1 BasiliskII --nogui true
|
|
@ -0,0 +1,3 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
xterm
|
|
@ -0,0 +1,7 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
vncserver -kill :1
|
||||||
|
vncserver -geometry 512x384
|
||||||
|
ssvncviewer -scale 0.625 :1 -fullscreen -passwd ~/.vnc/passwd &
|
||||||
|
DISPLAY=:1
|
||||||
|
xterm
|
|
@ -0,0 +1,3 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
chromium-browser --kiosk --app=http://simpleclock.surge.sh
|