Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fecd6f5834 | ||
|
|
625f6047ba | ||
|
|
7b06663ee7 | ||
|
|
69ab6a7bb6 | ||
|
|
eb0c5dddba | ||
|
|
5bfbd86b63 | ||
|
|
b4d8df78f1 | ||
|
|
30e7837cdb | ||
|
|
d7a756be80 | ||
|
|
33a69dcf9a | ||
|
|
7e5c449955 | ||
|
|
9ac330aadb | ||
|
|
a6777500ff | ||
|
|
1a2947488a | ||
|
|
e4386bdd4e | ||
|
|
0e5c25b4ac | ||
|
|
c4cea45b40 | ||
|
|
94a111d499 | ||
|
|
a3550409da | ||
|
|
07a9d5a5fc |
@@ -3,61 +3,39 @@
|
||||
|
||||
Run through this guide once before building, ensuring you have all the parts required. You'll also need a soldering iron and solder.
|
||||
|
||||
## LEDs
|
||||
First up, the LEDs.
|
||||
## Acrylic
|
||||
**STOP NOW!** I *know* it's tempting, but don't peel off the protective backing from all the acrylic yet.
|
||||
Once it's off, the pieces attract dust, which can make the rear look messy.
|
||||
|
||||

|
||||
**WARNING:** The top 2 plates (those with encoder holes) are fragile and easily snap if dropped. Take care when assembling. Once assembled, they are protected by the rest of the controller and should not break.
|
||||
|
||||
Take note, each LED point on the board has labelled connections for R, G and B. The long leg on the LEDs goes into the unmarked (ground) hole.
|
||||
Take off the protective backing from the top clear acrylic.
|
||||
Take your top clear plate and top black plate and place them over the LEDs. Take note of the clear plate - it has engraved edges for optimal lighting. It can be installed with the edges up or down, but they look best when facing up.
|
||||

|
||||

|
||||
|
||||

|
||||
|
||||
Insert the LEDs roughly to the red line, then bend them over:
|
||||

|
||||

|
||||
|
||||
Work on a slightly raised surface and place the board face down to solder, with the MACRO switch off the edge. This ensures all the LEDs are flush with the board surface.
|
||||

|
||||
|
||||
I recommend soldering one leg of each LED to keep it in place, then cutting off all the leads. This makes soldering the rest of the connections much easier.
|
||||
|
||||
The bend doesn't have to be perfect - the acrylic will diffuse the light.
|
||||

|
||||
|
||||
## Encoders
|
||||
You can solder the encoders now or after you install the switches, but I prefer to do them sooner. Solder one of the small pins to keep it in place then pump lots of solder into the big connecting lugs. These need to take your abuse, so make it a good joint!
|
||||

|
||||
Use the 1.5mm Allen key provided to screw the board together.
|
||||
Insert the top 8 bolts and 8 long nuts into the holes provided.
|
||||

|
||||
|
||||
## Switches
|
||||
**STOP NOW!** Have you finished soldering your LEDs? Have you tested them?
|
||||
Once you have soldered the switches you cannot fix anything without desoldering
|
||||
them again.
|
||||
|
||||
**WARNING:** The top 2 plates (those with encoder holes) are fragile and easily snap if dropped. Take care when assembling. Once assembled, they are protected by the rest of the controller and are much stronger.
|
||||
|
||||
Take your top clear plate and top black plate and place them over the LEDs. Take note of the clear plate - it has engraved edges for optimal lighting. It can be installed with the edges up or down, but they look best when facing up.
|
||||

|
||||
|
||||
Insert all your switches, and make sure they are seated properly. They are meant to be a tight fit into the PCB and should be completely flush with the surface.
|
||||

|
||||

|
||||
|
||||
Solder the switches. I solder with the back plate on, with its protective backing. This prevents flux from splashing over your board.
|
||||

|
||||
|
||||
## Nuts and bolts
|
||||
Use the 1.5mm Allen key provided to screw the board together.
|
||||
Insert the top 8 bolts and 8 long nuts into the holes provided. Take note, there are 3 holes in the PCB that are unused. These nuts can sometimes be a tight fit - you may need to push them into the case with a hard surface.
|
||||

|
||||
|
||||
Stack the bottom 2 plates and insert the remaining 8 bolts. Take care to align the cutout over the USB port. The bolts are a fraction too short, you may need to back off the top bolts by about 2 turns to get the nut close enough.
|
||||

|
||||
|
||||
## Rubber feet
|
||||
Stack the bottom 2 plates after removing their protective backing and insert the remaining 8 bolts.
|
||||
Take care to align the cutout over the USB port.
|
||||
Attach your 6 adhesive rubber feet. You can place these anywhere, but here is where I put them:
|
||||

|
||||

|
||||
|
||||
# Final touches
|
||||
Using the Allen key provided, attach the knobs. The encoder shaft is shaped like a D - ensure you tighten the grub screw on the flat part of the D.
|
||||
|
||||
*Optional:* Add 7 o-rings to your keycaps.
|
||||
*Optional:* Add 7 o-rings to your keycaps to make them quieter.
|
||||
|
||||
Install keycaps by simply pushing them onto the switches.
|
||||
|
||||

|
||||

|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
# Assembly
|
||||

|
||||
|
||||
Run through this guide once before building, ensuring you have all the parts required. You'll also need a soldering iron and solder.
|
||||
|
||||
## LEDs
|
||||
First up, the LEDs.
|
||||
|
||||

|
||||
|
||||
Take note, each LED point on the board has labelled connections for R, G and B. The long leg on the LEDs goes into the unmarked (ground) hole.
|
||||
|
||||

|
||||
|
||||
Insert the LEDs roughly to the red line, then bend them over:
|
||||

|
||||

|
||||
|
||||
Work on a slightly raised surface and place the board face down to solder, with the MACRO switch off the edge. This ensures all the LEDs are flush with the board surface.
|
||||

|
||||
|
||||
I recommend soldering one leg of each LED to keep it in place, then cutting off all the leads. This makes soldering the rest of the connections much easier.
|
||||
|
||||
The bend doesn't have to be perfect - the acrylic will diffuse the light.
|
||||

|
||||
|
||||
## Encoders
|
||||
You can solder the encoders now or after you install the switches, but I prefer to do them sooner. Solder one of the small pins to keep it in place then pump lots of solder into the big connecting lugs. These need to take your abuse, so make it a good joint!
|
||||

|
||||
|
||||
## Switches
|
||||
**STOP NOW!** Have you finished soldering your LEDs? Have you tested them?
|
||||
Once you have soldered the switches you cannot fix anything without desoldering
|
||||
them again.
|
||||
|
||||
**WARNING:** The top 2 plates (those with encoder holes) are fragile and easily snap if dropped. Take care when assembling. Once assembled, they are protected by the rest of the controller and are much stronger.
|
||||
|
||||
Take your top clear plate and top black plate and place them over the LEDs. Take note of the clear plate - it has engraved edges for optimal lighting. It can be installed with the edges up or down, but they look best when facing up.
|
||||

|
||||
|
||||
Insert all your switches, and make sure they are seated properly. They are meant to be a tight fit into the PCB and should be completely flush with the surface.
|
||||

|
||||
|
||||
## Nuts and bolts
|
||||
Use the 1.5mm Allen key provided to screw the board together.
|
||||
Insert the top 8 bolts and 8 long nuts into the holes provided. Take note, there are 3 holes in the PCB that are unused. These nuts can sometimes be a tight fit - you may need to push them into the case with a hard surface.
|
||||

|
||||
|
||||
Stack the bottom 2 plates and insert the remaining 8 bolts. Take care to align the cutout over the USB port. The bolts are a fraction too short, you may need to back off the top bolts by about 2 turns to get the nut close enough.
|
||||

|
||||
|
||||
## Rubber feet
|
||||
Attach your 6 adhesive rubber feet. You can place these anywhere, but here is where I put them:
|
||||

|
||||
|
||||
# Final touches
|
||||
Using the Allen key provided, attach the knobs. The encoder shaft is shaped like a D - ensure you tighten the grub screw on the flat part of the D.
|
||||
|
||||
*Optional:* Add 7 o-rings to your keycaps.
|
||||
|
||||
Install keycaps by simply pushing them onto the switches.
|
||||
|
||||

|
||||
@@ -12,6 +12,11 @@ If you are using b\*\*\*\*\*tools, configure as normal.
|
||||
For fast configuration of the HID lighting, download and run [this exe](https://github.com/mon/PocketVoltex/raw/master/Software/HidLights.exe)
|
||||
while config.exe is open and the controller is connected.
|
||||
|
||||
## KShootMania configuration
|
||||
I recommend using the mouse+keyboard mode, as I have noticed slight jitter when using joystick mode - it appears to be caused when the knob rolls over from its maximum value to its minimum value. This also lets you bind START to the enter key, which lets you begin songs with the controller.
|
||||
|
||||
However, if you would like to use gamepad mode, simply bind the keys as normal (page 3 of the input selection) and select `Analog X/Y` as the knob input. I find sensitivity at 100 works best.
|
||||
|
||||
## HID Lighting fix
|
||||
By default, HID lighting will crash after a few minutes of gameplay. To fix
|
||||
this, simply patch libinput.dll using [this tool](https://mon.im/bemanipatcher/pocketvoltex.html).
|
||||
|
||||
|
Before Width: | Height: | Size: 189 KiB After Width: | Height: | Size: 139 KiB |
|
After Width: | Height: | Size: 157 KiB |
|
After Width: | Height: | Size: 73 KiB |
|
After Width: | Height: | Size: 39 KiB |
|
After Width: | Height: | Size: 88 KiB |
|
After Width: | Height: | Size: 92 KiB |
|
Before Width: | Height: | Size: 190 KiB After Width: | Height: | Size: 190 KiB |
|
Before Width: | Height: | Size: 65 KiB After Width: | Height: | Size: 65 KiB |
|
Before Width: | Height: | Size: 140 KiB After Width: | Height: | Size: 140 KiB |
|
Before Width: | Height: | Size: 281 KiB After Width: | Height: | Size: 281 KiB |
|
Before Width: | Height: | Size: 173 KiB After Width: | Height: | Size: 173 KiB |
|
After Width: | Height: | Size: 189 KiB |
|
Before Width: | Height: | Size: 225 KiB After Width: | Height: | Size: 225 KiB |
|
Before Width: | Height: | Size: 110 KiB After Width: | Height: | Size: 110 KiB |
|
Before Width: | Height: | Size: 95 KiB After Width: | Height: | Size: 95 KiB |
|
Before Width: | Height: | Size: 105 KiB After Width: | Height: | Size: 105 KiB |
|
Before Width: | Height: | Size: 468 KiB After Width: | Height: | Size: 468 KiB |
|
Before Width: | Height: | Size: 52 KiB After Width: | Height: | Size: 52 KiB |
|
Before Width: | Height: | Size: 175 KiB After Width: | Height: | Size: 175 KiB |
|
Before Width: | Height: | Size: 92 KiB After Width: | Height: | Size: 92 KiB |
@@ -50,6 +50,7 @@ uint16_t MagicBootKey ATTR_NO_INIT;
|
||||
*/
|
||||
void Application_Jump_Check(void)
|
||||
{
|
||||
#ifdef SOFT_LEDS
|
||||
/* Always boot bootloader if RESET held
|
||||
* NOTE: This makes the assumption that
|
||||
* A) No code on the device uses RESET as an output
|
||||
@@ -58,6 +59,14 @@ void Application_Jump_Check(void)
|
||||
*/
|
||||
if(!(PINC & _BV(1)))
|
||||
return;
|
||||
#else
|
||||
/* New board - enable pullup for MACRO switch on PB4 */
|
||||
DDRB &= ~_BV(4);
|
||||
PORTB |= _BV(4);
|
||||
_delay_us(500);
|
||||
if(!(PINB & _BV(4)))
|
||||
return;
|
||||
#endif
|
||||
/* If power on boot or magic key set */
|
||||
if ((MCUSR & _BV(PORF)) || MagicBootKey == MAGIC_BOOT_KEY)
|
||||
{
|
||||
@@ -104,7 +113,7 @@ static void SetupHardware(void)
|
||||
/* Relocate the interrupt vector table to the bootloader section */
|
||||
MCUCR = (1 << IVCE);
|
||||
MCUCR = (1 << IVSEL);
|
||||
|
||||
|
||||
/* Initialize USB subsystem */
|
||||
USB_Init();
|
||||
}
|
||||
|
||||
@@ -49,5 +49,5 @@ include $(LUFA_PATH)/Build/lufa_doxygen.mk
|
||||
include $(LUFA_PATH)/Build/lufa_avrdude.mk
|
||||
include $(LUFA_PATH)/Build/lufa_atprogram.mk
|
||||
|
||||
flash: all
|
||||
$(AVRDUDE) -U flash:w:Bootloader.hex:i
|
||||
rev4: CC_FLAGS += -DSOFT_LEDS
|
||||
rev4: clean all
|
||||
|
||||
@@ -45,11 +45,21 @@ static const PROGMEM sdvx_config_t defaults = {
|
||||
HID_KEYBOARD_SC_KEYPAD_0_AND_INSERT,
|
||||
HID_KEYBOARD_SC_KEYPAD_0_AND_INSERT,
|
||||
HID_KEYBOARD_SC_KEYPAD_0_AND_INSERT},
|
||||
.ledBrightness = 31,
|
||||
.startColour = {0, BRIGHTNESS_MAX, 0}, // green
|
||||
};
|
||||
|
||||
void InitConfig(void) {
|
||||
// TODO: if config version changes, migrate settings
|
||||
// if config version changes, migrate settings
|
||||
switch(eeprom_read_word(&eeConfig.configVersion)) {
|
||||
// all of these fall through to upgrade each bit as we go
|
||||
case 2:
|
||||
// load in our defaults
|
||||
memcpy_P(&sdvxConfig, &defaults, CONFIG_SIZE);
|
||||
// update the ones that actually need upgrade
|
||||
eeprom_write_byte(&eeConfig.ledBrightness, sdvxConfig.ledBrightness);
|
||||
eeprom_update_block(&sdvxConfig.startColour, &eeConfig.startColour, sizeof(sdvxConfig.startColour));
|
||||
eeprom_write_word(&eeConfig.configVersion, CONFIG_VERSION);
|
||||
case CONFIG_VERSION: // nothing needs to change
|
||||
break;
|
||||
default:
|
||||
@@ -70,12 +80,23 @@ void UpdateConfig(void) {
|
||||
eeprom_update_block(&sdvxConfig, &eeConfig, CONFIG_SIZE);
|
||||
}
|
||||
|
||||
void LoadDefaults(void) {
|
||||
memcpy_P(&sdvxConfig, &defaults, CONFIG_SIZE);
|
||||
eeprom_update_block(&sdvxConfig, &eeConfig, CONFIG_SIZE);
|
||||
}
|
||||
|
||||
command_response_t HandleConfig(uint8_t* buffer) {
|
||||
command_t *command = (command_t*)buffer;
|
||||
switch(command->command) {
|
||||
case VERSION:
|
||||
command->data.version.version = FIRMWARE_VERSION;
|
||||
command->data.version.serial = 0xDEAD; // TODO set properly later
|
||||
#ifdef SOFT_LEDS
|
||||
// rev 4
|
||||
command->data.version.board = 0x4;
|
||||
#else
|
||||
// rev 6
|
||||
command->data.version.board = 0x6;
|
||||
#endif
|
||||
return RESPOND;
|
||||
case GETCONFIG:
|
||||
memcpy(&command->data.config, &sdvxConfig, CONFIG_SIZE);
|
||||
@@ -83,6 +104,9 @@ command_response_t HandleConfig(uint8_t* buffer) {
|
||||
case SETCONFIG:
|
||||
SetConfig(&command->data.config);
|
||||
return IGNORE;
|
||||
case DEFAULTCONFIG:
|
||||
LoadDefaults();
|
||||
return IGNORE;
|
||||
case RESET:
|
||||
return REBOOT;
|
||||
default:
|
||||
|
||||
@@ -12,9 +12,9 @@
|
||||
#define JOYSTICK_PPR (24 * 4)
|
||||
#define MAGIC_RESET_NUMBER 42
|
||||
// divide by 10 for actual version
|
||||
#define FIRMWARE_VERSION 14
|
||||
#define FIRMWARE_VERSION 15
|
||||
// increment whenever config structure has breaking changes
|
||||
#define CONFIG_VERSION 2
|
||||
#define CONFIG_VERSION 3
|
||||
|
||||
// not configurable since they're all the same switches
|
||||
#define SWITCH_DEBOUNCE 30
|
||||
@@ -46,19 +46,24 @@ typedef struct {
|
||||
// Reused for both tap or hold, at the end in case I decide to extend
|
||||
uint8_t macroLen; // placeholder not used yet
|
||||
uint8_t macroPin[4];
|
||||
|
||||
// added in firmware 1.5
|
||||
uint8_t ledBrightness; // rev6 and up
|
||||
RGB_t startColour;
|
||||
} ATTR_PACKED sdvx_config_t;
|
||||
|
||||
#define CONFIG_SIZE sizeof(sdvx_config_t)
|
||||
|
||||
typedef struct {
|
||||
uint16_t version;
|
||||
uint16_t serial;
|
||||
uint16_t board;
|
||||
} version_t;
|
||||
|
||||
typedef enum {
|
||||
GETCONFIG = 1,
|
||||
SETCONFIG = 2,
|
||||
VERSION = 3, // synced with bootloader, DO NOT CHANGE
|
||||
DEFAULTCONFIG = 4,
|
||||
RESET = MAGIC_RESET_NUMBER
|
||||
} command_action_t;
|
||||
|
||||
|
||||
@@ -63,9 +63,9 @@ def get_device_handle(context):
|
||||
# because there is the pseudo-composite-parent we ignore
|
||||
try:
|
||||
voltex = dev.open()
|
||||
print "Open success!"
|
||||
print("Open success!")
|
||||
except:
|
||||
print "Open fail"
|
||||
print("Open fail")
|
||||
return voltex
|
||||
|
||||
def bootloader_boot(device):
|
||||
@@ -93,13 +93,13 @@ def program_device(hex_data, device_info):
|
||||
# page sized chunks
|
||||
for addr in range(0, hex_data.maxaddr(), device_info['page_size']):
|
||||
# Compute the address range of the current page in the device
|
||||
current_page_range = range(addr, addr+device_info['page_size'])
|
||||
current_page_range = list(range(addr, addr+device_info['page_size']))
|
||||
|
||||
# Extract the data from the hex file at the specified start page
|
||||
# address and convert it to a regular list of bytes
|
||||
page_data = [hex_data[i] for i in current_page_range]
|
||||
|
||||
print("Writing address 0x%04X-0x%04X" % (current_page_range[0], current_page_range[-1]))
|
||||
print(("Writing address 0x%04X-0x%04X" % (current_page_range[0], current_page_range[-1])))
|
||||
|
||||
# Devices with more than 64KB of flash should shift down the page
|
||||
# address so that it is 16-bit (page size is guaranteed to be
|
||||
|
||||
@@ -14,13 +14,13 @@ const USB_Descriptor_HIDReport_Datatype_t PROGMEM LEDReport[] =
|
||||
// Globals
|
||||
HID_RI_REPORT_COUNT(8, LED_TOTAL_COUNT),
|
||||
HID_RI_REPORT_SIZE(8, 8),
|
||||
HID_RI_LOGICAL_MINIMUM(8, 0),
|
||||
HID_RI_LOGICAL_MAXIMUM(8, BRIGHTNESS_MAX),
|
||||
HID_RI_LOGICAL_MINIMUM(16, 0),
|
||||
HID_RI_LOGICAL_MAXIMUM(16, BRIGHTNESS_MAX),
|
||||
HID_RI_USAGE_PAGE(8, 0x0A), // Ordinals
|
||||
|
||||
// Locals
|
||||
0x79, STRING_ID_LED_Indiv, //HID_RI_STRING_MINIMUM(8, STRING_ID_LED_Indiv),
|
||||
0x89, STRING_ID_LED_Indiv + LED_TOTAL_COUNT, //HID_RI_STRING_MAXIMUM(8, STRING_ID_LED_Indiv + LED_COUNT),
|
||||
0x89, STRING_ID_LED_Indiv, //HID_RI_STRING_MINIMUM(8, STRING_ID_LED_Indiv),
|
||||
0x99, STRING_ID_LED_Indiv + LED_TOTAL_COUNT, //HID_RI_STRING_MAXIMUM(8, STRING_ID_LED_Indiv + LED_COUNT),
|
||||
HID_RI_USAGE_MINIMUM(8, 1), // LED 1
|
||||
HID_RI_USAGE_MAXIMUM(8, LED_TOTAL_COUNT), // LED 8 + buttons
|
||||
HID_RI_OUTPUT(8, HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_ABSOLUTE | HID_IOF_NON_VOLATILE),
|
||||
@@ -368,38 +368,71 @@ const USB_Descriptor_String_t PROGMEM ProductString = USB_STRING_DESCRIPTOR(L"Po
|
||||
const USB_Descriptor_String_t PROGMEM LEDString = USB_STRING_DESCRIPTOR(L"Pocket Voltex LEDs");
|
||||
const USB_Descriptor_String_t PROGMEM ControlsString = USB_STRING_DESCRIPTOR(L"Pocket Voltex Controls");
|
||||
const USB_Descriptor_String_t PROGMEM ConfigString = USB_STRING_DESCRIPTOR(L"Pocket Voltex Config");
|
||||
// There may be a better way to do this
|
||||
const USB_Descriptor_String_t PROGMEM LEDString_indiv[] = {
|
||||
USB_STRING_DESCRIPTOR(L"L1-B"),
|
||||
USB_STRING_DESCRIPTOR(L"L1-G"),
|
||||
USB_STRING_DESCRIPTOR(L"L1-R"),
|
||||
USB_STRING_DESCRIPTOR(L"L2-B"),
|
||||
USB_STRING_DESCRIPTOR(L"L2-G"),
|
||||
USB_STRING_DESCRIPTOR(L"L2-R"),
|
||||
USB_STRING_DESCRIPTOR(L"L3-B"),
|
||||
USB_STRING_DESCRIPTOR(L"L3-G"),
|
||||
USB_STRING_DESCRIPTOR(L"L3-R"),
|
||||
USB_STRING_DESCRIPTOR(L"L4-B"),
|
||||
USB_STRING_DESCRIPTOR(L"L4-G"),
|
||||
USB_STRING_DESCRIPTOR(L"L4-R"),
|
||||
USB_STRING_DESCRIPTOR(L"L5-B"),
|
||||
USB_STRING_DESCRIPTOR(L"L5-G"),
|
||||
USB_STRING_DESCRIPTOR(L"L5-R"),
|
||||
USB_STRING_DESCRIPTOR(L"L6-B"),
|
||||
USB_STRING_DESCRIPTOR(L"L6-G"),
|
||||
USB_STRING_DESCRIPTOR(L"L6-R"),
|
||||
USB_STRING_DESCRIPTOR(L"L7-B"),
|
||||
USB_STRING_DESCRIPTOR(L"L7-G"),
|
||||
USB_STRING_DESCRIPTOR(L"L7-R"),
|
||||
USB_STRING_DESCRIPTOR(L"L8-B"),
|
||||
USB_STRING_DESCRIPTOR(L"L8-G"),
|
||||
USB_STRING_DESCRIPTOR(L"L8-R"),
|
||||
USB_STRING_DESCRIPTOR(L"BT-A"),
|
||||
USB_STRING_DESCRIPTOR(L"BT-B"),
|
||||
USB_STRING_DESCRIPTOR(L"BT-C"),
|
||||
USB_STRING_DESCRIPTOR(L"BT-D"),
|
||||
USB_STRING_DESCRIPTOR(L"FX-L"),
|
||||
USB_STRING_DESCRIPTOR(L"FX-R"),
|
||||
|
||||
const USB_Descriptor_String_t PROGMEM
|
||||
LEDString_01 = USB_STRING_DESCRIPTOR(L"Top Left R"),
|
||||
LEDString_02 = USB_STRING_DESCRIPTOR(L"Top Left G"),
|
||||
LEDString_03 = USB_STRING_DESCRIPTOR(L"Top Left B"),
|
||||
LEDString_04 = USB_STRING_DESCRIPTOR(L"Top Right R"),
|
||||
LEDString_05 = USB_STRING_DESCRIPTOR(L"Top Right G"),
|
||||
LEDString_06 = USB_STRING_DESCRIPTOR(L"Top Right B"),
|
||||
LEDString_07 = USB_STRING_DESCRIPTOR(L"Upper Left R"),
|
||||
LEDString_08 = USB_STRING_DESCRIPTOR(L"Upper Left G"),
|
||||
LEDString_09 = USB_STRING_DESCRIPTOR(L"Upper Left B"),
|
||||
LEDString_10 = USB_STRING_DESCRIPTOR(L"Upper Right R"),
|
||||
LEDString_11 = USB_STRING_DESCRIPTOR(L"Upper Right G"),
|
||||
LEDString_12 = USB_STRING_DESCRIPTOR(L"Upper Right B"),
|
||||
LEDString_13 = USB_STRING_DESCRIPTOR(L"Lower Left R"),
|
||||
LEDString_14 = USB_STRING_DESCRIPTOR(L"Lower Left G"),
|
||||
LEDString_15 = USB_STRING_DESCRIPTOR(L"Lower Left B"),
|
||||
LEDString_16 = USB_STRING_DESCRIPTOR(L"Lower Right R"),
|
||||
LEDString_17 = USB_STRING_DESCRIPTOR(L"Lower Right G"),
|
||||
LEDString_18 = USB_STRING_DESCRIPTOR(L"Lower Right B"),
|
||||
LEDString_19 = USB_STRING_DESCRIPTOR(L"Bottom Left R"),
|
||||
LEDString_20 = USB_STRING_DESCRIPTOR(L"Bottom Left G"),
|
||||
LEDString_21 = USB_STRING_DESCRIPTOR(L"Bottom Left B"),
|
||||
LEDString_22 = USB_STRING_DESCRIPTOR(L"Bottom Right R"),
|
||||
LEDString_23 = USB_STRING_DESCRIPTOR(L"Bottom Right G"),
|
||||
LEDString_24 = USB_STRING_DESCRIPTOR(L"Bottom Right B"),
|
||||
LEDString_25 = USB_STRING_DESCRIPTOR(L"BT-A"),
|
||||
LEDString_26 = USB_STRING_DESCRIPTOR(L"BT-B"),
|
||||
LEDString_27 = USB_STRING_DESCRIPTOR(L"BT-C"),
|
||||
LEDString_28 = USB_STRING_DESCRIPTOR(L"BT-D"),
|
||||
LEDString_29 = USB_STRING_DESCRIPTOR(L"FX-L"),
|
||||
LEDString_30 = USB_STRING_DESCRIPTOR(L"FX-R"),
|
||||
LEDString_31 = USB_STRING_DESCRIPTOR(L"START");
|
||||
const USB_Descriptor_String_t *LEDString_indiv[] = {
|
||||
&LEDString_01,
|
||||
&LEDString_02,
|
||||
&LEDString_03,
|
||||
&LEDString_04,
|
||||
&LEDString_05,
|
||||
&LEDString_06,
|
||||
&LEDString_07,
|
||||
&LEDString_08,
|
||||
&LEDString_09,
|
||||
&LEDString_10,
|
||||
&LEDString_11,
|
||||
&LEDString_12,
|
||||
&LEDString_13,
|
||||
&LEDString_14,
|
||||
&LEDString_15,
|
||||
&LEDString_16,
|
||||
&LEDString_17,
|
||||
&LEDString_18,
|
||||
&LEDString_19,
|
||||
&LEDString_20,
|
||||
&LEDString_21,
|
||||
&LEDString_22,
|
||||
&LEDString_23,
|
||||
&LEDString_24,
|
||||
&LEDString_25,
|
||||
&LEDString_26,
|
||||
&LEDString_27,
|
||||
&LEDString_28,
|
||||
&LEDString_29,
|
||||
&LEDString_30,
|
||||
&LEDString_31,
|
||||
};
|
||||
|
||||
void USB_Process_BOS(void) {
|
||||
@@ -499,9 +532,9 @@ uint16_t CALLBACK_USB_GetDescriptor(const uint16_t wValue,
|
||||
Size = pgm_read_byte(&ConfigString.Header.Size);
|
||||
break;
|
||||
default:
|
||||
if(DescriptorNumber >= STRING_ID_LED_Indiv) {
|
||||
Address = &(LEDString_indiv[STRING_ID_LED_Indiv - DescriptorNumber]);
|
||||
Size = pgm_read_byte(&LEDString_indiv[STRING_ID_LED_Indiv - DescriptorNumber].Header.Size);
|
||||
if(DescriptorNumber >= STRING_ID_LED_Indiv && DescriptorNumber < (STRING_ID_LED_Indiv + LED_TOTAL_COUNT)) {
|
||||
Address = LEDString_indiv[DescriptorNumber - STRING_ID_LED_Indiv];
|
||||
Size = pgm_read_byte(&(LEDString_indiv[DescriptorNumber - STRING_ID_LED_Indiv]->Header.Size));
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -1,66 +1,13 @@
|
||||
#include "LED.h"
|
||||
|
||||
#define GND_COUNT 4
|
||||
// RGB * 2
|
||||
#define LED_PINS 6
|
||||
|
||||
// LED gnd 0-3 are on PC7-4
|
||||
#define GND_PORT PORTC
|
||||
#define GND_DDR DDRC
|
||||
#define GND_MASK 0xF0
|
||||
#define GND_OFFSET 4 // in bits
|
||||
|
||||
// LED power BGR BGR PB2-7
|
||||
#define LED_PORT PORTB
|
||||
#define LED_DDR DDRB
|
||||
#define LED_MASK (0b111111 << 2)
|
||||
|
||||
#define BRIGHTNESS_INCREMENT (BRIGHTNESS_LEVELS / BRIGHTNESS_DOWNSCALE)
|
||||
|
||||
#define UPDATE_HZ 100
|
||||
// prescaler is the div8
|
||||
#define TIMER_COMPARE ((F_CPU / 8 / UPDATE_HZ / GND_COUNT / BRIGHTNESS_DOWNSCALE)-1)
|
||||
#if TIMER_COMPARE > 255
|
||||
#error timer compare too large for timer register
|
||||
#endif
|
||||
|
||||
#define R 2
|
||||
#define G 1
|
||||
#define B 0
|
||||
|
||||
uint8_t leds[LED_PHYSICAL_COUNT];
|
||||
static volatile uint8_t leds_frontbuffer[LED_PHYSICAL_COUNT];
|
||||
|
||||
void led_init() {
|
||||
// all GNDs low level for high impedence or gnd
|
||||
GND_PORT &= ~GND_MASK;
|
||||
// all GNDs input
|
||||
GND_DDR &= ~GND_MASK;
|
||||
|
||||
// all LEDs off
|
||||
LED_PORT &= ~LED_MASK;
|
||||
// all LEDs output
|
||||
LED_DDR |= LED_MASK;
|
||||
|
||||
memset(leds, 0, LED_PHYSICAL_COUNT);
|
||||
memset((uint8_t*)leds_frontbuffer, 0, LED_PHYSICAL_COUNT);
|
||||
|
||||
// 64 light levels * 60Hz update * 4 different GND pins = 15360Hz
|
||||
// 520 clock cycles for our interrupt handler
|
||||
// CTC mode
|
||||
TCCR0A = _BV(WGM01);
|
||||
// clk/8 prescaler
|
||||
TCCR0B = _BV(CS01);
|
||||
OCR0A = TIMER_COMPARE;
|
||||
// Enable interrupt on OCR0A
|
||||
TIMSK0 = _BV(OCIE0A);
|
||||
// Clear interrupt
|
||||
TIFR0 = _BV(OCF0A);
|
||||
}
|
||||
|
||||
void led_commit(void) {
|
||||
memcpy((uint8_t*)leds_frontbuffer, leds, LED_PHYSICAL_COUNT);
|
||||
}
|
||||
// I can't decide if this is disgusting or delightful
|
||||
#ifdef SOFT_LEDS
|
||||
#include "LED_Driver_Software.c"
|
||||
#else
|
||||
#include "LED_Driver_SK9822.c"
|
||||
#endif
|
||||
|
||||
void led_set(uint8_t num, uint8_t r, uint8_t g, uint8_t b) {
|
||||
uint8_t offset = num * 3;
|
||||
@@ -147,69 +94,4 @@ void led_fade_all_rgb(RGB_t* colour, uint8_t strength) {
|
||||
|
||||
void led_set_all_rgb(RGB_t* colour) {
|
||||
led_set_all(colour->r, colour->g, colour->b);
|
||||
}
|
||||
|
||||
/* Straight voodoo magic, consult the Inline Assembler Cookbook
|
||||
Equivalent to:
|
||||
if(*led++ > brightness)
|
||||
out |= _BV(outPin)
|
||||
*/
|
||||
#define LED_PIN_SET(led, outPin) \
|
||||
__asm__ volatile( \
|
||||
"ld __tmp_reg__, %a["#led"]+ \n\t\
|
||||
cp %[bright], __tmp_reg__ \n\t\
|
||||
brcc skip%= \n\t\
|
||||
ori %[out], (1 << "#outPin") \n\t\
|
||||
skip%=:" \
|
||||
: [out] "+a" (out), [led] "+z" (led) /* outputs */ \
|
||||
: [bright] "r" (brightness) /* inputs */ )
|
||||
|
||||
// This function once took about 279 clock cycles.
|
||||
// Optimised GND accesses got it to 157
|
||||
// Optimised variables to static, got it to 100
|
||||
// Made LED setter assembly, got it to 90
|
||||
ISR(TIMER0_COMPA_vect) {
|
||||
/* Why are these static here instead of at the top of file?
|
||||
The compiler won't optimise 2 consecutive operations to use a register,
|
||||
and instead will perform a costly lds-sts every time. Making them
|
||||
static here will cache them in a local register.
|
||||
*/
|
||||
// Because we roll over on each loop and want to start at 0 this starts at max
|
||||
static uint8_t currentGnd = GND_COUNT - 1;
|
||||
// This saves us doing a costly dynamic _BV()
|
||||
static uint8_t currentGndMask = 0;
|
||||
static uint8_t brightness = BRIGHTNESS_LEVELS - BRIGHTNESS_INCREMENT;
|
||||
static volatile uint8_t* offset = &leds_frontbuffer[0];
|
||||
|
||||
uint8_t out = 0;
|
||||
|
||||
currentGnd++;
|
||||
currentGndMask >>= 1;
|
||||
if(currentGnd >= GND_COUNT) {
|
||||
currentGnd = 0;
|
||||
// Because we work backwards start at the high end and shift down
|
||||
currentGndMask = _BV(7);
|
||||
offset = &leds_frontbuffer[0];
|
||||
brightness += BRIGHTNESS_INCREMENT;
|
||||
// brightness rolls over cleanly due to being a multiple
|
||||
#if BRIGHTNESS_LEVELS != 256
|
||||
if(brightness > BRIGHTNESS_MAX)
|
||||
brightness = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
// Faster than loops
|
||||
// NOTE: ASM MACRO INCREMENTS OFFSET
|
||||
LED_PIN_SET(offset, 2);
|
||||
LED_PIN_SET(offset, 3);
|
||||
LED_PIN_SET(offset, 4);
|
||||
LED_PIN_SET(offset, 5);
|
||||
LED_PIN_SET(offset, 6);
|
||||
LED_PIN_SET(offset, 7);
|
||||
|
||||
// Turn off before switch
|
||||
LED_PORT &= ~LED_MASK;
|
||||
// Enable new ground
|
||||
GND_DDR = (GND_DDR & ~GND_MASK) | currentGndMask;
|
||||
LED_PORT |= out;
|
||||
}
|
||||
@@ -9,15 +9,12 @@
|
||||
|
||||
#define LED_COUNT 8
|
||||
#define LED_PHYSICAL_COUNT (LED_COUNT*3)
|
||||
// BT + FX
|
||||
#define LED_VIRTUAL_COUNT 6
|
||||
// BT + FX + START
|
||||
#define LED_VIRTUAL_COUNT 7
|
||||
#define LED_TOTAL_COUNT (LED_PHYSICAL_COUNT + LED_VIRTUAL_COUNT)
|
||||
// Internally how many brightness levels you can use - for higher res fades
|
||||
#define BRIGHTNESS_LEVELS 128
|
||||
#define BRIGHTNESS_LEVELS 256
|
||||
#define BRIGHTNESS_MAX (BRIGHTNESS_LEVELS-1)
|
||||
// How many are actually PWM'd, because the chip isn't that quick
|
||||
// MUST be a multiple of BRIGHTNESS_LEVELS
|
||||
#define BRIGHTNESS_DOWNSCALE 128
|
||||
|
||||
typedef struct {
|
||||
uint8_t r, g, b;
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
#include <Config.h>
|
||||
|
||||
#define R 0
|
||||
#define G 1
|
||||
#define B 2
|
||||
|
||||
static const uint8_t SK9822_map[] = {0, 2, 4, 6, 7, 5, 3, 1};
|
||||
|
||||
void led_init(void) {
|
||||
// SS/SCLK/MOSI PB0/1/2
|
||||
// We set SS to output so it's not used for SPI things
|
||||
// If SS = input, it can freeze SPI comms - see "SS Pin functionality"
|
||||
DDRB |= _BV(0) | _BV(1) | _BV(2);
|
||||
|
||||
// SPI enabled, master mode, CLK/4 speed
|
||||
SPCR = _BV(SPE)|_BV(MSTR);
|
||||
|
||||
// normal speed mode
|
||||
SPSR = 0;
|
||||
}
|
||||
|
||||
// busy wait
|
||||
void SPI_write(uint8_t val) {
|
||||
cli();
|
||||
SPDR = val;
|
||||
while(!(SPSR & _BV(SPIF)))
|
||||
;
|
||||
SPSR = _BV(SPIF); // clear flag
|
||||
sei();
|
||||
}
|
||||
|
||||
void led_commit(void) {
|
||||
SPI_write(0x00); // Start Frame
|
||||
SPI_write(0x00);
|
||||
SPI_write(0x00);
|
||||
SPI_write(0x00);
|
||||
|
||||
for (uint8_t i = 0; i < LED_COUNT; i++)
|
||||
{
|
||||
SPI_write(0xe0 | (sdvxConfig.ledBrightness & 31)); // Maximum global brightness
|
||||
uint8_t offset = SK9822_map[i] * 3;
|
||||
SPI_write(leds[offset+B]);
|
||||
SPI_write(leds[offset+G]);
|
||||
SPI_write(leds[offset+R]);
|
||||
}
|
||||
|
||||
// Reset frame - Only needed for SK9822, has no effect on APA102
|
||||
SPI_write(0x00);
|
||||
SPI_write(0x00);
|
||||
SPI_write(0x00);
|
||||
SPI_write(0x00);
|
||||
// End frame - 1 for every 16 LEDs
|
||||
SPI_write(0x00);
|
||||
}
|
||||
@@ -0,0 +1,128 @@
|
||||
#define GND_COUNT 4
|
||||
// RGB * 2
|
||||
#define LED_PINS 6
|
||||
|
||||
// LED gnd 0-3 are on PC7-4
|
||||
#define GND_PORT PORTC
|
||||
#define GND_DDR DDRC
|
||||
#define GND_MASK 0xF0
|
||||
#define GND_OFFSET 4 // in bits
|
||||
|
||||
// LED power BGR BGR PB2-7
|
||||
#define LED_PORT PORTB
|
||||
#define LED_DDR DDRB
|
||||
#define LED_MASK (0b111111 << 2)
|
||||
|
||||
// How many are actually PWM'd, because the chip isn't that quick
|
||||
// MUST be a multiple of BRIGHTNESS_LEVELS
|
||||
#define BRIGHTNESS_DOWNSCALE 128
|
||||
#define BRIGHTNESS_INCREMENT (BRIGHTNESS_LEVELS / BRIGHTNESS_DOWNSCALE)
|
||||
|
||||
#define UPDATE_HZ 100
|
||||
// prescaler is the div8
|
||||
#define TIMER_COMPARE ((F_CPU / 8 / UPDATE_HZ / GND_COUNT / BRIGHTNESS_DOWNSCALE)-1)
|
||||
#if TIMER_COMPARE > 255
|
||||
#error timer compare too large for timer register
|
||||
#endif
|
||||
|
||||
#define R 2
|
||||
#define G 1
|
||||
#define B 0
|
||||
|
||||
static volatile uint8_t leds_frontbuffer[LED_PHYSICAL_COUNT];
|
||||
|
||||
void led_init(void) {
|
||||
// all GNDs low level for high impedence or gnd
|
||||
GND_PORT &= ~GND_MASK;
|
||||
// all GNDs input
|
||||
GND_DDR &= ~GND_MASK;
|
||||
|
||||
// all LEDs off
|
||||
LED_PORT &= ~LED_MASK;
|
||||
// all LEDs output
|
||||
LED_DDR |= LED_MASK;
|
||||
|
||||
memset(leds, 0, LED_PHYSICAL_COUNT);
|
||||
memset((uint8_t*)leds_frontbuffer, 0, LED_PHYSICAL_COUNT);
|
||||
|
||||
// 64 light levels * 60Hz update * 4 different GND pins = 15360Hz
|
||||
// 520 clock cycles for our interrupt handler
|
||||
// CTC mode
|
||||
TCCR0A = _BV(WGM01);
|
||||
// clk/8 prescaler
|
||||
TCCR0B = _BV(CS01);
|
||||
OCR0A = TIMER_COMPARE;
|
||||
// Enable interrupt on OCR0A
|
||||
TIMSK0 = _BV(OCIE0A);
|
||||
// Clear interrupt
|
||||
TIFR0 = _BV(OCF0A);
|
||||
}
|
||||
|
||||
void led_commit(void) {
|
||||
memcpy((uint8_t*)leds_frontbuffer, leds, LED_PHYSICAL_COUNT);
|
||||
}
|
||||
|
||||
/* Straight voodoo magic, consult the Inline Assembler Cookbook
|
||||
Equivalent to:
|
||||
if(*led++ > brightness)
|
||||
out |= _BV(outPin)
|
||||
*/
|
||||
#define LED_PIN_SET(led, outPin) \
|
||||
__asm__ volatile( \
|
||||
"ld __tmp_reg__, %a["#led"]+ \n\t\
|
||||
cp %[bright], __tmp_reg__ \n\t\
|
||||
brcc skip%= \n\t\
|
||||
ori %[out], (1 << "#outPin") \n\t\
|
||||
skip%=:" \
|
||||
: [out] "+a" (out), [led] "+z" (led) /* outputs */ \
|
||||
: [bright] "r" (brightness) /* inputs */ )
|
||||
|
||||
// This function once took about 279 clock cycles.
|
||||
// Optimised GND accesses got it to 157
|
||||
// Optimised variables to static, got it to 100
|
||||
// Made LED setter assembly, got it to 90
|
||||
ISR(TIMER0_COMPA_vect) {
|
||||
/* Why are these static here instead of at the top of file?
|
||||
The compiler won't optimise 2 consecutive operations to use a register,
|
||||
and instead will perform a costly lds-sts every time. Making them
|
||||
static here will cache them in a local register.
|
||||
*/
|
||||
// Because we roll over on each loop and want to start at 0 this starts at max
|
||||
static uint8_t currentGnd = GND_COUNT - 1;
|
||||
// This saves us doing a costly dynamic _BV()
|
||||
static uint8_t currentGndMask = 0;
|
||||
static uint8_t brightness = BRIGHTNESS_LEVELS - BRIGHTNESS_INCREMENT;
|
||||
static volatile uint8_t* offset = &leds_frontbuffer[0];
|
||||
|
||||
uint8_t out = 0;
|
||||
|
||||
currentGnd++;
|
||||
currentGndMask >>= 1;
|
||||
if(currentGnd >= GND_COUNT) {
|
||||
currentGnd = 0;
|
||||
// Because we work backwards start at the high end and shift down
|
||||
currentGndMask = _BV(7);
|
||||
offset = &leds_frontbuffer[0];
|
||||
brightness += BRIGHTNESS_INCREMENT;
|
||||
// brightness rolls over cleanly due to being a multiple
|
||||
#if BRIGHTNESS_LEVELS != 256
|
||||
if(brightness > BRIGHTNESS_MAX)
|
||||
brightness = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
// Faster than loops
|
||||
// NOTE: ASM MACRO INCREMENTS OFFSET
|
||||
LED_PIN_SET(offset, 2);
|
||||
LED_PIN_SET(offset, 3);
|
||||
LED_PIN_SET(offset, 4);
|
||||
LED_PIN_SET(offset, 5);
|
||||
LED_PIN_SET(offset, 6);
|
||||
LED_PIN_SET(offset, 7);
|
||||
|
||||
// Turn off before switch
|
||||
LED_PORT &= ~LED_MASK;
|
||||
// Enable new ground
|
||||
GND_DDR = (GND_DDR & ~GND_MASK) | currentGndMask;
|
||||
LED_PORT |= out;
|
||||
}
|
||||
@@ -6,12 +6,22 @@
|
||||
#include "Macro.h"
|
||||
|
||||
#define LOAD_SWITCH(source, sourceBit, result, resultBit) result |= !((source) & _BV(sourceBit)) << resultBit
|
||||
// B 0,1
|
||||
#define SWITCH_MASKB 0b00000011
|
||||
// C 1,2
|
||||
#define SWITCH_MASKC 0b00000110
|
||||
// D 4,5,6,7
|
||||
#define SWITCH_MASKD 0b11110000
|
||||
|
||||
#ifdef SOFT_LEDS
|
||||
// B 0,1
|
||||
#define SWITCH_MASKB 0b00000011
|
||||
// C 1,2
|
||||
#define SWITCH_MASKC 0b00000110
|
||||
// D 4,5,6,7
|
||||
#define SWITCH_MASKD 0b11110000
|
||||
#else
|
||||
// B 4,5,6
|
||||
#define SWITCH_MASKB 0b01110000
|
||||
// C 2
|
||||
#define SWITCH_MASKC 0b00000100
|
||||
// D 4,5,6,7
|
||||
#define SWITCH_MASKD 0b11110000
|
||||
#endif
|
||||
|
||||
// How long to wait before moving to internal lighting
|
||||
#define HID_LED_TIMEOUT 2000
|
||||
@@ -104,12 +114,21 @@ uint8_t load_switches(void) {
|
||||
uint8_t tmp;
|
||||
uint8_t result = 0;
|
||||
|
||||
#ifdef SOFT_LEDS
|
||||
tmp = PINB;
|
||||
LOAD_SWITCH(tmp, 1, result, 1); // PINB1, A
|
||||
LOAD_SWITCH(tmp, 0, result, 5); // PINB0, FX L
|
||||
tmp = PINC;
|
||||
LOAD_SWITCH(tmp, 2, result, 0); // PINC2, START
|
||||
LOAD_SWITCH(tmp, 1, result, 7); // PINC1, MACRO
|
||||
#else
|
||||
tmp = PINB;
|
||||
LOAD_SWITCH(tmp, 6, result, 1); // PINB6, A
|
||||
LOAD_SWITCH(tmp, 5, result, 5); // PINB5, FX L
|
||||
LOAD_SWITCH(tmp, 4, result, 7); // PINB4, MACRO
|
||||
tmp = PINC;
|
||||
LOAD_SWITCH(tmp, 2, result, 0); // PINC2, START
|
||||
#endif
|
||||
tmp = PIND;
|
||||
LOAD_SWITCH(tmp, 7, result, 2); // PIND7, B
|
||||
LOAD_SWITCH(tmp, 5, result, 3); // PIND5, C
|
||||
@@ -191,6 +210,10 @@ int main(void)
|
||||
led_set_rgb(ledMap[i-1], &sdvxConfig.fxColour);
|
||||
}
|
||||
}
|
||||
// START
|
||||
if(switches[0].state) {
|
||||
led_set_all_rgb(&sdvxConfig.startColour);
|
||||
}
|
||||
}
|
||||
}
|
||||
// knob lights go above all
|
||||
@@ -208,9 +231,8 @@ int main(void)
|
||||
void SetupHardware()
|
||||
{
|
||||
uint8_t i;
|
||||
|
||||
/* Disable watchdog if enabled by bootloader/fuses */
|
||||
MCUSR &= ~(1 << WDRF);
|
||||
MCUSR &= ~_BV(WDRF);
|
||||
wdt_disable();
|
||||
|
||||
for(i = 0; i < SWITCH_COUNT; i++) {
|
||||
@@ -225,7 +247,9 @@ void SetupHardware()
|
||||
// Pullups
|
||||
PORTB |= SWITCH_MASKB;
|
||||
PORTC |= SWITCH_MASKC;
|
||||
#ifdef SOFT_LEDS
|
||||
PORTC &= ~_BV(1); // RESET has its own pullup
|
||||
#endif
|
||||
PORTD |= SWITCH_MASKD;
|
||||
|
||||
/* Hardware Initialization */
|
||||
@@ -364,15 +388,17 @@ void CALLBACK_HID_Device_ProcessHIDReport(USB_ClassInfo_HID_Device_t* const HIDI
|
||||
hidTimeout = 0;
|
||||
|
||||
LED_Report_t* LEDReport = (LED_Report_t*)ReportData;
|
||||
//memcpy((uint8_t*)leds, LEDReport->mainLights, LED_PHYSICAL_COUNT);
|
||||
#ifdef SOFT_LEDS
|
||||
// Load the user set colours as R/G/B instead of B/G/R
|
||||
for(uint8_t i = 0; i < LED_PHYSICAL_COUNT; ) {
|
||||
uint8_t offset = i+2;
|
||||
for(uint8_t j = 0; j < 3; j++) {
|
||||
// cast away the volatile for faster ops
|
||||
leds[i++] = LEDReport->mainLights[offset--];
|
||||
}
|
||||
}
|
||||
#else
|
||||
memcpy((uint8_t*)leds, LEDReport->mainLights, LED_PHYSICAL_COUNT);
|
||||
#endif
|
||||
|
||||
// Keep normal lights but override when we get flashes on BT or FX
|
||||
// BT LEDs
|
||||
@@ -387,6 +413,9 @@ void CALLBACK_HID_Device_ProcessHIDReport(USB_ClassInfo_HID_Device_t* const HIDI
|
||||
led_set_rgb(ledMap[i], &sdvxConfig.fxColour);
|
||||
}
|
||||
}
|
||||
if(LEDReport->btFx[6]) { // start
|
||||
led_set_all_rgb(&sdvxConfig.startColour);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,283 @@
|
||||
#include "PocketVoltex.h"
|
||||
#include "Config.h"
|
||||
#include "Encoder.h"
|
||||
#include "LED.h"
|
||||
#include "LEDPatterns.h"
|
||||
#include "Macro.h"
|
||||
#include <util/delay.h>
|
||||
|
||||
#undef SK9822_BRIGHTNESS
|
||||
#define SK9822_BRIGHTNESS 1
|
||||
|
||||
#define LOAD_SWITCH(source, sourceBit, result, resultBit) result |= !((source) & _BV(sourceBit)) << resultBit
|
||||
|
||||
// B 0,4,5
|
||||
#define SWITCH_MASKB 0b00110001
|
||||
// C 2
|
||||
#define SWITCH_MASKC 0b00000100
|
||||
// D 4,5,6,7
|
||||
#define SWITCH_MASKD 0b11110000
|
||||
|
||||
// How long to wait before moving to internal lighting
|
||||
#define HID_LED_TIMEOUT 2000
|
||||
|
||||
// If I add more buttons with the macro key I don't need to care
|
||||
#if SWITCH_COUNT <= 8
|
||||
#define SWITCH_BITMASK_UINT uint8_t
|
||||
#elif SWITCH_COUNT <= 16
|
||||
#define SWITCH_BITMASK_UINT uint16_t
|
||||
#else
|
||||
#error TOO MANY SWITCHES
|
||||
#endif
|
||||
typedef struct
|
||||
{
|
||||
int8_t X; // VOL-L
|
||||
int8_t Y; // VOL-R
|
||||
SWITCH_BITMASK_UINT Buttons; // bitmask
|
||||
} Joystick_Report_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint8_t Modifier; // Keyboard modifier byte indicating pressed modifier keys (\c HID_KEYBOARD_MODIFER_* masks)
|
||||
uint8_t Reserved; // Reserved for OEM use, always set to 0.
|
||||
uint8_t KeyCode[SWITCH_COUNT]; // Length determined by the number of keys that can be reported
|
||||
} Keyboard_Report_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint8_t mainLights[LED_PHYSICAL_COUNT];
|
||||
uint8_t btFx[6];
|
||||
} LED_Report_t;
|
||||
|
||||
static uint8_t updateLEDs = 1;
|
||||
|
||||
/** LUFA HID Class driver interface configuration and state information. This structure is
|
||||
* passed to all HID Class driver functions, so that multiple instances of the same class
|
||||
* within a device can be differentiated from one another.
|
||||
*/
|
||||
USB_ClassInfo_HID_Device_t Inputs_HID_Interface =
|
||||
{
|
||||
.Config =
|
||||
{
|
||||
.InterfaceNumber = INTERFACE_ID_Inputs,
|
||||
.ReportINEndpoint =
|
||||
{
|
||||
.Address = INPUTS_EPADDR,
|
||||
.Size = INPUTS_EPSIZE,
|
||||
.Banks = 1,
|
||||
},
|
||||
.PrevReportINBuffer = NULL,
|
||||
.PrevReportINBufferSize = MAX(MAX(sizeof(Keyboard_Report_t), sizeof(Joystick_Report_t)), sizeof(USB_MouseReport_Data_t)),
|
||||
},
|
||||
};
|
||||
|
||||
USB_ClassInfo_HID_Device_t LED_HID_Interface =
|
||||
{
|
||||
.Config =
|
||||
{
|
||||
.InterfaceNumber = INTERFACE_ID_LED,
|
||||
.ReportINEndpoint =
|
||||
{
|
||||
.Address = LED_EPADDR,
|
||||
.Size = LED_EPSIZE,
|
||||
.Banks = 1,
|
||||
},
|
||||
.PrevReportINBuffer = NULL,
|
||||
.PrevReportINBufferSize = sizeof(LED_Report_t),
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
// Set to max already so we have our init flash
|
||||
|
||||
void RebootToBootloader(void) {
|
||||
/* Disconnect from the host - USB interface will be reset later along with the AVR */
|
||||
USB_Detach();
|
||||
|
||||
// Back to the bootloader
|
||||
wdt_enable(WDTO_250MS);
|
||||
while(1);
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
GlobalInterruptDisable();
|
||||
|
||||
InitConfig();
|
||||
|
||||
SetupHardware();
|
||||
|
||||
GlobalInterruptEnable();
|
||||
|
||||
while(1) {
|
||||
int8_t x = encoder_get(0);
|
||||
int8_t y = encoder_get(1);
|
||||
led_knobs_update(x, y);
|
||||
encoder_set(0, 0);
|
||||
encoder_set(1, 0);
|
||||
if(led_on_frame()) {
|
||||
updateLEDs = 1;
|
||||
}
|
||||
|
||||
if(updateLEDs) {
|
||||
updateLEDs = 0;
|
||||
led_set_all(32,32,32);
|
||||
//led_pattern_animate();
|
||||
// knob lights go above all
|
||||
led_overlay_knobs();
|
||||
led_commit();
|
||||
}
|
||||
_delay_ms(1);
|
||||
}
|
||||
|
||||
for (;;)
|
||||
{
|
||||
HID_Device_USBTask(&Inputs_HID_Interface);
|
||||
HID_Device_USBTask(&LED_HID_Interface);
|
||||
USB_USBTask();
|
||||
|
||||
Endpoint_SelectEndpoint(CONFIG_OUT_EPADDR);
|
||||
if (Endpoint_IsOUTReceived()) {
|
||||
uint8_t ReceivedData[COMMAND_BYTES];
|
||||
Endpoint_Read_Stream_LE(ReceivedData, COMMAND_BYTES, NULL);
|
||||
Endpoint_ClearOUT();
|
||||
|
||||
command_response_t respond = HandleConfig(ReceivedData);
|
||||
switch(respond) {
|
||||
// we are returning the requested data
|
||||
case RESPOND:
|
||||
Endpoint_SelectEndpoint(CONFIG_IN_EPADDR);
|
||||
Endpoint_Write_Stream_LE(ReceivedData, COMMAND_BYTES, NULL);
|
||||
Endpoint_ClearIN();
|
||||
break;
|
||||
case REBOOT:
|
||||
RebootToBootloader();
|
||||
break;
|
||||
// no data to return
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(updateLEDs) {
|
||||
updateLEDs = 0;
|
||||
led_set_all(32,32,32);
|
||||
//led_pattern_animate();
|
||||
// knob lights go above all
|
||||
led_overlay_knobs();
|
||||
led_commit();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Configures the board hardware and chip peripherals */
|
||||
void SetupHardware()
|
||||
{
|
||||
/* Disable watchdog if enabled by bootloader/fuses */
|
||||
MCUSR &= ~_BV(WDRF);
|
||||
wdt_disable();
|
||||
|
||||
// Inputs
|
||||
DDRB &= ~SWITCH_MASKB;
|
||||
DDRC &= ~SWITCH_MASKC;
|
||||
DDRD &= ~SWITCH_MASKD;
|
||||
// Pullups
|
||||
PORTB |= SWITCH_MASKB;
|
||||
PORTC |= SWITCH_MASKC;
|
||||
PORTD |= SWITCH_MASKD;
|
||||
|
||||
/* Hardware Initialization */
|
||||
encoder_init();
|
||||
led_init();
|
||||
led_pattern_init();
|
||||
|
||||
//USB_Init();
|
||||
}
|
||||
|
||||
/** HID class driver callback function for the creation of HID reports to the host.
|
||||
*
|
||||
* \param[in] HIDInterfaceInfo Pointer to the HID class interface configuration structure being referenced
|
||||
* \param[in,out] ReportID Report ID requested by the host if non-zero, otherwise callback should set to the generated report ID
|
||||
* \param[in] ReportType Type of the report to create, either HID_REPORT_ITEM_In or HID_REPORT_ITEM_Feature
|
||||
* \param[out] ReportData Pointer to a buffer where the created report should be stored
|
||||
* \param[out] ReportSize Number of bytes written in the report (or zero if no report is to be sent)
|
||||
*
|
||||
* \return Boolean \c true to force the sending of the report, \c false to let the library determine if it needs to be sent
|
||||
*/
|
||||
bool CALLBACK_HID_Device_CreateHIDReport(USB_ClassInfo_HID_Device_t* const HIDInterfaceInfo,
|
||||
uint8_t* const ReportID,
|
||||
const uint8_t ReportType,
|
||||
void* ReportData,
|
||||
uint16_t* const ReportSize)
|
||||
{
|
||||
*ReportSize = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
/** HID class driver callback function for the processing of HID reports from the host.
|
||||
*
|
||||
* \param[in] HIDInterfaceInfo Pointer to the HID class interface configuration structure being referenced
|
||||
* \param[in] ReportID Report ID of the received report from the host
|
||||
* \param[in] ReportType The type of report that the host has sent, either HID_REPORT_ITEM_Out or HID_REPORT_ITEM_Feature
|
||||
* \param[in] ReportData Pointer to a buffer where the received report has been stored
|
||||
* \param[in] ReportSize Size in bytes of the received HID report
|
||||
*/
|
||||
void CALLBACK_HID_Device_ProcessHIDReport(USB_ClassInfo_HID_Device_t* const HIDInterfaceInfo,
|
||||
const uint8_t ReportID,
|
||||
const uint8_t ReportType,
|
||||
const void* ReportData,
|
||||
const uint16_t ReportSize)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
/** Event handler for the library USB Connection event. */
|
||||
void EVENT_USB_Device_Connect(void)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/** Event handler for the library USB Disconnection event. */
|
||||
void EVENT_USB_Device_Disconnect(void)
|
||||
{
|
||||
led_set_all(0,0,0);
|
||||
led_commit();
|
||||
}
|
||||
|
||||
/** Event handler for the library USB Configuration Changed event. */
|
||||
void EVENT_USB_Device_ConfigurationChanged(void)
|
||||
{
|
||||
Endpoint_ConfigureEndpoint(CONFIG_OUT_EPADDR, EP_TYPE_BULK, CONFIG_EPSIZE, 1);
|
||||
Endpoint_ConfigureEndpoint(CONFIG_IN_EPADDR, EP_TYPE_BULK, CONFIG_EPSIZE, 1);
|
||||
HID_Device_ConfigureEndpoints(&Inputs_HID_Interface);
|
||||
HID_Device_ConfigureEndpoints(&LED_HID_Interface);
|
||||
|
||||
USB_Device_EnableSOFEvents();
|
||||
}
|
||||
|
||||
/** Event handler for the library USB Control Request reception event. */
|
||||
void EVENT_USB_Device_ControlRequest(void)
|
||||
{
|
||||
USB_Process_BOS();
|
||||
HID_Device_ProcessControlRequest(&Inputs_HID_Interface);
|
||||
HID_Device_ProcessControlRequest(&LED_HID_Interface);
|
||||
}
|
||||
|
||||
/** Event handler for the USB device Start Of Frame event. */
|
||||
void EVENT_USB_Device_StartOfFrame(void)
|
||||
{
|
||||
HID_Device_MillisecondElapsed(&Inputs_HID_Interface);
|
||||
HID_Device_MillisecondElapsed(&LED_HID_Interface);
|
||||
|
||||
int8_t x = encoder_get(0);
|
||||
int8_t y = encoder_get(1);
|
||||
led_knobs_update(x, y);
|
||||
encoder_set(0, 0);
|
||||
encoder_set(1, 0);
|
||||
// we use a sentinel since this is actually inside an interrupt!
|
||||
// less LED flicker if ran outside
|
||||
if(led_on_frame()) {
|
||||
updateLEDs = 1;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
avrdude -c usbasp -p atmega16u2 -U lfuse:w:0xde:m -U hfuse:w:0xda:m -U efuse:w:0xfe:m -U flash:w:PocketVoltex_WithBoot.hex:i
|
||||
@@ -20,10 +20,10 @@ OPTIMIZATION = s
|
||||
TARGET = PocketVoltex
|
||||
SRC = $(TARGET).c asciihid.c Descriptors.c Config.c Encoder.c LED.c LEDPatterns.c Macro.c $(LUFA_SRC_USB) $(LUFA_SRC_USBCLASS)
|
||||
LUFA_PATH = ../LUFA
|
||||
CC_FLAGS = -DUSE_LUFA_CONFIG_HEADER -IConfig/
|
||||
CC_FLAGS = -DUSE_LUFA_CONFIG_HEADER -IConfig/ -Werror
|
||||
LD_FLAGS =
|
||||
|
||||
AVRDUDE = avrdude -B 8 -c usbasp -p $(MCU)
|
||||
AVRDUDE = avrdude -c usbasp -p $(MCU)
|
||||
|
||||
|
||||
# Default target
|
||||
@@ -40,12 +40,28 @@ include $(LUFA_PATH)/Build/lufa_hid.mk
|
||||
include $(LUFA_PATH)/Build/lufa_avrdude.mk
|
||||
include $(LUFA_PATH)/Build/lufa_atprogram.mk
|
||||
|
||||
# This does not work with variables as pre-requisites. Use `make test TARGET=TestingApp`
|
||||
#test: TARGET = TestingApp
|
||||
test: all
|
||||
cat TestingApp.hex | grep -v '^:00000001FF' > TestFull.hex
|
||||
cat DFU/BootloaderUSB.hex >> TestFull.hex
|
||||
|
||||
$(TARGET)_WithBoot.hex: $(TARGET).hex
|
||||
cat $(TARGET).hex | grep -v '^:00000001FF' > $(TARGET)_WithBoot.hex
|
||||
cat DFU/BootloaderUSB.hex >> $(TARGET)_WithBoot.hex
|
||||
|
||||
debug: CC_FLAGS += -DDEBUG
|
||||
debug: clean flash
|
||||
|
||||
init: erase wfuse flashboot disablereset flash
|
||||
rev4: CC_FLAGS += -DSOFT_LEDS
|
||||
rev4: clean all
|
||||
|
||||
initboot: erase wfuse flashboot
|
||||
initboot_rev4: erase wfuse flashboot_rev4
|
||||
|
||||
init: $(TARGET)_WithBoot.hex
|
||||
$(AVRDUDE) -U lfuse:w:0xde:m -U hfuse:w:0xda:m -U efuse:w:0xfe:m -U flash:w:$(TARGET)_WithBoot.hex:i
|
||||
init_rev4: initboot_rev4 disablereset flash
|
||||
|
||||
erase:
|
||||
$(AVRDUDE) -e
|
||||
@@ -56,16 +72,24 @@ rfuse:
|
||||
wfuse:
|
||||
# no more HWB, boot directly to bootloader
|
||||
$(AVRDUDE) -U lfuse:w:0xde:m -U hfuse:w:0xda:m -U efuse:w:0xfe:m
|
||||
|
||||
|
||||
disablereset:
|
||||
$(AVRDUDE) -U lfuse:w:0xde:m -U hfuse:w:0x9a:m -U efuse:w:0xfe:m
|
||||
|
||||
# To make this hex, compile the bootloader up a level
|
||||
flashboot_rev4:
|
||||
$(AVRDUDE) -U flash:w:DFU/BootloaderUSB_rev4.hex:i
|
||||
flashboot:
|
||||
$(AVRDUDE) -U flash:w:DFU/BootloaderUSB.hex:i
|
||||
|
||||
flash: all
|
||||
cd DFU && python control_bootloader.py atmega16u2 ../$(TARGET).hex
|
||||
|
||||
flash_with_boot: $(TARGET)_WithBoot.hex
|
||||
$(AVRDUDE) -U flash:w:$(TARGET)_WithBoot.hex:i
|
||||
|
||||
testflash: test wfuse
|
||||
$(AVRDUDE) -U flash:w:TestFull.hex:i
|
||||
|
||||
md5: all
|
||||
md5sum $(TARGET).bin
|
||||
@@ -0,0 +1,8 @@
|
||||
@echo off
|
||||
:loop
|
||||
make init
|
||||
IF %ERRORLEVEL% EQU 0 (
|
||||
echo Success!
|
||||
ping -n 5 127.0.0.1 >nul
|
||||
)
|
||||
goto loop
|
||||
|
Before Width: | Height: | Size: 7.7 MiB |
@@ -1,65 +0,0 @@
|
||||
Make visible only the layers you care for
|
||||
|
||||
File -> Save as -> DXF/DWG
|
||||
Autocad 2007, DXF, Metric
|
||||
Check "Export pads" "On dedicated hole layers"
|
||||
Tracks "Export with rounded"
|
||||
Primitives to export with zero line width "All"
|
||||
Layers "Currently visible"
|
||||
|
||||
Open dxf in inkscape
|
||||
>Manual scale
|
||||
>Factor 1.0
|
||||
x/y axis origin 0,0
|
||||
|
||||
Delete via layer
|
||||
|
||||
Select the pad which is the origin
|
||||
Go to transform->move and see where it is in mm by unchecking Relative Move.
|
||||
Select all objects and relative move -(pad position - pad size / 2) in mm
|
||||
Do this for all layers
|
||||
Select all and relative move -(pad stroke width / 2) IN PIXELS
|
||||
Delete pad layer
|
||||
|
||||
For board shape:
|
||||
Select the 2 curves, right click "Move to layer" keepout
|
||||
Select all
|
||||
Path->Combine
|
||||
Go to node tool (below mouse, left toolbar)
|
||||
Select all again
|
||||
Click "Join selected nodes" in toolbar
|
||||
|
||||
Delete layer 0
|
||||
|
||||
For tracks:
|
||||
Select all
|
||||
Stroke style -> Width = the track width (use mm)
|
||||
Cap: round
|
||||
Path->Combine
|
||||
Path->Stroke to path
|
||||
|
||||
For artwork laser cutting output:
|
||||
Cross reference with altium to make layers for tracks
|
||||
1.5mm
|
||||
1.2mm
|
||||
1mm
|
||||
0.75mm
|
||||
0.5mm
|
||||
0.254mm
|
||||
Raster Fill
|
||||
Path->Combine each individual letter (todo: actually needed?)
|
||||
Also do long lines in 0.75mm layer
|
||||
|
||||
You may need to Path->Union everything for artwork layers to render nicely
|
||||
|
||||
Extensions->Modify Path->Flatten Beziers (flatness 0.1)
|
||||
Save as -> Desktop cutting plotter dxf
|
||||
Use LWPOLYLINE
|
||||
Base unit mm
|
||||
Visible layers only
|
||||
|
||||
Altium seems to like exporting for these offsets,
|
||||
sometimes the decimals are different, check them.
|
||||
-100.579
|
||||
-112.896
|
||||
Then do the 0.5px too
|
||||
@@ -0,0 +1,563 @@
|
||||
use <imports/font.ttf>
|
||||
use <imports/dimlines.scad>
|
||||
|
||||
include <board_primitives.scad>
|
||||
use <board_shape.scad>
|
||||
use <case.scad>
|
||||
use <utils.scad>
|
||||
|
||||
$fn = 128;
|
||||
|
||||
// palette, adjust actual values if needed
|
||||
black = "black";
|
||||
white = "white";
|
||||
grey = "gray";
|
||||
blue = [0.15,0.5,0.75,1];
|
||||
pink = [0.86,0.24,0.46,1];
|
||||
orange = "orange";
|
||||
|
||||
border_offset = 1;
|
||||
|
||||
// enabled in commandline flags
|
||||
enable_bleed = 0;
|
||||
module bleed_trim() {
|
||||
if(enable_bleed) {
|
||||
board();
|
||||
} else {
|
||||
art_outline();
|
||||
}
|
||||
}
|
||||
|
||||
module box_polygon(width, height, inset_len_bot, inset_len_top,
|
||||
inset_len_side, inset = 1.6) {
|
||||
// always nice angles
|
||||
inset_begin = inset > 0 ? inset : -inset;
|
||||
inset_end = inset > 0 ? -inset : inset;
|
||||
bot_off = (width - inset_len_bot) / 2;
|
||||
top_off = (width - inset_len_top) / 2;
|
||||
side_off = (height - inset_len_side) / 2;
|
||||
translate([-width/2, -height/2])
|
||||
polygon([
|
||||
// bottom
|
||||
[0,0],
|
||||
[bot_off,0],
|
||||
[bot_off+inset_begin, inset],
|
||||
[width-bot_off+inset_end,inset],
|
||||
[width-bot_off,0],
|
||||
[width,0],
|
||||
// right
|
||||
[width, side_off],
|
||||
[width-inset, side_off+inset_begin],
|
||||
[width-inset, height-side_off+inset_end],
|
||||
[width, height-side_off],
|
||||
[width, height],
|
||||
// top
|
||||
[width-top_off, height],
|
||||
[width-top_off+inset_end, height-inset],
|
||||
[top_off+inset_begin, height-inset],
|
||||
[top_off,height],
|
||||
[0, height],
|
||||
// left
|
||||
[0, height-side_off],
|
||||
[inset, height-side_off+inset_end],
|
||||
[inset, side_off+inset_begin],
|
||||
[0, side_off],
|
||||
]);
|
||||
}
|
||||
|
||||
module box_outline(thick, width, height, inset_len_bot, inset_len_top,
|
||||
inset_len_side, inset = 1.6) {
|
||||
difference() {
|
||||
box_polygon(width, height, inset_len_bot, inset_len_top,
|
||||
inset_len_side, inset);
|
||||
offset(-thick)
|
||||
box_polygon(width, height, inset_len_bot, inset_len_top,
|
||||
inset_len_side, inset);
|
||||
}
|
||||
}
|
||||
|
||||
btbox_width = 125;
|
||||
btbox_height = 35;
|
||||
btbox_inset_len_bot = 49.5;
|
||||
btbox_inset_len_top = 69;
|
||||
btbox_inset_len_side = 25;
|
||||
module bt_box_polygon() {
|
||||
translate([0, bt_map[1][1]-1])
|
||||
box_polygon(btbox_width, btbox_height, btbox_inset_len_bot,
|
||||
btbox_inset_len_top, btbox_inset_len_side);
|
||||
}
|
||||
module bt_box_outline() {
|
||||
translate([0, bt_map[1][1]-1])
|
||||
box_outline(0.8, btbox_width, btbox_height, btbox_inset_len_bot,
|
||||
btbox_inset_len_top, btbox_inset_len_side);
|
||||
}
|
||||
|
||||
fxbox_width = 44;
|
||||
fxbox_height = 19;
|
||||
fxbox_inset_len_bot = 20;
|
||||
fxbox_inset_len_top = 20;
|
||||
fxbox_inset_len_side = 10;
|
||||
module fx_box_polygon() {
|
||||
box_polygon(fxbox_width, fxbox_height, fxbox_inset_len_bot,
|
||||
fxbox_inset_len_top, fxbox_inset_len_side);
|
||||
}
|
||||
module fx_box_outline() {
|
||||
box_outline(0.8, fxbox_width, fxbox_height, fxbox_inset_len_bot,
|
||||
fxbox_inset_len_top, fxbox_inset_len_side);
|
||||
}
|
||||
|
||||
module fx_inner() {
|
||||
intersection() {
|
||||
fx()
|
||||
offset(-1.6)
|
||||
fx_box_polygon();
|
||||
|
||||
bleed_trim();
|
||||
}
|
||||
}
|
||||
|
||||
module fx_outline() {
|
||||
intersection() {
|
||||
fx()
|
||||
fx_box_outline();
|
||||
|
||||
bleed_trim();
|
||||
}
|
||||
}
|
||||
|
||||
module fx_keepout() {
|
||||
fx()
|
||||
fx_box_polygon();
|
||||
}
|
||||
|
||||
module sdvx_text(string, size=3) {
|
||||
text(string, font="Digital:style=Regular", size=size, halign="center", valign="center");
|
||||
}
|
||||
|
||||
module tick(width, height, radius) {
|
||||
translate([-width/2,radius]) {
|
||||
//square([width,height]);
|
||||
square([width, height-width]);
|
||||
translate([width/2,height-width])
|
||||
circle(d=width);
|
||||
}
|
||||
}
|
||||
|
||||
module knob_highlights(offset) {
|
||||
intersection() {
|
||||
bleed_trim();
|
||||
translate(offset)
|
||||
ring(encoder_radius_board-top_plate_shrink, 3);
|
||||
}
|
||||
}
|
||||
|
||||
module knob_ticks() {
|
||||
ticks_radius = encoder_radius + 1.9;
|
||||
ticks = [
|
||||
// ticks per rev, width, height
|
||||
[128, 0.2, 0.75],
|
||||
[64, 0.2, 1.5],
|
||||
[16, 0.4, 2],
|
||||
[8, 0.8, 2.5],
|
||||
[4, 1, 3.3],
|
||||
];
|
||||
intersection() {
|
||||
bleed_trim();
|
||||
union() {
|
||||
encoders()
|
||||
ring(encoder_radius+top_plate_shrink*2, 0.4);
|
||||
|
||||
for(t = ticks) {
|
||||
interval = 360/t[0];
|
||||
for(i = [0:t[0]-1]) {
|
||||
rot = interval * i;
|
||||
encoders()
|
||||
rotate([0,0,rot])
|
||||
tick(t[1], t[2], ticks_radius);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module perspective_mesh(thick, num_horiz, num_vert, bottom_width, top_width, top_height) {
|
||||
translate([-bottom_width/2,0])
|
||||
for(x = [0:num_horiz]) {
|
||||
logguh = ((x / num_horiz) * 9) + 1; // input 1-10 so log is 0-1
|
||||
height = top_height * log(logguh);
|
||||
polygon([
|
||||
[0, height],
|
||||
[bottom_width, height],
|
||||
[bottom_width, height+thick],
|
||||
[0, height+thick]
|
||||
]);
|
||||
}
|
||||
top_offset = (bottom_width - top_width) / 2;
|
||||
translate([-bottom_width/2,0])
|
||||
for(y = [0:num_vert]) {
|
||||
startx = bottom_width / num_vert * y;
|
||||
endx = top_width / num_vert * y;
|
||||
polygon([
|
||||
[startx, 0],
|
||||
[endx - thick/2 + top_offset, top_height],
|
||||
[endx + thick/2 + top_offset, top_height],
|
||||
[startx+thick, 0]
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
module labels() {
|
||||
// BT
|
||||
for(s = [ for (i = [1:4]) bt_map[i] ]) {
|
||||
translate([s.x, s.y - 13])
|
||||
sdvx_text(s[4]);
|
||||
}
|
||||
// FX
|
||||
for(s = fx_map) {
|
||||
translate([s.x, s.y + 13])
|
||||
sdvx_text(s[4]);
|
||||
}
|
||||
// START
|
||||
s = bt_map[0];
|
||||
translate([s.x + 0.15, s.y - 11.5])
|
||||
sdvx_text(s[4]);
|
||||
|
||||
// MACRO
|
||||
translate(macro_pos + [0,3.5])
|
||||
sdvx_text("MACRO", 1.5);
|
||||
|
||||
// VOL
|
||||
translate([0,-24]) {
|
||||
translate(encoder_map[0] + [0.5,0])
|
||||
sdvx_text("VOL-L", 4);
|
||||
translate(encoder_map[1] + [0,0])
|
||||
sdvx_text("VOL-R", 4);
|
||||
}
|
||||
}
|
||||
|
||||
module start_arrows() {
|
||||
tri_base = 7;
|
||||
tri_height = 2.5;
|
||||
s = bt_map[0];
|
||||
for(i = [-1:2:1]) {
|
||||
translate([s.x + i*12, s.y - tri_base/2])
|
||||
polygon([
|
||||
[0,0],
|
||||
[0, tri_base],
|
||||
[tri_height*i, tri_base/2]
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
module start_necklace_half() {
|
||||
thick = 1.5;
|
||||
top_thick = 6;
|
||||
bottom_y = -15.5;
|
||||
pivot_point = 30;
|
||||
top_x = 48.5;
|
||||
top_y = 10;
|
||||
|
||||
intersection() {
|
||||
polygon([
|
||||
[0,bottom_y],
|
||||
[pivot_point+thick, bottom_y],
|
||||
[top_x+top_thick/2, top_y],
|
||||
[top_x-top_thick/2, top_y],
|
||||
[pivot_point, bottom_y+thick],
|
||||
[0, bottom_y+thick],
|
||||
]);
|
||||
bleed_trim();
|
||||
}
|
||||
}
|
||||
|
||||
module start_necklace() {
|
||||
start_necklace_half();
|
||||
mirror([1,0,0])
|
||||
start_necklace_half();
|
||||
}
|
||||
|
||||
module logo() {
|
||||
w = 16;
|
||||
translate([0,-82.9]) {
|
||||
box_outline(0.3, 23, 2.0, w, w, 2, inset = -0.5);
|
||||
sdvx_text("POCKET VOLTEX", 1.3);
|
||||
}
|
||||
}
|
||||
|
||||
module macro_arrows() {
|
||||
tri_w = 2;
|
||||
tri_h = 1;
|
||||
tri_off = tri_w/2;
|
||||
|
||||
translate(macro_pos) {
|
||||
for(r = [0:180:180]) {
|
||||
rotate([0,0,r])
|
||||
translate([macro_diam/2 + 0.6,0])
|
||||
polygon([
|
||||
[0,0],
|
||||
[tri_h, tri_off],
|
||||
[tri_h, -tri_off]
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// this is actually straight up disgusting
|
||||
module angled_lines(segments, offset = [0,0], prev) {
|
||||
num_segs = len(segments);
|
||||
if(num_segs > 0) {
|
||||
s = segments[0];
|
||||
difference() {
|
||||
translate(offset) {
|
||||
difference() {
|
||||
rotate([0, 0, s[2]])
|
||||
translate([-s.y/2,-s.y/2])
|
||||
difference() {
|
||||
// extra len for cutting off
|
||||
square([s.x+s.y, s.y]);
|
||||
}
|
||||
if(prev == undef || s.y >= prev.y) {
|
||||
rotate([0,0,90+prev[2]])
|
||||
translate([-s.y,-s.x*2])
|
||||
square([s.y,s.x*4]);
|
||||
}
|
||||
}
|
||||
}
|
||||
if(num_segs > 1 && (prev == undef || s.y >= prev.y)) {
|
||||
diff = [cos(s[2])*s.x - s.y/2,sin(s[2])*s.x];
|
||||
translate(diff)
|
||||
rotate([0,0,90+segments[1][2]])
|
||||
translate([segments[1].y/2,-s.x/2])
|
||||
square([s.y*2,s.x]);
|
||||
}
|
||||
}
|
||||
}
|
||||
if(num_segs > 1) {
|
||||
s = segments[0];
|
||||
diff = [cos(s[2])*s.x - s.y/2,sin(s[2])*s.x];
|
||||
|
||||
angled_lines([ for (i = [1:num_segs-1]) segments[i] ],
|
||||
offset + diff,
|
||||
s);
|
||||
}
|
||||
}
|
||||
|
||||
module wings_half() {
|
||||
entry_thick = 5;
|
||||
down_thick = 4;
|
||||
exit_thick = 5;
|
||||
gap = 0.5;
|
||||
count = 4;
|
||||
|
||||
entry_x = 27;
|
||||
entry_y = -2;
|
||||
|
||||
down_x = entry_x + 4;
|
||||
down_y = entry_y - 35;
|
||||
|
||||
exit_x = down_x + 20;
|
||||
exit_y = down_y - 5;
|
||||
|
||||
offx = down_thick+gap - 2;
|
||||
offy = entry_thick+gap;
|
||||
|
||||
angle = 55;
|
||||
|
||||
difference() {
|
||||
intersection() {
|
||||
translate([-85,-27])
|
||||
union() {
|
||||
len1 = 20;
|
||||
width1 = 4;
|
||||
ang1 = -10;
|
||||
ang2 = -85;
|
||||
difference() {
|
||||
angled_lines([
|
||||
[len1,width1,ang1],
|
||||
[37,2,-84],
|
||||
[11,2,-20],
|
||||
]);
|
||||
translate([35,-51])
|
||||
rotate([0,0,13])
|
||||
square([60,25]);
|
||||
}
|
||||
for(i = [1:3]) {
|
||||
translate([-i*2,-i*4])
|
||||
angled_lines([
|
||||
[len1,width1, ang1 - i*7],
|
||||
[36-i*3,2,ang2+i],
|
||||
[20+i*2,2,-22+i*3],
|
||||
]);
|
||||
}
|
||||
/*for(i=[0:count-1]) {
|
||||
translate([i*offx,i*offy])
|
||||
polygon([
|
||||
[0,0],
|
||||
[entry_x, entry_y],
|
||||
[down_x, down_y],
|
||||
[exit_x, exit_y],
|
||||
|
||||
[exit_x, exit_y+exit_thick],
|
||||
[down_x+down_thick/2, down_y+exit_thick/2],
|
||||
[entry_x, entry_thick+entry_y],
|
||||
[0,entry_thick],
|
||||
]);
|
||||
}*/
|
||||
}
|
||||
bleed_trim();
|
||||
}
|
||||
offset(border_offset)
|
||||
fx_keepout();
|
||||
offset(border_offset)
|
||||
bt_box_polygon();
|
||||
// kill some bleed in a hacky way
|
||||
translate([0,-15])
|
||||
fx_keepout();
|
||||
}
|
||||
}
|
||||
|
||||
module wings() {
|
||||
wings_half();
|
||||
mirror([1,0])
|
||||
wings_half();
|
||||
}
|
||||
|
||||
/*line(length, width=DIM_LINE_WIDTH,
|
||||
height=DIM_HEIGHT,
|
||||
left_arrow=false,
|
||||
right_arrow=false
|
||||
)*/
|
||||
|
||||
module dims_single(width, y_offset) {
|
||||
line_size = 0.4;
|
||||
font_scale = 0.5;
|
||||
|
||||
line_start_y = 48;
|
||||
line_length = y_offset - line_start_y + 5;
|
||||
|
||||
translate([-width/2,-y_offset])
|
||||
dimensions(width, line_size, DIM_FONTSCALE=font_scale);
|
||||
|
||||
reflect()
|
||||
translate([-width/2,-line_start_y])
|
||||
rotate([0,0,-90])
|
||||
line(line_length, width=line_size);
|
||||
}
|
||||
|
||||
module draw_dimensions() {
|
||||
width = board_width();
|
||||
small_width = board_width() - top_plate_shrink*2;
|
||||
|
||||
// we want 2D
|
||||
projection() {
|
||||
dims_single(width, 100);
|
||||
dims_single(small_width, 90);
|
||||
}
|
||||
}
|
||||
|
||||
module artwork_white() {
|
||||
labels();
|
||||
logo();
|
||||
start_arrows();
|
||||
start_necklace();
|
||||
wings();
|
||||
macro_arrows();
|
||||
bt_box_outline();
|
||||
fx_outline();
|
||||
knob_ticks();
|
||||
}
|
||||
|
||||
module artwork_grey() {
|
||||
// mesh. big difference() to keep it out of the other sections
|
||||
difference() {
|
||||
intersection() {
|
||||
bleed_trim();
|
||||
translate([0,-90])
|
||||
perspective_mesh(0.3, 23, 15/*14*3, 7*3*/, 450, -50, 150);
|
||||
}
|
||||
offset(border_offset) {
|
||||
bt_box_polygon();
|
||||
fx_keepout();
|
||||
labels();
|
||||
start_arrows();
|
||||
start_necklace();
|
||||
wings();
|
||||
rad = encoder_radius_board-top_plate_shrink;
|
||||
encoders() circle(r=rad, center = true);
|
||||
logo();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module artwork_orange() {
|
||||
fx_inner();
|
||||
}
|
||||
|
||||
module artwork_blue() {
|
||||
knob_highlights(encoder_map[0]);
|
||||
}
|
||||
module artwork_pink() {
|
||||
knob_highlights(encoder_map[1]);
|
||||
}
|
||||
|
||||
module artwork_2d() {
|
||||
artwork_white();
|
||||
artwork_grey();
|
||||
artwork_orange();
|
||||
artwork_pink();
|
||||
artwork_blue();
|
||||
}
|
||||
|
||||
module artwork() {
|
||||
color(black)
|
||||
linear_extrude(0.05)
|
||||
bleed_trim();
|
||||
|
||||
color(white)
|
||||
linear_extrude(0.1)
|
||||
artwork_white();
|
||||
|
||||
color(grey)
|
||||
linear_extrude(0.1)
|
||||
artwork_grey();
|
||||
|
||||
color(orange)
|
||||
linear_extrude(0.1)
|
||||
artwork_orange();
|
||||
|
||||
color(blue)
|
||||
linear_extrude(0.1)
|
||||
artwork_blue();
|
||||
|
||||
color(pink)
|
||||
linear_extrude(0.1)
|
||||
artwork_pink();
|
||||
|
||||
/*color(black)
|
||||
linear_extrude(0.1)
|
||||
draw_dimensions();*/
|
||||
}
|
||||
|
||||
// override in commandline
|
||||
build = "render";
|
||||
if(build == "render") {
|
||||
// correct lighting for fullbright
|
||||
//light_from_above()
|
||||
artwork();
|
||||
} else if(build == "black") {
|
||||
bleed_trim();
|
||||
} else if(build == "white") {
|
||||
artwork_white();
|
||||
} else if(build == "grey") {
|
||||
artwork_grey();
|
||||
} else if(build == "orange") {
|
||||
artwork_orange();
|
||||
} else if(build == "blue") {
|
||||
artwork_blue();
|
||||
} else if(build == "pink") {
|
||||
artwork_pink();
|
||||
} else if(build == "cuts") {
|
||||
art_outline();
|
||||
} else if(build == "dimensions") {
|
||||
draw_dimensions();
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
use <utils.scad>
|
||||
|
||||
black = [0.1,0.1,0.1];
|
||||
blue = [0,0.6,1];
|
||||
// x, y, keycap width in units, colour, text
|
||||
bt_map = [[0,0, 1, blue, "START"],
|
||||
[-42.862,-37.592, 1.25, "white", "BT-A"],
|
||||
[ 42.862,-37.592, 1.25, "white", "BT-D"],
|
||||
[-14.287,-37.592, 1.25, "white", "BT-B"],
|
||||
[ 14.287,-37.592, 1.25, "white", "BT-C"]];
|
||||
fx_map = [[-33.3375,-75.692, 2.25, black, "FX-L"],
|
||||
[ 33.3375,-75.692, 2.25, black, "FX-R"]];
|
||||
|
||||
bolt_map = [[37.4, 6.65],
|
||||
[80.5, -15.5],
|
||||
[80.5, 16.5],
|
||||
[52.732, -82.792]
|
||||
];
|
||||
encoder_map = [[-73,0.5],
|
||||
[ 73,0.5]];
|
||||
// Not the encoders themselves, but the cutout that surrounds them
|
||||
encoder_radius = 13;
|
||||
// and for the board outline
|
||||
encoder_radius_board = 22.222;
|
||||
|
||||
// encoder solder points hit the case unless we cut these out
|
||||
// x, y, hole size
|
||||
encoder_holes = [[-8, 0, 4],
|
||||
[ 8, 0, 4]];
|
||||
// the 3 A/B/Gnd connections
|
||||
// x (mirrored), y, hole size
|
||||
encoder_hull = [5, -10.5, 3];
|
||||
|
||||
// x, y, rotation
|
||||
led_map = [[47.1, -1.7, 0],
|
||||
[65, -30, 90],
|
||||
[57, -68, 45],
|
||||
[12, -80, 0]];
|
||||
led_size = [7.5, 6.5];
|
||||
|
||||
macro_pos = [0,-75.692];
|
||||
macro_diam = 4.8;
|
||||
|
||||
usb_dims = [11, 12];
|
||||
usb_pos = [-26.52, 10.17];
|
||||
|
||||
// So you get a little clear acrylic edge and it looks nice
|
||||
top_plate_shrink = 1;
|
||||
|
||||
fudge = 0.2;
|
||||
|
||||
bolt_diam = 2;
|
||||
bolt_fudge = 0.1;
|
||||
bolt_size = bolt_diam + bolt_fudge;
|
||||
spacer_size = bolt_size + 1.7 + fudge; // extra wiggle
|
||||
|
||||
module bolts() {
|
||||
reflect([1,0,0])
|
||||
for(bolt = bolt_map) {
|
||||
translate(bolt)
|
||||
children();
|
||||
}
|
||||
}
|
||||
|
||||
module bolts_external() {
|
||||
bolts()
|
||||
circle(d=bolt_size);
|
||||
}
|
||||
|
||||
module bolts_internal() {
|
||||
bolts()
|
||||
circle(d=spacer_size);
|
||||
}
|
||||
|
||||
module switches(map, apply_scaling, colour) {
|
||||
for(sw = map) {
|
||||
color(colour ? sw[3] : "gray")
|
||||
translate([sw.x,sw.y])
|
||||
scale([apply_scaling ? sw[2] : 1,1])
|
||||
children();
|
||||
}
|
||||
}
|
||||
|
||||
module bt(apply_scaling = false, colour = true) {
|
||||
switches(bt_map, apply_scaling, colour)
|
||||
children();
|
||||
}
|
||||
|
||||
module fx(apply_scaling = false, colour = true) {
|
||||
switches(fx_map, apply_scaling, colour)
|
||||
children();
|
||||
}
|
||||
|
||||
module switches_all(apply_scaling = false, colour = true) {
|
||||
switches(fx_map, apply_scaling, colour)
|
||||
children();
|
||||
switches(bt_map, apply_scaling, colour)
|
||||
children();
|
||||
}
|
||||
|
||||
module encoders() {
|
||||
for(enc = encoder_map) {
|
||||
translate(enc)
|
||||
children();
|
||||
}
|
||||
}
|
||||
|
||||
module leds() {
|
||||
reflect([1,0,0])
|
||||
for(led = led_map) {
|
||||
translate([led.x, led.y])
|
||||
rotate([0,0,led[2]])
|
||||
children();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
include <board_primitives.scad>
|
||||
use <utils.scad>
|
||||
use <cutouts.scad>
|
||||
|
||||
encoder_side_gap = 11;
|
||||
function board_width() = (abs(encoder_map[0][0]) + encoder_side_gap)*2;
|
||||
|
||||
module board_half() {
|
||||
// 1mm gap for the important bits
|
||||
top_gap = 10.16;
|
||||
|
||||
// arbitrary
|
||||
height = 96.64;
|
||||
angled_xoff = 55;
|
||||
|
||||
// calculated
|
||||
width = board_width()/2;
|
||||
|
||||
// main body
|
||||
translate([0, -height + top_gap])
|
||||
difference() {
|
||||
square([width, height]);
|
||||
|
||||
translate([angled_xoff,0])
|
||||
rotate([0,0,-35])
|
||||
square([width, height]);
|
||||
}
|
||||
|
||||
// encoder bits
|
||||
difference() {
|
||||
translate(encoder_map[1])
|
||||
circle(r=encoder_radius_board);
|
||||
|
||||
translate([width, -height/2])
|
||||
square([width, height]);
|
||||
}
|
||||
}
|
||||
|
||||
module board() {
|
||||
reflect([1,0,0])
|
||||
board_half();
|
||||
}
|
||||
|
||||
module top_outline() {
|
||||
difference() {
|
||||
board();
|
||||
encoder_cutouts(smooth = true);
|
||||
}
|
||||
}
|
||||
|
||||
board();
|
||||
@@ -1,3 +0,0 @@
|
||||
use <case.scad>;
|
||||
|
||||
bottom_plate_outline();
|
||||
@@ -1,6 +0,0 @@
|
||||
use <case.scad>;
|
||||
|
||||
difference() {
|
||||
bottom_ring_outline();
|
||||
mcu_hole();
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
use <case.scad>;
|
||||
use <board_primitives.scad>
|
||||
use <board_shape.scad>
|
||||
|
||||
$fn=128;
|
||||
|
||||
// to easily automate exports
|
||||
produce = 0;
|
||||
if(produce == 0)
|
||||
render();
|
||||
else if(produce == 1)
|
||||
bottom_padding();
|
||||
else if(produce == 2)
|
||||
mainCuts();
|
||||
else if(produce == 3)
|
||||
padding();
|
||||
|
||||
knobOffset = 83;
|
||||
knobY = -83;
|
||||
main_thickness = 42;
|
||||
bottom_thickness = 5;
|
||||
padding_thickness = 14;
|
||||
|
||||
encoderShaftHole = 5.5;
|
||||
|
||||
// to work out viewports for render
|
||||
//echo(str($vpt[0],",",$vpt[1],",",$vpt[2],",",$vpr[0],",",$vpr[1],",",$vpr[2],",",$vpd));
|
||||
|
||||
// x, y, size
|
||||
finger_holes = [
|
||||
[85, -25, 20],
|
||||
[-85, -25, 20],
|
||||
[0, 5, 20],
|
||||
[0, -85, 20],
|
||||
];
|
||||
|
||||
loosen = 3; // so things aren't impossible to remove
|
||||
gap = 1; // for the top cover
|
||||
|
||||
size = [200, 140];
|
||||
|
||||
module mainCuts() {
|
||||
difference() {
|
||||
translate([0,-30])
|
||||
square(size, center = true);
|
||||
|
||||
offset(delta = loosen)
|
||||
board();
|
||||
|
||||
translate([-knobOffset, knobY])
|
||||
circle(d = 25 + loosen);
|
||||
translate([knobOffset,knobY])
|
||||
circle(d = 25 + loosen);
|
||||
|
||||
// not needed any more
|
||||
//translate([0, 15])
|
||||
//square([80, 3], center = true);
|
||||
|
||||
translate([0, 28])
|
||||
square([100, 13], center = true);
|
||||
|
||||
for(f = finger_holes) {
|
||||
translate([f.x,f.y])
|
||||
circle(d=f[2]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module padding() {
|
||||
difference() {
|
||||
offset(delta = -gap)
|
||||
board();
|
||||
|
||||
encoders()
|
||||
circle(d=encoderShaftHole);
|
||||
}
|
||||
}
|
||||
|
||||
module bottom_padding() {
|
||||
square(size, center = true);
|
||||
}
|
||||
|
||||
module render() {
|
||||
full_stack(false);
|
||||
|
||||
color([0.3,0.3,0.3,0.9])
|
||||
linear_extrude(main_thickness)
|
||||
mainCuts();
|
||||
|
||||
color([0.3,0.3,0.3,0.9])
|
||||
// extra 1 for visualisation purposes
|
||||
translate([0,-30,-bottom_thickness-1])
|
||||
linear_extrude(bottom_thickness)
|
||||
bottom_padding();
|
||||
|
||||
color([0.3,0.3,0.3,0.9])
|
||||
translate([0, 0, 150]) // raise it up to see the board
|
||||
translate([0, 0, 25.5])
|
||||
linear_extrude(padding_thickness)
|
||||
padding();
|
||||
|
||||
translate([-knobOffset, knobY])
|
||||
encoder_knob();
|
||||
translate([knobOffset,knobY])
|
||||
encoder_knob();
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
@echo off
|
||||
SET scad="C:\Program Files\OpenSCAD\openscad.exe"
|
||||
SET folder=outputs
|
||||
|
||||
for %%i in (bottom_plate,bottom_ring,top_plate,top_plate_holes,top_plate_outline,top_ring,holes_internal,holes_surface) DO (
|
||||
%scad% -o "%folder%\%%i.dxf" "%%i.scad"
|
||||
)
|
||||
@@ -0,0 +1,4 @@
|
||||
call .\build_case.bat
|
||||
call .\build_box.bat
|
||||
call .\build_art_svg.bat
|
||||
call .\build_animation.bat
|
||||
@@ -0,0 +1 @@
|
||||
python build_animation.py
|
||||
@@ -0,0 +1,66 @@
|
||||
# openscad will not adjust viewports set in code when rendering from the cmdline
|
||||
# what a shame! so we do it here
|
||||
|
||||
import os
|
||||
import subprocess
|
||||
from math import floor, ceil
|
||||
|
||||
scad = 'C:\\Program Files\\OpenSCAD\\openscad.exe'
|
||||
folder = 'outputs'
|
||||
|
||||
final_size = [800, 600]
|
||||
render_size = [x*2 for x in final_size]
|
||||
|
||||
def quad_ease_inout(t):
|
||||
return 2*t*t if t<.5 else -1+(4-2*t)*t
|
||||
|
||||
def interpolate(vec, index_float):
|
||||
vec1 = vec[floor(index_float)]
|
||||
vec2 = vec[ceil(index_float)]
|
||||
percent = index_float % 1
|
||||
return [percent*(high-low) + low for low, high in zip(vec1, vec2)]
|
||||
|
||||
def thread_call(args):
|
||||
print(' '.join(args))
|
||||
subprocess.check_output(args)
|
||||
|
||||
def gen_args():
|
||||
interval = 2
|
||||
percents = [i / 100.0 for i in range(0, 100+interval, interval)]
|
||||
|
||||
# vpt[3], vpr[3], vpd[1]
|
||||
anim = [
|
||||
[0, -65.9053, 71.5148, 30, 0, 0, 360],
|
||||
[-16.5687, -50.6543, 84.6026, 66.5,0, -37.8, 550.777]
|
||||
]
|
||||
|
||||
for p in percents:
|
||||
camera = interpolate(anim, quad_ease_inout(p))
|
||||
args = [
|
||||
scad,
|
||||
'-o', "{}/anim_{}.png".format(folder, p),
|
||||
'-D', '$t={}'.format(p),
|
||||
'--imgsize={}'.format(','.join(str(x) for x in render_size)),
|
||||
'--camera={}'.format(','.join(str(x) for x in camera)),
|
||||
'--colorscheme=Tomorrow',
|
||||
'--projection=p',
|
||||
'case.scad',
|
||||
'-D', 'build="render"'
|
||||
]
|
||||
yield args
|
||||
|
||||
from multiprocessing.dummy import Pool as ThreadPool
|
||||
pool = ThreadPool(4)
|
||||
pool.map(thread_call, gen_args())
|
||||
|
||||
def call_and_log(cmd):
|
||||
print(cmd)
|
||||
os.system(cmd)
|
||||
# openscad has no anti-aliasing so let's just do it ourselves
|
||||
pngs = [arg[2] for arg in gen_args()]
|
||||
pngs = ['-delay 200', pngs[0], '-delay 5'] + pngs[1:-1] + ['-delay 200', pngs[-1]]
|
||||
call_and_log('bash -c "convert {pngs} -resize {img_size} \\"{folder}/render_animation.gif\\""'.format(
|
||||
pngs=' '.join(pngs),
|
||||
folder=folder,
|
||||
img_size='x'.join(str(x) for x in final_size)))
|
||||
call_and_log('bash -c "rm {folder}/anim_*.png"'.format(folder=folder))
|
||||
@@ -0,0 +1,20 @@
|
||||
@echo off
|
||||
SET scad="C:\Program Files\OpenSCAD\openscad.exe"
|
||||
SET inkscape="C:\Program Files\Inkscape\inkscape.exe"
|
||||
SET folder=outputs
|
||||
|
||||
for %%i in (black,white,grey,orange,blue,pink,cuts,dimensions) DO (
|
||||
@echo on
|
||||
%scad% -o "%folder%\art_%%i.svg" "artwork.scad" -D enable_bleed=1 -D "build=\"%%i\""
|
||||
)
|
||||
|
||||
python stack_art.py
|
||||
%inkscape% --export-png=outputs/artwork.png --export-dpi=1200 --without-gui outputs/artwork.svg
|
||||
|
||||
@echo off
|
||||
|
||||
for %%i in (black,white,grey,orange,blue,pink,cuts,dimensions) DO (
|
||||
del "%folder%\art_%%i.svg"
|
||||
)
|
||||
|
||||
REM pause
|
||||
@@ -0,0 +1,13 @@
|
||||
@echo off
|
||||
SET scad="C:\Program Files\OpenSCAD\openscad.exe"
|
||||
SET folder=outputs
|
||||
|
||||
@echo on
|
||||
%scad% -o "%folder%\5mm_box_bottom.dxf" "box.scad" -D produce=1
|
||||
%scad% -o "%folder%\42mm_box_middle.dxf" "box.scad" -D produce=2
|
||||
%scad% -o "%folder%\14mm_box_insert.dxf" "box.scad" -D produce=3
|
||||
|
||||
%scad% -o "%folder%\render_box.png" "box.scad" -D produce=0 --colorscheme=Tomorrow --imgsize=3840,4320 --camera=32.3082,9.69532,33.9842,45.9,0,314.3,839.47 --projection=p
|
||||
bash -c "convert '%folder%/render_box.png' -resize 960x1080 '%folder%/render_box.png'"
|
||||
|
||||
REM pause
|
||||
@@ -0,0 +1,37 @@
|
||||
|
||||
SET scad="C:\Program Files\OpenSCAD\openscad.exe"
|
||||
SET folder=outputs
|
||||
|
||||
REM fiducials are for stacking layers - my software centers the piece,
|
||||
REM which results in imperfect alignment. Delete them afterwards
|
||||
REM set to 0 if your software can handle coords properly
|
||||
SET fiducials=0
|
||||
|
||||
REM intitial render
|
||||
for %%i in (bottom_plate,bottom_spacer,top_spacer,top_spacer_engrave,top_reflector,top_plate,art_cutout) DO (
|
||||
@echo on
|
||||
%scad% -o "%folder%\%%i.dxf" "case.scad" -D enable_fiducials=%fiducials% -D "build=\"%%i\""
|
||||
)
|
||||
|
||||
REM clean polylines for single layers
|
||||
for %%i in (bottom_plate,bottom_spacer,top_plate,top_reflector) DO (
|
||||
@echo on
|
||||
py -2 odmt.py --input "%folder%\%%i.dxf" --output "%folder%\%%i.dxf"
|
||||
)
|
||||
|
||||
REM combine DXF for multiple layers
|
||||
py -2 odmt.py --input "%folder%\top_spacer.dxf" "%folder%\top_spacer_engrave.dxf" --output "%folder%\top_spacer.dxf"
|
||||
|
||||
REM delete the multi-layer leftovers
|
||||
DEL "%folder%\top_spacer_engrave.dxf"
|
||||
|
||||
REM openscad has no anti-aliasing so let's just do it ourselves
|
||||
REM main render
|
||||
%scad% -o "%folder%\render.png" "case.scad" -D "build=\"render\"" --colorscheme=Tomorrow --imgsize=5600,4320 --camera=7.40041,-3.99594,-17.4439,44.5,0,327.6,401.516 --projection=p
|
||||
bash -c "convert '%folder%/render.png' -resize 1400x1080 '%folder%/render.png'"
|
||||
|
||||
REM exploded render
|
||||
%scad% -o "%folder%\render_exploded.png" "case.scad" -D "build=\"render\"" -D $t=1 --colorscheme=Tomorrow --imgsize=3440,4320 --camera=49.3894,45.0844,40.101,66.2,0,320.6,679.971 --projection=p
|
||||
bash -c "convert '%folder%/render_exploded.png' -resize 860x1080 '%folder%/render_exploded.png'"
|
||||
|
||||
REM pause
|
||||
@@ -1,433 +1,333 @@
|
||||
include <board_primitives.scad>
|
||||
use <board_shape.scad>
|
||||
use <cutouts.scad>
|
||||
use <artwork.scad>
|
||||
|
||||
use <imports/cherry_mx.scad>
|
||||
include <imports/mx_keycap.scad>
|
||||
key_profile_index = 11;
|
||||
|
||||
$fn = 64;
|
||||
|
||||
// x, y, keycap width in units, isBlack
|
||||
switches = [[0,0, 1],
|
||||
[-42.862,-37.592, 1.25],
|
||||
[ 42.862,-37.592, 1.25],
|
||||
[-14.287,-37.592, 1.25],
|
||||
[ 14.287,-37.592, 1.25],
|
||||
[-28.5,-75.692, 1.75, 1],
|
||||
[ 28.5,-75.692, 1.75, 1]];
|
||||
bolts = [[30.025, 6.65],
|
||||
[71, -16.925],
|
||||
[71, 16.5],
|
||||
[42.732, -82.791],
|
||||
// Middle hole, remove if not needed
|
||||
[0, -37.592]];
|
||||
// Not the encoders themselves, but the circle that surrounds them
|
||||
encoders = [[-64,0.4],
|
||||
[ 64,0.4]];
|
||||
encoderRadius = 13;
|
||||
|
||||
// encoder solder points hit the case unless we cut these out
|
||||
// x, y, hole size
|
||||
encoderHoles = [[-8, 0, 3],
|
||||
[ 8, 0, 3]];
|
||||
// the 3 A/B/Gnd connections + room for their decoupling caps
|
||||
// x (mirrored), y, hole size
|
||||
encoderHull = [5, -11, 5];
|
||||
|
||||
// x, y, rotation
|
||||
leds = [[-26.475, -13.625, 35],
|
||||
[-55.5, -37.25, 90],
|
||||
[-47, -57.25, 135],
|
||||
[-13.5, -65, 180]];
|
||||
ledDims = [6, 3];
|
||||
ledTopLength = 10;
|
||||
|
||||
macroHole = [0,-75.692];
|
||||
macroDiam = 3;
|
||||
|
||||
usbWidth = 9;
|
||||
usbPos = [-21.311, 10.3];
|
||||
// bottom to top, last 2 are white/black sections of the 1 plate
|
||||
plate_thickness = [3, 3, 1.6, 3, 1.5, 0.1];
|
||||
|
||||
fudge = 0.2;
|
||||
|
||||
// So you get a little clear acrylic edge and it looks nice
|
||||
wallOverlap = 1;
|
||||
|
||||
boltDiam = 2;
|
||||
boltFudge = 0.1;
|
||||
boltSize = boltDiam + boltFudge;
|
||||
spacerSize = boltSize + 1;
|
||||
|
||||
boltExpand = boltDiam;
|
||||
|
||||
// bolt + half on either side
|
||||
wallStrength = 6;
|
||||
|
||||
// 0 = full spec, 1 = half spec, 2 = plain square
|
||||
holetype = 2;
|
||||
$fn = 256;
|
||||
|
||||
// For the animation
|
||||
explodeFactor = 20;
|
||||
explode_factor = 20;
|
||||
|
||||
module switch(holetype){
|
||||
//Hole size, from Cherry MX data sheet
|
||||
holesize=14;
|
||||
//height of switch clasp cutouts
|
||||
cutoutheight = 3;
|
||||
//width of switch clasp cutouts
|
||||
cutoutwidth = 1;
|
||||
translate([-holesize/2, -holesize/2])
|
||||
if (holetype == 0){
|
||||
union(){
|
||||
square([holesize,holesize]);
|
||||
layer_thickness = [
|
||||
3, // bottom cover
|
||||
3.5, // bottom spacer
|
||||
1.6, // PCB
|
||||
2, // top spacer
|
||||
1.5, // top reflector
|
||||
0.1, // artwork
|
||||
1.5, // top cover
|
||||
1.5, // knob spacer
|
||||
1.5, // knob cover
|
||||
];
|
||||
|
||||
translate([-cutoutwidth,1])
|
||||
square([holesize+2*cutoutwidth,cutoutheight]);
|
||||
// to work out viewports for render
|
||||
//echo(str($vpt[0],",",$vpt[1],",",$vpt[2],",",$vpr[0],",",$vpr[1],",",$vpr[2],",",$vpd));
|
||||
|
||||
translate([-cutoutwidth,holesize-1-cutoutheight])
|
||||
square([holesize+2*cutoutwidth,cutoutheight]);
|
||||
}
|
||||
} else if (holetype == 1){
|
||||
union(){
|
||||
square([holesize,holesize]);
|
||||
|
||||
translate([-cutoutwidth,1])
|
||||
square([holesize+2*cutoutwidth,holesize-2]);
|
||||
}
|
||||
} else {
|
||||
square([holesize,holesize]);
|
||||
}
|
||||
}
|
||||
|
||||
module switches_fx() {
|
||||
for(i = [5:6]) {
|
||||
translate([switches[i][0], switches[i][1]])
|
||||
switch(holetype);
|
||||
}
|
||||
}
|
||||
|
||||
module switches() {
|
||||
for(sw = switches) {
|
||||
translate([sw[0], sw[1]])
|
||||
switch(holetype);
|
||||
}
|
||||
}
|
||||
|
||||
module switch_models() {
|
||||
for(sw = switches) {
|
||||
translate([sw[0], sw[1]])
|
||||
cherry_mx_model();
|
||||
}
|
||||
}
|
||||
|
||||
module switch_keycaps() {
|
||||
for(sw = switches) {
|
||||
color(sw[3] ? [0.1,0.1,0.1] : [1,1,1])
|
||||
translate([sw[0], sw[1], 11.5])
|
||||
scale([sw[2],1,1])
|
||||
key();
|
||||
}
|
||||
}
|
||||
|
||||
module bolt_spacers() {
|
||||
for(bolt = bolts) {
|
||||
translate([bolt[0], bolt[1]])
|
||||
circle(d = spacerSize, center = true);
|
||||
|
||||
// mirror
|
||||
translate([-bolt[0], bolt[1]])
|
||||
circle(d = spacerSize, center = true);
|
||||
}
|
||||
}
|
||||
|
||||
module bolts() {
|
||||
for(bolt = bolts) {
|
||||
translate([bolt[0], bolt[1]])
|
||||
circle(d = boltSize, center = true);
|
||||
|
||||
// mirror
|
||||
translate([-bolt[0], bolt[1]])
|
||||
circle(d = boltSize, center = true);
|
||||
}
|
||||
}
|
||||
|
||||
// Only used to see if my distances are right
|
||||
module bolts_expansion() {
|
||||
offset(r = boltExpand)
|
||||
bolt_spacers();
|
||||
}
|
||||
|
||||
module encoders() {
|
||||
for(enc = encoders) {
|
||||
translate([enc[0], enc[1]])
|
||||
circle(r=encoderRadius, center = true);
|
||||
}
|
||||
}
|
||||
|
||||
module encoder_holes() {
|
||||
for(enc = encoders) {
|
||||
translate([enc[0], enc[1]]) {
|
||||
// A/B/Gnd
|
||||
hull() {
|
||||
translate([encoderHull[0], encoderHull[1]])
|
||||
circle(d=encoderHull[2], center = true);
|
||||
translate([-encoderHull[0], encoderHull[1]])
|
||||
circle(d=encoderHull[2], center = true);
|
||||
}
|
||||
for(hole = encoderHoles) {
|
||||
translate([hole[0], hole[1]])
|
||||
circle(d=hole[2], center = true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module encoder_model() {
|
||||
translate([0,0,5.5])
|
||||
rotate([90,0,0])
|
||||
import("imports/PEC16.stl");
|
||||
|
||||
translate([0,0,13])
|
||||
cylinder(20, d = 25);
|
||||
}
|
||||
|
||||
module encoder_model_full() {
|
||||
for(enc = encoders) {
|
||||
translate([enc[0], enc[1]])
|
||||
encoder_model();
|
||||
}
|
||||
}
|
||||
|
||||
module led_holes() {
|
||||
led_holes_half();
|
||||
mirror([1,0,0])
|
||||
led_holes_half();
|
||||
}
|
||||
|
||||
module led_holes_half() {
|
||||
for(led = leds) {
|
||||
translate([led[0], led[1]])
|
||||
rotate([0,0,led[2]]) {
|
||||
translate([-ledDims[0]/2, -ledDims[1]/2])
|
||||
square([ledDims[0], ledTopLength]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module led_leg_holes() {
|
||||
led_leg_holes_half();
|
||||
mirror([1,0,0])
|
||||
led_leg_holes_half();
|
||||
}
|
||||
|
||||
module led_leg_holes_half() {
|
||||
for(led = leds) {
|
||||
translate([led[0], led[1]])
|
||||
rotate([0,0,led[2]])
|
||||
hull() {
|
||||
offset = ledDims[1]/2 - ledDims[0]/2;
|
||||
translate([offset,0])
|
||||
circle(d=3, center = true);
|
||||
translate([-offset,0])
|
||||
circle(d=3, center = true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// don't do the same thing twice
|
||||
module usb_half() {
|
||||
w = usbWidth / 2;
|
||||
h = wallStrength + fudge*2;
|
||||
curveWidth = h / 2;
|
||||
|
||||
// USB connector origin is at board edge
|
||||
translate([0, -h, 0]) {
|
||||
square([w, h]);
|
||||
|
||||
translate([w, curveWidth, 0])
|
||||
difference() {
|
||||
square(curveWidth);
|
||||
translate([curveWidth, 0, 0])
|
||||
circle(r=curveWidth);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module usb() {
|
||||
usb_half();
|
||||
mirror()
|
||||
usb_half();
|
||||
}
|
||||
|
||||
module board() {
|
||||
import("imports/BOARD_SHAPE.dxf");
|
||||
}
|
||||
|
||||
module board_encoderhole() {
|
||||
module bottom_cover() {
|
||||
difference() {
|
||||
board();
|
||||
encoders();
|
||||
bolts_external();
|
||||
}
|
||||
}
|
||||
|
||||
module top_plate_outline() {
|
||||
offset(delta = -wallOverlap)
|
||||
difference() {
|
||||
board();
|
||||
encoders();
|
||||
}
|
||||
}
|
||||
|
||||
module top_plate_holes() {
|
||||
switches();
|
||||
bolts();
|
||||
translate([macroHole[0], macroHole[1], 0])
|
||||
circle(d = macroDiam, center = true);
|
||||
}
|
||||
|
||||
module top_plate() {
|
||||
module bottom_spacer() {
|
||||
difference() {
|
||||
top_plate_outline();
|
||||
top_plate_holes();
|
||||
}
|
||||
}
|
||||
|
||||
module top_ring_outline() {
|
||||
board_encoderhole();
|
||||
}
|
||||
|
||||
module top_ring() {
|
||||
difference() {
|
||||
top_ring_outline();
|
||||
switches();
|
||||
led_holes();
|
||||
translate(macroHole)
|
||||
square(10, center = true);
|
||||
bolt_spacers();
|
||||
board();
|
||||
bolts_internal();
|
||||
switch_socket_holes();
|
||||
mcu_cutout();
|
||||
usb_cutout();
|
||||
encoder_pins();
|
||||
}
|
||||
}
|
||||
|
||||
module pcb() {
|
||||
difference() {
|
||||
board();
|
||||
bolt_spacers();
|
||||
bolts_internal();
|
||||
}
|
||||
}
|
||||
|
||||
module artwork() {
|
||||
import("imports/Artwork.dxf");
|
||||
module top_outline_offset() {
|
||||
offset(delta = -top_plate_shrink)
|
||||
top_outline();
|
||||
}
|
||||
|
||||
module bottom_ring_outline() {
|
||||
module top_spacer() {
|
||||
difference() {
|
||||
board();
|
||||
translate(usbPos)
|
||||
usb();
|
||||
top_outline();
|
||||
bolts_internal();
|
||||
switch_internal();
|
||||
led_cutouts();
|
||||
macro_internal();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
module mcu_hole() {
|
||||
polygon([[-13.3, 3.9],
|
||||
[-13.3, -8],
|
||||
[-20.15, -17],
|
||||
[-33.65, -17],
|
||||
[-40.5, -8],
|
||||
[-40.5, 3.9]]);
|
||||
}
|
||||
|
||||
module bottom_ring() {
|
||||
difference() {
|
||||
bottom_ring_outline();
|
||||
bolt_spacers();
|
||||
encoder_holes();
|
||||
led_leg_holes();
|
||||
mcu_hole();
|
||||
// Room for FX
|
||||
switches();
|
||||
}
|
||||
}
|
||||
|
||||
module bottom_plate_outline() {
|
||||
board();
|
||||
}
|
||||
|
||||
module bottom_plate() {
|
||||
difference() {
|
||||
board();
|
||||
bolts();
|
||||
}
|
||||
}
|
||||
|
||||
module art_trimmed() {
|
||||
intersection() {
|
||||
// Won't work cause I'm an idiot
|
||||
//offset(delta = -0.5)
|
||||
top_plate();
|
||||
artwork();
|
||||
}
|
||||
}
|
||||
|
||||
// This is kinda disgusting
|
||||
module full_stack() {
|
||||
// quadratic ease out
|
||||
t = $t -1;
|
||||
boom = -explodeFactor * (t*t*t*t - 1);
|
||||
|
||||
color([1, 1, 1, 0.4])
|
||||
linear_extrude(plate_thickness[0])
|
||||
bottom_plate();
|
||||
translate([0, 0, plate_thickness[0] + boom]) {
|
||||
color([1, 1, 1, 0.4])
|
||||
linear_extrude(plate_thickness[1])
|
||||
bottom_ring();
|
||||
translate([0, 0, plate_thickness[1] + boom]) {
|
||||
color([1,1,1, 1])
|
||||
linear_extrude(plate_thickness[2])
|
||||
pcb();
|
||||
// not-as-pretty model of macro key
|
||||
translate([macroHole[0], macroHole[1], plate_thickness[2]])
|
||||
color([1,0.5,0])
|
||||
cylinder(h = 5.2, d = macroDiam);
|
||||
module top_spacer_engrave() {
|
||||
engraveInterval = 0.05;
|
||||
wallOverlap = 1;
|
||||
// go in intervals of 2 to avoid final implicit union()
|
||||
for(i = [0.05:engraveInterval*2:wallOverlap+engraveInterval]) {
|
||||
difference() {
|
||||
offset(delta=-i)
|
||||
top_outline();
|
||||
|
||||
translate([0, 0, plate_thickness[2] + boom]) {
|
||||
// pretty models of stuff
|
||||
translate([0, 0, boom*2]) {
|
||||
color([0.8,0.8,0.8,1])
|
||||
encoder_model_full();
|
||||
|
||||
switch_models();
|
||||
switch_keycaps();
|
||||
};
|
||||
|
||||
color([1, 1, 1, 0.4])
|
||||
linear_extrude(plate_thickness[3])
|
||||
top_ring();
|
||||
translate([0, 0, plate_thickness[3] + boom]) {
|
||||
color([1,1,1, 1])
|
||||
linear_extrude(plate_thickness[4])
|
||||
top_plate();
|
||||
translate([0, 0, plate_thickness[4]]) {
|
||||
color([0,0,0, 1])
|
||||
linear_extrude(plate_thickness[5]) {
|
||||
difference() {
|
||||
top_plate();
|
||||
art_trimmed();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
offset(delta=-(i+engraveInterval))
|
||||
top_outline();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//board();
|
||||
full_stack();
|
||||
//linear_extrude(plate_thickness[0])
|
||||
// bottom_plate();
|
||||
//linear_extrude(plate_thickness[1])
|
||||
// bottom_ring();
|
||||
//linear_extrude(plate_thickness[3])
|
||||
// top_ring();
|
||||
//linear_extrude(plate_thickness[4])
|
||||
// top_plate();
|
||||
module top_reflector() {
|
||||
difference() {
|
||||
top_outline_offset();
|
||||
bolts_external();
|
||||
switch_internal();
|
||||
macro_internal();
|
||||
}
|
||||
}
|
||||
|
||||
module art_outline() {
|
||||
difference() {
|
||||
top_outline_offset();
|
||||
bolts_external();
|
||||
switch_artwork();
|
||||
macro_external();
|
||||
}
|
||||
}
|
||||
|
||||
module top_cover() {
|
||||
difference() {
|
||||
top_outline_offset();
|
||||
bolts_external();
|
||||
switch_external();
|
||||
macro_external();
|
||||
}
|
||||
}
|
||||
|
||||
module knob_spacer() {
|
||||
intersection() {
|
||||
top_outline_offset();
|
||||
|
||||
encoders()
|
||||
circle(r=encoder_radius_board-top_plate_shrink);
|
||||
}
|
||||
}
|
||||
|
||||
module knob_cover_panel() {
|
||||
intersection() {
|
||||
offset(delta = -top_plate_shrink)
|
||||
board();
|
||||
|
||||
encoders()
|
||||
circle(r=encoder_radius_board-top_plate_shrink);
|
||||
}
|
||||
}
|
||||
|
||||
module knob_cover_holes() {
|
||||
encoders() {
|
||||
circle(d=9.3);
|
||||
|
||||
translate([0,-9])
|
||||
circle(d=3.3);
|
||||
}
|
||||
}
|
||||
|
||||
module knob_cover() {
|
||||
difference() {
|
||||
// panel
|
||||
knob_cover_panel();
|
||||
|
||||
// panel holes
|
||||
knob_cover_holes();
|
||||
}
|
||||
}
|
||||
|
||||
module boop() {
|
||||
difference() {
|
||||
knob_cover_panel();
|
||||
board_half();
|
||||
}
|
||||
}
|
||||
|
||||
module knob_cover_cnc() {
|
||||
difference() {
|
||||
union() {
|
||||
linear_extrude(1.5)
|
||||
difference() {
|
||||
knob_spacer();
|
||||
bolts_external();
|
||||
}
|
||||
|
||||
translate([0,0,1.5])
|
||||
hull() {
|
||||
linear_extrude(0.01)
|
||||
boop();
|
||||
translate([0,0,1.5])
|
||||
linear_extrude(0.01)
|
||||
offset(r=-1.5)
|
||||
boop();
|
||||
}
|
||||
}
|
||||
linear_extrude(10){
|
||||
bolts_external();
|
||||
knob_cover_holes();
|
||||
}
|
||||
|
||||
translate([0,0,-0.1])
|
||||
linear_extrude(5)
|
||||
board_half();
|
||||
}
|
||||
}
|
||||
|
||||
module macro_model() {
|
||||
translate([0,0,2])
|
||||
rotate([90,0,0])
|
||||
import("imports/KSC521J.stl");
|
||||
}
|
||||
|
||||
module stab_model() {
|
||||
color("gray")
|
||||
rotate([0,0,180])
|
||||
import("imports/mx_pcb_stab_open.stl");
|
||||
}
|
||||
|
||||
module switch_models() {
|
||||
switches_all(colour = false)
|
||||
cherry_mx_model();
|
||||
|
||||
fx(colour = false)
|
||||
stab_model();
|
||||
}
|
||||
|
||||
module switch_keycaps() {
|
||||
translate([0,0,11.5])
|
||||
switches_all(apply_scaling = true)
|
||||
key();
|
||||
}
|
||||
|
||||
module encoder_knob() {
|
||||
color([0.7,0.7,0.7])
|
||||
cylinder(20, d = 25);
|
||||
}
|
||||
|
||||
module encoder_model(knob = true) {
|
||||
translate([0,0,5.5])
|
||||
rotate([90,0,0])
|
||||
import("imports/PEC16.stl");
|
||||
|
||||
// Shaft
|
||||
encoder_shaft = 6;
|
||||
encoder_flat = 4.5;
|
||||
translate([0,0,6.5])
|
||||
linear_extrude(20)
|
||||
intersection() {
|
||||
circle(d = encoder_shaft);
|
||||
translate([0, (encoder_shaft-encoder_flat)/2])
|
||||
square([encoder_shaft, encoder_flat], center = true);
|
||||
}
|
||||
|
||||
if(knob) {
|
||||
translate([0,0,13.5])
|
||||
encoder_knob();
|
||||
}
|
||||
}
|
||||
|
||||
module animate_layer(index) {
|
||||
boom = 20 * quad_ease_inout($t);
|
||||
|
||||
translate([0,0,boom*index + sum(layer_thickness, index)])
|
||||
children();
|
||||
}
|
||||
|
||||
module extrude_plate(index) {
|
||||
animate_layer(index)
|
||||
linear_extrude(layer_thickness[index])
|
||||
children();
|
||||
}
|
||||
|
||||
module full_stack(knobs = true) {
|
||||
color([1, 1, 1, 0.4])
|
||||
extrude_plate(0)
|
||||
bottom_cover();
|
||||
|
||||
color([0.8, 0.8, 0.8, 0.2])
|
||||
extrude_plate(1)
|
||||
bottom_spacer();
|
||||
|
||||
color([1,1,1, 1])
|
||||
extrude_plate(2)
|
||||
pcb();
|
||||
|
||||
color([0.8, 0.8, 0.8, 0.2])
|
||||
extrude_plate(3)
|
||||
top_spacer();
|
||||
|
||||
color([1,1,1, 1])
|
||||
extrude_plate(4)
|
||||
top_reflector();
|
||||
|
||||
animate_layer(5)
|
||||
artwork();
|
||||
|
||||
color([0.8, 0.8, 0.8, 0.4])
|
||||
extrude_plate(6)
|
||||
top_cover();
|
||||
|
||||
// this isn't ready yet - need bevel
|
||||
/*color([0.8, 0.8, 0.8, 0.3])
|
||||
extrude_plate(7)
|
||||
knob_spacer();
|
||||
|
||||
color([0.8, 0.8, 0.8, 0.4])
|
||||
extrude_plate(8)
|
||||
knob_cover();*/
|
||||
|
||||
// some nice models
|
||||
animate_layer(2)
|
||||
translate([macro_pos.x, macro_pos.y, layer_thickness[2]])
|
||||
color("gray")
|
||||
macro_model();
|
||||
|
||||
// start at layer 2 but rise up above layer 6
|
||||
translate([0,0,90 * quad_ease_inout($t)])
|
||||
animate_layer(2) {
|
||||
color([0.8,0.8,0.8,1])
|
||||
encoders()
|
||||
encoder_model(knobs);
|
||||
|
||||
switch_models();
|
||||
switch_keycaps();
|
||||
}
|
||||
}
|
||||
|
||||
// override in commandline
|
||||
build = "render";
|
||||
if(build == "render") {
|
||||
full_stack();
|
||||
} else if(build == "bottom_plate") {
|
||||
bottom_cover();
|
||||
} else if(build == "bottom_spacer") {
|
||||
bottom_spacer();
|
||||
} else if(build == "top_spacer") {
|
||||
top_spacer();
|
||||
} else if(build == "top_reflector") {
|
||||
top_reflector();
|
||||
} else if(build == "top_spacer_engrave") {
|
||||
top_spacer_engrave();
|
||||
} else if(build == "top_plate") {
|
||||
top_cover();
|
||||
} else if(build == "art_cutout") {
|
||||
art_outline();
|
||||
} else if(build == "knob_spacer") {
|
||||
knob_spacer();
|
||||
} else if(build == "knob_cover") {
|
||||
knob_cover();
|
||||
} else if(build == "knob_cover_cnc") {
|
||||
knob_cover_cnc();
|
||||
}
|
||||
@@ -0,0 +1,252 @@
|
||||
include <board_primitives.scad>
|
||||
use <board_shape.scad>
|
||||
|
||||
// SWITCHES
|
||||
|
||||
module switch_socket_holes() {
|
||||
switches_all() {
|
||||
holesize = [19,11];
|
||||
translate([-holesize.x/2, -3])
|
||||
rounded_square(holesize.x, holesize.y, 2);
|
||||
}
|
||||
|
||||
fx() {
|
||||
reflect([1,0,0])
|
||||
mirror([0,1,0]) { // my switches have upside down stabs
|
||||
|
||||
translate([11.9,7])
|
||||
circle(d=4.5);
|
||||
|
||||
hull() {
|
||||
translate([11.9,-8.24])
|
||||
circle(d=4);
|
||||
|
||||
translate([11.9,-10])
|
||||
circle(d=4);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
a = 23.8; // mx datasheet, good for 2/2.25/2.75 units
|
||||
main_box = [6.65,12.3];
|
||||
|
||||
module stabiliser_cutout_offset() {
|
||||
// my switches have upside down stabs
|
||||
mirror([0,1,0])
|
||||
// per datasheet
|
||||
translate([a/2,main_box.y/2 - 6.77])
|
||||
children();
|
||||
}
|
||||
|
||||
module stabiliser_cutout_bare_minimum() {
|
||||
stabiliser_cutout_offset() {
|
||||
// main body of the stabs
|
||||
square(main_box, center=true);
|
||||
|
||||
// cutout for the bar to pivot
|
||||
translate([0,-1.2])
|
||||
square([3, main_box.y], center=true);
|
||||
|
||||
// linking gap to main switch body
|
||||
translate([-a/4,0])
|
||||
square([a/2, main_box.y - 1.6], center=true);
|
||||
}
|
||||
}
|
||||
|
||||
module stabiliser_cutout_panel_bits() {
|
||||
// cutout for the side bits on a panel-mount
|
||||
stabiliser_cutout_offset()
|
||||
translate([0.875,3/2-0.5])
|
||||
square([main_box.x, 2.8], center=true);
|
||||
}
|
||||
|
||||
module stabiliser_cutout_external() {
|
||||
stabiliser_cutout_bare_minimum();
|
||||
stabiliser_cutout_panel_bits();
|
||||
}
|
||||
|
||||
module stabiliser_cutout_internal() {
|
||||
// since we want most of it
|
||||
stabiliser_cutout_external();
|
||||
|
||||
// get rid of the fingers at the bottom
|
||||
//resize([20,0,0])
|
||||
//switch_hole(expansion=1);
|
||||
|
||||
stabiliser_cutout_offset() {
|
||||
// space for the bar to move
|
||||
|
||||
translate([-a/4,-2.5])
|
||||
square([a/2, main_box.y], center=true);
|
||||
|
||||
// cut off ugly bottom bits
|
||||
translate([-a/4,-2.5])
|
||||
square([a/2, main_box.y], center=true);
|
||||
|
||||
// also space for the stab itself
|
||||
translate([0,-0.5])
|
||||
square([7.4, 19], center=true);
|
||||
}
|
||||
}
|
||||
|
||||
module stabiliser_cutout_artwork() {
|
||||
stabiliser_cutout_bare_minimum();
|
||||
// no panel bits, if you swap to panel mount,
|
||||
// cut a new thing yourself
|
||||
|
||||
// linking gap to main switch body, but bigger
|
||||
// Less flappy bits, nicer cuts
|
||||
extra=0.3;
|
||||
stabiliser_cutout_offset() {
|
||||
translate([-a/4,-extra/2])
|
||||
square([a/2, main_box.y+extra], center=true);
|
||||
}
|
||||
}
|
||||
|
||||
module switch_hole(expansion = false) {
|
||||
// from Cherry MX data sheet
|
||||
holesize = 14;
|
||||
|
||||
translate([-holesize/2, -holesize/2])
|
||||
square([holesize,holesize]);
|
||||
|
||||
// expansion for inner layers so the clips have something to grab
|
||||
if(expansion) {
|
||||
expand_hole = [5, 15];
|
||||
translate(-expand_hole/2)
|
||||
square(expand_hole);
|
||||
}
|
||||
}
|
||||
|
||||
module switch_external() {
|
||||
switches_all()
|
||||
switch_hole();
|
||||
|
||||
fx()
|
||||
reflect()
|
||||
stabiliser_cutout_external();
|
||||
}
|
||||
|
||||
module switch_internal() {
|
||||
switches_all()
|
||||
switch_hole(expansion = true);
|
||||
|
||||
fx()
|
||||
reflect()
|
||||
stabiliser_cutout_internal();
|
||||
}
|
||||
|
||||
module switch_artwork() {
|
||||
switches_all()
|
||||
switch_hole(expansion = true);
|
||||
|
||||
fx()
|
||||
reflect()
|
||||
stabiliser_cutout_artwork();
|
||||
}
|
||||
|
||||
// ENCODERS
|
||||
|
||||
module encoder_pins() {
|
||||
encoders() {
|
||||
// A/B/Gnd
|
||||
hull() {
|
||||
translate([encoder_hull[0], encoder_hull[1]])
|
||||
circle(d=encoder_hull[2], center = true);
|
||||
translate([-encoder_hull[0], encoder_hull[1]])
|
||||
circle(d=encoder_hull[2], center = true);
|
||||
}
|
||||
for(hole = encoder_holes) {
|
||||
translate([hole[0], hole[1]])
|
||||
circle(d=hole[2], center = true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module board_encoders_only() {
|
||||
difference() {
|
||||
board();
|
||||
encoder_cutouts();
|
||||
}
|
||||
}
|
||||
|
||||
module enc_smooth() {
|
||||
r = 3;
|
||||
intersection() {
|
||||
// the rounded bits
|
||||
difference() {
|
||||
board_encoders_only();
|
||||
minkowski() {
|
||||
offset(delta=-r)
|
||||
board_encoders_only();
|
||||
|
||||
circle(r=r);
|
||||
}
|
||||
}
|
||||
// only affect the encoders
|
||||
encoders()
|
||||
square(encoder_radius*2.5, center=true);
|
||||
}
|
||||
}
|
||||
|
||||
module encoder_cutouts(smooth = false) {
|
||||
encoders()
|
||||
circle(r=encoder_radius, center = true);
|
||||
|
||||
// smooth harsh edges so you don't cut yourself
|
||||
if(smooth) {
|
||||
enc_smooth();
|
||||
}
|
||||
}
|
||||
|
||||
// MCU/USB HOLE
|
||||
|
||||
module mcu_cutout() {
|
||||
corners = [[-17, -40],[-16, -1]];
|
||||
polygon([[corners.x[0], corners.y[0]],
|
||||
[corners.x[0], corners.y[1]],
|
||||
[corners.x[1], corners.y[1]],
|
||||
[corners.x[1], corners.y[0]]]);
|
||||
}
|
||||
|
||||
module usb_cutout() {
|
||||
wall_strength = 6; // bolt + half on either side
|
||||
w = usb_dims.x / 2;
|
||||
h = wall_strength + fudge*2;
|
||||
curve_width = h / 2;
|
||||
|
||||
translate(usb_pos)
|
||||
reflect()
|
||||
translate([0, -h, 0]) { // USB connector origin is at board edge
|
||||
translate([0,-(usb_dims.y-h)])
|
||||
square([w, usb_dims.y]);
|
||||
|
||||
translate([w, curve_width, 0])
|
||||
difference() {
|
||||
square(curve_width);
|
||||
translate([curve_width, 0, 0])
|
||||
circle(r=curve_width);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// LEDs
|
||||
|
||||
module led_cutouts() {
|
||||
leds()
|
||||
translate(-led_size/2)
|
||||
square(led_size);
|
||||
}
|
||||
|
||||
// MACRO BUTTON
|
||||
|
||||
module macro_internal() {
|
||||
translate(macro_pos)
|
||||
square(10, center = true);
|
||||
}
|
||||
|
||||
module macro_external() {
|
||||
translate(macro_pos)
|
||||
circle(d=macro_diam);
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
use <case.scad>;
|
||||
|
||||
bolt_spacers();
|
||||
@@ -1,3 +0,0 @@
|
||||
use <case.scad>;
|
||||
|
||||
bolts();
|
||||
@@ -0,0 +1,139 @@
|
||||
//Draw text
|
||||
scale([4,4,4]) drawtext("Hello World!");
|
||||
|
||||
//Draw character set
|
||||
//scale([2,2,2]) drawtext(" !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}");
|
||||
|
||||
module drawtext(text) {
|
||||
//Characters
|
||||
chars = " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}";
|
||||
|
||||
//Chracter table defining 5x7 characters
|
||||
//Adapted from: http://www.geocities.com/dinceraydin/djlcdsim/chartable.js
|
||||
char_table = [ [ 0, 0, 0, 0, 0, 0, 0],
|
||||
[ 4, 0, 4, 4, 4, 4, 4],
|
||||
[ 0, 0, 0, 0,10,10,10],
|
||||
[10,10,31,10,31,10,10],
|
||||
[ 4,30, 5,14,20,15, 4],
|
||||
[ 3,19, 8, 4, 2,25,24],
|
||||
[13,18,21, 8,20,18,12],
|
||||
[ 0, 0, 0, 0, 8, 4,12],
|
||||
[ 2, 4, 8, 8, 8, 4, 2],
|
||||
[ 8, 4, 2, 2, 2, 4, 8],
|
||||
[ 0, 4,21,14,21, 4, 0],
|
||||
[ 0, 4, 4,31, 4, 4, 0],
|
||||
[ 8, 4,12, 0, 0, 0, 0],
|
||||
[ 0, 0, 0,31, 0, 0, 0],
|
||||
[12,12, 0, 0, 0, 0, 0],
|
||||
[ 0,16, 8, 4, 2, 1, 0],
|
||||
[14,17,25,21,19,17,14],
|
||||
[14, 4, 4, 4, 4,12, 4],
|
||||
[31, 8, 4, 2, 1,17,14],
|
||||
[14,17, 1, 2, 4, 2,31],
|
||||
[ 2, 2,31,18,10, 6, 2],
|
||||
[14,17, 1, 1,30,16,31],
|
||||
[14,17,17,30,16, 8, 6],
|
||||
[ 8, 8, 8, 4, 2, 1,31],
|
||||
[14,17,17,14,17,17,14],
|
||||
[12, 2, 1,15,17,17,14],
|
||||
[ 0,12,12, 0,12,12, 0],
|
||||
[ 8, 4,12, 0,12,12, 0],
|
||||
[ 2, 4, 8,16, 8, 4, 2],
|
||||
[ 0, 0,31, 0,31, 0, 0],
|
||||
[16, 8, 4, 2, 4, 8,16],
|
||||
[ 4, 0, 4, 2, 1,17,14],
|
||||
[14,21,21,13, 1,17,14],
|
||||
[17,17,31,17,17,17,14],
|
||||
[30,17,17,30,17,17,30],
|
||||
[14,17,16,16,16,17,14],
|
||||
[30,17,17,17,17,17,30],
|
||||
[31,16,16,30,16,16,31],
|
||||
[16,16,16,30,16,16,31],
|
||||
[15,17,17,23,16,17,14],
|
||||
[17,17,17,31,17,17,17],
|
||||
[14, 4, 4, 4, 4, 4,14],
|
||||
[12,18, 2, 2, 2, 2, 7],
|
||||
[17,18,20,24,20,18,17],
|
||||
[31,16,16,16,16,16,16],
|
||||
[17,17,17,21,21,27,17],
|
||||
[17,17,19,21,25,17,17],
|
||||
[14,17,17,17,17,17,14],
|
||||
[16,16,16,30,17,17,30],
|
||||
[13,18,21,17,17,17,14],
|
||||
[17,18,20,30,17,17,30],
|
||||
[30, 1, 1,14,16,16,15],
|
||||
[ 4, 4, 4, 4, 4, 4,31],
|
||||
[14,17,17,17,17,17,17],
|
||||
[ 4,10,17,17,17,17,17],
|
||||
[10,21,21,21,17,17,17],
|
||||
[17,17,10, 4,10,17,17],
|
||||
[ 4, 4, 4,10,17,17,17],
|
||||
[31,16, 8, 4, 2, 1,31],
|
||||
[14, 8, 8, 8, 8, 8,14],
|
||||
[ 0, 1, 2, 4, 8,16, 0],
|
||||
[14, 2, 2, 2, 2, 2,14],
|
||||
[ 0, 0, 0, 0,17,10, 4],
|
||||
[31, 0, 0, 0, 0, 0, 0],
|
||||
[ 0, 0, 0, 0, 2, 4, 8],
|
||||
[15,17,15, 1,14, 0, 0],
|
||||
[30,17,17,25,22,16,16],
|
||||
[14,17,16,16,14, 0, 0],
|
||||
[15,17,17,19,13, 1, 1],
|
||||
[14,16,31,17,14, 0, 0],
|
||||
[ 8, 8, 8,28, 8, 9, 6],
|
||||
[14, 1,15,17,15, 0, 0],
|
||||
[17,17,17,25,22,16,16],
|
||||
[14, 4, 4, 4,12, 0, 4],
|
||||
[12,18, 2, 2, 2, 6, 2],
|
||||
[18,20,24,20,18,16,16],
|
||||
[14, 4, 4, 4, 4, 4,12],
|
||||
[17,17,21,21,26, 0, 0],
|
||||
[17,17,17,25,22, 0, 0],
|
||||
[14,17,17,17,14, 0, 0],
|
||||
[16,16,30,17,30, 0, 0],
|
||||
[ 1, 1,15,19,13, 0, 0],
|
||||
[16,16,16,25,22, 0, 0],
|
||||
[30, 1,14,16,15, 0, 0],
|
||||
[ 6, 9, 8, 8,28, 8, 8],
|
||||
[13,19,17,17,17, 0, 0],
|
||||
[ 4,10,17,17,17, 0, 0],
|
||||
[10,21,21,17,17, 0, 0],
|
||||
[17,10, 4,10,17, 0, 0],
|
||||
[14, 1,15,17,17, 0, 0],
|
||||
[31, 8, 4, 2,31, 0, 0],
|
||||
[ 2, 4, 4, 8, 4, 4, 2],
|
||||
[ 4, 4, 4, 4, 4, 4, 4],
|
||||
[ 8, 4, 4, 2, 4, 4, 8] ];
|
||||
|
||||
//Binary decode table
|
||||
dec_table = [ "00000", "00001", "00010", "00011", "00100", "00101",
|
||||
"00110", "00111", "01000", "01001", "01010", "01011",
|
||||
"01100", "01101", "01110", "01111", "10000", "10001",
|
||||
"10010", "10011", "10100", "10101", "10110", "10111",
|
||||
"11000", "11001", "11010", "11011", "11100", "11101",
|
||||
"11110", "11111" ];
|
||||
|
||||
//Process string one character at a time
|
||||
for(itext = [0:len(text)-1]) {
|
||||
//Convert character to index
|
||||
ichar = search(text[itext],chars,1)[0];
|
||||
|
||||
//Decode character - rows
|
||||
for(irow = [0:6]) {
|
||||
//Select value to draw from table
|
||||
val = dec_table[char_table[ichar][irow]];
|
||||
|
||||
//Decode character - cols
|
||||
for(icol = [0:4]) {
|
||||
// Retrieve bit to draw
|
||||
bit = search(val[icol],"01",1)[0];
|
||||
|
||||
if(bit) {
|
||||
//Output cube
|
||||
translate([icol + (6*itext), irow, 0])
|
||||
cube([1.0001,1.0001,1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,784 @@
|
||||
/* This is a first pass at dimension lines for OpenSCAD. The text generated for
|
||||
* this comes from http://www.thingiverse.com/thing:59817, and I gratefully
|
||||
* acknowledge user PGreenland for creating this dotmatrix style font.
|
||||
*
|
||||
* Download his file first, TextGenerator.scad, before attempting to run this
|
||||
* program.
|
||||
*
|
||||
* What this program does:
|
||||
*
|
||||
* This program can draw lines with arrows and has a primitive dimensioning
|
||||
* element for putting text within arrows. In addition, should the area being
|
||||
* dimensioned be too narrow, there is a provision for putting the text on
|
||||
* either side of the arrows.
|
||||
*
|
||||
* The dimension lines are drawn on the xy plane and are meant to be seen in a
|
||||
* top view.
|
||||
*
|
||||
* =======================================================
|
||||
* Be sure to view this from above -- ctrl-4
|
||||
* =======================================================
|
||||
*
|
||||
* Available:
|
||||
*
|
||||
* Assorted constants to ease the use of dimensioning line. Because there is
|
||||
* no introspection regarding the dimensions of your creations, you will want
|
||||
* to adjust the parameters to fit the context of your creation. You can adjust
|
||||
* the size of the text, lines, etc to match the rest of your objects.
|
||||
*
|
||||
* the following functions or modules are available.
|
||||
*
|
||||
* line(length, width, height=DIM_HEIGHT, left_arrow=false, right_arrow=false)
|
||||
* Can draw a line with the options of including an arrow at either end
|
||||
*
|
||||
* circle_center(radius, size, line_width)
|
||||
* Draws the cross in the center of a circle. There are defaults for the
|
||||
* cross size and line width
|
||||
*
|
||||
* dimensions(length, line_width, loc=DIM_CENTER)
|
||||
* draws text within lines, such as <--- 3.5 --->
|
||||
* with the use of the variable loc you can alter the placement of the text
|
||||
* loc=DIM_CENTER <--- 3.5 ---> this is the default
|
||||
* loc=DIM_LEFT 3.5 <---->
|
||||
* loc=DIM_RIGHT <----> 3.5
|
||||
* loc=DIM_OUTSIDE ---> 3.5 <---
|
||||
*
|
||||
* leader_line(angle, radius, angle_length, horz_line_length,
|
||||
* direction=DIM_RIGHT, line_width, text)
|
||||
*
|
||||
* for use in pointing to the edge of a circle and showing text
|
||||
*
|
||||
* usage of the leader line:
|
||||
* translate to the center of the circle
|
||||
* Typically leader lines have a bend in them. The angle variable is used
|
||||
* to specify the angle from which the line will point to the center of the
|
||||
* circle. The radius specifies the location of the arrow. The
|
||||
* angle_length is distance that the leader line takes until meeting the
|
||||
* horizontal line. Once the angled line meets the horizontal line, that
|
||||
* line will either extend to the right or left. direction and therefore
|
||||
* be either DIM_RIGHT or DIM_LEFT. line_width typically would be whatever
|
||||
* constant you have selected for all your dimensioned lines. Finally, the
|
||||
* text will be the value that you wish to show, such as R 0.500.
|
||||
*
|
||||
*
|
||||
* Created by Don Smiley
|
||||
*/
|
||||
|
||||
use <TextGenerator.scad>
|
||||
|
||||
// these variables are used within the modules
|
||||
DIM_CENTER = 0;
|
||||
DIM_LEFT = 1;
|
||||
DIM_RIGHT = 2;
|
||||
DIM_OUTSIDE = 3;
|
||||
DIM_HORZ = 0;
|
||||
DIM_VERT = 1;
|
||||
DIM_UPPER_LEFT = 0;
|
||||
DIM_UPPER_RIGHT = 1;
|
||||
DIM_LOWER_LEFT = 2;
|
||||
DIM_LOWER_RIGHT = 3;
|
||||
|
||||
/* Constants related to the annotation lines
|
||||
*
|
||||
* Because the dimension of the part to be documented can vary widely, you
|
||||
* probably are going to need to adjust the parameters to fit the context of
|
||||
* your part.
|
||||
*
|
||||
* For example, the following parameters were used for a part 3.5 units long.
|
||||
* In addition, DIM_HEIGHT is a height meant to be slightly above your tallest
|
||||
* part.
|
||||
*/
|
||||
|
||||
DIM_LINE_WIDTH = .025; // width of dimension lines
|
||||
DIM_SPACE = .1; // a spacing value to make it easier to adjust line spacing etc
|
||||
DIM_HEIGHT = .01; // height of lines
|
||||
|
||||
// refers to the size of the cross within a circle
|
||||
DIM_HOLE_CENTER = DIM_LINE_WIDTH * 6;
|
||||
|
||||
// an approximation that sets the font size relative to the line widths
|
||||
DIM_FONTSCALE = DIM_LINE_WIDTH * .7;
|
||||
|
||||
|
||||
|
||||
OFFSET = .05; // added to the hole length to extend past the surface of the cube
|
||||
|
||||
module arrow(arr_points, arr_length, height) {
|
||||
// arrow points to the left
|
||||
linear_extrude(height=height, convexity=2)
|
||||
|
||||
polygon(
|
||||
points = [[0, 0],
|
||||
[arr_points, arr_points / 2],
|
||||
[arr_length, 0],
|
||||
[arr_points, -arr_points / 2]],
|
||||
paths = [[0, 1, 2, 3]], convexity = 2);
|
||||
}
|
||||
|
||||
module line(length, width=DIM_LINE_WIDTH,
|
||||
height=DIM_HEIGHT,
|
||||
left_arrow=false,
|
||||
right_arrow=false
|
||||
) {
|
||||
/* This module draws a line that can have an arrow on either end. Because
|
||||
* the intended use is to be viewed strictly from above, the height of the
|
||||
* line is set arbitrarily thin.
|
||||
*
|
||||
* The factors arr_length and arr_points are used to create a proportionate
|
||||
* arrow. Your sense of asthetics may lead you to choose different
|
||||
* numbers.
|
||||
*/
|
||||
|
||||
arr_points = width * 4;
|
||||
arr_length = arr_points * .6;
|
||||
|
||||
union() {
|
||||
if (left_arrow && right_arrow) {
|
||||
translate([arr_length, -width / 2, 0])
|
||||
cube([length - arr_length * 2, width, height], center=false);
|
||||
} else {
|
||||
|
||||
if (left_arrow) {
|
||||
translate([arr_length, -width / 2, 0])
|
||||
cube([length - arr_length, width, height], center=false);
|
||||
} else {
|
||||
if (right_arrow) {
|
||||
translate([0, -width / 2, 0])
|
||||
cube([length - arr_length, width, height], center=false);
|
||||
} else {
|
||||
translate([0, -width / 2, 0])
|
||||
cube([length, width, height], center=false);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if (left_arrow) {
|
||||
arrow(arr_points, arr_length, height);
|
||||
}
|
||||
|
||||
if (right_arrow) {
|
||||
translate([length, 0, 0])
|
||||
rotate([0, 0, 180])
|
||||
arrow(arr_points, arr_length, height);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
module circle_center(radius, size=DIM_HOLE_CENTER, line_width=DIM_LINE_WIDTH) {
|
||||
|
||||
translate([-size / 2, 0, 0])
|
||||
line(length=size, width=line_width, height=DIM_HEIGHT, left_arrow=false,
|
||||
right_arrow=false);
|
||||
|
||||
translate([radius - size / 2, 0, 0])
|
||||
line(length=size, width=line_width, height=DIM_HEIGHT, left_arrow=false,
|
||||
right_arrow=false);
|
||||
|
||||
translate([-radius - size / 2, 0, 0])
|
||||
line(length=size, width=line_width, height=DIM_HEIGHT, left_arrow=false,
|
||||
right_arrow=false);
|
||||
|
||||
translate([0, -size / 2, 0])
|
||||
rotate([0, 0, 90])
|
||||
line(length=size, width=line_width, height=DIM_HEIGHT, left_arrow=false,
|
||||
right_arrow=false);
|
||||
|
||||
translate([0, radius - size / 2, 0])
|
||||
rotate([0, 0, 90])
|
||||
line(length=size, width=line_width, height=DIM_HEIGHT, left_arrow=false,
|
||||
right_arrow=false);
|
||||
|
||||
translate([0, -radius - size / 2, 0])
|
||||
rotate([0, 0, 90])
|
||||
line(length=size, width=line_width, height=DIM_HEIGHT, left_arrow=false,
|
||||
right_arrow=false);
|
||||
|
||||
}
|
||||
|
||||
module dimensions(length, line_width=DIM_LINE_WIDTH, loc=DIM_CENTER) {
|
||||
|
||||
|
||||
text = str(length);
|
||||
space = len(text) * DIM_FONTSCALE * 7;
|
||||
|
||||
if (loc == DIM_CENTER) {
|
||||
line(length=length / 2 - space / 2, width=line_width, height=DIM_HEIGHT,
|
||||
left_arrow=true, right_arrow=false);
|
||||
translate([(length) / 2 - space / 2 * .9, -DIM_FONTSCALE * 3, 0])
|
||||
scale([DIM_FONTSCALE, DIM_FONTSCALE, DIM_FONTSCALE])
|
||||
drawtext(text);
|
||||
|
||||
translate([length / 2 + space / 2, 0, 0])
|
||||
line(length=length / 2 - space / 2, width=line_width, height=DIM_HEIGHT,
|
||||
left_arrow=false, right_arrow=true);
|
||||
} else {
|
||||
|
||||
if (loc == DIM_LEFT) {
|
||||
line(length=length, width=line_width, height=DIM_HEIGHT,
|
||||
left_arrow=true, right_arrow=true);
|
||||
|
||||
translate([-space, -DIM_FONTSCALE * 3, 0])
|
||||
scale([DIM_FONTSCALE, DIM_FONTSCALE, DIM_FONTSCALE])
|
||||
drawtext(text);
|
||||
} else {
|
||||
if (loc == DIM_RIGHT) {
|
||||
line(length=length, width=line_width, height=DIM_HEIGHT,
|
||||
left_arrow=true, right_arrow=true);
|
||||
|
||||
translate([length + space, -DIM_FONTSCALE * 3, 0])
|
||||
scale([DIM_FONTSCALE, DIM_FONTSCALE, DIM_FONTSCALE])
|
||||
drawtext(text);
|
||||
} else {
|
||||
if (loc == DIM_OUTSIDE) {
|
||||
|
||||
rotate([0, 180, 0])
|
||||
line(length=length / 2, width=line_width, height=DIM_HEIGHT,
|
||||
left_arrow=true, right_arrow=false);
|
||||
|
||||
translate([(length) / 2 - space / 2 * .9,
|
||||
-DIM_FONTSCALE * 3, 0])
|
||||
scale([DIM_FONTSCALE, DIM_FONTSCALE, DIM_FONTSCALE])
|
||||
drawtext(text);
|
||||
|
||||
translate([length, 0, 0])
|
||||
line(length=length / 2, width=line_width, height=DIM_HEIGHT,
|
||||
left_arrow=true, right_arrow=false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module leader_line(angle, radius, angle_length, horz_line_length,
|
||||
direction=DIM_RIGHT, line_width=DIM_LINE_WIDTH, text, do_circle=false) {
|
||||
/* leader_line
|
||||
*
|
||||
* Creates a line that points directly at a center point from the given
|
||||
* radius.
|
||||
* Then, a short horzizontal line is generated, followed by text. The
|
||||
* direction of the horizontal short line defaults to the right, the
|
||||
* choice made by either DIM_RIGHT or DIM_LEFT
|
||||
*/
|
||||
|
||||
text_length = len(text) * DIM_FONTSCALE * 6;
|
||||
space = DIM_FONTSCALE * 6;
|
||||
|
||||
rotate([0, 0, angle])
|
||||
translate([radius, 0, 0])
|
||||
line(length=angle_length, width=line_width, height=DIM_HEIGHT,
|
||||
left_arrow=true, right_arrow=false);
|
||||
|
||||
rotate([0, 0, angle])
|
||||
translate([radius + angle_length, 0, 0])
|
||||
rotate([0, 0, -angle])
|
||||
union() {
|
||||
if (direction == DIM_RIGHT) {
|
||||
line(length=horz_line_length, width=line_width, height=DIM_HEIGHT,
|
||||
left_arrow=false, right_arrow=false);
|
||||
|
||||
translate([(horz_line_length + space), -DIM_FONTSCALE * 3, 0])
|
||||
scale([DIM_FONTSCALE, DIM_FONTSCALE, DIM_FONTSCALE])
|
||||
drawtext(text);
|
||||
|
||||
if (do_circle) {
|
||||
translate([(horz_line_length + space + text_length/2),
|
||||
0, 0])
|
||||
difference() {
|
||||
cylinder(h=DIM_HEIGHT, r=text_length + space - line_width,
|
||||
center=true, $fn=100);
|
||||
cylinder(h=.05, r=text_length + space - line_width * 2,
|
||||
center=true, $fn=100);
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
translate([-horz_line_length, 0, 0])
|
||||
line(length=horz_line_length, width=line_width, height=DIM_HEIGHT,
|
||||
left_arrow=false, right_arrow=false);
|
||||
|
||||
translate([-(horz_line_length + space + text_length),
|
||||
-DIM_FONTSCALE * 3,
|
||||
0])
|
||||
scale([DIM_FONTSCALE, DIM_FONTSCALE, DIM_FONTSCALE])
|
||||
drawtext(text);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module titleblock(lines, descs, details) {
|
||||
/* titleblock
|
||||
*
|
||||
* This module accepts the following arrays with formats:
|
||||
*
|
||||
* holds the description of the lines. width is a factor that
|
||||
* expands the line width beyond DIM_LINE_WIDTH
|
||||
*
|
||||
* lines = [[startx, starty, horz/vert, length, width],
|
||||
* [startx, starty, horz/vert, length, width]]
|
||||
*
|
||||
* holds the descriptions of the title blocks. these are meant to sit in
|
||||
* the upper left corner. size, like width above, is a factor that
|
||||
* increases/decreases the size of the font
|
||||
*
|
||||
* descs = [[startx, starty, horz/vert, text, size],
|
||||
* [startx, starty, horz/vert, text, size]]
|
||||
*
|
||||
* holds the detail associated with the part being documented
|
||||
*
|
||||
* details = [[startx, starty, horz/vert, text, size],
|
||||
* [startx, starty, horz/vert, text, size]]
|
||||
*/
|
||||
|
||||
DIM_FONTSCALE = DIM_LINE_WIDTH * .7;
|
||||
|
||||
for (line = lines) {
|
||||
translate([line[0] * DIM_LINE_WIDTH,
|
||||
line[1] * DIM_LINE_WIDTH,
|
||||
0])
|
||||
if (line[2] == DIM_VERT) {
|
||||
rotate([0, 0, -90])
|
||||
line(length=line[3] * DIM_LINE_WIDTH,
|
||||
width=DIM_LINE_WIDTH * line[4], height=DIM_HEIGHT,
|
||||
left_arrow=false, right_arrow=false);
|
||||
} else {
|
||||
line(length=(line[3] + 1) * DIM_LINE_WIDTH,
|
||||
width=DIM_LINE_WIDTH * line[4], height=DIM_HEIGHT,
|
||||
left_arrow=false, right_arrow=false);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
for (line = descs) {
|
||||
translate([line[0] * DIM_LINE_WIDTH, line[1] * DIM_LINE_WIDTH, 0])
|
||||
if (line[2] == DIM_VERT) {
|
||||
rotate([0, 0, 90])
|
||||
scale([DIM_FONTSCALE * line[4], DIM_FONTSCALE * line[4],
|
||||
DIM_FONTSCALE * line[4]])
|
||||
drawtext(line[3]);
|
||||
} else {
|
||||
scale([DIM_FONTSCALE * line[4], DIM_FONTSCALE * line[4],
|
||||
DIM_FONTSCALE * line[4]])
|
||||
drawtext(line[3]);
|
||||
}
|
||||
}
|
||||
|
||||
for (line = details) {
|
||||
translate([line[0] * DIM_LINE_WIDTH, line[1] * DIM_LINE_WIDTH, 0])
|
||||
if (line[2] == DIM_VERT) {
|
||||
rotate([0, 0, 90])
|
||||
scale([DIM_FONTSCALE * line[4], DIM_FONTSCALE * line[4],
|
||||
DIM_FONTSCALE * line[4]])
|
||||
drawtext(line[3]);
|
||||
} else {
|
||||
scale([DIM_FONTSCALE * line[4], DIM_FONTSCALE * line[4],
|
||||
DIM_FONTSCALE * line[4]])
|
||||
drawtext(line[3]);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
module sample_titleblock1() {
|
||||
/* sample titleblock
|
||||
*
|
||||
* Note the use of double thickness lines around the perimeter. Any line
|
||||
* can be adjusted to be thinner or thicker.
|
||||
*
|
||||
* Note also that since lines are centered on their widths, some adjustments
|
||||
* for half-width spacing is needed to avoid a jagged look on corners.
|
||||
* You can see that in the horizontal lines in the first section that are
|
||||
* offset by 1, which is the half-width of the outside line.
|
||||
*/
|
||||
title_width = 290;
|
||||
row_height = 15;
|
||||
|
||||
cols = [-1, 50, 114, 200, 215, 260];
|
||||
rows = [0, -row_height, -row_height * 2, -row_height * 3, -row_height * 4];
|
||||
|
||||
// spacing tweaks to fit into the blocks
|
||||
desc_x = 2; // column offset for start of small text
|
||||
desc_y = -5; // row offset for start of small text
|
||||
det_y = -12; // row offset for start of detail text
|
||||
desc_size = .75; // relative size of description text
|
||||
|
||||
lines = [
|
||||
// horizontal lines
|
||||
[cols[0], rows[0], DIM_HORZ, title_width, 2],
|
||||
[cols[0], rows[1], DIM_HORZ, title_width, 1],
|
||||
[cols[2], rows[2], DIM_HORZ, title_width - cols[2] - 1, 1],
|
||||
[cols[3], rows[3], DIM_HORZ, title_width - cols[3] - 1, 1],
|
||||
[cols[0], rows[4] - 1, DIM_HORZ, title_width, 2],
|
||||
|
||||
// vertical lines
|
||||
[0, 0, DIM_VERT, row_height * 4, 2],
|
||||
[cols[1], rows[0], DIM_VERT, row_height, 1],
|
||||
[cols[2], rows[0], DIM_VERT, row_height * 4, 1],
|
||||
[cols[3], rows[0], DIM_VERT, row_height * 4, 1],
|
||||
[cols[4], rows[3], DIM_VERT, row_height, 1],
|
||||
[cols[5], rows[3], DIM_VERT, row_height, 1],
|
||||
[title_width - 1, 0, DIM_VERT, row_height * 4, 2],
|
||||
];
|
||||
|
||||
descs = [
|
||||
[cols[0] + desc_x, rows[0] + desc_y, DIM_HORZ,
|
||||
"Responsible dep", desc_size],
|
||||
[cols[1] + desc_x, rows[0] + desc_y, DIM_HORZ,
|
||||
"Technical reference", desc_size],
|
||||
[cols[2] + desc_x, rows[0] + desc_y, DIM_HORZ,
|
||||
"Creator", desc_size],
|
||||
[cols[3] + desc_x, rows[0] + desc_y, DIM_HORZ,
|
||||
"Approval person", desc_size],
|
||||
[cols[2] + desc_x, rows[1] + desc_y, DIM_HORZ,
|
||||
"Document type", desc_size],
|
||||
[cols[3] + desc_x, rows[1] + desc_y, DIM_HORZ,
|
||||
"Document status", desc_size],
|
||||
[cols[2] + desc_x, rows[2] + desc_y, DIM_HORZ,
|
||||
"Title", desc_size],
|
||||
[cols[3] + desc_x, rows[2] + desc_y, DIM_HORZ,
|
||||
"Identification number", desc_size],
|
||||
[cols[3] + desc_x, rows[3] + desc_y, DIM_HORZ,
|
||||
"Rev", desc_size],
|
||||
[cols[4] + desc_x, rows[3] + desc_y, DIM_HORZ,
|
||||
"Date of issue", desc_size],
|
||||
[cols[5] + desc_x, rows[3] + desc_y, DIM_HORZ,
|
||||
"Sheet", desc_size]
|
||||
];
|
||||
|
||||
details = [
|
||||
[cols[0] + desc_x, rows[0] + det_y, DIM_HORZ,
|
||||
" ", 1], //Responsible dep.
|
||||
[cols[1] + desc_x, rows[0] + det_y, DIM_HORZ,
|
||||
" ", 1], //Technical reference
|
||||
[cols[2] + desc_x, rows[0] + det_y, DIM_HORZ,
|
||||
"D. Smiley ", 1], //Creator
|
||||
[cols[3] + desc_x, rows[0] + det_y, DIM_HORZ,
|
||||
" ", 1], //Approval person
|
||||
[cols[0] + desc_x + 10, rows[2] + det_y, DIM_HORZ,
|
||||
"My OpenSCAD Project", 1],
|
||||
[cols[2] + desc_x, rows[1] + det_y, DIM_HORZ,
|
||||
" ", 1], //Document type
|
||||
[cols[3] + desc_x, rows[1] + det_y, DIM_HORZ,
|
||||
"First issue", 1], //Document status
|
||||
[cols[2] + desc_x, rows[2] + det_y, DIM_HORZ,
|
||||
"Sample Part", 1], //Title
|
||||
[cols[3] + desc_x, rows[2] + det_y, DIM_HORZ,
|
||||
"123", 1], //Identification number
|
||||
[cols[3] + desc_x, rows[3] + det_y, DIM_HORZ,
|
||||
" ", 1], //Rev
|
||||
[cols[4] + desc_x, rows[3] + det_y, DIM_HORZ,
|
||||
"2013-3-31", 1], //Date of issue
|
||||
[cols[5] + desc_x, rows[3] + det_y, DIM_HORZ,
|
||||
"1/100", 1] //Sheet
|
||||
];
|
||||
|
||||
|
||||
titleblock(lines, descs, details);
|
||||
}
|
||||
|
||||
module sample_revisionblock(revisions) {
|
||||
|
||||
DIM_FONTSCALE = DIM_LINE_WIDTH * .7;
|
||||
|
||||
// revision block headings
|
||||
row_height = 15;
|
||||
revision_width = 100;
|
||||
desc_x = 2;
|
||||
desc_y = -10;
|
||||
desc_size = 1;
|
||||
|
||||
cols = [0, 20, 60, revision_width];
|
||||
rows = [0, -row_height, -row_height * 2];
|
||||
|
||||
// draw
|
||||
lines = [
|
||||
// horizontal lines
|
||||
[cols[0], rows[0], DIM_HORZ, revision_width, 1],
|
||||
[cols[0], rows[1], DIM_HORZ, revision_width, 1],
|
||||
[cols[0], rows[2], DIM_HORZ, revision_width, 1],
|
||||
|
||||
// vertical lines
|
||||
[cols[0], rows[0], DIM_VERT, row_height * 2, 1],
|
||||
[cols[1], rows[0], DIM_VERT, row_height, 1],
|
||||
[cols[2], rows[0], DIM_VERT, row_height, 1],
|
||||
[cols[3], rows[0], DIM_VERT, row_height * 2, 1],
|
||||
];
|
||||
|
||||
descs = [
|
||||
[cols[0] + desc_x, rows[0] + desc_y, DIM_HORZ,
|
||||
"Rev.", desc_size],
|
||||
[cols[1] + desc_x, rows[0] + desc_y, DIM_HORZ,
|
||||
"Date", desc_size],
|
||||
[cols[2] + desc_x, rows[0] + desc_y, DIM_HORZ,
|
||||
"Initials", desc_size],
|
||||
[cols[1] + desc_x, rows[1] + desc_y, DIM_HORZ,
|
||||
"Revisions", desc_size],
|
||||
];
|
||||
|
||||
details = [];
|
||||
num_revisions = len(revisions);
|
||||
|
||||
translate([-(revision_width + 40) * DIM_LINE_WIDTH,
|
||||
row_height * 2 * DIM_LINE_WIDTH, 0])
|
||||
union() {
|
||||
titleblock(lines, descs, details);
|
||||
|
||||
// now for the start of actual revisions
|
||||
// do this piecemeal -- draw the vertical first
|
||||
|
||||
for (col = [0: len(cols)]) {
|
||||
translate([cols[col] * DIM_LINE_WIDTH, 0, 0])
|
||||
rotate([0, 0, 90])
|
||||
line(num_revisions * row_height * DIM_LINE_WIDTH);
|
||||
}
|
||||
|
||||
for (row = [0: len(revisions)]) {
|
||||
translate([0, row * row_height * DIM_LINE_WIDTH, 0])
|
||||
line(revision_width * DIM_LINE_WIDTH);
|
||||
|
||||
for (col = [0:2]) {
|
||||
translate([(cols[col] + desc_x) * DIM_LINE_WIDTH,
|
||||
((row + 1) * row_height + desc_y) * DIM_LINE_WIDTH, 0])
|
||||
scale([DIM_FONTSCALE, DIM_FONTSCALE, DIM_FONTSCALE])
|
||||
drawtext(revisions[row][col]);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
module sample_titleblock2() {
|
||||
|
||||
row_height = 20;
|
||||
|
||||
cols = [-.5, 100, 154, 270];
|
||||
title_width = cols[3];
|
||||
|
||||
rows = [0, -row_height, -row_height * 2, -row_height * 3, -row_height * 4,
|
||||
-row_height * 5, -row_height * 6, -row_height * 7
|
||||
];
|
||||
|
||||
// spacing tweaks to fit into the blocks
|
||||
desc_x = 2; // column offset for start of small text
|
||||
desc_y = -5; // row offset for start of small text
|
||||
det_x = 15; // col offset for start of detail text
|
||||
det_y = -15; // row offset for start of detail text
|
||||
desc_size = .75; // relative size of description text
|
||||
|
||||
|
||||
lines = [
|
||||
// horizontal lines
|
||||
[-.5, 0, DIM_HORZ, title_width, 1],
|
||||
|
||||
[cols[2], rows[1], DIM_HORZ, cols[3] - cols[2] - .5, 1],
|
||||
[cols[0], rows[2], DIM_HORZ, cols[1] - cols[0] - .5, 1],
|
||||
[cols[0], rows[3], DIM_HORZ, cols[3] - .5, 1],
|
||||
[cols[0], rows[4], DIM_HORZ, cols[2] - .5, 1],
|
||||
[cols[0], rows[5], DIM_HORZ, cols[3] - .5, 1],
|
||||
[cols[0], rows[6], DIM_HORZ, cols[2] - .5, 1],
|
||||
[cols[0], rows[7], DIM_HORZ, cols[2] - .5, 1],
|
||||
|
||||
[cols[0], rows[7], DIM_HORZ, title_width, 1],
|
||||
|
||||
// vertical lines
|
||||
[cols[0], rows[0], DIM_VERT, -rows[7], 1],
|
||||
[cols[1], rows[0], DIM_VERT, -rows[7], 1],
|
||||
[cols[2], rows[0], DIM_VERT, -rows[7], 1],
|
||||
[cols[3], rows[0], DIM_VERT, -rows[7], 1],
|
||||
];
|
||||
|
||||
part_desc = ["Material", "Finish", "Weight", "Part No."];
|
||||
doc_desc = ["Drawing Number",
|
||||
"Created by",
|
||||
"Reviewed by",
|
||||
"Date of issue"
|
||||
];
|
||||
|
||||
// aspects of the part
|
||||
part_details = [
|
||||
"My Sample Part", // title
|
||||
"Stainless Steel", // material
|
||||
" ", // finish
|
||||
"2.5", // weight
|
||||
"123", // part no
|
||||
];
|
||||
|
||||
// aspects documenting the creation of the part
|
||||
doc_details = [
|
||||
"33-2", // Drawing No.
|
||||
"D. Smiley", // Created by
|
||||
" ", // Reviewd by
|
||||
"2013-3-31", // Date
|
||||
];
|
||||
|
||||
// the organization making the part
|
||||
org_details = [
|
||||
"My logo",
|
||||
"Canny Machines",
|
||||
"Org Address, phone"
|
||||
];
|
||||
|
||||
descs = [
|
||||
|
||||
// part description
|
||||
[cols[0] + desc_x, rows[2] + desc_y, DIM_HORZ, part_desc[0], desc_size],
|
||||
[cols[0] + desc_x, rows[3] + desc_y, DIM_HORZ, part_desc[1], desc_size],
|
||||
[cols[0] + desc_x, rows[4] + desc_y, DIM_HORZ, part_desc[2], desc_size],
|
||||
[cols[0] + desc_x, rows[5] + desc_y, DIM_HORZ, part_desc[3], desc_size],
|
||||
|
||||
// documentation description
|
||||
[cols[1] + desc_x, rows[3] + desc_y, DIM_HORZ, doc_desc[0], desc_size],
|
||||
[cols[1] + desc_x, rows[4] + desc_y, DIM_HORZ, doc_desc[1], desc_size],
|
||||
[cols[1] + desc_x, rows[5] + desc_y, DIM_HORZ, doc_desc[2], desc_size],
|
||||
[cols[1] + desc_x, rows[6] + desc_y, DIM_HORZ, doc_desc[3], desc_size],
|
||||
];
|
||||
|
||||
details = [
|
||||
[cols[0] + desc_x, rows[0] + det_y, DIM_HORZ, part_details[0], 1.5],
|
||||
[cols[0] + desc_x, rows[2] + det_y, DIM_HORZ, part_details[1], 1],
|
||||
[cols[0] + desc_x, rows[3] + det_y, DIM_HORZ, part_details[2], 1],
|
||||
[cols[0] + desc_x, rows[4] + det_y, DIM_HORZ, part_details[3], 1],
|
||||
[cols[0] + desc_x, rows[5] + det_y, DIM_HORZ, part_details[4], 1],
|
||||
|
||||
[cols[1] + desc_x * 2, rows[3] + det_y, DIM_HORZ, doc_details[0], 1],
|
||||
[cols[1] + desc_x * 2, rows[4] + det_y, DIM_HORZ, doc_details[1], 1],
|
||||
[cols[1] + desc_x * 2, rows[5] + det_y, DIM_HORZ, doc_details[2], 1],
|
||||
[cols[1] + desc_x * 2, rows[6] + det_y, DIM_HORZ, doc_details[3], 1],
|
||||
|
||||
// Organization Details
|
||||
[cols[1] + desc_x, rows[1] + det_y, DIM_HORZ, org_details[0], 1.5],
|
||||
[cols[2] + desc_x, rows[0] + det_y, DIM_HORZ, org_details[1], 1.5],
|
||||
[cols[2] + desc_x, rows[1] + det_y, DIM_HORZ, org_details[2], 1],
|
||||
|
||||
];
|
||||
|
||||
titleblock(lines, descs, details);
|
||||
|
||||
revisions = [
|
||||
["1a", "2013-4-1", "ds"],
|
||||
["1b", "2013-4-2", "ds"],
|
||||
["2a", "2013-4-3", "ds"],
|
||||
["3a", "2013-4-5", "ds"],
|
||||
["4a", "2013-4-15", "ds"],
|
||||
];
|
||||
|
||||
rotate([0, 0, 90])
|
||||
sample_revisionblock(revisions);
|
||||
|
||||
|
||||
}
|
||||
|
||||
module sample_lines(){
|
||||
// sample lines
|
||||
union() {
|
||||
line(length=2, width=DIM_LINE_WIDTH, height=DIM_HEIGHT,
|
||||
left_arrow=false, right_arrow=false);
|
||||
translate([0, -0.25, 0])
|
||||
line(length=2, width=DIM_LINE_WIDTH, height=DIM_HEIGHT, left_arrow=true,
|
||||
right_arrow=false);
|
||||
translate([0, -0.5, 0])
|
||||
line(length=2, width=DIM_LINE_WIDTH, height=DIM_HEIGHT,
|
||||
left_arrow=false, right_arrow=true);
|
||||
translate([0, -0.75, 0])
|
||||
line(length=2, width=DIM_LINE_WIDTH, height=DIM_HEIGHT, left_arrow=true,
|
||||
right_arrow=true);
|
||||
}
|
||||
}
|
||||
|
||||
module sample_dimensions() {
|
||||
|
||||
/* shows all possibilities
|
||||
DIM_CENTER = 0;
|
||||
DIM_LEFT = 1;
|
||||
DIM_RIGHT = 2;
|
||||
DIM_OUTSIDE = 3;
|
||||
*/
|
||||
|
||||
length = 2.5;
|
||||
|
||||
// The following two lines are vertical lines that bracket the dimensions
|
||||
// left arrow
|
||||
translate([0, -1.75, 0])
|
||||
rotate([0, 0, 90])
|
||||
line(length=length, width=DIM_LINE_WIDTH, height=DIM_HEIGHT,
|
||||
left_arrow=false, right_arrow=false);
|
||||
|
||||
// right arrow
|
||||
translate([length, -1.75, 0])
|
||||
rotate([0, 0, 90])
|
||||
line(length=length, width=DIM_LINE_WIDTH, height=DIM_HEIGHT,
|
||||
left_arrow=false, right_arrow=false);
|
||||
|
||||
// The following runs through all the dimension types
|
||||
for (i = [0:4]) {
|
||||
translate([0, -.5 * i, 0])
|
||||
dimensions(length=length, line_width=DIM_LINE_WIDTH, loc=i);
|
||||
}
|
||||
}
|
||||
|
||||
module sample_leaderlines() {
|
||||
|
||||
radius = .25;
|
||||
for (i = [0:6]) {
|
||||
leader_line(angle=i * 15, radius=.25, angle_length=(i * .25),
|
||||
horz_line_length=.5, direction=DIM_RIGHT,
|
||||
line_width=DIM_LINE_WIDTH,
|
||||
text=str("leader line angle: ", i * 15 + 90),
|
||||
do_circle=false
|
||||
);
|
||||
}
|
||||
|
||||
for (i = [1:7]) {
|
||||
leader_line(angle=i * 20 + 90, radius=.25,
|
||||
angle_length=.75,
|
||||
horz_line_length=.5, direction=DIM_LEFT,
|
||||
line_width=DIM_LINE_WIDTH,
|
||||
text=str("leader line angle: ", i * 20 + 90));
|
||||
}
|
||||
for (i = [1:4]) {
|
||||
leader_line(angle=-i * 20, radius=.25, angle_length=1.5,
|
||||
horz_line_length=.25, direction=DIM_RIGHT,
|
||||
line_width=DIM_LINE_WIDTH,
|
||||
text=str(i),
|
||||
do_circle=true
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
module sample_circlecenter() {
|
||||
|
||||
radius = .25;
|
||||
difference() {
|
||||
cube([1, 1, 1], center=true);
|
||||
cylinder(h=1.1, r=radius, center=true, $fn=100);
|
||||
}
|
||||
color("Black")
|
||||
translate([0, 0, .51])
|
||||
circle_center(radius=radius, size=DIM_HOLE_CENTER,
|
||||
line_width=DIM_LINE_WIDTH);
|
||||
|
||||
}
|
||||
|
||||
// uncomment these to sample
|
||||
// sample_lines();
|
||||
//
|
||||
// translate([-5.5, 0, 0])
|
||||
// sample_dimensions();
|
||||
//
|
||||
// translate([4, 0, 0])
|
||||
// sample_circlecenter();
|
||||
//
|
||||
// translate([-2, 3, 0])
|
||||
// sample_leaderlines();
|
||||
//
|
||||
// translate([3, 4, 0])
|
||||
// sample_titleblock1();
|
||||
//
|
||||
// translate([0, -2, 0])
|
||||
// sample_titleblock2();
|
||||
|
||||
|
||||
@@ -0,0 +1,244 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
'''
|
||||
@license GPLv3
|
||||
@sources https://github.com/lautr3k/odmt
|
||||
@author Sebastien Mischler <skarab>
|
||||
@author http://www.onlfait.ch
|
||||
'''
|
||||
|
||||
import argparse, os, sys, fnmatch, ezdxf
|
||||
|
||||
# configuration
|
||||
app_name = 'odmt'
|
||||
app_version = '1.0.0'
|
||||
app_description = 'OpenSCAD DXF Merge Tool (odmt) - v' + app_version
|
||||
|
||||
# default i/o
|
||||
input = ['./input']
|
||||
output = './output/merged.dxf'
|
||||
|
||||
# search and ignore files pattern
|
||||
search = ['*.dxf']
|
||||
ignore = ['*_ignore_*']
|
||||
|
||||
# layers indexed colors
|
||||
# http://sub-atomic.com/~moses/acadcolors.html
|
||||
colors = range(10)
|
||||
colors.extend(range(10, 250, 10))
|
||||
colors = map(str, colors)
|
||||
|
||||
# command line parser
|
||||
parser = argparse.ArgumentParser(
|
||||
prog = app_name,
|
||||
description = app_description)
|
||||
parser.add_argument('--input', '-i',
|
||||
nargs = '+',
|
||||
default = input,
|
||||
metavar = 'path',
|
||||
help = 'input file or directory - default: ['
|
||||
+ ', '.join(input) + ']')
|
||||
parser.add_argument('--output', '-o',
|
||||
default = output,
|
||||
metavar = 'path',
|
||||
help = 'output file - default: ' + output)
|
||||
parser.add_argument('--search',
|
||||
nargs = '+',
|
||||
default = search,
|
||||
metavar = 'pattern',
|
||||
help = 'search file pattern - default: ['
|
||||
+ ', '.join(search) + ']')
|
||||
parser.add_argument('--ignore',
|
||||
nargs = '+',
|
||||
default = ignore,
|
||||
metavar = 'pattern',
|
||||
help = 'ignored file/directory pattern - default: ['
|
||||
+ ', '.join(ignore) + ']')
|
||||
parser.add_argument('--colors',
|
||||
nargs = '+',
|
||||
default = colors,
|
||||
metavar = 'index',
|
||||
help = 'layers indexed colors - default: ['
|
||||
+ ', '.join(colors) + ']')
|
||||
parser.add_argument('--nolayers',
|
||||
action = 'store_true',
|
||||
help = 'if set, all files will be merged into the same layer')
|
||||
parser.add_argument('--version', '-v',
|
||||
action = 'version',
|
||||
version = '%(prog)s ' + app_version)
|
||||
|
||||
# parse the command line
|
||||
args = parser.parse_args()
|
||||
|
||||
# local variables assignment
|
||||
input = args.input
|
||||
output = os.path.realpath(args.output)
|
||||
search = args.search
|
||||
ignore = args.ignore
|
||||
colors = map(int, args.colors)
|
||||
nolayers = args.nolayers
|
||||
|
||||
# test output directory
|
||||
output_dir = os.path.dirname(output)
|
||||
|
||||
if os.path.isdir(output_dir) == False:
|
||||
print 'output directory not found :', output_dir
|
||||
sys.exit(1);
|
||||
|
||||
def file_match(input, patterns):
|
||||
'return if input match at least one pattern'
|
||||
for pattern in patterns:
|
||||
if fnmatch.fnmatch(input, pattern):
|
||||
return True
|
||||
return False
|
||||
|
||||
def dxf_search(input):
|
||||
'scan an input file or directory for DXF file'
|
||||
found = []
|
||||
ignored = []
|
||||
if os.path.isdir(input):
|
||||
for file in os.listdir(input):
|
||||
r = dxf_search(os.path.join(input, file))
|
||||
found.extend(r[0])
|
||||
ignored.extend(r[1])
|
||||
elif os.path.isfile(input):
|
||||
if file_match(input, search):
|
||||
if file_match(input, ignore):
|
||||
ignored.append(input)
|
||||
else:
|
||||
found.append(input)
|
||||
else:
|
||||
ignored.append(input)
|
||||
return found, ignored
|
||||
|
||||
def dxf_parse(file):
|
||||
'''
|
||||
extract all LINE tags from an OpenSCAD DXF file
|
||||
and return an array of POLYLINE points
|
||||
'''
|
||||
counter = 0
|
||||
points = []
|
||||
last_block = []
|
||||
polylines = []
|
||||
|
||||
with open(file) as f:
|
||||
for line in f:
|
||||
line = line.strip('\n');
|
||||
|
||||
# block start
|
||||
if line == 'LINE':
|
||||
counter = 1;
|
||||
block = [[0, 0], [0, 0]];
|
||||
|
||||
# in the block
|
||||
if counter > 0:
|
||||
# start line
|
||||
if counter == 5:
|
||||
block[0][0] = line
|
||||
if counter == 7:
|
||||
block[0][1] = line
|
||||
# end line
|
||||
if counter == 9:
|
||||
block[1][0] = line
|
||||
if counter == 11:
|
||||
block[1][1] = line
|
||||
# increment
|
||||
counter += 1
|
||||
|
||||
# end block
|
||||
if counter == 13:
|
||||
counter = 0
|
||||
|
||||
# discontinued line
|
||||
if len(last_block) and block[0] != last_block[1]:
|
||||
polylines.append(points)
|
||||
points = []
|
||||
|
||||
points.append((block[0][0], block[0][1]))
|
||||
points.append((block[1][0], block[1][1]))
|
||||
last_block = block
|
||||
|
||||
# return polylines
|
||||
if len(points):
|
||||
polylines.append(points)
|
||||
return polylines
|
||||
|
||||
# no polyline found
|
||||
return None
|
||||
|
||||
def dxf_merge(files, colors = range(0, 256), nolayer = False):
|
||||
'merge DXF file and convert continuous line to polyline.'
|
||||
|
||||
# DXF file
|
||||
dwg = ezdxf.new('AC1015')
|
||||
msp = dwg.modelspace()
|
||||
|
||||
# layer vars
|
||||
layer_num = 1
|
||||
|
||||
layer_name = 'layer0'
|
||||
layer_names = []
|
||||
|
||||
layer_colors = iter(colors)
|
||||
layer_color = next(layer_colors)
|
||||
|
||||
# for each files
|
||||
for file in files:
|
||||
# layer name
|
||||
if nolayers == False:
|
||||
layer_name = os.path.basename(file)
|
||||
n = layer_name
|
||||
i = 1
|
||||
while n in layer_names:
|
||||
n = layer_name + '_' + str(i)
|
||||
i += 1
|
||||
layer_names.append(n)
|
||||
layer_name = n
|
||||
|
||||
# create layer
|
||||
if layer_num < 2 or nolayers == False:
|
||||
try:
|
||||
dwg.layers.create(
|
||||
name = layer_name,
|
||||
dxfattribs = {'color': layer_color})
|
||||
except AttributeError: # new syntax
|
||||
dwg.layers.new(
|
||||
name = layer_name,
|
||||
dxfattribs = {'color': layer_color})
|
||||
|
||||
# parse file
|
||||
polylines = dxf_parse(file)
|
||||
if len(polylines):
|
||||
for polyline in polylines:
|
||||
msp.add_lwpolyline(polyline, dxfattribs={'layer': layer_name})
|
||||
|
||||
# next layer color
|
||||
layer_color = next(layer_colors, False)
|
||||
if layer_color == False:
|
||||
layer_colors = iter(colors)
|
||||
layer_color = next(layer_colors)
|
||||
|
||||
# increment layer num
|
||||
layer_num += 1
|
||||
|
||||
#return the dwg object
|
||||
return dwg
|
||||
|
||||
# DXF files
|
||||
input_files = []
|
||||
ignored_files = []
|
||||
|
||||
# make the files tree
|
||||
for item in input:
|
||||
result = dxf_search(os.path.realpath(item))
|
||||
input_files.extend(result[0])
|
||||
ignored_files.extend(result[1])
|
||||
|
||||
# do the serious job
|
||||
dxf_merge(input_files, colors, nolayers).saveas(output)
|
||||
|
||||
# success message
|
||||
print 'input :', '\n\t '.join(input_files)
|
||||
if len(ignored_files):
|
||||
print '\nignored :', '\n\t '.join(ignored_files)
|
||||
print '\noutput :', output
|
||||
@@ -0,0 +1,104 @@
|
||||
from lxml import etree
|
||||
|
||||
class Art(object):
|
||||
def __init__(self, name, colour = None):
|
||||
self.name = name
|
||||
self.colour = colour if colour else name
|
||||
self.load()
|
||||
self.recolour()
|
||||
|
||||
@property
|
||||
def path(self):
|
||||
return 'outputs/art_{}.svg'.format(self.name)
|
||||
|
||||
def load(self):
|
||||
with open(self.path, 'rb') as f:
|
||||
self.xml = etree.parse(f)
|
||||
self.root = self.xml.getroot()
|
||||
|
||||
self.polygon = self.find_el('path')
|
||||
if self.polygon is None:
|
||||
raise AttributeError('Loaded svg has no path element')
|
||||
|
||||
def find_el(self, el):
|
||||
return self.root.find('{{*}}{}'.format(el))
|
||||
|
||||
def recolour(self):
|
||||
attribs = self.polygon.attrib
|
||||
attribs['stroke'] = 'none'
|
||||
attribs['style'] = 'stroke:none'
|
||||
attribs['fill'] = self.colour
|
||||
attribs['stroke-width'] = '0'
|
||||
|
||||
def set_dims(self, value):
|
||||
self.root.attrib['width'] = str(value[0]) + 'mm'
|
||||
self.root.attrib['height'] = str(value[1]) + 'mm'
|
||||
|
||||
@property
|
||||
def viewbox(self):
|
||||
return [int(x) for x in self.root.attrib['viewBox'].split(' ')]
|
||||
|
||||
@viewbox.setter
|
||||
def viewbox(self, value):
|
||||
self.root.attrib['viewBox'] = ' '.join(str(x) for x in value)
|
||||
|
||||
def add_layer(master, layer_id, layer_name, contents):
|
||||
group = etree.Element('g')
|
||||
group.attrib['{http://www.inkscape.org/namespaces/inkscape}groupmode'] = 'layer'
|
||||
group.attrib['id'] = layer_id
|
||||
group.attrib['{http://www.inkscape.org/namespaces/inkscape}label'] = layer_name
|
||||
for c in contents:
|
||||
group.append(c.polygon)
|
||||
master.root.append(group)
|
||||
|
||||
layers = [
|
||||
Art('black'),
|
||||
Art('white'),
|
||||
Art('grey'),
|
||||
Art('orange'),
|
||||
Art('blue', 'rgb(38,128,192)'),
|
||||
Art('pink', 'rgb(220,64,117)'),
|
||||
Art('cuts', 'rgb(255,0,255)'),
|
||||
Art('dimensions', 'rgb(0,0,0)')
|
||||
]
|
||||
|
||||
master = layers[0]
|
||||
|
||||
title = master.find_el('title')
|
||||
if title is not None:
|
||||
title.text = 'Pocket Voltex Artwork'
|
||||
|
||||
# cuts get stroke instead of fill
|
||||
cuts = layers[-2]
|
||||
cut_attribs = cuts.polygon.attrib
|
||||
cut_attribs['stroke'] = cuts.colour
|
||||
cut_attribs['stroke-width'] = '0.1'
|
||||
cut_attribs['fill'] = 'none'
|
||||
cut_attribs.pop('style')
|
||||
|
||||
# delete layer 0's path
|
||||
master.polygon.getparent().remove(master.polygon)
|
||||
|
||||
# layers with actual names
|
||||
add_layer(master, "layer1", "artwork", layers[:-2])
|
||||
add_layer(master, "layer2", "cuts", [cuts])
|
||||
add_layer(master, "layer3", "dimensions", [layers[-1]])
|
||||
|
||||
# fix viewbox
|
||||
bottom_left_corner = master.viewbox[:2]
|
||||
upper_right_corner = [left+size for left, size in zip(bottom_left_corner, master.viewbox[2:])]
|
||||
for l in layers[1:]:
|
||||
layer_bottom_left = l.viewbox[:2]
|
||||
layer_upper_right = [left+size for left, size in zip(layer_bottom_left, l.viewbox[2:])]
|
||||
for i in range(2):
|
||||
# left start x, y
|
||||
bottom_left_corner[i] = min(bottom_left_corner[i], layer_bottom_left[i])
|
||||
# width and height
|
||||
upper_right_corner[i] = max(upper_right_corner[i], layer_upper_right[i])
|
||||
box = bottom_left_corner + [topright-bottomleft for topright, bottomleft in zip(upper_right_corner, bottom_left_corner)]
|
||||
master.viewbox = box
|
||||
master.set_dims(box[2:])
|
||||
|
||||
out = etree.tostring(master.xml, pretty_print=True)
|
||||
with open('outputs/artwork.svg', 'wb') as f:
|
||||
f.write(out)
|
||||
@@ -1,3 +0,0 @@
|
||||
use <case.scad>;
|
||||
|
||||
top_plate();
|
||||
@@ -1,3 +0,0 @@
|
||||
use <case.scad>;
|
||||
|
||||
top_plate_holes();
|
||||
@@ -1,3 +0,0 @@
|
||||
use <case.scad>;
|
||||
|
||||
top_plate_outline();
|
||||
@@ -1,3 +0,0 @@
|
||||
use <case.scad>;
|
||||
|
||||
top_ring_outline();
|
||||
@@ -0,0 +1,39 @@
|
||||
|
||||
// like mirror, but leaves the original too
|
||||
module reflect(axis) {
|
||||
children();
|
||||
|
||||
mirror(axis)
|
||||
children();
|
||||
}
|
||||
|
||||
module rounded_square(w, h, r) {
|
||||
translate([r,r])
|
||||
minkowski() {
|
||||
square([w,h]-[r*2,r*2]);
|
||||
circle(r=r);
|
||||
}
|
||||
}
|
||||
|
||||
module ring(outer_radius, thickness) {
|
||||
difference() {
|
||||
circle(r=outer_radius);
|
||||
circle(r=outer_radius-thickness);
|
||||
}
|
||||
}
|
||||
|
||||
// to get consistent colours on our render
|
||||
module light_from_above() {
|
||||
rotate([-40,0,0]) scale([1,1/cos(40),0.01])children();
|
||||
}
|
||||
|
||||
// sum from 0 to end, like python sum(v[:end])
|
||||
function sum(v, end=-1, i=0, r=0) = (i<len(v) && (end < 0 || i < end)) ? sum(v, end, i+1, r+v[i]) : r;
|
||||
|
||||
function lookup3D(index, v) = [
|
||||
lookup(index, [for (el = v) [el[0], el[1].x]]),
|
||||
lookup(index, [for (el = v) [el[0], el[1].y]]),
|
||||
lookup(index, [for (el = v) [el[0], el[1].z]]),
|
||||
];
|
||||
|
||||
function quad_ease_inout(t) = t<.5 ? 2*t*t : -1+(4-2*t)*t;
|
||||
@@ -0,0 +1,22 @@
|
||||
EESchema-LIBRARY Version 2.3
|
||||
#encoding utf-8
|
||||
#
|
||||
# SK9822
|
||||
#
|
||||
DEF SK9822 D 0 40 Y Y 1 F N
|
||||
F0 "D" 0 100 60 H V C CNN
|
||||
F1 "SK9822" 0 0 60 H V C CNN
|
||||
F2 "" 0 0 60 H I C CNN
|
||||
F3 "" 0 0 60 H I C CNN
|
||||
DRAW
|
||||
S -250 -50 250 -350 0 1 0 f
|
||||
X SDI 1 -450 -100 200 R 50 50 1 1 I
|
||||
X CKI 2 -450 -200 200 R 50 50 1 1 I
|
||||
X GND 3 -450 -300 200 R 50 50 1 1 W
|
||||
X VCC 4 450 -300 200 L 50 50 1 1 W
|
||||
X CKO 5 450 -200 200 L 50 50 1 1 O
|
||||
X SDO 6 450 -100 200 L 50 50 1 1 O
|
||||
ENDDRAW
|
||||
ENDDEF
|
||||
#
|
||||
#End Library
|
||||
@@ -0,0 +1,16 @@
|
||||
(module Cherry-MX-Kailh-only (layer F.Cu) (tedit 5AF00F94)
|
||||
(fp_text reference REF** (at 2.5 5.5) (layer B.SilkS)
|
||||
(effects (font (size 1 1) (thickness 0.15)) (justify mirror))
|
||||
)
|
||||
(fp_arc (start 3.815415 4.483532) (end 6.085 4.483532) (angle 90) (layer B.SilkS) (width 0.3))
|
||||
(fp_arc (start -0.53 0) (end 2.1 0.85) (angle 73.52157766) (layer B.SilkS) (width 0.3))
|
||||
(fp_line (start 6.085 4.5) (end 6.085 0.865) (layer B.SilkS) (width 0.3))
|
||||
(fp_line (start 2.1 0.85) (end 6.085 0.865) (layer B.SilkS) (width 0.3))
|
||||
(fp_line (start -4.815 6.755) (end 3.9 6.75) (layer B.SilkS) (width 0.3))
|
||||
(fp_line (start -4.815 6.755) (end -4.815 2.755) (layer B.SilkS) (width 0.3))
|
||||
(fp_line (start -4.815 2.755) (end -0.53 2.755) (layer B.SilkS) (width 0.3))
|
||||
(pad "" np_thru_hole circle (at 3.81 2.54) (size 3 3) (drill 3) (layers *.Cu *.Mask))
|
||||
(pad "" np_thru_hole circle (at -2.54 5.08) (size 3 3) (drill 3) (layers *.Cu *.Mask))
|
||||
(pad 1 smd rect (at -6.3 5.08) (size 2.55 2.5) (layers B.Cu B.Paste B.Mask))
|
||||
(pad 2 smd rect (at 7.6 2.54) (size 2.55 2.5) (layers B.Cu B.Paste B.Mask))
|
||||
)
|
||||
@@ -0,0 +1,32 @@
|
||||
(module Encoder_Bourns_PEC16 (layer F.Cu) (tedit 5AF0166B)
|
||||
(fp_text reference REF** (at 0 -5.08) (layer F.SilkS)
|
||||
(effects (font (size 1 1) (thickness 0.15)))
|
||||
)
|
||||
(fp_text value Encoder_Bourns_PEC16 (at 0 3.81) (layer F.Fab)
|
||||
(effects (font (size 1 1) (thickness 0.15)))
|
||||
)
|
||||
(fp_line (start -8 10.5) (end -8 2.5) (layer F.SilkS) (width 0.3))
|
||||
(fp_line (start -6.5 10.5) (end -8 10.5) (layer F.SilkS) (width 0.3))
|
||||
(fp_line (start -1.5 10.5) (end -3.5 10.5) (layer F.SilkS) (width 0.3))
|
||||
(fp_line (start 3.5 10.5) (end 1.5 10.5) (layer F.SilkS) (width 0.3))
|
||||
(fp_line (start 8 10.5) (end 6.5 10.5) (layer F.SilkS) (width 0.3))
|
||||
(fp_line (start 8 2.5) (end 8 10.5) (layer F.SilkS) (width 0.3))
|
||||
(fp_line (start 8 -7) (end 8 -2.5) (layer F.SilkS) (width 0.3))
|
||||
(fp_line (start -8 -7) (end 8 -7) (layer F.SilkS) (width 0.3))
|
||||
(fp_line (start -8 -2.5) (end -8 -7) (layer F.SilkS) (width 0.3))
|
||||
(fp_line (start -10.2 12.4) (end 10.2 12.4) (layer F.CrtYd) (width 0.3))
|
||||
(fp_line (start -10.2 -8.4) (end -10.2 12.4) (layer F.CrtYd) (width 0.3))
|
||||
(fp_line (start 10.2 -8.4) (end -10.2 -8.4) (layer F.CrtYd) (width 0.3))
|
||||
(fp_line (start 10.2 12.4) (end 10.2 -8.4) (layer F.CrtYd) (width 0.3))
|
||||
(fp_circle (center 0 0) (end -1 -1) (layer F.SilkS) (width 0.3))
|
||||
(pad 1 thru_hole circle (at -5 10.5) (size 1.6 1.6) (drill 1.2) (layers *.Cu *.Mask))
|
||||
(pad 2 thru_hole circle (at 5 10.5) (size 1.6 1.6) (drill 1.2) (layers *.Cu *.Mask))
|
||||
(pad 3 thru_hole circle (at 0 10.5) (size 1.6 1.6) (drill 1.2) (layers *.Cu *.Mask))
|
||||
(pad "" thru_hole oval (at 8 0) (size 3.8 3.4) (drill oval 2.8 2.4) (layers *.Cu *.Mask))
|
||||
(pad "" thru_hole oval (at -8 0) (size 3.8 3.4) (drill oval 2.8 2.4) (layers *.Cu *.Mask))
|
||||
(model ${KIPRJMOD}/PocketVoltex.pretty/PEC16-4X20F-SXXXX_sp.wrl
|
||||
(at (xyz 0 0 0))
|
||||
(scale (xyz 1 1 1))
|
||||
(rotate (xyz 0 0 0))
|
||||
)
|
||||
)
|
||||
@@ -0,0 +1,41 @@
|
||||
(module LED_SK9822 (layer F.Cu) (tedit 5B1B5528)
|
||||
(descr http://cdn.sparkfun.com/datasheets/Components/LED/5060BRG4.pdf)
|
||||
(tags "RGB LED 5050-6")
|
||||
(attr smd)
|
||||
(fp_text reference REF** (at 0 -3.5 180) (layer F.SilkS)
|
||||
(effects (font (size 1 1) (thickness 0.15)))
|
||||
)
|
||||
(fp_text value LED_SK9822 (at 0 3.3) (layer F.Fab)
|
||||
(effects (font (size 1 1) (thickness 0.15)))
|
||||
)
|
||||
(fp_line (start 0 -2.3) (end -0.8 -1.7) (layer F.SilkS) (width 0.15))
|
||||
(fp_line (start 0 -1.1) (end 0 -2.3) (layer F.SilkS) (width 0.15))
|
||||
(fp_line (start -0.8 -1.7) (end 0 -1.1) (layer F.SilkS) (width 0.15))
|
||||
(fp_line (start -2.5 -1.9) (end -1.9 -2.5) (layer F.Fab) (width 0.1))
|
||||
(fp_line (start 2.5 -2.5) (end -2.5 -2.5) (layer F.Fab) (width 0.1))
|
||||
(fp_line (start 2.5 2.5) (end 2.5 -2.5) (layer F.Fab) (width 0.1))
|
||||
(fp_line (start -2.5 2.5) (end 2.5 2.5) (layer F.Fab) (width 0.1))
|
||||
(fp_line (start -2.5 -2.5) (end -2.5 2.5) (layer F.Fab) (width 0.1))
|
||||
(fp_line (start -3.6 -2.7) (end 2.5 -2.7) (layer F.SilkS) (width 0.12))
|
||||
(fp_line (start -3.6 -1.6) (end -3.6 -2.7) (layer F.SilkS) (width 0.12))
|
||||
(fp_line (start 2.5 2.7) (end -2.5 2.7) (layer F.SilkS) (width 0.12))
|
||||
(fp_line (start 3.65 -2.75) (end -3.65 -2.75) (layer F.CrtYd) (width 0.05))
|
||||
(fp_line (start 3.65 2.75) (end 3.65 -2.75) (layer F.CrtYd) (width 0.05))
|
||||
(fp_line (start -3.65 2.75) (end 3.65 2.75) (layer F.CrtYd) (width 0.05))
|
||||
(fp_line (start -3.65 -2.75) (end -3.65 2.75) (layer F.CrtYd) (width 0.05))
|
||||
(fp_text user %R (at 0 0) (layer F.Fab)
|
||||
(effects (font (size 0.6 0.6) (thickness 0.06)))
|
||||
)
|
||||
(fp_circle (center 0 0) (end 0 -1.9) (layer F.Fab) (width 0.1))
|
||||
(pad 1 smd rect (at -2.4 -1.7 90) (size 1.1 2) (layers F.Cu F.Paste F.Mask))
|
||||
(pad 2 smd rect (at -2.4 0 90) (size 1.1 2) (layers F.Cu F.Paste F.Mask))
|
||||
(pad 3 smd rect (at -2.4 1.7 90) (size 1.1 2) (layers F.Cu F.Paste F.Mask))
|
||||
(pad 4 smd rect (at 2.4 1.7 90) (size 1.1 2) (layers F.Cu F.Paste F.Mask))
|
||||
(pad 5 smd rect (at 2.4 0 90) (size 1.1 2) (layers F.Cu F.Paste F.Mask))
|
||||
(pad 6 smd rect (at 2.4 -1.7 90) (size 1.1 2) (layers F.Cu F.Paste F.Mask))
|
||||
(model ${KISYS3DMOD}/LEDs.3dshapes/LED_RGB_5050-6.wrl
|
||||
(at (xyz 0 0 0))
|
||||
(scale (xyz 1 1 1))
|
||||
(rotate (xyz 0 0 0))
|
||||
)
|
||||
)
|
||||
@@ -0,0 +1,48 @@
|
||||
(module SW_Cherry_MX1A_1.00u_PCB_Socket (layer F.Cu) (tedit 5AF00FFB)
|
||||
(descr "Cherry MX keyswitch, MX1A, 1u, PCB mount, http://cherryamericas.com/wp-content/uploads/2014/12/mx_cat.pdf")
|
||||
(tags "cherry mx keyswitch MX1A 1u PCB")
|
||||
(fp_text value SW_Cherry_MX1A_1.00u_PCB (at 0 7.874) (layer F.Fab)
|
||||
(effects (font (size 1 1) (thickness 0.15)))
|
||||
)
|
||||
(fp_text user %R (at 0 -7.874) (layer F.Fab)
|
||||
(effects (font (size 1 1) (thickness 0.15)))
|
||||
)
|
||||
(fp_line (start -6.35 -6.35) (end 6.35 -6.35) (layer F.Fab) (width 0.15))
|
||||
(fp_line (start 6.35 -6.35) (end 6.35 6.35) (layer F.Fab) (width 0.15))
|
||||
(fp_line (start 6.35 6.35) (end -6.35 6.35) (layer F.Fab) (width 0.15))
|
||||
(fp_line (start -6.35 6.35) (end -6.35 -6.35) (layer F.Fab) (width 0.15))
|
||||
(fp_line (start -7.24 7.24) (end -7.24 -7.24) (layer F.CrtYd) (width 0.05))
|
||||
(fp_line (start 7.24 7.24) (end -7.24 7.24) (layer F.CrtYd) (width 0.05))
|
||||
(fp_line (start 7.24 -7.24) (end 7.24 7.24) (layer F.CrtYd) (width 0.05))
|
||||
(fp_line (start -7.24 -7.24) (end 7.24 -7.24) (layer F.CrtYd) (width 0.05))
|
||||
(fp_line (start -9.525 -9.525) (end 9.525 -9.525) (layer Dwgs.User) (width 0.15))
|
||||
(fp_line (start 9.525 -9.525) (end 9.525 9.525) (layer Dwgs.User) (width 0.15))
|
||||
(fp_line (start 9.525 9.525) (end -9.525 9.525) (layer Dwgs.User) (width 0.15))
|
||||
(fp_line (start -9.525 9.525) (end -9.525 -9.525) (layer Dwgs.User) (width 0.15))
|
||||
(fp_line (start -6.985 -6.985) (end 6.985 -6.985) (layer F.SilkS) (width 0.12))
|
||||
(fp_line (start 6.985 -6.985) (end 6.985 6.985) (layer F.SilkS) (width 0.12))
|
||||
(fp_line (start 6.985 6.985) (end -6.985 6.985) (layer F.SilkS) (width 0.12))
|
||||
(fp_line (start -6.985 6.985) (end -6.985 -6.985) (layer F.SilkS) (width 0.12))
|
||||
(pad "" np_thru_hole circle (at 0 0) (size 4 4) (drill 4) (layers *.Cu *.Mask))
|
||||
(pad "" np_thru_hole circle (at -5.08 0) (size 1.7 1.7) (drill 1.7) (layers *.Cu *.Mask))
|
||||
(pad "" np_thru_hole circle (at 5.08 0) (size 1.7 1.7) (drill 1.7) (layers *.Cu *.Mask))
|
||||
(model ${KISYS3DMOD}/Buttons_Switches_Keyboard.3dshapes/SW_Cherry_MX1A_1.00u_PCB.wrl
|
||||
(at (xyz 0 0 0))
|
||||
(scale (xyz 1 1 1))
|
||||
(rotate (xyz 0 0 0))
|
||||
)
|
||||
(fp_text reference REF** (at 2.5 5.5) (layer B.SilkS)
|
||||
(effects (font (size 1 1) (thickness 0.15)) (justify mirror))
|
||||
)
|
||||
(fp_arc (start 3.815415 4.483532) (end 6.085 4.483532) (angle 90) (layer B.SilkS) (width 0.3))
|
||||
(fp_arc (start -0.53 0) (end 2.1 0.85) (angle 73.52157766) (layer B.SilkS) (width 0.3))
|
||||
(fp_line (start 6.085 4.5) (end 6.085 0.865) (layer B.SilkS) (width 0.3))
|
||||
(fp_line (start 2.1 0.85) (end 6.085 0.865) (layer B.SilkS) (width 0.3))
|
||||
(fp_line (start -4.815 6.755) (end 3.9 6.75) (layer B.SilkS) (width 0.3))
|
||||
(fp_line (start -4.815 6.755) (end -4.815 2.755) (layer B.SilkS) (width 0.3))
|
||||
(fp_line (start -4.815 2.755) (end -0.53 2.755) (layer B.SilkS) (width 0.3))
|
||||
(pad "" np_thru_hole circle (at 3.81 2.54) (size 3 3) (drill 3) (layers *.Cu *.Mask))
|
||||
(pad "" np_thru_hole circle (at -2.54 5.08) (size 3 3) (drill 3) (layers *.Cu *.Mask))
|
||||
(pad 1 smd rect (at -6.3 5.08) (size 2.55 2.5) (layers B.Cu B.Paste B.Mask))
|
||||
(pad 2 smd rect (at 7.6 2.54) (size 2.55 2.5) (layers B.Cu B.Paste B.Mask))
|
||||
)
|
||||
@@ -0,0 +1,48 @@
|
||||
(module SW_Cherry_MX1A_1.25u_PCB_Socket (layer F.Cu) (tedit 5AF00F4D)
|
||||
(descr "Cherry MX keyswitch, MX1A, 1.25u, PCB mount, http://cherryamericas.com/wp-content/uploads/2014/12/mx_cat.pdf")
|
||||
(tags "cherry mx keyswitch MX1A 1.25u PCB")
|
||||
(fp_text value SW_Cherry_MX1A_1.25u_PCB (at 0 7.874) (layer F.Fab)
|
||||
(effects (font (size 1 1) (thickness 0.15)))
|
||||
)
|
||||
(fp_text user %R (at 0 -7.874) (layer F.Fab)
|
||||
(effects (font (size 1 1) (thickness 0.15)))
|
||||
)
|
||||
(fp_line (start -6.35 -6.35) (end 6.35 -6.35) (layer F.Fab) (width 0.15))
|
||||
(fp_line (start 6.35 -6.35) (end 6.35 6.35) (layer F.Fab) (width 0.15))
|
||||
(fp_line (start 6.35 6.35) (end -6.35 6.35) (layer F.Fab) (width 0.15))
|
||||
(fp_line (start -6.35 6.35) (end -6.35 -6.35) (layer F.Fab) (width 0.15))
|
||||
(fp_line (start -7.24 7.24) (end -7.24 -7.24) (layer F.CrtYd) (width 0.05))
|
||||
(fp_line (start 7.24 7.24) (end -7.24 7.24) (layer F.CrtYd) (width 0.05))
|
||||
(fp_line (start 7.24 -7.24) (end 7.24 7.24) (layer F.CrtYd) (width 0.05))
|
||||
(fp_line (start -7.24 -7.24) (end 7.24 -7.24) (layer F.CrtYd) (width 0.05))
|
||||
(fp_line (start -11.90625 -9.525) (end 11.90625 -9.525) (layer Dwgs.User) (width 0.15))
|
||||
(fp_line (start 11.90625 -9.525) (end 11.90625 9.525) (layer Dwgs.User) (width 0.15))
|
||||
(fp_line (start 11.90625 9.525) (end -11.90625 9.525) (layer Dwgs.User) (width 0.15))
|
||||
(fp_line (start -11.90625 9.525) (end -11.90625 -9.525) (layer Dwgs.User) (width 0.15))
|
||||
(fp_line (start -6.985 -6.985) (end 6.985 -6.985) (layer F.SilkS) (width 0.12))
|
||||
(fp_line (start 6.985 -6.985) (end 6.985 6.985) (layer F.SilkS) (width 0.12))
|
||||
(fp_line (start 6.985 6.985) (end -6.985 6.985) (layer F.SilkS) (width 0.12))
|
||||
(fp_line (start -6.985 6.985) (end -6.985 -6.985) (layer F.SilkS) (width 0.12))
|
||||
(pad "" np_thru_hole circle (at 0 0) (size 4 4) (drill 4) (layers *.Cu *.Mask))
|
||||
(pad "" np_thru_hole circle (at -5.08 0) (size 1.7 1.7) (drill 1.7) (layers *.Cu *.Mask))
|
||||
(pad "" np_thru_hole circle (at 5.08 0) (size 1.7 1.7) (drill 1.7) (layers *.Cu *.Mask))
|
||||
(model ${KISYS3DMOD}/Buttons_Switches_Keyboard.3dshapes/SW_Cherry_MX1A_1.25u_PCB.wrl
|
||||
(at (xyz 0 0 0))
|
||||
(scale (xyz 1 1 1))
|
||||
(rotate (xyz 0 0 0))
|
||||
)
|
||||
(fp_text reference REF** (at 2.5 5.5) (layer B.SilkS)
|
||||
(effects (font (size 1 1) (thickness 0.15)) (justify mirror))
|
||||
)
|
||||
(fp_arc (start 3.815415 4.483532) (end 6.085 4.483532) (angle 90) (layer B.SilkS) (width 0.3))
|
||||
(fp_arc (start -0.53 0) (end 2.1 0.85) (angle 73.52157766) (layer B.SilkS) (width 0.3))
|
||||
(fp_line (start 6.085 4.5) (end 6.085 0.865) (layer B.SilkS) (width 0.3))
|
||||
(fp_line (start 2.1 0.85) (end 6.085 0.865) (layer B.SilkS) (width 0.3))
|
||||
(fp_line (start -4.815 6.755) (end 3.9 6.75) (layer B.SilkS) (width 0.3))
|
||||
(fp_line (start -4.815 6.755) (end -4.815 2.755) (layer B.SilkS) (width 0.3))
|
||||
(fp_line (start -4.815 2.755) (end -0.53 2.755) (layer B.SilkS) (width 0.3))
|
||||
(pad "" np_thru_hole circle (at 3.81 2.54) (size 3 3) (drill 3) (layers *.Cu *.Mask))
|
||||
(pad "" np_thru_hole circle (at -2.54 5.08) (size 3 3) (drill 3) (layers *.Cu *.Mask))
|
||||
(pad 1 smd rect (at -6.3 5.08) (size 2.55 2.5) (layers B.Cu B.Paste B.Mask))
|
||||
(pad 2 smd rect (at 7.6 2.54) (size 2.55 2.5) (layers B.Cu B.Paste B.Mask))
|
||||
)
|
||||
@@ -0,0 +1,57 @@
|
||||
(module SW_Cherry_MX1A_2.25u_PCB_Socket (layer F.Cu) (tedit 5AF01062)
|
||||
(descr "Cherry MX keyswitch, MX1A, 2.25u, PCB mount, http://cherryamericas.com/wp-content/uploads/2014/12/mx_cat.pdf")
|
||||
(tags "cherry mx keyswitch MX1A 2.25u PCB")
|
||||
(fp_text value SW_Cherry_MX1A_2.25u_PCB (at 0 7.874) (layer F.Fab)
|
||||
(effects (font (size 1 1) (thickness 0.15)))
|
||||
)
|
||||
(fp_text user %R (at 0 -7.874) (layer F.Fab)
|
||||
(effects (font (size 1 1) (thickness 0.15)))
|
||||
)
|
||||
(fp_line (start -6.35 -6.35) (end 6.35 -6.35) (layer F.Fab) (width 0.15))
|
||||
(fp_line (start 6.35 -6.35) (end 6.35 6.35) (layer F.Fab) (width 0.15))
|
||||
(fp_line (start 6.35 6.35) (end -6.35 6.35) (layer F.Fab) (width 0.15))
|
||||
(fp_line (start -6.35 6.35) (end -6.35 -6.35) (layer F.Fab) (width 0.15))
|
||||
(fp_line (start -7.24 7.24) (end -7.24 -7.24) (layer F.CrtYd) (width 0.05))
|
||||
(fp_line (start 7.24 7.24) (end -7.24 7.24) (layer F.CrtYd) (width 0.05))
|
||||
(fp_line (start 7.24 -7.24) (end 7.24 7.24) (layer F.CrtYd) (width 0.05))
|
||||
(fp_line (start -7.24 -7.24) (end 7.24 -7.24) (layer F.CrtYd) (width 0.05))
|
||||
(fp_line (start -21.43125 -9.525) (end 21.43125 -9.525) (layer Dwgs.User) (width 0.15))
|
||||
(fp_line (start 21.43125 -9.525) (end 21.43125 9.525) (layer Dwgs.User) (width 0.15))
|
||||
(fp_line (start 21.43125 9.525) (end -21.43125 9.525) (layer Dwgs.User) (width 0.15))
|
||||
(fp_line (start -21.43125 9.525) (end -21.43125 -9.525) (layer Dwgs.User) (width 0.15))
|
||||
(fp_line (start -6.985 -6.985) (end 6.985 -6.985) (layer F.SilkS) (width 0.12))
|
||||
(fp_line (start 6.985 -6.985) (end 6.985 6.985) (layer F.SilkS) (width 0.12))
|
||||
(fp_line (start 6.985 6.985) (end -6.985 6.985) (layer F.SilkS) (width 0.12))
|
||||
(fp_line (start -6.985 6.985) (end -6.985 -6.985) (layer F.SilkS) (width 0.12))
|
||||
(pad "" np_thru_hole circle (at 0 0) (size 4 4) (drill 4) (layers *.Cu *.Mask))
|
||||
(pad "" np_thru_hole circle (at -5.08 0) (size 1.7 1.7) (drill 1.7) (layers *.Cu *.Mask))
|
||||
(pad "" np_thru_hole circle (at 5.08 0) (size 1.7 1.7) (drill 1.7) (layers *.Cu *.Mask))
|
||||
(pad "" np_thru_hole circle (at 11.9 8.24) (size 4 4) (drill 4) (layers *.Cu *.Mask))
|
||||
(pad "" np_thru_hole circle (at -11.9 8.24) (size 4 4) (drill 4) (layers *.Cu *.Mask))
|
||||
(pad "" np_thru_hole circle (at -11.9 -7) (size 3.05 3.05) (drill 3.05) (layers *.Cu *.Mask))
|
||||
(pad "" np_thru_hole circle (at 11.9 -7) (size 3.05 3.05) (drill 3.05) (layers *.Cu *.Mask))
|
||||
(model ${KISYS3DMOD}/Buttons_Switches_Keyboard.3dshapes/SW_Cherry_MX1A_2.25u_PCB.wrl
|
||||
(at (xyz 0 0 0))
|
||||
(scale (xyz 1 1 1))
|
||||
(rotate (xyz 0 0 0))
|
||||
)
|
||||
(fp_text reference REF** (at 2.5 5.5) (layer B.SilkS)
|
||||
(effects (font (size 1 1) (thickness 0.15)) (justify mirror))
|
||||
)
|
||||
(fp_arc (start 3.815415 4.483532) (end 6.085 4.483532) (angle 90) (layer B.SilkS) (width 0.3))
|
||||
(fp_arc (start -0.53 0) (end 2.1 0.85) (angle 73.52157766) (layer B.SilkS) (width 0.3))
|
||||
(fp_line (start 6.085 4.5) (end 6.085 0.865) (layer B.SilkS) (width 0.3))
|
||||
(fp_line (start 2.1 0.85) (end 6.085 0.865) (layer B.SilkS) (width 0.3))
|
||||
(fp_line (start -4.815 6.755) (end 3.9 6.75) (layer B.SilkS) (width 0.3))
|
||||
(fp_line (start -4.815 6.755) (end -4.815 2.755) (layer B.SilkS) (width 0.3))
|
||||
(fp_line (start -4.815 2.755) (end -0.53 2.755) (layer B.SilkS) (width 0.3))
|
||||
(pad "" np_thru_hole circle (at 3.81 2.54) (size 3 3) (drill 3) (layers *.Cu *.Mask))
|
||||
(pad "" np_thru_hole circle (at -2.54 5.08) (size 3 3) (drill 3) (layers *.Cu *.Mask))
|
||||
(pad 1 smd rect (at -6.3 5.08) (size 2.55 2.5) (layers B.Cu B.Paste B.Mask))
|
||||
(pad 2 smd rect (at 7.6 2.54) (size 2.55 2.5) (layers B.Cu B.Paste B.Mask))
|
||||
(model ${KIPRJMOD}/PocketVoltex.pretty/mx_stab_pcb_open.wrl
|
||||
(at (xyz 0 0 0))
|
||||
(scale (xyz 1 1 1))
|
||||
(rotate (xyz 0 0 0))
|
||||
)
|
||||
)
|
||||
@@ -0,0 +1,17 @@
|
||||
(module SW_SPST_KSC-G (layer F.Cu) (tedit 5AF6C0C2)
|
||||
(fp_text reference REF** (at 0 0.5) (layer F.SilkS)
|
||||
(effects (font (size 1 1) (thickness 0.15)))
|
||||
)
|
||||
(fp_text value SW_SPST_KSC-G (at 0 -0.5) (layer F.Fab)
|
||||
(effects (font (size 1 1) (thickness 0.15)))
|
||||
)
|
||||
(pad 1 smd rect (at 4.45 2) (size 3.1 1) (layers F.Cu F.Paste F.Mask))
|
||||
(pad 1 smd rect (at -4.45 2) (size 3.1 1) (layers F.Cu F.Paste F.Mask))
|
||||
(pad 2 smd rect (at 4.45 -2) (size 3.1 1) (layers F.Cu F.Paste F.Mask))
|
||||
(pad 2 smd rect (at -4.45 -2) (size 3.1 1) (layers F.Cu F.Paste F.Mask))
|
||||
(model ${KIPRJMOD}/PocketVoltex.pretty/KSC5.wrl
|
||||
(at (xyz 0 0 0))
|
||||
(scale (xyz 1 1 1))
|
||||
(rotate (xyz 0 0 0))
|
||||
)
|
||||
)
|
||||
@@ -0,0 +1,17 @@
|
||||
(module SW_SPST_KSC-J (layer F.Cu) (tedit 5B192C9B)
|
||||
(fp_text reference REF** (at 0 0.5) (layer F.SilkS)
|
||||
(effects (font (size 1 1) (thickness 0.15)))
|
||||
)
|
||||
(fp_text value SW_SPST_KSC-J (at 0 -0.5) (layer F.Fab)
|
||||
(effects (font (size 1 1) (thickness 0.15)))
|
||||
)
|
||||
(pad 1 smd rect (at 2.9 2) (size 2.8 1) (layers F.Cu F.Paste F.Mask))
|
||||
(pad 1 smd rect (at -2.9 2) (size 2.8 1) (layers F.Cu F.Paste F.Mask))
|
||||
(pad 2 smd rect (at 2.9 -2) (size 2.8 1) (layers F.Cu F.Paste F.Mask))
|
||||
(pad 2 smd rect (at -2.9 -2) (size 2.8 1) (layers F.Cu F.Paste F.Mask))
|
||||
(model ${KIPRJMOD}/PocketVoltex.pretty/KSC5.wrl
|
||||
(at (xyz 0 0 0))
|
||||
(scale (xyz 1 1 1))
|
||||
(rotate (xyz 0 0 0))
|
||||
)
|
||||
)
|
||||
@@ -0,0 +1,53 @@
|
||||
(module USB_C_Receptacle_UJ31-CH-31-SMT-TR (layer F.Cu) (tedit 5AF6C356)
|
||||
(fp_text reference REF** (at 0 5.08) (layer F.SilkS)
|
||||
(effects (font (size 1 1) (thickness 0.15)))
|
||||
)
|
||||
(fp_text value USB_C (at 0 7.62) (layer F.Fab)
|
||||
(effects (font (size 1 1) (thickness 0.15)))
|
||||
)
|
||||
(fp_line (start -5 -0.5) (end 5 -0.5) (layer F.CrtYd) (width 0.15))
|
||||
(fp_line (start -5 10.5) (end -5 -0.5) (layer F.CrtYd) (width 0.15))
|
||||
(fp_line (start 5 10.5) (end -5 10.5) (layer F.CrtYd) (width 0.15))
|
||||
(fp_line (start 5 -0.5) (end 5 10.5) (layer F.CrtYd) (width 0.15))
|
||||
(fp_text user "PCB EDGE" (at 0 11) (layer F.Fab)
|
||||
(effects (font (size 0.5 0.5) (thickness 0.07)))
|
||||
)
|
||||
(fp_line (start -4.5 10.26) (end 4.5 10.26) (layer F.Fab) (width 0.15))
|
||||
(pad A1 smd rect (at -2.75 0) (size 0.32 0.7) (layers F.Cu F.Paste F.Mask))
|
||||
(pad A2 smd rect (at -2.25 0) (size 0.32 0.7) (layers F.Cu F.Paste F.Mask))
|
||||
(pad A3 smd rect (at -1.75 0) (size 0.32 0.7) (layers F.Cu F.Paste F.Mask))
|
||||
(pad A4 smd rect (at -1.25 0) (size 0.32 0.7) (layers F.Cu F.Paste F.Mask))
|
||||
(pad A5 smd rect (at -0.75 0) (size 0.32 0.7) (layers F.Cu F.Paste F.Mask))
|
||||
(pad A6 smd rect (at -0.25 0) (size 0.32 0.7) (layers F.Cu F.Paste F.Mask))
|
||||
(pad A7 smd rect (at 0.25 0) (size 0.32 0.7) (layers F.Cu F.Paste F.Mask))
|
||||
(pad A8 smd rect (at 0.75 0) (size 0.32 0.7) (layers F.Cu F.Paste F.Mask))
|
||||
(pad A9 smd rect (at 1.25 0) (size 0.32 0.7) (layers F.Cu F.Paste F.Mask))
|
||||
(pad A10 smd rect (at 1.75 0) (size 0.32 0.7) (layers F.Cu F.Paste F.Mask))
|
||||
(pad A11 smd rect (at 2.25 0) (size 0.32 0.7) (layers F.Cu F.Paste F.Mask))
|
||||
(pad A12 smd rect (at 2.75 0) (size 0.32 0.7) (layers F.Cu F.Paste F.Mask))
|
||||
(pad "" np_thru_hole circle (at -3.6 0.66) (size 0.85 0.85) (drill 0.85) (layers *.Cu *.Mask))
|
||||
(pad "" np_thru_hole oval (at 3.6 0.66) (size 1.15 0.85) (drill oval 1.15 0.85) (layers *.Cu *.Mask))
|
||||
(pad S1 thru_hole oval (at -4.33 7.86) (size 0.9 1.4) (drill oval 0.6 1.1) (layers *.Cu *.Mask))
|
||||
(pad S1 thru_hole oval (at 4.33 7.86) (size 0.9 1.4) (drill oval 0.6 1.1) (layers *.Cu *.Mask))
|
||||
(pad S1 thru_hole oval (at -4.33 1.91) (size 0.9 1.4) (drill oval 0.6 1.1) (layers *.Cu *.Mask))
|
||||
(pad S1 thru_hole oval (at 4.33 1.91) (size 0.9 1.4) (drill oval 0.6 1.1) (layers *.Cu *.Mask))
|
||||
(pad S1 thru_hole oval (at -4.005 1.66 90) (size 0.9 1.55) (drill oval 0.6 1.25) (layers *.Cu *.Mask))
|
||||
(pad B12 thru_hole circle (at -2.8 1.31) (size 0.6 0.6) (drill 0.4) (layers *.Cu *.Mask))
|
||||
(pad B9 thru_hole circle (at -1.2 1.31) (size 0.6 0.6) (drill 0.4) (layers *.Cu *.Mask))
|
||||
(pad B7 thru_hole circle (at -0.4 1.31) (size 0.6 0.6) (drill 0.4) (layers *.Cu *.Mask))
|
||||
(pad B6 thru_hole circle (at 0.4 1.31) (size 0.6 0.6) (drill 0.4) (layers *.Cu *.Mask))
|
||||
(pad B4 thru_hole circle (at 1.2 1.31) (size 0.6 0.6) (drill 0.4) (layers *.Cu *.Mask))
|
||||
(pad B1 thru_hole circle (at 2.8 1.31) (size 0.6 0.6) (drill 0.4) (layers *.Cu *.Mask))
|
||||
(pad B11 thru_hole circle (at -2.4 2.01) (size 0.6 0.6) (drill 0.4) (layers *.Cu *.Mask))
|
||||
(pad B10 thru_hole circle (at -1.6 2.01) (size 0.6 0.6) (drill 0.4) (layers *.Cu *.Mask))
|
||||
(pad B8 thru_hole circle (at -0.8 2.01) (size 0.6 0.6) (drill 0.4) (layers *.Cu *.Mask))
|
||||
(pad B5 thru_hole circle (at 0.8 2.01) (size 0.6 0.6) (drill 0.4) (layers *.Cu *.Mask))
|
||||
(pad B3 thru_hole circle (at 1.6 2.01) (size 0.6 0.6) (drill 0.4) (layers *.Cu *.Mask))
|
||||
(pad B2 thru_hole circle (at 2.4 2.01) (size 0.6 0.6) (drill 0.4) (layers *.Cu *.Mask))
|
||||
(pad S1 thru_hole oval (at 4.005 1.66 90) (size 0.9 1.55) (drill oval 0.6 1.25) (layers *.Cu *.Mask))
|
||||
(model ${KIPRJMOD}/PocketVoltex.pretty/UJ31-CH-31-SMT-TR.wrl
|
||||
(at (xyz 0 0 0))
|
||||
(scale (xyz 1 1 1))
|
||||
(rotate (xyz 0 0 0))
|
||||
)
|
||||
)
|
||||
@@ -0,0 +1,10 @@
|
||||
(module VIA_0.4mm (layer F.Cu) (tedit 5B1925A5)
|
||||
(fp_text reference REF** (at 0 0.5) (layer F.SilkS) hide
|
||||
(effects (font (size 0.127 0.127) (thickness 0.03175)))
|
||||
)
|
||||
(fp_text value VIA_0.4mm (at 0 -0.5) (layer F.Fab) hide
|
||||
(effects (font (size 0.127 0.127) (thickness 0.03175)))
|
||||
)
|
||||
(pad 1 thru_hole circle (at 0 0) (size 0.6 0.6) (drill 0.4) (layers *.Cu)
|
||||
(zone_connect 2))
|
||||
)
|
||||
@@ -0,0 +1,21 @@
|
||||
(module murata-resonator_SMD_CSTCE16M0V53-R0 (layer F.Cu) (tedit 553BC69A)
|
||||
(descr ./Docs/MURATA__p17e.pdf)
|
||||
(tags "resonator, murata, SMD, CSTCE16M0V53-R0")
|
||||
(fp_text reference X? (at 0 -2.4) (layer F.SilkS)
|
||||
(effects (font (size 1 1) (thickness 0.2)))
|
||||
)
|
||||
(fp_text value VAL** (at 0 2.6) (layer F.SilkS) hide
|
||||
(effects (font (size 1 1) (thickness 0.2)))
|
||||
)
|
||||
(fp_line (start -1.8 1.1) (end -1.8 -1.1) (layer F.CrtYd) (width 0.05))
|
||||
(fp_line (start 1.8 1.1) (end -1.8 1.1) (layer F.CrtYd) (width 0.05))
|
||||
(fp_line (start 1.8 -1.1) (end 1.8 1.1) (layer F.CrtYd) (width 0.05))
|
||||
(fp_line (start -1.8 -1.1) (end 1.8 -1.1) (layer F.CrtYd) (width 0.05))
|
||||
(fp_line (start 1.6 0.65) (end -1.6 0.65) (layer F.SilkS) (width 0.2))
|
||||
(fp_line (start -1.6 -0.65) (end 1.6 -0.65) (layer F.SilkS) (width 0.2))
|
||||
(fp_line (start 1.6 -0.65) (end 1.6 0.65) (layer F.SilkS) (width 0.2))
|
||||
(fp_line (start -1.6 -0.65) (end -1.6 0.65) (layer F.SilkS) (width 0.2))
|
||||
(pad 1 smd rect (at -0.95 0) (size 0.6 2) (layers F.Cu F.Paste F.Mask))
|
||||
(pad 2 smd rect (at 0 0) (size 0.6 2) (layers F.Cu F.Paste F.Mask))
|
||||
(pad 3 smd rect (at 0.95 0) (size 0.6 2) (layers F.Cu F.Paste F.Mask))
|
||||
)
|
||||
@@ -0,0 +1,40 @@
|
||||
update=16/08/2018 10:39:03 PM
|
||||
version=1
|
||||
last_client=kicad
|
||||
[pcbnew]
|
||||
version=1
|
||||
LastNetListRead=
|
||||
UseCmpFile=1
|
||||
PadDrill=0.600000000000
|
||||
PadDrillOvalY=0.600000000000
|
||||
PadSizeH=1.500000000000
|
||||
PadSizeV=1.500000000000
|
||||
PcbTextSizeV=1.500000000000
|
||||
PcbTextSizeH=1.500000000000
|
||||
PcbTextThickness=0.300000000000
|
||||
ModuleTextSizeV=1.000000000000
|
||||
ModuleTextSizeH=1.000000000000
|
||||
ModuleTextSizeThickness=0.150000000000
|
||||
SolderMaskClearance=0.000000000000
|
||||
SolderMaskMinWidth=0.000000000000
|
||||
DrawSegmentWidth=0.200000000000
|
||||
BoardOutlineThickness=0.100000000000
|
||||
ModuleOutlineThickness=0.150000000000
|
||||
[cvpcb]
|
||||
version=1
|
||||
NetIExt=net
|
||||
[general]
|
||||
version=1
|
||||
[eeschema]
|
||||
version=1
|
||||
LibDir=
|
||||
[schematic_editor]
|
||||
version=1
|
||||
PageLayoutDescrFile=
|
||||
PlotDirectoryName=
|
||||
SubpartIdSeparator=0
|
||||
SubpartFirstId=65
|
||||
NetFmtName=
|
||||
SpiceAjustPassiveValues=0
|
||||
LabSize=50
|
||||
ERC_TestSimilarLabels=1
|
||||
@@ -0,0 +1,2 @@
|
||||
Cherry MX Stabiliser:
|
||||
https://grabcad.com/library/cherry-mx-stabilizer-mx-1
|
||||