diff options
Diffstat (limited to 'keyboards')
43 files changed, 3943 insertions, 77 deletions
diff --git a/keyboards/atomic/readme.md b/keyboards/atomic/readme.md index 674dcf113b..1224c415f0 100644 --- a/keyboards/atomic/readme.md +++ b/keyboards/atomic/readme.md @@ -1,26 +1,16 @@ -Atomic keyboard firmware -====================== -DIY/Assembled ortholinear 60% keyboard by [Ortholinear Keyboards](http://ortholinearkeyboards.com). +Atomic +=== -## Quantum MK Firmware +![Atomic](http://i.imgur.com/3gNDJAh.jpg) -For the full Quantum feature list, see [the parent readme.md](/readme.md). +A compact 60% (15x5) ortholinear keyboard kit made and sold by OLKB. [More info on qmk.fm](http://qmk.fm/atomic/) -## Building +Keyboard Maintainer: [Jack Humbert](https://github.com/jackhumbert) +Hardware Supported: Atomic PCB rev1, Teensy 2.0 +Hardware Availability: no longer available -Download or clone the whole firmware and navigate to the keyboards/atomic folder. Once your dev env is setup, you'll be able to type `make` to generate your .hex - you can then use `make dfu` to program your PCB once you hit the reset button. +Make example for this keyboard (after setting up your build environment): -Depending on which keymap you would like to use, you will have to compile slightly differently. + make atomic-default -### Default -To build with the default keymap, simply run `make default`. - -### Other Keymaps -Several version of keymap are available in advance but you are recommended to define your favorite layout yourself. To define your own keymap create a file in the keymaps folder named `<name>.c` and see keymap document (you can find in top readme.md) and existent keymap files. - -To build the firmware binary hex file with a keymap just do `make` with a keymap like this: - -``` -$ make [default|jack|<name>] -``` -Keymaps follow the format **__\<name\>.c__** and are stored in the `keymaps` folder. +See [build environment setup](https://docs.qmk.fm/build_environment_setup.html) then the [make instructions](https://docs.qmk.fm/make_instructions.html) for more information.
\ No newline at end of file diff --git a/keyboards/ergodox/infinity/config.h b/keyboards/ergodox/infinity/config.h index 95f713819e..25cc8af0fc 100644 --- a/keyboards/ergodox/infinity/config.h +++ b/keyboards/ergodox/infinity/config.h @@ -56,6 +56,11 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. #define VISUALIZER_USER_DATA_SIZE 16 +#define LCD_DISPLAY_NUMBER 0 +#define LED_DISPLAY_NUMBER 1 + +#define LED_NUM_ROWS 7 +#define LED_NUM_COLS 7 /* * Feature disable options * These options are also useful to firmware size reduction. diff --git a/keyboards/orthodox/Makefile b/keyboards/orthodox/Makefile new file mode 100644 index 0000000000..f5c87d4d65 --- /dev/null +++ b/keyboards/orthodox/Makefile @@ -0,0 +1,5 @@ +SUBPROJECT_DEFAULT = rev2 + +ifndef MAKEFILE_INCLUDED + include ../../Makefile +endif diff --git a/keyboards/orthodox/common/glcdfont.c b/keyboards/orthodox/common/glcdfont.c new file mode 100644 index 0000000000..6f88bd23a7 --- /dev/null +++ b/keyboards/orthodox/common/glcdfont.c @@ -0,0 +1,276 @@ +// This is the 'classic' fixed-space bitmap font for Adafruit_GFX since 1.0. +// See gfxfont.h for newer custom bitmap font info. + +#ifndef FONT5X7_H +#define FONT5X7_H + +#ifdef __AVR__ + #include <avr/io.h> + #include <avr/pgmspace.h> +#elif defined(ESP8266) + #include <pgmspace.h> +#else + #define PROGMEM +#endif + +// Standard ASCII 5x7 font + +static const unsigned char font[] PROGMEM = { + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x3E, 0x5B, 0x4F, 0x5B, 0x3E, + 0x3E, 0x6B, 0x4F, 0x6B, 0x3E, + 0x1C, 0x3E, 0x7C, 0x3E, 0x1C, + 0x18, 0x3C, 0x7E, 0x3C, 0x18, + 0x1C, 0x57, 0x7D, 0x57, 0x1C, + 0x1C, 0x5E, 0x7F, 0x5E, 0x1C, + 0x00, 0x18, 0x3C, 0x18, 0x00, + 0xFF, 0xE7, 0xC3, 0xE7, 0xFF, + 0x00, 0x18, 0x24, 0x18, 0x00, + 0xFF, 0xE7, 0xDB, 0xE7, 0xFF, + 0x30, 0x48, 0x3A, 0x06, 0x0E, + 0x26, 0x29, 0x79, 0x29, 0x26, + 0x40, 0x7F, 0x05, 0x05, 0x07, + 0x40, 0x7F, 0x05, 0x25, 0x3F, + 0x5A, 0x3C, 0xE7, 0x3C, 0x5A, + 0x7F, 0x3E, 0x1C, 0x1C, 0x08, + 0x08, 0x1C, 0x1C, 0x3E, 0x7F, + 0x14, 0x22, 0x7F, 0x22, 0x14, + 0x5F, 0x5F, 0x00, 0x5F, 0x5F, + 0x06, 0x09, 0x7F, 0x01, 0x7F, + 0x00, 0x66, 0x89, 0x95, 0x6A, + 0x60, 0x60, 0x60, 0x60, 0x60, + 0x94, 0xA2, 0xFF, 0xA2, 0x94, + 0x08, 0x04, 0x7E, 0x04, 0x08, + 0x10, 0x20, 0x7E, 0x20, 0x10, + 0x08, 0x08, 0x2A, 0x1C, 0x08, + 0x08, 0x1C, 0x2A, 0x08, 0x08, + 0x1E, 0x10, 0x10, 0x10, 0x10, + 0x0C, 0x1E, 0x0C, 0x1E, 0x0C, + 0x30, 0x38, 0x3E, 0x38, 0x30, + 0x06, 0x0E, 0x3E, 0x0E, 0x06, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x5F, 0x00, 0x00, + 0x00, 0x07, 0x00, 0x07, 0x00, + 0x14, 0x7F, 0x14, 0x7F, 0x14, + 0x24, 0x2A, 0x7F, 0x2A, 0x12, + 0x23, 0x13, 0x08, 0x64, 0x62, + 0x36, 0x49, 0x56, 0x20, 0x50, + 0x00, 0x08, 0x07, 0x03, 0x00, + 0x00, 0x1C, 0x22, 0x41, 0x00, + 0x00, 0x41, 0x22, 0x1C, 0x00, + 0x2A, 0x1C, 0x7F, 0x1C, 0x2A, + 0x08, 0x08, 0x3E, 0x08, 0x08, + 0x00, 0x80, 0x70, 0x30, 0x00, + 0x08, 0x08, 0x08, 0x08, 0x08, + 0x00, 0x00, 0x60, 0x60, 0x00, + 0x20, 0x10, 0x08, 0x04, 0x02, + 0x3E, 0x51, 0x49, 0x45, 0x3E, + 0x00, 0x42, 0x7F, 0x40, 0x00, + 0x72, 0x49, 0x49, 0x49, 0x46, + 0x21, 0x41, 0x49, 0x4D, 0x33, + 0x18, 0x14, 0x12, 0x7F, 0x10, + 0x27, 0x45, 0x45, 0x45, 0x39, + 0x3C, 0x4A, 0x49, 0x49, 0x31, + 0x41, 0x21, 0x11, 0x09, 0x07, + 0x36, 0x49, 0x49, 0x49, 0x36, + 0x46, 0x49, 0x49, 0x29, 0x1E, + 0x00, 0x00, 0x14, 0x00, 0x00, + 0x00, 0x40, 0x34, 0x00, 0x00, + 0x00, 0x08, 0x14, 0x22, 0x41, + 0x14, 0x14, 0x14, 0x14, 0x14, + 0x00, 0x41, 0x22, 0x14, 0x08, + 0x02, 0x01, 0x59, 0x09, 0x06, + 0x3E, 0x41, 0x5D, 0x59, 0x4E, + 0x7C, 0x12, 0x11, 0x12, 0x7C, + 0x7F, 0x49, 0x49, 0x49, 0x36, + 0x3E, 0x41, 0x41, 0x41, 0x22, + 0x7F, 0x41, 0x41, 0x41, 0x3E, + 0x7F, 0x49, 0x49, 0x49, 0x41, + 0x7F, 0x09, 0x09, 0x09, 0x01, + 0x3E, 0x41, 0x41, 0x51, 0x73, + 0x7F, 0x08, 0x08, 0x08, 0x7F, + 0x00, 0x41, 0x7F, 0x41, 0x00, + 0x20, 0x40, 0x41, 0x3F, 0x01, + 0x7F, 0x08, 0x14, 0x22, 0x41, + 0x7F, 0x40, 0x40, 0x40, 0x40, + 0x7F, 0x02, 0x1C, 0x02, 0x7F, + 0x7F, 0x04, 0x08, 0x10, 0x7F, + 0x3E, 0x41, 0x41, 0x41, 0x3E, + 0x7F, 0x09, 0x09, 0x09, 0x06, + 0x3E, 0x41, 0x51, 0x21, 0x5E, + 0x7F, 0x09, 0x19, 0x29, 0x46, + 0x26, 0x49, 0x49, 0x49, 0x32, + 0x03, 0x01, 0x7F, 0x01, 0x03, + 0x3F, 0x40, 0x40, 0x40, 0x3F, + 0x1F, 0x20, 0x40, 0x20, 0x1F, + 0x3F, 0x40, 0x38, 0x40, 0x3F, + 0x63, 0x14, 0x08, 0x14, 0x63, + 0x03, 0x04, 0x78, 0x04, 0x03, + 0x61, 0x59, 0x49, 0x4D, 0x43, + 0x00, 0x7F, 0x41, 0x41, 0x41, + 0x02, 0x04, 0x08, 0x10, 0x20, + 0x00, 0x41, 0x41, 0x41, 0x7F, + 0x04, 0x02, 0x01, 0x02, 0x04, + 0x40, 0x40, 0x40, 0x40, 0x40, + 0x00, 0x03, 0x07, 0x08, 0x00, + 0x20, 0x54, 0x54, 0x78, 0x40, + 0x7F, 0x28, 0x44, 0x44, 0x38, + 0x38, 0x44, 0x44, 0x44, 0x28, + 0x38, 0x44, 0x44, 0x28, 0x7F, + 0x38, 0x54, 0x54, 0x54, 0x18, + 0x00, 0x08, 0x7E, 0x09, 0x02, + 0x18, 0xA4, 0xA4, 0x9C, 0x78, + 0x7F, 0x08, 0x04, 0x04, 0x78, + 0x00, 0x44, 0x7D, 0x40, 0x00, + 0x20, 0x40, 0x40, 0x3D, 0x00, + 0x7F, 0x10, 0x28, 0x44, 0x00, + 0x00, 0x41, 0x7F, 0x40, 0x00, + 0x7C, 0x04, 0x78, 0x04, 0x78, + 0x7C, 0x08, 0x04, 0x04, 0x78, + 0x38, 0x44, 0x44, 0x44, 0x38, + 0xFC, 0x18, 0x24, 0x24, 0x18, + 0x18, 0x24, 0x24, 0x18, 0xFC, + 0x7C, 0x08, 0x04, 0x04, 0x08, + 0x48, 0x54, 0x54, 0x54, 0x24, + 0x04, 0x04, 0x3F, 0x44, 0x24, + 0x3C, 0x40, 0x40, 0x20, 0x7C, + 0x1C, 0x20, 0x40, 0x20, 0x1C, + 0x3C, 0x40, 0x30, 0x40, 0x3C, + 0x44, 0x28, 0x10, 0x28, 0x44, + 0x4C, 0x90, 0x90, 0x90, 0x7C, + 0x44, 0x64, 0x54, 0x4C, 0x44, + 0x00, 0x08, 0x36, 0x41, 0x00, + 0x00, 0x00, 0x77, 0x00, 0x00, + 0x00, 0x41, 0x36, 0x08, 0x00, + 0x02, 0x01, 0x02, 0x04, 0x02, + 0x3C, 0x26, 0x23, 0x26, 0x3C, + 0x1E, 0xA1, 0xA1, 0x61, 0x12, + 0x3A, 0x40, 0x40, 0x20, 0x7A, + 0x38, 0x54, 0x54, 0x55, 0x59, + 0x21, 0x55, 0x55, 0x79, 0x41, + 0x22, 0x54, 0x54, 0x78, 0x42, // a-umlaut + 0x21, 0x55, 0x54, 0x78, 0x40, + 0x20, 0x54, 0x55, 0x79, 0x40, + 0x0C, 0x1E, 0x52, 0x72, 0x12, + 0x39, 0x55, 0x55, 0x55, 0x59, + 0x39, 0x54, 0x54, 0x54, 0x59, + 0x39, 0x55, 0x54, 0x54, 0x58, + 0x00, 0x00, 0x45, 0x7C, 0x41, + 0x00, 0x02, 0x45, 0x7D, 0x42, + 0x00, 0x01, 0x45, 0x7C, 0x40, + 0x7D, 0x12, 0x11, 0x12, 0x7D, // A-umlaut + 0xF0, 0x28, 0x25, 0x28, 0xF0, + 0x7C, 0x54, 0x55, 0x45, 0x00, + 0x20, 0x54, 0x54, 0x7C, 0x54, + 0x7C, 0x0A, 0x09, 0x7F, 0x49, + 0x32, 0x49, 0x49, 0x49, 0x32, + 0x3A, 0x44, 0x44, 0x44, 0x3A, // o-umlaut + 0x32, 0x4A, 0x48, 0x48, 0x30, + 0x3A, 0x41, 0x41, 0x21, 0x7A, + 0x3A, 0x42, 0x40, 0x20, 0x78, + 0x00, 0x9D, 0xA0, 0xA0, 0x7D, + 0x3D, 0x42, 0x42, 0x42, 0x3D, // O-umlaut + 0x3D, 0x40, 0x40, 0x40, 0x3D, + 0x3C, 0x24, 0xFF, 0x24, 0x24, + 0x48, 0x7E, 0x49, 0x43, 0x66, + 0x2B, 0x2F, 0xFC, 0x2F, 0x2B, + 0xFF, 0x09, 0x29, 0xF6, 0x20, + 0xC0, 0x88, 0x7E, 0x09, 0x03, + 0x20, 0x54, 0x54, 0x79, 0x41, + 0x00, 0x00, 0x44, 0x7D, 0x41, + 0x30, 0x48, 0x48, 0x4A, 0x32, + 0x38, 0x40, 0x40, 0x22, 0x7A, + 0x00, 0x7A, 0x0A, 0x0A, 0x72, + 0x7D, 0x0D, 0x19, 0x31, 0x7D, + 0x26, 0x29, 0x29, 0x2F, 0x28, + 0x26, 0x29, 0x29, 0x29, 0x26, + 0x30, 0x48, 0x4D, 0x40, 0x20, + 0x38, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x38, + 0x2F, 0x10, 0xC8, 0xAC, 0xBA, + 0x2F, 0x10, 0x28, 0x34, 0xFA, + 0x00, 0x00, 0x7B, 0x00, 0x00, + 0x08, 0x14, 0x2A, 0x14, 0x22, + 0x22, 0x14, 0x2A, 0x14, 0x08, + 0x55, 0x00, 0x55, 0x00, 0x55, // #176 (25% block) missing in old code + 0xAA, 0x55, 0xAA, 0x55, 0xAA, // 50% block + 0xFF, 0x55, 0xFF, 0x55, 0xFF, // 75% block + 0x00, 0x00, 0x00, 0xFF, 0x00, + 0x10, 0x10, 0x10, 0xFF, 0x00, + 0x14, 0x14, 0x14, 0xFF, 0x00, + 0x10, 0x10, 0xFF, 0x00, 0xFF, + 0x10, 0x10, 0xF0, 0x10, 0xF0, + 0x14, 0x14, 0x14, 0xFC, 0x00, + 0x14, 0x14, 0xF7, 0x00, 0xFF, + 0x00, 0x00, 0xFF, 0x00, 0xFF, + 0x14, 0x14, 0xF4, 0x04, 0xFC, + 0x14, 0x14, 0x17, 0x10, 0x1F, + 0x10, 0x10, 0x1F, 0x10, 0x1F, + 0x14, 0x14, 0x14, 0x1F, 0x00, + 0x10, 0x10, 0x10, 0xF0, 0x00, + 0x00, 0x00, 0x00, 0x1F, 0x10, + 0x10, 0x10, 0x10, 0x1F, 0x10, + 0x10, 0x10, 0x10, 0xF0, 0x10, + 0x00, 0x00, 0x00, 0xFF, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0xFF, 0x10, + 0x00, 0x00, 0x00, 0xFF, 0x14, + 0x00, 0x00, 0xFF, 0x00, 0xFF, + 0x00, 0x00, 0x1F, 0x10, 0x17, + 0x00, 0x00, 0xFC, 0x04, 0xF4, + 0x14, 0x14, 0x17, 0x10, 0x17, + 0x14, 0x14, 0xF4, 0x04, 0xF4, + 0x00, 0x00, 0xFF, 0x00, 0xF7, + 0x14, 0x14, 0x14, 0x14, 0x14, + 0x14, 0x14, 0xF7, 0x00, 0xF7, + 0x14, 0x14, 0x14, 0x17, 0x14, + 0x10, 0x10, 0x1F, 0x10, 0x1F, + 0x14, 0x14, 0x14, 0xF4, 0x14, + 0x10, 0x10, 0xF0, 0x10, 0xF0, + 0x00, 0x00, 0x1F, 0x10, 0x1F, + 0x00, 0x00, 0x00, 0x1F, 0x14, + 0x00, 0x00, 0x00, 0xFC, 0x14, + 0x00, 0x00, 0xF0, 0x10, 0xF0, + 0x10, 0x10, 0xFF, 0x10, 0xFF, + 0x14, 0x14, 0x14, 0xFF, 0x14, + 0x10, 0x10, 0x10, 0x1F, 0x00, + 0x00, 0x00, 0x00, 0xF0, 0x10, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xFF, 0xFF, + 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, + 0x38, 0x44, 0x44, 0x38, 0x44, + 0xFC, 0x4A, 0x4A, 0x4A, 0x34, // sharp-s or beta + 0x7E, 0x02, 0x02, 0x06, 0x06, + 0x02, 0x7E, 0x02, 0x7E, 0x02, + 0x63, 0x55, 0x49, 0x41, 0x63, + 0x38, 0x44, 0x44, 0x3C, 0x04, + 0x40, 0x7E, 0x20, 0x1E, 0x20, + 0x06, 0x02, 0x7E, 0x02, 0x02, + 0x99, 0xA5, 0xE7, 0xA5, 0x99, + 0x1C, 0x2A, 0x49, 0x2A, 0x1C, + 0x4C, 0x72, 0x01, 0x72, 0x4C, + 0x30, 0x4A, 0x4D, 0x4D, 0x30, + 0x30, 0x48, 0x78, 0x48, 0x30, + 0xBC, 0x62, 0x5A, 0x46, 0x3D, + 0x3E, 0x49, 0x49, 0x49, 0x00, + 0x7E, 0x01, 0x01, 0x01, 0x7E, + 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, + 0x44, 0x44, 0x5F, 0x44, 0x44, + 0x40, 0x51, 0x4A, 0x44, 0x40, + 0x40, 0x44, 0x4A, 0x51, 0x40, + 0x00, 0x00, 0xFF, 0x01, 0x03, + 0xE0, 0x80, 0xFF, 0x00, 0x00, + 0x08, 0x08, 0x6B, 0x6B, 0x08, + 0x36, 0x12, 0x36, 0x24, 0x36, + 0x06, 0x0F, 0x09, 0x0F, 0x06, + 0x00, 0x00, 0x18, 0x18, 0x00, + 0x00, 0x00, 0x10, 0x10, 0x00, + 0x30, 0x40, 0xFF, 0x01, 0x01, + 0x00, 0x1F, 0x01, 0x01, 0x1E, + 0x00, 0x19, 0x1D, 0x17, 0x12, + 0x00, 0x3C, 0x3C, 0x3C, 0x3C, + 0x00, 0x00, 0x00, 0x00, 0x00 // #255 NBSP +}; +#endif // FONT5X7_H diff --git a/keyboards/orthodox/config.h b/keyboards/orthodox/config.h new file mode 100644 index 0000000000..008fb09789 --- /dev/null +++ b/keyboards/orthodox/config.h @@ -0,0 +1,32 @@ +/* +Copyright 2012 Jun Wako <wakojun@gmail.com> + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef CONFIG_H +#define CONFIG_H + +#include "config_common.h" + +#ifdef SUBPROJECT_rev1 + #include "rev1/config.h" +#endif +#ifdef SUBPROJECT_rev2 + #include "rev2/config.h" +#endif +#ifdef SUBPROJECT_rev2fliphalf + #include "../../rev2fliphalf/config.h" +#endif +#endif diff --git a/keyboards/orthodox/i2c.c b/keyboards/orthodox/i2c.c new file mode 100644 index 0000000000..084c890c40 --- /dev/null +++ b/keyboards/orthodox/i2c.c @@ -0,0 +1,162 @@ +#include <util/twi.h> +#include <avr/io.h> +#include <stdlib.h> +#include <avr/interrupt.h> +#include <util/twi.h> +#include <stdbool.h> +#include "i2c.h" + +#ifdef USE_I2C + +// Limits the amount of we wait for any one i2c transaction. +// Since were running SCL line 100kHz (=> 10μs/bit), and each transactions is +// 9 bits, a single transaction will take around 90μs to complete. +// +// (F_CPU/SCL_CLOCK) => # of μC cycles to transfer a bit +// poll loop takes at least 8 clock cycles to execute +#define I2C_LOOP_TIMEOUT (9+1)*(F_CPU/SCL_CLOCK)/8 + +#define BUFFER_POS_INC() (slave_buffer_pos = (slave_buffer_pos+1)%SLAVE_BUFFER_SIZE) + +volatile uint8_t i2c_slave_buffer[SLAVE_BUFFER_SIZE]; + +static volatile uint8_t slave_buffer_pos; +static volatile bool slave_has_register_set = false; + +// Wait for an i2c operation to finish +inline static +void i2c_delay(void) { + uint16_t lim = 0; + while(!(TWCR & (1<<TWINT)) && lim < I2C_LOOP_TIMEOUT) + lim++; + + // easier way, but will wait slightly longer + // _delay_us(100); +} + +// Setup twi to run at 100kHz +void i2c_master_init(void) { + // no prescaler + TWSR = 0; + // Set TWI clock frequency to SCL_CLOCK. Need TWBR>10. + // Check datasheets for more info. + TWBR = ((F_CPU/SCL_CLOCK)-16)/2; +} + +// Start a transaction with the given i2c slave address. The direction of the +// transfer is set with I2C_READ and I2C_WRITE. +// returns: 0 => success +// 1 => error +uint8_t i2c_master_start(uint8_t address) { + TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWSTA); + + i2c_delay(); + + // check that we started successfully + if ( (TW_STATUS != TW_START) && (TW_STATUS != TW_REP_START)) + return 1; + + TWDR = address; + TWCR = (1<<TWINT) | (1<<TWEN); + + i2c_delay(); + + if ( (TW_STATUS != TW_MT_SLA_ACK) && (TW_STATUS != TW_MR_SLA_ACK) ) + return 1; // slave did not acknowledge + else + return 0; // success +} + + +// Finish the i2c transaction. +void i2c_master_stop(void) { + TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWSTO); + + uint16_t lim = 0; + while(!(TWCR & (1<<TWSTO)) && lim < I2C_LOOP_TIMEOUT) + lim++; +} + +// Write one byte to the i2c slave. +// returns 0 => slave ACK +// 1 => slave NACK +uint8_t i2c_master_write(uint8_t data) { + TWDR = data; + TWCR = (1<<TWINT) | (1<<TWEN); + + i2c_delay(); + + // check if the slave acknowledged us + return (TW_STATUS == TW_MT_DATA_ACK) ? 0 : 1; +} + +// Read one byte from the i2c slave. If ack=1 the slave is acknowledged, +// if ack=0 the acknowledge bit is not set. +// returns: byte read from i2c device +uint8_t i2c_master_read(int ack) { + TWCR = (1<<TWINT) | (1<<TWEN) | (ack<<TWEA); + + i2c_delay(); + return TWDR; +} + +void i2c_reset_state(void) { + TWCR = 0; +} + +void i2c_slave_init(uint8_t address) { + TWAR = address << 0; // slave i2c address + // TWEN - twi enable + // TWEA - enable address acknowledgement + // TWINT - twi interrupt flag + // TWIE - enable the twi interrupt + TWCR = (1<<TWIE) | (1<<TWEA) | (1<<TWINT) | (1<<TWEN); +} + +ISR(TWI_vect); + +ISR(TWI_vect) { + uint8_t ack = 1; + switch(TW_STATUS) { + case TW_SR_SLA_ACK: + // this device has been addressed as a slave receiver + slave_has_register_set = false; + break; + + case TW_SR_DATA_ACK: + // this device has received data as a slave receiver + // The first byte that we receive in this transaction sets the location + // of the read/write location of the slaves memory that it exposes over + // i2c. After that, bytes will be written at slave_buffer_pos, incrementing + // slave_buffer_pos after each write. + if(!slave_has_register_set) { + slave_buffer_pos = TWDR; + // don't acknowledge the master if this memory loctaion is out of bounds + if ( slave_buffer_pos >= SLAVE_BUFFER_SIZE ) { + ack = 0; + slave_buffer_pos = 0; + } + slave_has_register_set = true; + } else { + i2c_slave_buffer[slave_buffer_pos] = TWDR; + BUFFER_POS_INC(); + } + break; + + case TW_ST_SLA_ACK: + case TW_ST_DATA_ACK: + // master has addressed this device as a slave transmitter and is + // requesting data. + TWDR = i2c_slave_buffer[slave_buffer_pos]; + BUFFER_POS_INC(); + break; + + case TW_BUS_ERROR: // something went wrong, reset twi state + TWCR = 0; + default: + break; + } + // Reset everything, so we are ready for the next TWI interrupt + TWCR |= (1<<TWIE) | (1<<TWINT) | (ack<<TWEA) | (1<<TWEN); +} +#endif diff --git a/keyboards/orthodox/i2c.h b/keyboards/orthodox/i2c.h new file mode 100644 index 0000000000..2af843ff60 --- /dev/null +++ b/keyboards/orthodox/i2c.h @@ -0,0 +1,50 @@ +#ifndef I2C_H +#define I2C_H + +#include <stdint.h> +#include "matrix.h" + +#ifndef F_CPU +#define F_CPU 16000000UL +#endif + +#define I2C_READ 1 +#define I2C_WRITE 0 + +#define I2C_ACK 1 +#define I2C_NACK 0 + +#define SLAVE_BUFFER_SIZE 0x10 + +// i2c SCL clock frequency +#define SCL_CLOCK 100000UL + +extern volatile uint8_t i2c_slave_buffer[SLAVE_BUFFER_SIZE]; + +void i2c_master_init(void); +uint8_t i2c_master_start(uint8_t address); +void i2c_master_stop(void); +uint8_t i2c_master_write(uint8_t data); +uint8_t i2c_master_read(int); +void i2c_reset_state(void); +void i2c_slave_init(uint8_t address); + + +static inline unsigned char i2c_start_read(unsigned char addr) { + return i2c_master_start((addr << 1) | I2C_READ); +} + +static inline unsigned char i2c_start_write(unsigned char addr) { + return i2c_master_start((addr << 1) | I2C_WRITE); +} + +// from SSD1306 scrips +extern unsigned char i2c_rep_start(unsigned char addr); +extern void i2c_start_wait(unsigned char addr); +extern unsigned char i2c_readAck(void); +extern unsigned char i2c_readNak(void); +extern unsigned char i2c_read(unsigned char ack); + +#define i2c_read(ack) (ack) ? i2c_readAck() : i2c_readNak(); + +#endif diff --git a/keyboards/orthodox/keymaps/i2c/config.h b/keyboards/orthodox/keymaps/i2c/config.h new file mode 100644 index 0000000000..5425297199 --- /dev/null +++ b/keyboards/orthodox/keymaps/i2c/config.h @@ -0,0 +1,34 @@ +/* +Copyright 2012 Jun Wako <wakojun@gmail.com> + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + + +#define USE_I2C + +//#define MASTER_LEFT +//#define _MASTER_RIGHT +#define EE_HANDS + + +#ifdef SUBPROJECT_rev1 + #include "../../rev1/config.h" +#endif +#ifdef SUBPROJECT_rev2 + #include "../../rev2/config.h" +#endif +#ifdef SUBPROJECT_rev2fliphalf + #include "../../rev2fliphalf/config.h" +#endif diff --git a/keyboards/orthodox/keymaps/i2c/keymap.c b/keyboards/orthodox/keymaps/i2c/keymap.c new file mode 100644 index 0000000000..ed24a3a1f0 --- /dev/null +++ b/keyboards/orthodox/keymaps/i2c/keymap.c @@ -0,0 +1,132 @@ +#include "orthodox.h" +#include "action_layer.h" +#include "eeconfig.h" + +extern keymap_config_t keymap_config; + +// Each layer gets a name for readability, which is then used in the keymap matrix below. +// The underscores don't mean anything - you can have a layer called STUFF or any other name. +// Layer names don't all need to be of the same length, obviously, and you can also skip them +// entirely and just use numbers. +#define _QWERTY 0 +#define _COLEMAK 1 +#define _DVORAK 2 +#define _LOWER 3 +#define _RAISE 4 +#define _ADJUST 16 + +enum custom_keycodes { + QWERTY = SAFE_RANGE, + COLEMAK, + DVORAK, + LOWER, + RAISE, + ADJUST, +}; + +// Fillers to make layering more clear +#define _______ KC_TRNS +#define XXXXXXX KC_NO + +#define LS__SPC MT(MOD_LSFT, KC_SPC) + +const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { + +[_QWERTY] = KEYMAP( \ + KC_TAB, KC_Q, KC_W, KC_E, KC_R, KC_T, KC_Y, KC_U, KC_I, KC_O, KC_P, KC_BSPC, \ + KC_ESC, KC_A, KC_S, KC_D, KC_F, KC_G, KC_LEFT, XXXXXXX, KC_DOWN, KC_UP, XXXXXXX, KC_RIGHT,KC_H, KC_J, KC_K, KC_L, KC_SCLN, KC_QUOT, \ + KC_LCTL, KC_Z, KC_X, KC_C, KC_V, KC_B, LOWER, KC_BSPC, KC_ENT, KC_RALT, LS__SPC, RAISE, KC_N, KC_M, KC_COMM, KC_DOT, KC_SLSH, KC_LGUI \ +), + +[_LOWER] = KEYMAP( \ + KC_TILD, KC_EXLM, KC_AT, KC_HASH, KC_DLR, KC_PERC, KC_CIRC, KC_AMPR, KC_ASTR, KC_LPRN, KC_RPRN, KC_BSPC, \ + KC_DEL, KC_F1, KC_F2, KC_F3, KC_F4, KC_F5, KC_LCTL, XXXXXXX, _______, _______, XXXXXXX, KC_RCTL, KC_F6, KC_UNDS, KC_PLUS, KC_LCBR, KC_RCBR, KC_PIPE, \ + _______, KC_F7, KC_F8, KC_F9, KC_F10, KC_F11, _______, _______, _______, _______, _______, _______, KC_F12, KC_HOME, KC_COMM, KC_DOT, KC_END, _______ \ +), + +[_RAISE] = KEYMAP( \ + KC_GRV, KC_1, KC_2, KC_3, KC_4, KC_5, KC_6, KC_7, KC_8, KC_9, KC_0, KC_BSPC, \ + KC_DEL, KC_F1, KC_F2, KC_F3, KC_F4, KC_F5, _______, XXXXXXX, _______, _______, XXXXXXX, _______, KC_F6, KC_MINS, KC_EQL, KC_LBRC, KC_RBRC, KC_BSLS, \ + _______, KC_F7, KC_F8, KC_F9, KC_F10, KC_F11, _______, _______, _______, _______, _______, _______, KC_F12, KC_PGUP, KC_COMM, KC_DOT, KC_PGDN, _______ \ +), + +[_ADJUST] = KEYMAP( \ + _______, RESET, _______, _______, _______, _______, _______, _______, _______, _______, _______, KC_DEL, \ + _______, _______, _______, AU_ON, AU_OFF, AG_NORM, _______, XXXXXXX, _______, _______, XXXXXXX, _______, AG_SWAP, QWERTY , COLEMAK, DVORAK, _______, _______, \ + _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, KC_MNXT, KC_VOLD, KC_VOLU, KC_MPLY \ +) + + +}; + +#ifdef AUDIO_ENABLE +float tone_qwerty[][2] = SONG(QWERTY_SOUND); +float tone_dvorak[][2] = SONG(DVORAK_SOUND); +float tone_colemak[][2] = SONG(COLEMAK_SOUND); +#endif + +void persistent_default_layer_set(uint16_t default_layer) { + eeconfig_update_default_layer(default_layer); + default_layer_set(default_layer); +} + +bool process_record_user(uint16_t keycode, keyrecord_t *record) { + switch (keycode) { + case QWERTY: + if (record->event.pressed) { + #ifdef AUDIO_ENABLE + PLAY_NOTE_ARRAY(tone_qwerty, false, 0); + #endif + persistent_default_layer_set(1UL<<_QWERTY); + } + return false; + break; + case COLEMAK: + if (record->event.pressed) { + #ifdef AUDIO_ENABLE + PLAY_NOTE_ARRAY(tone_colemak, false, 0); + #endif + persistent_default_layer_set(1UL<<_COLEMAK); + } + return false; + break; + case DVORAK: + if (record->event.pressed) { + #ifdef AUDIO_ENABLE + PLAY_NOTE_ARRAY(tone_dvorak, false, 0); + #endif + persistent_default_layer_set(1UL<<_DVORAK); + } + return false; + break; + case LOWER: + if (record->event.pressed) { + layer_on(_LOWER); + update_tri_layer(_LOWER, _RAISE, _ADJUST); + } else { + layer_off(_LOWER); + update_tri_layer(_LOWER, _RAISE, _ADJUST); + } + return false; + break; + case RAISE: + if (record->event.pressed) { + layer_on(_RAISE); + update_tri_layer(_LOWER, _RAISE, _ADJUST); + } else { + layer_off(_RAISE); + update_tri_layer(_LOWER, _RAISE, _ADJUST); + } + return false; + break; + case ADJUST: + if (record->event.pressed) { + layer_on(_ADJUST); + } else { + layer_off(_ADJUST); + } + return false; + break; + } + return true; +} diff --git a/keyboards/orthodox/keymaps/serial/config.h b/keyboards/orthodox/keymaps/serial/config.h new file mode 100644 index 0000000000..5169452baa --- /dev/null +++ b/keyboards/orthodox/keymaps/serial/config.h @@ -0,0 +1,34 @@ +/* +Copyright 2012 Jun Wako <wakojun@gmail.com> + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + + +#define USE_SERIAL + +//#define MASTER_LEFT +//#define _MASTER_RIGHT +#define EE_HANDS + + +#ifdef SUBPROJECT_rev1 + #include "../../rev1/config.h" +#endif +#ifdef SUBPROJECT_rev2 + #include "../../rev2/config.h" +#endif +#ifdef SUBPROJECT_rev2fliphalf + #include "../../rev2fliphalf/config.h" +#endif diff --git a/keyboards/orthodox/keymaps/serial/keymap.c b/keyboards/orthodox/keymaps/serial/keymap.c new file mode 100644 index 0000000000..ed24a3a1f0 --- /dev/null +++ b/keyboards/orthodox/keymaps/serial/keymap.c @@ -0,0 +1,132 @@ +#include "orthodox.h" +#include "action_layer.h" +#include "eeconfig.h" + +extern keymap_config_t keymap_config; + +// Each layer gets a name for readability, which is then used in the keymap matrix below. +// The underscores don't mean anything - you can have a layer called STUFF or any other name. +// Layer names don't all need to be of the same length, obviously, and you can also skip them +// entirely and just use numbers. +#define _QWERTY 0 +#define _COLEMAK 1 +#define _DVORAK 2 +#define _LOWER 3 +#define _RAISE 4 +#define _ADJUST 16 + +enum custom_keycodes { + QWERTY = SAFE_RANGE, + COLEMAK, + DVORAK, + LOWER, + RAISE, + ADJUST, +}; + +// Fillers to make layering more clear +#define _______ KC_TRNS +#define XXXXXXX KC_NO + +#define LS__SPC MT(MOD_LSFT, KC_SPC) + +const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { + +[_QWERTY] = KEYMAP( \ + KC_TAB, KC_Q, KC_W, KC_E, KC_R, KC_T, KC_Y, KC_U, KC_I, KC_O, KC_P, KC_BSPC, \ + KC_ESC, KC_A, KC_S, KC_D, KC_F, KC_G, KC_LEFT, XXXXXXX, KC_DOWN, KC_UP, XXXXXXX, KC_RIGHT,KC_H, KC_J, KC_K, KC_L, KC_SCLN, KC_QUOT, \ + KC_LCTL, KC_Z, KC_X, KC_C, KC_V, KC_B, LOWER, KC_BSPC, KC_ENT, KC_RALT, LS__SPC, RAISE, KC_N, KC_M, KC_COMM, KC_DOT, KC_SLSH, KC_LGUI \ +), + +[_LOWER] = KEYMAP( \ + KC_TILD, KC_EXLM, KC_AT, KC_HASH, KC_DLR, KC_PERC, KC_CIRC, KC_AMPR, KC_ASTR, KC_LPRN, KC_RPRN, KC_BSPC, \ + KC_DEL, KC_F1, KC_F2, KC_F3, KC_F4, KC_F5, KC_LCTL, XXXXXXX, _______, _______, XXXXXXX, KC_RCTL, KC_F6, KC_UNDS, KC_PLUS, KC_LCBR, KC_RCBR, KC_PIPE, \ + _______, KC_F7, KC_F8, KC_F9, KC_F10, KC_F11, _______, _______, _______, _______, _______, _______, KC_F12, KC_HOME, KC_COMM, KC_DOT, KC_END, _______ \ +), + +[_RAISE] = KEYMAP( \ + KC_GRV, KC_1, KC_2, KC_3, KC_4, KC_5, KC_6, KC_7, KC_8, KC_9, KC_0, KC_BSPC, \ + KC_DEL, KC_F1, KC_F2, KC_F3, KC_F4, KC_F5, _______, XXXXXXX, _______, _______, XXXXXXX, _______, KC_F6, KC_MINS, KC_EQL, KC_LBRC, KC_RBRC, KC_BSLS, \ + _______, KC_F7, KC_F8, KC_F9, KC_F10, KC_F11, _______, _______, _______, _______, _______, _______, KC_F12, KC_PGUP, KC_COMM, KC_DOT, KC_PGDN, _______ \ +), + +[_ADJUST] = KEYMAP( \ + _______, RESET, _______, _______, _______, _______, _______, _______, _______, _______, _______, KC_DEL, \ + _______, _______, _______, AU_ON, AU_OFF, AG_NORM, _______, XXXXXXX, _______, _______, XXXXXXX, _______, AG_SWAP, QWERTY , COLEMAK, DVORAK, _______, _______, \ + _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, KC_MNXT, KC_VOLD, KC_VOLU, KC_MPLY \ +) + + +}; + +#ifdef AUDIO_ENABLE +float tone_qwerty[][2] = SONG(QWERTY_SOUND); +float tone_dvorak[][2] = SONG(DVORAK_SOUND); +float tone_colemak[][2] = SONG(COLEMAK_SOUND); +#endif + +void persistent_default_layer_set(uint16_t default_layer) { + eeconfig_update_default_layer(default_layer); + default_layer_set(default_layer); +} + +bool process_record_user(uint16_t keycode, keyrecord_t *record) { + switch (keycode) { + case QWERTY: + if (record->event.pressed) { + #ifdef AUDIO_ENABLE + PLAY_NOTE_ARRAY(tone_qwerty, false, 0); + #endif + persistent_default_layer_set(1UL<<_QWERTY); + } + return false; + break; + case COLEMAK: + if (record->event.pressed) { + #ifdef AUDIO_ENABLE + PLAY_NOTE_ARRAY(tone_colemak, false, 0); + #endif + persistent_default_layer_set(1UL<<_COLEMAK); + } + return false; + break; + case DVORAK: + if (record->event.pressed) { + #ifdef AUDIO_ENABLE + PLAY_NOTE_ARRAY(tone_dvorak, false, 0); + #endif + persistent_default_layer_set(1UL<<_DVORAK); + } + return false; + break; + case LOWER: + if (record->event.pressed) { + layer_on(_LOWER); + update_tri_layer(_LOWER, _RAISE, _ADJUST); + } else { + layer_off(_LOWER); + update_tri_layer(_LOWER, _RAISE, _ADJUST); + } + return false; + break; + case RAISE: + if (record->event.pressed) { + layer_on(_RAISE); + update_tri_layer(_LOWER, _RAISE, _ADJUST); + } else { + layer_off(_RAISE); + update_tri_layer(_LOWER, _RAISE, _ADJUST); + } + return false; + break; + case ADJUST: + if (record->event.pressed) { + layer_on(_ADJUST); + } else { + layer_off(_ADJUST); + } + return false; + break; + } + return true; +} diff --git a/keyboards/orthodox/matrix.c b/keyboards/orthodox/matrix.c new file mode 100644 index 0000000000..3b60cead84 --- /dev/null +++ b/keyboards/orthodox/matrix.c @@ -0,0 +1,351 @@ +/* +Copyright 2012 Jun Wako <wakojun@gmail.com> + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +/* + * scan matrix + */ +#include <stdint.h> +#include <stdbool.h> +#ifdef USE_I2C +// provides memcpy for copying TWI slave buffer +// #include <string.h> +#endif +#include <avr/io.h> +#include <avr/wdt.h> +#include <avr/interrupt.h> +#include <util/delay.h> +#include "print.h" +#include "debug.h" +#include "util.h" +#include "matrix.h" +#include "split_util.h" +#include "pro_micro.h" +#include "config.h" + +#ifdef USE_I2C +# include "i2c.h" +#else // USE_SERIAL +# include "serial.h" +#endif + +#ifndef DEBOUNCE +# define DEBOUNCE 5 +#endif + +#define ERROR_DISCONNECT_COUNT 5 + +static uint8_t debouncing = DEBOUNCE; +static const int ROWS_PER_HAND = MATRIX_ROWS/2; +static uint8_t error_count = 0; + +static const uint8_t row_pins[MATRIX_ROWS] = MATRIX_ROW_PINS; +static const uint8_t col_pins[MATRIX_COLS] = MATRIX_COL_PINS; + +/* matrix state(1:on, 0:off) */ +static matrix_row_t matrix[MATRIX_ROWS]; +static matrix_row_t matrix_debouncing[MATRIX_ROWS]; + +static matrix_row_t read_cols(void); +static void init_cols(void); +static void unselect_rows(void); +static void select_row(uint8_t row); + +__attribute__ ((weak)) +void matrix_init_quantum(void) { + matrix_init_kb(); +} + +__attribute__ ((weak)) +void matrix_scan_quantum(void) { + matrix_scan_kb(); +} + +__attribute__ ((weak)) +void matrix_init_kb(void) { + matrix_init_user(); +} + +__attribute__ ((weak)) +void matrix_scan_kb(void) { + matrix_scan_user(); +} + +__attribute__ ((weak)) +void matrix_init_user(void) { +} + +__attribute__ ((weak)) +void matrix_scan_user(void) { +} + +inline +uint8_t matrix_rows(void) +{ + return MATRIX_ROWS; +} + +inline +uint8_t matrix_cols(void) +{ + return MATRIX_COLS; +} + +void matrix_init(void) +{ + debug_enable = true; + debug_matrix = true; + debug_mouse = true; + // initialize row and col + unselect_rows(); + init_cols(); + + TX_RX_LED_INIT; + + // initialize matrix state: all keys off + for (uint8_t i=0; i < MATRIX_ROWS; i++) { + matrix[i] = 0; + matrix_debouncing[i] = 0; + } + + matrix_init_quantum(); +} + +uint8_t _matrix_scan(void) +{ + // Right hand is stored after the left in the matrix so, we need to offset it + int offset = isLeftHand ? 0 : (ROWS_PER_HAND); + + for (uint8_t i = 0; i < ROWS_PER_HAND; i++) { + select_row(i); + _delay_us(30); // without this wait read unstable value. + matrix_row_t cols = read_cols(); + if (matrix_debouncing[i+offset] != cols) { + matrix_debouncing[i+offset] = cols; + debouncing = DEBOUNCE; + } + unselect_rows(); + } + + if (debouncing) { + if (--debouncing) { + _delay_ms(1); + } else { + for (uint8_t i = 0; i < ROWS_PER_HAND; i++) { + matrix[i+offset] = matrix_debouncing[i+offset]; + } + } + } + + return 1; +} + +#ifdef USE_I2C + +// Get rows from other half over i2c +int i2c_transaction(void) { + int slaveOffset = (isLeftHand) ? (ROWS_PER_HAND) : 0; + + int err = i2c_master_start(SLAVE_I2C_ADDRESS + I2C_WRITE); + if (err) goto i2c_error; + + // start of matrix stored at 0x00 + err = i2c_master_write(0x00); + if (err) goto i2c_error; + + // Start read + err = i2c_master_start(SLAVE_I2C_ADDRESS + I2C_READ); + if (err) goto i2c_error; + + if (!err) { + /* + // read from TWI byte-by-byte into matrix_row_t memory space + size_t i; + for (i = 0; i < SLAVE_BUFFER_SIZE-1; ++i) { + *((uint8_t*)&matrix[slaveOffset]+i) = i2c_master_read(I2C_ACK); + } + // last byte to be read / end of chunk + *((uint8_t*)&matrix[slaveOffset]+i) = i2c_master_read(I2C_NACK); + */ + + // kludge for column #9: unpack bits for keys (2,9) and (3,9) from (1,7) and (1,8) + // i2c_master_read(I2C_ACK); + matrix[slaveOffset+0] = i2c_master_read(I2C_ACK); + // i2c_master_read(I2C_ACK); + matrix[slaveOffset+1] = (matrix_row_t)i2c_master_read(I2C_ACK)\ + | (matrix[slaveOffset+0]&0x40U)<<2; + // i2c_master_read(I2C_ACK); + matrix[slaveOffset+2] = (matrix_row_t)i2c_master_read(I2C_NACK)\ + | (matrix[slaveOffset+0]&0x80U)<<1; + // clear highest two bits on row 1, where the col9 bits were transported + matrix[slaveOffset+0] &= 0x3F; + + i2c_master_stop(); + } else { +i2c_error: // the cable is disconnected, or something else went wrong + i2c_reset_state(); + return err; + } + + return 0; +} + +#else // USE_SERIAL + +int serial_transaction(void) { + int slaveOffset = (isLeftHand) ? (ROWS_PER_HAND) : 0; + + if (serial_update_buffers()) { + return 1; + } + + for (int i = 0; i < ROWS_PER_HAND; ++i) { + matrix[slaveOffset+i] = serial_slave_buffer[i]; + } + return 0; +} +#endif + +uint8_t matrix_scan(void) +{ + int ret = _matrix_scan(); + + + +#ifdef USE_I2C + if( i2c_transaction() ) { +#else // USE_SERIAL + if( serial_transaction() ) { +#endif + // turn on the indicator led when halves are disconnected + TXLED1; + + error_count++; + + if (error_count > ERROR_DISCONNECT_COUNT) { + // reset other half if disconnected + int slaveOffset = (isLeftHand) ? (ROWS_PER_HAND) : 0; + for (int i = 0; i < ROWS_PER_HAND; ++i) { + matrix[slaveOffset+i] = 0; + } + } + } else { + // turn off the indicator led on no error + TXLED0; + error_count = 0; + } + matrix_scan_quantum(); + return ret; +} + +void matrix_slave_scan(void) { + _matrix_scan(); + + int offset = (isLeftHand) ? 0 : ROWS_PER_HAND; + +#ifdef USE_I2C + // SLAVE_BUFFER_SIZE is from i2c.h + // (MATRIX_ROWS/2*sizeof(matrix_row_t)) + // memcpy((void*)i2c_slave_buffer, (const void*)&matrix[offset], (ROWS_PER_HAND*sizeof(matrix_row_t))); + + // kludge for column #9: put bits for keys (2,9) and (3,9) into (1,7) and (1,8) + i2c_slave_buffer[0] = (uint8_t)(matrix[offset+0])\ + | (matrix[offset+1]&0x100U)>>2\ + | (matrix[offset+2]&0x100U)>>1; + i2c_slave_buffer[1] = (uint8_t)(matrix[offset+1]); + i2c_slave_buffer[2] = (uint8_t)(matrix[offset+2]); + // note: looks like a possible operator-precedence bug here, in last version? + /* + i2c_slave_buffer[1] = (uint8_t)matrix[offset+0]; + i2c_slave_buffer[2] = (uint8_t)(matrix[offset+1]>>8); + i2c_slave_buffer[3] = (uint8_t)(matrix[offset+1]>>8); + i2c_slave_buffer[4] = (uint8_t)(matrix[offset+2]>>8); + i2c_slave_buffer[5] = (uint8_t)matrix[offset+2]; + */ +#else // USE_SERIAL + for (int i = 0; i < ROWS_PER_HAND; ++i) { + serial_slave_buffer[i] = matrix[offset+i]; + } +#endif +} + +bool matrix_is_modified(void) +{ + if (debouncing) return false; + return true; +} + +inline +bool matrix_is_on(uint8_t row, uint8_t col) +{ + return (matrix[row] & ((matrix_row_t)1<<col)); +} + +inline +matrix_row_t matrix_get_row(uint8_t row) +{ + return matrix[row]; +} + +void matrix_print(void) +{ + print("\nr/c 0123456789ABCDEF\n"); + for (uint8_t row = 0; row < MATRIX_ROWS; row++) { + phex(row); print(": "); + pbin_reverse16(matrix_get_row(row)); + print("\n"); + } +} + +uint8_t matrix_key_count(void) +{ + uint8_t count = 0; + for (uint8_t i = 0; i < MATRIX_ROWS; i++) { + count += bitpop16(matrix[i]); + } + return count; +} + +static void init_cols(void) +{ + for(int x = 0; x < MATRIX_COLS; x++) { + _SFR_IO8((col_pins[x] >> 4) + 1) &= ~_BV(col_pins[x] & 0xF); + _SFR_IO8((col_pins[x] >> 4) + 2) |= _BV(col_pins[x] & 0xF); + } +} + +static matrix_row_t read_cols(void) +{ + matrix_row_t result = 0; + for(int x = 0; x < MATRIX_COLS; x++) { + result |= (_SFR_IO8(col_pins[x] >> 4) & _BV(col_pins[x] & 0xF)) ? 0 : (1 << x); + } + return result; +} + +static void unselect_rows(void) +{ + for(int x = 0; x < ROWS_PER_HAND; x++) { + _SFR_IO8((row_pins[x] >> 4) + 1) &= ~_BV(row_pins[x] & 0xF); + _SFR_IO8((row_pins[x] >> 4) + 2) |= _BV(row_pins[x] & 0xF); + } +} + +static void select_row(uint8_t row) +{ + _SFR_IO8((row_pins[row] >> 4) + 1) |= _BV(row_pins[row] & 0xF); + _SFR_IO8((row_pins[row] >> 4) + 2) &= ~_BV(row_pins[row] & 0xF); +} diff --git a/keyboards/orthodox/orthodox.c b/keyboards/orthodox/orthodox.c new file mode 100644 index 0000000000..0b366e9449 --- /dev/null +++ b/keyboards/orthodox/orthodox.c @@ -0,0 +1 @@ +#include "orthodox.h"
\ No newline at end of file diff --git a/keyboards/orthodox/orthodox.h b/keyboards/orthodox/orthodox.h new file mode 100644 index 0000000000..bb7efb6ad1 --- /dev/null +++ b/keyboards/orthodox/orthodox.h @@ -0,0 +1,30 @@ +#ifndef ORTHODOX_H +#define ORTHODOX_H + +#ifdef SUBPROJECT_rev1 + #include "rev1.h" +#endif +#ifdef SUBPROJECT_rev2 + #include "rev2.h" +#endif +#ifdef SUBPROJECT_rev2fliphalf + #include "rev2fliphalf.h" +#endif + +// Used to create a keymap using only KC_ prefixed keys +#define KC_KEYMAP( \ + L00, L01, L02, L03, L04, L05, R00, R01, R02, R03, R04, R05, \ + L10, L11, L12, L13, L14, L15, R10, R11, R12, R13, R14, R15, \ + L20, L21, L22, L23, L24, L25, R20, R21, R22, R23, R24, R25, \ + L30, L31, L32, L33, L34, L35, R30, R31, R32, R33, R34, R35 \ + ) \ + KEYMAP( \ + KC_##L00, KC_##L01, KC_##L02, KC_##L03, KC_##L04, KC_##L05, KC_##R00, KC_##R01, KC_##R02, KC_##R03, KC_##R04, KC_##R05, \ + KC_##L10, KC_##L11, KC_##L12, KC_##L13, KC_##L14, KC_##L15, KC_##R10, KC_##R11, KC_##R12, KC_##R13, KC_##R14, KC_##R15, \ + KC_##L20, KC_##L21, KC_##L22, KC_##L23, KC_##L24, KC_##L25, KC_##R20, KC_##R21, KC_##R22, KC_##R23, KC_##R24, KC_##R25, \ + KC_##L30, KC_##L31, KC_##L32, KC_##L33, KC_##L34, KC_##L35, KC_##R30, KC_##R31, KC_##R32, KC_##R33, KC_##R34, KC_##R35 \ + ) + +#include "quantum.h" + +#endif
\ No newline at end of file diff --git a/keyboards/orthodox/pro_micro.h b/keyboards/orthodox/pro_micro.h new file mode 100644 index 0000000000..f9e7ed75d9 --- /dev/null +++ b/keyboards/orthodox/pro_micro.h @@ -0,0 +1,362 @@ +/* + pins_arduino.h - Pin definition functions for Arduino + Part of Arduino - http://www.arduino.cc/ + + Copyright (c) 2007 David A. Mellis + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General + Public License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place, Suite 330, + Boston, MA 02111-1307 USA + + $Id: wiring.h 249 2007-02-03 16:52:51Z mellis $ +*/ + +#ifndef Pins_Arduino_h +#define Pins_Arduino_h + +#include <avr/pgmspace.h> + +// Workaround for wrong definitions in "iom32u4.h". +// This should be fixed in the AVR toolchain. +#undef UHCON +#undef UHINT +#undef UHIEN +#undef UHADDR +#undef UHFNUM +#undef UHFNUML +#undef UHFNUMH +#undef UHFLEN +#undef UPINRQX +#undef UPINTX +#undef UPNUM +#undef UPRST +#undef UPCONX +#undef UPCFG0X +#undef UPCFG1X +#undef UPSTAX +#undef UPCFG2X +#undef UPIENX +#undef UPDATX +#undef TCCR2A +#undef WGM20 +#undef WGM21 +#undef COM2B0 +#undef COM2B1 +#undef COM2A0 +#undef COM2A1 +#undef TCCR2B +#undef CS20 +#undef CS21 +#undef CS22 +#undef WGM22 +#undef FOC2B +#undef FOC2A +#undef TCNT2 +#undef TCNT2_0 +#undef TCNT2_1 +#undef TCNT2_2 +#undef TCNT2_3 +#undef TCNT2_4 +#undef TCNT2_5 +#undef TCNT2_6 +#undef TCNT2_7 +#undef OCR2A +#undef OCR2_0 +#undef OCR2_1 +#undef OCR2_2 +#undef OCR2_3 +#undef OCR2_4 +#undef OCR2_5 +#undef OCR2_6 +#undef OCR2_7 +#undef OCR2B +#undef OCR2_0 +#undef OCR2_1 +#undef OCR2_2 +#undef OCR2_3 +#undef OCR2_4 +#undef OCR2_5 +#undef OCR2_6 +#undef OCR2_7 + +#define NUM_DIGITAL_PINS 30 +#define NUM_ANALOG_INPUTS 12 + +#define TX_RX_LED_INIT DDRD |= (1<<5), DDRB |= (1<<0) +#define TXLED0 PORTD |= (1<<5) +#define TXLED1 PORTD &= ~(1<<5) +#define RXLED0 PORTB |= (1<<0) +#define RXLED1 PORTB &= ~(1<<0) + +static const uint8_t SDA = 2; +static const uint8_t SCL = 3; +#define LED_BUILTIN 13 + +// Map SPI port to 'new' pins D14..D17 +static const uint8_t SS = 17; +static const uint8_t MOSI = 16; +static const uint8_t MISO = 14; +static const uint8_t SCK = 15; + +// Mapping of analog pins as digital I/O +// A6-A11 share with digital pins +static const uint8_t ADC0 = 18; +static const uint8_t ADC1 = 19; +static const uint8_t ADC2 = 20; +static const uint8_t ADC3 = 21; +static const uint8_t ADC4 = 22; +static const uint8_t ADC5 = 23; +static const uint8_t ADC6 = 24; // D4 +static const uint8_t ADC7 = 25; // D6 +static const uint8_t ADC8 = 26; // D8 +static const uint8_t ADC9 = 27; // D9 +static const uint8_t ADC10 = 28; // D10 +static const uint8_t ADC11 = 29; // D12 + +#define digitalPinToPCICR(p) ((((p) >= 8 && (p) <= 11) || ((p) >= 14 && (p) <= 17) || ((p) >= A8 && (p) <= A10)) ? (&PCICR) : ((uint8_t *)0)) +#define digitalPinToPCICRbit(p) 0 +#define digitalPinToPCMSK(p) ((((p) >= 8 && (p) <= 11) || ((p) >= 14 && (p) <= 17) || ((p) >= A8 && (p) <= A10)) ? (&PCMSK0) : ((uint8_t *)0)) +#define digitalPinToPCMSKbit(p) ( ((p) >= 8 && (p) <= 11) ? (p) - 4 : ((p) == 14 ? 3 : ((p) == 15 ? 1 : ((p) == 16 ? 2 : ((p) == 17 ? 0 : (p - A8 + 4)))))) + +// __AVR_ATmega32U4__ has an unusual mapping of pins to channels +extern const uint8_t PROGMEM analog_pin_to_channel_PGM[]; +#define analogPinToChannel(P) ( pgm_read_byte( analog_pin_to_channel_PGM + (P) ) ) + +#define digitalPinToInterrupt(p) ((p) == 0 ? 2 : ((p) == 1 ? 3 : ((p) == 2 ? 1 : ((p) == 3 ? 0 : ((p) == 7 ? 4 : NOT_AN_INTERRUPT))))) + +#ifdef ARDUINO_MAIN + +// On the Arduino board, digital pins are also used +// for the analog output (software PWM). Analog input +// pins are a separate set. + +// ATMEL ATMEGA32U4 / ARDUINO LEONARDO +// +// D0 PD2 RXD1/INT2 +// D1 PD3 TXD1/INT3 +// D2 PD1 SDA SDA/INT1 +// D3# PD0 PWM8/SCL OC0B/SCL/INT0 +// D4 A6 PD4 ADC8 +// D5# PC6 ??? OC3A/#OC4A +// D6# A7 PD7 FastPWM #OC4D/ADC10 +// D7 PE6 INT6/AIN0 +// +// D8 A8 PB4 ADC11/PCINT4 +// D9# A9 PB5 PWM16 OC1A/#OC4B/ADC12/PCINT5 +// D10# A10 PB6 PWM16 OC1B/0c4B/ADC13/PCINT6 +// D11# PB7 PWM8/16 0C0A/OC1C/#RTS/PCINT7 +// D12 A11 PD6 T1/#OC4D/ADC9 +// D13# PC7 PWM10 CLK0/OC4A +// +// A0 D18 PF7 ADC7 +// A1 D19 PF6 ADC6 +// A2 D20 PF5 ADC5 +// A3 D21 PF4 ADC4 +// A4 D22 PF1 ADC1 +// A5 D23 PF0 ADC0 +// +// New pins D14..D17 to map SPI port to digital pins +// +// MISO D14 PB3 MISO,PCINT3 +// SCK D15 PB1 SCK,PCINT1 +// MOSI D16 PB2 MOSI,PCINT2 +// SS D17 PB0 RXLED,SS/PCINT0 +// +// Connected LEDs on board for TX and RX +// TXLED D24 PD5 XCK1 +// RXLED D17 PB0 +// HWB PE2 HWB + +// these arrays map port names (e.g. port B) to the +// appropriate addresses for various functions (e.g. reading +// and writing) +const uint16_t PROGMEM port_to_mode_PGM[] = { + NOT_A_PORT, + NOT_A_PORT, + (uint16_t) &DDRB, + (uint16_t) &DDRC, + (uint16_t) &DDRD, + (uint16_t) &DDRE, + (uint16_t) &DDRF, +}; + +const uint16_t PROGMEM port_to_output_PGM[] = { + NOT_A_PORT, + NOT_A_PORT, + (uint16_t) &PORTB, + (uint16_t) &PORTC, + (uint16_t) &PORTD, + (uint16_t) &PORTE, + (uint16_t) &PORTF, +}; + +const uint16_t PROGMEM port_to_input_PGM[] = { + NOT_A_PORT, + NOT_A_PORT, + (uint16_t) &PINB, + (uint16_t) &PINC, + (uint16_t) &PIND, + (uint16_t) &PINE, + (uint16_t) &PINF, +}; + +const uint8_t PROGMEM digital_pin_to_port_PGM[] = { + PD, // D0 - PD2 + PD, // D1 - PD3 + PD, // D2 - PD1 + PD, // D3 - PD0 + PD, // D4 - PD4 + PC, // D5 - PC6 + PD, // D6 - PD7 + PE, // D7 - PE6 + + PB, // D8 - PB4 + PB, // D9 - PB5 + PB, // D10 - PB6 + PB, // D11 - PB7 + PD, // D12 - PD6 + PC, // D13 - PC7 + + PB, // D14 - MISO - PB3 + PB, // D15 - SCK - PB1 + PB, // D16 - MOSI - PB2 + PB, // D17 - SS - PB0 + + PF, // D18 - A0 - PF7 + PF, // D19 - A1 - PF6 + PF, // D20 - A2 - PF5 + PF, // D21 - A3 - PF4 + PF, // D22 - A4 - PF1 + PF, // D23 - A5 - PF0 + + PD, // D24 - PD5 + PD, // D25 / D6 - A7 - PD7 + PB, // D26 / D8 - A8 - PB4 + PB, // D27 / D9 - A9 - PB5 + PB, // D28 / D10 - A10 - PB6 + PD, // D29 / D12 - A11 - PD6 +}; + +const uint8_t PROGMEM digital_pin_to_bit_mask_PGM[] = { + _BV(2), // D0 - PD2 + _BV(3), // D1 - PD3 + _BV(1), // D2 - PD1 + _BV(0), // D3 - PD0 + _BV(4), // D4 - PD4 + _BV(6), // D5 - PC6 + _BV(7), // D6 - PD7 + _BV(6), // D7 - PE6 + + _BV(4), // D8 - PB4 + _BV(5), // D9 - PB5 + _BV(6), // D10 - PB6 + _BV(7), // D11 - PB7 + _BV(6), // D12 - PD6 + _BV(7), // D13 - PC7 + + _BV(3), // D14 - MISO - PB3 + _BV(1), // D15 - SCK - PB1 + _BV(2), // D16 - MOSI - PB2 + _BV(0), // D17 - SS - PB0 + + _BV(7), // D18 - A0 - PF7 + _BV(6), // D19 - A1 - PF6 + _BV(5), // D20 - A2 - PF5 + _BV(4), // D21 - A3 - PF4 + _BV(1), // D22 - A4 - PF1 + _BV(0), // D23 - A5 - PF0 + + _BV(5), // D24 - PD5 + _BV(7), // D25 / D6 - A7 - PD7 + _BV(4), // D26 / D8 - A8 - PB4 + _BV(5), // D27 / D9 - A9 - PB5 + _BV(6), // D28 / D10 - A10 - PB6 + _BV(6), // D29 / D12 - A11 - PD6 +}; + +const uint8_t PROGMEM digital_pin_to_timer_PGM[] = { + NOT_ON_TIMER, + NOT_ON_TIMER, + NOT_ON_TIMER, + TIMER0B, /* 3 */ + NOT_ON_TIMER, + TIMER3A, /* 5 */ + TIMER4D, /* 6 */ + NOT_ON_TIMER, + + NOT_ON_TIMER, + TIMER1A, /* 9 */ + TIMER1B, /* 10 */ + TIMER0A, /* 11 */ + + NOT_ON_TIMER, + TIMER4A, /* 13 */ + + NOT_ON_TIMER, + NOT_ON_TIMER, + NOT_ON_TIMER, + NOT_ON_TIMER, + NOT_ON_TIMER, + NOT_ON_TIMER, + + NOT_ON_TIMER, + NOT_ON_TIMER, + NOT_ON_TIMER, + NOT_ON_TIMER, + NOT_ON_TIMER, + NOT_ON_TIMER, + NOT_ON_TIMER, + NOT_ON_TIMER, + NOT_ON_TIMER, + NOT_ON_TIMER, +}; + +const uint8_t PROGMEM analog_pin_to_channel_PGM[] = { + 7, // A0 PF7 ADC7 + 6, // A1 PF6 ADC6 + 5, // A2 PF5 ADC5 + 4, // A3 PF4 ADC4 + 1, // A4 PF1 ADC1 + 0, // A5 PF0 ADC0 + 8, // A6 D4 PD4 ADC8 + 10, // A7 D6 PD7 ADC10 + 11, // A8 D8 PB4 ADC11 + 12, // A9 D9 PB5 ADC12 + 13, // A10 D10 PB6 ADC13 + 9 // A11 D12 PD6 ADC9 +}; + +#endif /* ARDUINO_MAIN */ + +// These serial port names are intended to allow libraries and architecture-neutral +// sketches to automatically default to the correct port name for a particular type +// of use. For example, a GPS module would normally connect to SERIAL_PORT_HARDWARE_OPEN, +// the first hardware serial port whose RX/TX pins are not dedicated to another use. +// +// SERIAL_PORT_MONITOR Port which normally prints to the Arduino Serial Monitor +// +// SERIAL_PORT_USBVIRTUAL Port which is USB virtual serial +// +// SERIAL_PORT_LINUXBRIDGE Port which connects to a Linux system via Bridge library +// +// SERIAL_PORT_HARDWARE Hardware serial port, physical RX & TX pins. +// +// SERIAL_PORT_HARDWARE_OPEN Hardware serial ports which are open for use. Their RX & TX +// pins are NOT connected to anything by default. +#define SERIAL_PORT_MONITOR Serial +#define SERIAL_PORT_USBVIRTUAL Serial +#define SERIAL_PORT_HARDWARE Serial1 +#define SERIAL_PORT_HARDWARE_OPEN Serial1 + +#endif /* Pins_Arduino_h */ diff --git a/keyboards/orthodox/readme.md b/keyboards/orthodox/readme.md new file mode 100644 index 0000000000..94bb8ebb97 --- /dev/null +++ b/keyboards/orthodox/readme.md @@ -0,0 +1,165 @@ +Orthodox +======== + +*Please note this guide is a work in progress and is based directly on the Let's Split guide.* + +Orthodox is a split ortholinear keyboard with thumb-clusters designed in 2017 by /u/Deductivemonkee, expected to be available in group buys. +Each half has 18 keys in a 3x6 grid and a five key thumb-cluster, of which three use 1.25-unit keycaps. + +![Example prototype build by /u/Deductivemonkee](http://i.imgur.com/R4PPKdog.jpg) + +Its firmware is based on the Let's Split's. +Each side is controlled by an Arduino Pro Micro (or compatible), and they're connected by a TRRS cable using the serial protocol. +Support for the protocol using TWI (i2c®) is a work-in-progress. + + +## Revisions + +- `Rev.1` Prototype GB version, supporting only Pro Micro in the corner footprint, and using PCB top- and bottom-plates. + +Note that the second number after the `Rev.` text is the pcb *order number.* The prototypes will say 1, and the next order of any revision will say 2 and so on. + +## Keymaps + +[The default layout can be unofficially referred to here.](http://www.keyboard-layout-editor.com/#/gists/f120e2703a22a6a69c7be9a65a9d1342) + +The thumb-clusters are an extension of row 2 and row 3 along columns 7, 8, and 9. +Row 2 does not have a physical key in column 8, so when editing keymaps a placeholder constant (`XXXXXXX` or `KC_NO`) must be used in the row2-col8 position. + +## Build Guide + +[Official build guide by /u/Deductivemonkee](http://imgur.com/a/9c0NP) + +For further reading on build- and flashing-procedures for split ortholinear skeleton-case keyboards, please refer to [An Overly Verbose Guide to Building a Let's Split Keyboard](https://github.com/nicinabox/lets-split-guide), much of which can be applied to the Orthodox. + +## First Time Setup + +Download or clone the whole firmware and navigate to the keyboards/orthodox directory. Once your dev env is setup, you'll be able to generate the default .hex using: + +``` +$ make rev1 +``` + +You will see a lot of output and if everything worked correctly you will see the built hex files in your *root qmk_firmware directory* two levels up: + +``` +orthodox_rev1_serial.hex +``` + +If you would like to use one of the alternative keymaps, or create your own, copy one of the existing [keymaps](keymaps/) and run make like so: + + +``` +$ make rev1-YOUR_KEYMAP_NAME +``` + +If everything worked correctly you will see a file: + +``` +orthodox_rev1_YOUR_KEYMAP_NAME.hex +``` + +For more information on customizing keymaps, take a look at the primary documentation for [Customizing Your Keymap](/readme.md##customizing-your-keymap) in the main readme.md. + + +Features +-------- + +For the full Quantum Mechanical Keyboard feature list, see [the parent readme.md](/readme.md). + +Some features supported by the firmware: + +* Either half can connect to the computer via USB, or both halves can be used + independently. +* You only need 3 wires to connect the two halves. Two for VCC and GND and one + for serial communication. + + +Required Hardware +----------------- + +Apart from diodes and key switches for the keyboard matrix in each half, you +will need: + +* 2 Arduino Pro Micro's. You can find theses on aliexpress for ≈3.50USD each. +* 2 TRRS sockets and 1 TRRS cable + + +Notes on Software Configuration +------------------------------- + +Configuring the firmware is similar to any other QMK project. One thing +to note is that `MATRIX_ROWS` in `config.h` is the total number of rows between +the two halves, i.e. if your split keyboard has 3 rows in each half, then +`MATRIX_ROWS=6`. + + +Flashing +------- +From the keymap directory run `make SUBPROJECT-KEYMAP-avrdude` for automatic serial port resolution and flashing. +Example: `make rev2-serial-avrdude` + + +Choosing which board to plug the USB cable into (choosing Master) +-------- +Because the two boards are identical, the firmware has logic to differentiate the left and right board. + +It uses two strategies to figure things out: look at the EEPROM (memory on the chip) or looks if the current board has the usb cable. + +The EEPROM approach requires additional setup (flashing the eeeprom) but allows you to swap the usb cable to either side. + +The USB cable approach is easier to setup and if you just want the usb cable on the left board, you do not need to do anything extra. + +### Setting the left hand as master +If you always plug the usb cable into the left board, nothing extra is needed as this is the default. Comment out `EE_HANDS` and comment out `I2C_MASTER_RIGHT` or `MASTER_RIGHT` if for some reason it was set. + +### Setting the right hand as master +If you always plug the usb cable into the right board, add an extra flag to your `config.h` +``` + #define MASTER_RIGHT +``` + +### Setting EE_hands to use either hands as master +If you define `EE_HANDS` in your `config.h`, you will need to set the +EEPROM for the left and right halves. + +The EEPROM is used to store whether the +half is left handed or right handed. This makes it so that the same firmware +file will run on both hands instead of having to flash left and right handed +versions of the firmware to each half. To flash the EEPROM file for the left +half run: +``` +avrdude -p atmega32u4 -P $(COM_PORT) -c avr109 -U eeprom:w:eeprom-lefthand.eep +// or the equivalent in dfu-programmer + +``` +and similarly for right half +``` +avrdude -p atmega32u4 -P $(COM_PORT) -c avr109 -U eeprom:w:eeprom-righhand.eep +// or the equivalent in dfu-programmer +``` + +NOTE: replace `$(COM_PORT)` with the port of your device (e.g. `/dev/ttyACM0`) + +After you have flashed the EEPROM, you then need to set `EE_HANDS` in your config.h, rebuild the hex files and reflash. + +Note that you need to program both halves, but you have the option of using +different keymaps for each half. You could program the left half with a QWERTY +layout and the right half with a Colemak layout using bootmagic's default layout option. +Then if you connect the left half to a computer by USB the keyboard will use QWERTY and Colemak when the +right half is connected. + + +Notes on Using Pro Micro 3.3V +----------------------------- + +Do update the `F_CPU` parameter in `rules.mk` to `8000000` which reflects +the frequency on the 3.3V board. + +Also, if the slave board is producing weird characters in certain columns, +update the following line in `matrix.c` to the following: + +``` +// _delay_us(30); // without this wait read unstable value. +_delay_us(300); // without this wait read unstable value. +``` diff --git a/keyboards/orthodox/rev1/Makefile b/keyboards/orthodox/rev1/Makefile new file mode 100644 index 0000000000..4e2a6f00fd --- /dev/null +++ b/keyboards/orthodox/rev1/Makefile @@ -0,0 +1,3 @@ +ifndef MAKEFILE_INCLUDED + include ../../Makefile +endif
\ No newline at end of file diff --git a/keyboards/orthodox/rev1/config.h b/keyboards/orthodox/rev1/config.h new file mode 100644 index 0000000000..46bb994402 --- /dev/null +++ b/keyboards/orthodox/rev1/config.h @@ -0,0 +1,99 @@ +/* +Copyright 2012 Jun Wako <wakojun@gmail.com> + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef CONFIG_H +#define CONFIG_H + +#include "config_common.h" + +/* USB Device descriptor parameter */ +#define VENDOR_ID 0xFEED +#define PRODUCT_ID 0x3060 +#define DEVICE_VER 0x0001 +#define MANUFACTURER deductivemonkee +#define PRODUCT Monkeebs Orthodox Rev.1 +#define DESCRIPTION Oreodox + +/* key matrix size */ +// Rows are doubled-up +#define MATRIX_ROWS 6 +#define MATRIX_COLS 9 + +// wiring of each half + + +//PRO MICRO +#define MATRIX_ROW_PINS { D4, B4, B5 } +#define MATRIX_COL_PINS { D7, F4, F5, F6, F7, B1, B3, B2, B6 } +//#define MATRIX_COL_PINS { B2, B3, B1, F7, F6, F5, F4, D7 } + +/*/ +//TEENSY +#define MATRIX_ROW_PINS { D0, C6, C7, } +#define MATRIX_COL_PINS { D2, F5, F6, F7, B6, B5, B4, D7, D6 } +/*/ + +#define CATERINA_BOOTLOADER + +/* COL2ROW or ROW2COL */ +#define DIODE_DIRECTION COL2ROW + +/* define if matrix has ghost */ +//#define MATRIX_HAS_GHOST + +/* number of backlight levels */ +// #define BACKLIGHT_LEVELS 3 + +/* Set 0 if debouncing isn't needed */ +#define DEBOUNCING_DELAY 5 + +/* Mechanical locking support. Use KC_LCAP, KC_LNUM or KC_LSCR instead in keymap */ +// #define LOCKING_SUPPORT_ENABLE +/* Locking resynchronize hack */ +// #define LOCKING_RESYNC_ENABLE + +/* key combination for command */ +#define IS_COMMAND() ( \ + keyboard_report->mods == (MOD_BIT(KC_LSHIFT) | MOD_BIT(KC_RSHIFT)) \ +) + +/* ws2812 RGB LED */ +//#define RGB_DI_PIN D3 +//#define RGBLIGHT_TIMER +//#define RGBLED_NUM 16 // Number of LEDs +//#define ws2812_PORTREG PORTD +//#define ws2812_DDRREG DDRD + +/* + * Feature disable options + * These options are also useful to firmware size reduction. + */ + +/* disable debug print */ +// #define NO_DEBUG + +/* disable print */ +// #define NO_PRINT + +/* disable action features */ +//#define NO_ACTION_LAYER +//#define NO_ACTION_TAPPING +//#define NO_ACTION_ONESHOT +//#define NO_ACTION_MACRO +//#define NO_ACTION_FUNCTION + +#endif diff --git a/keyboards/orthodox/rev1/rev1.c b/keyboards/orthodox/rev1/rev1.c new file mode 100644 index 0000000000..10ece03f08 --- /dev/null +++ b/keyboards/orthodox/rev1/rev1.c @@ -0,0 +1,32 @@ +#include "orthodox.h" + +#ifdef AUDIO_ENABLE + float tone_startup[][2] = SONG(STARTUP_SOUND); + float tone_goodbye[][2] = SONG(GOODBYE_SOUND); +#endif + +void matrix_init_kb(void) { + + #ifdef AUDIO_ENABLE + _delay_ms(20); // gets rid of tick + PLAY_NOTE_ARRAY(tone_startup, false, 0); + #endif + + // // green led on + // DDRD |= (1<<5); + // PORTD &= ~(1<<5); + + // // orange led on + // DDRB |= (1<<0); + // PORTB &= ~(1<<0); + + matrix_init_user(); +}; + +void shutdown_user(void) { + #ifdef AUDIO_ENABLE + PLAY_NOTE_ARRAY(tone_goodbye, false, 0); + _delay_ms(150); + stop_all_notes(); + #endif +} diff --git a/keyboards/orthodox/rev1/rev1.h b/keyboards/orthodox/rev1/rev1.h new file mode 100644 index 0000000000..4f163299d1 --- /dev/null +++ b/keyboards/orthodox/rev1/rev1.h @@ -0,0 +1,25 @@ +#ifndef REV1_H +#define REV1_H + +#include "../orthodox.h" + +//void promicro_bootloader_jmp(bool program); +#include "quantum.h" + +//void promicro_bootloader_jmp(bool program); + +#define KEYMAP( \ + L00, L01, L02, L03, L04, L05, R00, R01, R02, R03, R04, R05, \ + L10, L11, L12, L13, L14, L15, L16, L17, L18, R10, R11, R12, R13, R14, R15, R16, R17, R18, \ + L20, L21, L22, L23, L24, L25, L26, L27, L28, R20, R21, R22, R23, R24, R25, R26, R27, R28 \ + ) \ + { \ + { L00, L01, L02, L03, L04, L05 }, \ + { L10, L11, L12, L13, L14, L15, L16, L17, L18}, \ + { L20, L21, L22, L23, L24, L25, L26, L27, L28 }, \ + { R05, R04, R03, R02, R01, R00 }, \ + { R18, R17, R16, R15, R14, R13, R12, R11, R10 }, \ + { R28, R27, R26, R25, R24, R23, R22, R21, R20 } \ + } + +#endif
\ No newline at end of file diff --git a/keyboards/orthodox/rev1/rules.mk b/keyboards/orthodox/rev1/rules.mk new file mode 100644 index 0000000000..a0825b4ef6 --- /dev/null +++ b/keyboards/orthodox/rev1/rules.mk @@ -0,0 +1,5 @@ +BACKLIGHT_ENABLE = no + +ifndef QUANTUM_DIR + include ../../../Makefile +endif
\ No newline at end of file diff --git a/keyboards/orthodox/rules.mk b/keyboards/orthodox/rules.mk new file mode 100644 index 0000000000..0efa785505 --- /dev/null +++ b/keyboards/orthodox/rules.mk @@ -0,0 +1,87 @@ +SRC += matrix.c \ + i2c.c \ + split_util.c \ + serial.c + +# MCU name +#MCU = at90usb1287 +MCU = atmega32u4 + +# Processor frequency. +# This will define a symbol, F_CPU, in all source code files equal to the +# processor frequency in Hz. You can then use this symbol in your source code to +# calculate timings. Do NOT tack on a 'UL' at the end, this will be done +# automatically to create a 32-bit value in your source code. +# +# This will be an integer division of F_USB below, as it is sourced by +# F_USB after it has run through any CPU prescalers. Note that this value +# does not *change* the processor frequency - it should merely be updated to +# reflect the processor speed set externally so that the code can use accurate +# software delays. +F_CPU = 16000000 + +# +# LUFA specific +# +# Target architecture (see library "Board Types" documentation). +ARCH = AVR8 + +# Input clock frequency. +# This will define a symbol, F_USB, in all source code files equal to the +# input clock frequency (before any prescaling is performed) in Hz. This value may +# differ from F_CPU if prescaling is used on the latter, and is required as the +# raw input clock is fed directly to the PLL sections of the AVR for high speed +# clock generation for the USB and other AVR subsections. Do NOT tack on a 'UL' +# at the end, this will be done automatically to create a 32-bit value in your +# source code. +# +# If no clock division is performed on the input clock inside the AVR (via the +# CPU clock adjust registers or the clock division fuses), this will be equal to F_CPU. +F_USB = $(F_CPU) + +# Interrupt driven control endpoint task(+60) +OPT_DEFS += -DINTERRUPT_CONTROL_ENDPOINT + + +# Boot Section Size in *bytes* +# Teensy halfKay 512 +# Teensy++ halfKay 1024 +# Atmel DFU loader 4096 +# LUFA bootloader 4096 +# USBaspLoader 2048 +OPT_DEFS += -DBOOTLOADER_SIZE=4096 + +# Build Options +# change to "no" to disable the options, or define them in the Makefile in +# the appropriate keymap folder that will get included automatically +# +BOOTMAGIC_ENABLE ?= no # Virtual DIP switch configuration(+1000) +MOUSEKEY_ENABLE ?= yes # Mouse keys(+4700) +EXTRAKEY_ENABLE ?= yes # Audio control and System control(+450) +CONSOLE_ENABLE ?= no # Console for debug(+400) +COMMAND_ENABLE ?= yes # Commands for debug and configuration +NKRO_ENABLE ?= no # Nkey Rollover - if this doesn't work, see here: https://github.com/tmk/tmk_keyboard/wiki/FAQ#nkro-doesnt-work +BACKLIGHT_ENABLE ?= no # Enable keyboard backlight functionality +MIDI_ENABLE ?= no # MIDI controls +AUDIO_ENABLE ?= no # Audio output on port C6 +UNICODE_ENABLE ?= no # Unicode +BLUETOOTH_ENABLE ?= no # Enable Bluetooth with the Adafruit EZ-Key HID +RGBLIGHT_ENABLE ?= no # Enable WS2812 RGB underlight. Do not enable this with audio at the same time. +SUBPROJECT_rev1 ?= yes +USE_I2C ?= yes +# Do not enable SLEEP_LED_ENABLE. it uses the same timer as BACKLIGHT_ENABLE +SLEEP_LED_ENABLE ?= no # Breathing sleep LED during USB suspend + +CUSTOM_MATRIX = yes + +avrdude: build + ls /dev/tty* > /tmp/1; \ + echo "Reset your Pro Micro now"; \ + while [[ -z $$USB ]]; do \ + sleep 1; \ + ls /dev/tty* > /tmp/2; \ + USB=`diff /tmp/1 /tmp/2 | grep -o '/dev/tty.*'`; \ + done; \ + avrdude -p $(MCU) -c avr109 -P $$USB -U flash:w:$(BUILD_DIR)/$(TARGET).hex + +.PHONY: avrdude diff --git a/keyboards/orthodox/serial.c b/keyboards/orthodox/serial.c new file mode 100644 index 0000000000..4936e4249f --- /dev/null +++ b/keyboards/orthodox/serial.c @@ -0,0 +1,230 @@ +/* + * WARNING: be careful changing this code, it is very timing dependent + */ + +#ifndef F_CPU +#define F_CPU 16000000 +#endif + +#include <avr/io.h> +#include <avr/interrupt.h> +#include <util/delay.h> +#include <stdbool.h> +#include "serial.h" + +#ifdef USE_SERIAL + +// Serial pulse period in microseconds. Its probably a bad idea to lower this +// value. +#define SERIAL_DELAY 24 + +matrix_row_t volatile serial_slave_buffer[SERIAL_SLAVE_BUFFER_LENGTH] = {0}; +matrix_row_t volatile serial_master_buffer[SERIAL_MASTER_BUFFER_LENGTH] = {0}; + +#define ROW_MASK (((matrix_row_t)0-1)>>(8*sizeof(matrix_row_t)-MATRIX_COLS)) + +#define SLAVE_DATA_CORRUPT (1<<0) +volatile uint8_t status = 0; + +inline static +void serial_delay(void) { + _delay_us(SERIAL_DELAY); +} + +inline static +void serial_output(void) { + SERIAL_PIN_DDR |= SERIAL_PIN_MASK; +} + +// make the serial pin an input with pull-up resistor +inline static +void serial_input(void) { + SERIAL_PIN_DDR &= ~SERIAL_PIN_MASK; + SERIAL_PIN_PORT |= SERIAL_PIN_MASK; +} + +inline static +matrix_row_t serial_read_pin(void) { + return !!(SERIAL_PIN_INPUT & SERIAL_PIN_MASK); +} + +inline static +void serial_low(void) { + SERIAL_PIN_PORT &= ~SERIAL_PIN_MASK; +} + +inline static +void serial_high(void) { + SERIAL_PIN_PORT |= SERIAL_PIN_MASK; +} + +void serial_master_init(void) { + serial_output(); + serial_high(); +} + +void serial_slave_init(void) { + serial_input(); + + // Enable INT0 + EIMSK |= _BV(INT0); + // Trigger on falling edge of INT0 + EICRA &= ~(_BV(ISC00) | _BV(ISC01)); +} + +// Used by the master to synchronize timing with the slave. +static +void sync_recv(void) { + serial_input(); + // This shouldn't hang if the slave disconnects because the + // serial line will float to high if the slave does disconnect. + while (!serial_read_pin()); + serial_delay(); +} + +// Used by the slave to send a synchronization signal to the master. +static +void sync_send(void) { + serial_output(); + + serial_low(); + serial_delay(); + + serial_high(); +} + +// Reads a byte from the serial line +static +matrix_row_t serial_read_byte(void) { + matrix_row_t byte = 0; + serial_input(); + for ( uint8_t i = 0; i < MATRIX_COLS; ++i) { + byte = (byte << 1) | serial_read_pin(); + serial_delay(); + _delay_us(1); + } + + return byte; +} + +// Sends a byte with MSB ordering +static +void serial_write_byte(matrix_row_t data) { + matrix_row_t b = MATRIX_COLS; + serial_output(); + while( b-- ) { + if(data & (1UL << b)) { + serial_high(); + } else { + serial_low(); + } + serial_delay(); + } +} + +// interrupt handle to be used by the slave device +ISR(SERIAL_PIN_INTERRUPT) { + sync_send(); + + matrix_row_t checksum = 0; + for (int i = 0; i < SERIAL_SLAVE_BUFFER_LENGTH; ++i) { + serial_write_byte(serial_slave_buffer[i]); + sync_send(); + checksum += ROW_MASK & serial_slave_buffer[i]; + } + serial_write_byte(checksum); + sync_send(); + + // wait for the sync to finish sending + serial_delay(); + + // read the middle of pulses + _delay_us(SERIAL_DELAY/2); + + matrix_row_t checksum_computed = 0; + for (int i = 0; i < SERIAL_MASTER_BUFFER_LENGTH; ++i) { + serial_master_buffer[i] = serial_read_byte(); + sync_send(); + checksum_computed += ROW_MASK & serial_master_buffer[i]; + } + matrix_row_t checksum_received = serial_read_byte(); + sync_send(); + + serial_input(); // end transaction + + if ( checksum_computed != checksum_received ) { + status |= SLAVE_DATA_CORRUPT; + } else { + status &= ~SLAVE_DATA_CORRUPT; + } +} + +inline +bool serial_slave_DATA_CORRUPT(void) { + return status & SLAVE_DATA_CORRUPT; +} + +// Copies the serial_slave_buffer to the master and sends the +// serial_master_buffer to the slave. +// +// Returns: +// 0 => no error +// 1 => slave did not respond +int serial_update_buffers(void) { + // this code is very time dependent, so we need to disable interrupts + cli(); + + // signal to the slave that we want to start a transaction + serial_output(); + serial_low(); + _delay_us(1); + + // wait for the slaves response + serial_input(); + serial_high(); + _delay_us(SERIAL_DELAY); + + // check if the slave is present + if (serial_read_pin()) { + // slave failed to pull the line low, assume not present + sei(); + return 1; + } + + // if the slave is present syncronize with it + sync_recv(); + + matrix_row_t checksum_computed = 0; + // receive data from the slave + for (int i = 0; i < SERIAL_SLAVE_BUFFER_LENGTH; ++i) { + serial_slave_buffer[i] = serial_read_byte(); + sync_recv(); + checksum_computed += ROW_MASK & serial_slave_buffer[i]; + } + matrix_row_t checksum_received = serial_read_byte(); + sync_recv(); + + if (checksum_computed != checksum_received) { + sei(); + return 1; + } + + matrix_row_t checksum = 0; + // send data to the slave + for (int i = 0; i < SERIAL_MASTER_BUFFER_LENGTH; ++i) { + serial_write_byte(serial_master_buffer[i]); + sync_recv(); + checksum += ROW_MASK & serial_master_buffer[i]; + } + serial_write_byte(checksum); + sync_recv(); + + // always, release the line when not in use + serial_output(); + serial_high(); + + sei(); + return 0; +} + +#endif diff --git a/keyboards/orthodox/serial.h b/keyboards/orthodox/serial.h new file mode 100644 index 0000000000..a46a98c947 --- /dev/null +++ b/keyboards/orthodox/serial.h @@ -0,0 +1,27 @@ +#ifndef MY_SERIAL_H +#define MY_SERIAL_H + +#include "config.h" +#include <stdbool.h> +#include "matrix.h" + +/* TODO: some defines for interrupt setup */ +#define SERIAL_PIN_DDR DDRD +#define SERIAL_PIN_PORT PORTD +#define SERIAL_PIN_INPUT PIND +#define SERIAL_PIN_MASK _BV(PD0) +#define SERIAL_PIN_INTERRUPT INT0_vect + +#define SERIAL_SLAVE_BUFFER_LENGTH MATRIX_ROWS/2 +#define SERIAL_MASTER_BUFFER_LENGTH 1 + +// Buffers for master - slave communication +extern volatile matrix_row_t serial_slave_buffer[SERIAL_SLAVE_BUFFER_LENGTH]; +extern volatile matrix_row_t serial_master_buffer[SERIAL_MASTER_BUFFER_LENGTH]; + +void serial_master_init(void); +void serial_slave_init(void); +int serial_update_buffers(void); +bool serial_slave_data_corrupt(void); + +#endif diff --git a/keyboards/orthodox/split_util.c b/keyboards/orthodox/split_util.c new file mode 100644 index 0000000000..39639c3b4b --- /dev/null +++ b/keyboards/orthodox/split_util.c @@ -0,0 +1,84 @@ +#include <avr/io.h> +#include <avr/wdt.h> +#include <avr/power.h> +#include <avr/interrupt.h> +#include <util/delay.h> +#include <avr/eeprom.h> +#include "split_util.h" +#include "matrix.h" +#include "keyboard.h" +#include "config.h" + +#ifdef USE_I2C +# include "i2c.h" +#else +# include "serial.h" +#endif + +volatile bool isLeftHand = true; + +static void setup_handedness(void) { + #ifdef EE_HANDS + isLeftHand = eeprom_read_byte(EECONFIG_HANDEDNESS); + #else + // I2C_MASTER_RIGHT is deprecated, use MASTER_RIGHT instead, since this works for both serial and i2c + #if defined(I2C_MASTER_RIGHT) || defined(MASTER_RIGHT) + isLeftHand = !has_usb(); + #else + isLeftHand = has_usb(); + #endif + #endif +} + +static void keyboard_master_setup(void) { +#ifdef USE_I2C + i2c_master_init(); +#ifdef SSD1306OLED + matrix_master_OLED_init (); +#endif +#else + serial_master_init(); +#endif +} + +static void keyboard_slave_setup(void) { +#ifdef USE_I2C + i2c_slave_init(SLAVE_I2C_ADDRESS); +#else + serial_slave_init(); +#endif +} + +bool has_usb(void) { + USBCON |= (1 << OTGPADE); //enables VBUS pad + _delay_us(5); + return (USBSTA & (1<<VBUS)); //checks state of VBUS +} + +void split_keyboard_setup(void) { + setup_handedness(); + + if (has_usb()) { + keyboard_master_setup(); + } else { + keyboard_slave_setup(); + } + sei(); +} + +void keyboard_slave_loop(void) { + matrix_init(); + + while (1) { + matrix_slave_scan(); + } +} + +// this code runs before the usb and keyboard is initialized +void matrix_setup(void) { + split_keyboard_setup(); + + if (!has_usb()) { + keyboard_slave_loop(); + } +} diff --git a/keyboards/orthodox/split_util.h b/keyboards/orthodox/split_util.h new file mode 100644 index 0000000000..3ae76c209a --- /dev/null +++ b/keyboards/orthodox/split_util.h @@ -0,0 +1,24 @@ +#ifndef SPLIT_KEYBOARD_UTIL_H +#define SPLIT_KEYBOARD_UTIL_H + +#include <stdbool.h> + +#ifdef EE_HANDS + #define EECONFIG_BOOTMAGIC_END (uint8_t *)10 + #define EECONFIG_HANDEDNESS EECONFIG_BOOTMAGIC_END +#endif + +#define SLAVE_I2C_ADDRESS 0x32 + +extern volatile bool isLeftHand; + +// slave version of matix scan, defined in matrix.c +void matrix_slave_scan(void); + +void split_keyboard_setup(void); +bool has_usb(void); +void keyboard_slave_loop(void); + +void matrix_master_OLED_init (void); + +#endif diff --git a/keyboards/orthodox/ssd1306.c b/keyboards/orthodox/ssd1306.c new file mode 100644 index 0000000000..5c6dff27f8 --- /dev/null +++ b/keyboards/orthodox/ssd1306.c @@ -0,0 +1,470 @@ +#ifdef SSD1306OLED + +#include "ssd1306.h" +#include "config.h" +#include "i2c.h" +#include <string.h> +#include "print.h" +#include "lets_split.h" +#include "common/glcdfont.c" +#ifdef ADAFRUIT_BLE_ENABLE +#include "adafruit_ble.h" +#endif +#ifdef PROTOCOL_LUFA +#include "lufa.h" +#endif +#include "sendchar.h" +#include "pincontrol.h" + +//assign the right code to your layers +#define _BASE 0 +#define _LOWER 8 +#define _RAISE 16 +#define _FNLAYER 64 +#define _NUMLAY 128 +#define _NLOWER 136 +#define _NFNLAYER 192 +#define _MOUSECURSOR 256 +#define _ADJUST 65560 + +// Set this to 1 to help diagnose early startup problems +// when testing power-on with ble. Turn it off otherwise, +// as the latency of printing most of the debug info messes +// with the matrix scan, causing keys to drop. +#define DEBUG_TO_SCREEN 0 + +// Controls the SSD1306 128x32 OLED display via i2c + +#define i2cAddress 0x3C + +#define DisplayHeight 32 +#define DisplayWidth 128 + +#define FontHeight 8 +#define FontWidth 6 + +#define MatrixRows (DisplayHeight / FontHeight) +#define MatrixCols (DisplayWidth / FontWidth) + +struct CharacterMatrix { + uint8_t display[MatrixRows][MatrixCols]; + uint8_t *cursor; + bool dirty; +}; + +static struct CharacterMatrix display; +//static uint16_t last_battery_update; +//static uint32_t vbat; +//#define BatteryUpdateInterval 10000 /* milliseconds */ +#define ScreenOffInterval 300000 /* milliseconds */ +#if DEBUG_TO_SCREEN +static uint8_t displaying; +#endif +static uint16_t last_flush; + +enum ssd1306_cmds { + DisplayOff = 0xAE, + DisplayOn = 0xAF, + + SetContrast = 0x81, + DisplayAllOnResume = 0xA4, + + DisplayAllOn = 0xA5, + NormalDisplay = 0xA6, + InvertDisplay = 0xA7, + SetDisplayOffset = 0xD3, + SetComPins = 0xda, + SetVComDetect = 0xdb, + SetDisplayClockDiv = 0xD5, + SetPreCharge = 0xd9, + SetMultiPlex = 0xa8, + SetLowColumn = 0x00, + SetHighColumn = 0x10, + SetStartLine = 0x40, + + SetMemoryMode = 0x20, + ColumnAddr = 0x21, + PageAddr = 0x22, + + ComScanInc = 0xc0, + ComScanDec = 0xc8, + SegRemap = 0xa0, + SetChargePump = 0x8d, + ExternalVcc = 0x01, + SwitchCapVcc = 0x02, + + ActivateScroll = 0x2f, + DeActivateScroll = 0x2e, + SetVerticalScrollArea = 0xa3, + RightHorizontalScroll = 0x26, + LeftHorizontalScroll = 0x27, + VerticalAndRightHorizontalScroll = 0x29, + VerticalAndLeftHorizontalScroll = 0x2a, +}; + + +// Write command sequence. +// Returns true on success. +static inline bool _send_cmd1(uint8_t cmd) { + bool res = false; + + if (i2c_start_write(i2cAddress)) { + xprintf("failed to start write to %d\n", i2cAddress); + goto done; + } + + if (i2c_master_write(0x0 /* command byte follows */)) { + print("failed to write control byte\n"); + + goto done; + } + + if (i2c_master_write(cmd)) { + xprintf("failed to write command %d\n", cmd); + goto done; + } + res = true; +done: + i2c_master_stop(); + return res; +} + +// Write 2-byte command sequence. +// Returns true on success +static inline bool _send_cmd2(uint8_t cmd, uint8_t opr) { + if (!_send_cmd1(cmd)) { + return false; + } + return _send_cmd1(opr); +} + +// Write 3-byte command sequence. +// Returns true on success +static inline bool _send_cmd3(uint8_t cmd, uint8_t opr1, uint8_t opr2) { + if (!_send_cmd1(cmd)) { + return false; + } + if (!_send_cmd1(opr1)) { + return false; + } + return _send_cmd1(opr2); +} + +#define send_cmd1(c) if (!_send_cmd1(c)) {goto done;} +#define send_cmd2(c,o) if (!_send_cmd2(c,o)) {goto done;} +#define send_cmd3(c,o1,o2) if (!_send_cmd3(c,o1,o2)) {goto done;} + +static void matrix_clear(struct CharacterMatrix *matrix); + +static void clear_display(void) { + matrix_clear(&display); + + // Clear all of the display bits (there can be random noise + // in the RAM on startup) + send_cmd3(PageAddr, 0, (DisplayHeight / 8) - 1); + send_cmd3(ColumnAddr, 0, DisplayWidth - 1); + + if (i2c_start_write(i2cAddress)) { + goto done; + } + if (i2c_master_write(0x40)) { + // Data mode + goto done; + } + for (uint8_t row = 0; row < MatrixRows; ++row) { + for (uint8_t col = 0; col < DisplayWidth; ++col) { + i2c_master_write(0); + } + } + + display.dirty = false; + +done: + i2c_master_stop(); +} + +#if DEBUG_TO_SCREEN +#undef sendchar +static int8_t capture_sendchar(uint8_t c) { + sendchar(c); + iota_gfx_write_char(c); + + if (!displaying) { + iota_gfx_flush(); + } + return 0; +} +#endif + +bool iota_gfx_init(void) { + bool success = false; + + send_cmd1(DisplayOff); + send_cmd2(SetDisplayClockDiv, 0x80); + send_cmd2(SetMultiPlex, DisplayHeight - 1); + + send_cmd2(SetDisplayOffset, 0); + + + send_cmd1(SetStartLine | 0x0); + send_cmd2(SetChargePump, 0x14 /* Enable */); + send_cmd2(SetMemoryMode, 0 /* horizontal addressing */); + +/// Flips the display orientation 0 degrees + send_cmd1(SegRemap | 0x1); + send_cmd1(ComScanDec); +/* +// the following Flip the display orientation 180 degrees + send_cmd1(SegRemap); + send_cmd1(ComScanInc); +// end flip */ + send_cmd2(SetComPins, 0x2); + send_cmd2(SetContrast, 0x8f); + send_cmd2(SetPreCharge, 0xf1); + send_cmd2(SetVComDetect, 0x40); + send_cmd1(DisplayAllOnResume); + send_cmd1(NormalDisplay); + send_cmd1(DeActivateScroll); + send_cmd1(DisplayOn); + + send_cmd2(SetContrast, 0); // Dim + + clear_display(); + + success = true; + + iota_gfx_flush(); + +#if DEBUG_TO_SCREEN + print_set_sendchar(capture_sendchar); +#endif + +done: + return success; +} + +bool iota_gfx_off(void) { + bool success = false; + + send_cmd1(DisplayOff); + success = true; + +done: + return success; +} + +bool iota_gfx_on(void) { + bool success = false; + + send_cmd1(DisplayOn); + success = true; + +done: + return success; +} + +static void matrix_write_char_inner(struct CharacterMatrix *matrix, uint8_t c) { + *matrix->cursor = c; + ++matrix->cursor; + + if (matrix->cursor - &matrix->display[0][0] == sizeof(matrix->display)) { + // We went off the end; scroll the display upwards by one line + memmove(&matrix->display[0], &matrix->display[1], + MatrixCols * (MatrixRows - 1)); + matrix->cursor = &matrix->display[MatrixRows - 1][0]; + memset(matrix->cursor, ' ', MatrixCols); + } +} + +static void matrix_write_char(struct CharacterMatrix *matrix, uint8_t c) { + matrix->dirty = true; + + if (c == '\n') { + // Clear to end of line from the cursor and then move to the + // start of the next line + uint8_t cursor_col = (matrix->cursor - &matrix->display[0][0]) % MatrixCols; + + while (cursor_col++ < MatrixCols) { + matrix_write_char_inner(matrix, ' '); + } + return; + } + + matrix_write_char_inner(matrix, c); +} + +void iota_gfx_write_char(uint8_t c) { + matrix_write_char(&display, c); +} + +static void matrix_write(struct CharacterMatrix *matrix, const char *data) { + const char *end = data + strlen(data); + while (data < end) { + matrix_write_char(matrix, *data); + ++data; + } +} + +void iota_gfx_write(const char *data) { + matrix_write(&display, data); +} + +static void matrix_write_P(struct CharacterMatrix *matrix, const char *data) { + while (true) { + uint8_t c = pgm_read_byte(data); + if (c == 0) { + return; + } + matrix_write_char(matrix, c); + ++data; + } +} + +void iota_gfx_write_P(const char *data) { + matrix_write_P(&display, data); +} + +static void matrix_clear(struct CharacterMatrix *matrix) { + memset(matrix->display, ' ', sizeof(matrix->display)); + matrix->cursor = &matrix->display[0][0]; + matrix->dirty = true; +} + +void iota_gfx_clear_screen(void) { + matrix_clear(&display); +} + +static void matrix_render(struct CharacterMatrix *matrix) { + last_flush = timer_read(); + iota_gfx_on(); +#if DEBUG_TO_SCREEN + ++displaying; +#endif + + // Move to the home position + send_cmd3(PageAddr, 0, MatrixRows - 1); + send_cmd3(ColumnAddr, 0, (MatrixCols * FontWidth) - 1); + + if (i2c_start_write(i2cAddress)) { + goto done; + } + if (i2c_master_write(0x40)) { + // Data mode + goto done; + } + + for (uint8_t row = 0; row < MatrixRows; ++row) { + for (uint8_t col = 0; col < MatrixCols; ++col) { + const uint8_t *glyph = font + (matrix->display[row][col] * (FontWidth - 1)); + + for (uint8_t glyphCol = 0; glyphCol < FontWidth - 1; ++glyphCol) { + uint8_t colBits = pgm_read_byte(glyph + glyphCol); + i2c_master_write(colBits); + } + + // 1 column of space between chars (it's not included in the glyph) + i2c_master_write(0); + } + } + + matrix->dirty = false; + +done: + i2c_master_stop(); +#if DEBUG_TO_SCREEN + --displaying; +#endif +} + +void iota_gfx_flush(void) { + matrix_render(&display); +} + +static void matrix_update(struct CharacterMatrix *dest, + const struct CharacterMatrix *source) { + if (memcmp(dest->display, source->display, sizeof(dest->display))) { + memcpy(dest->display, source->display, sizeof(dest->display)); + dest->dirty = true; + } +} + +static void render_status_info(void) { +#if DEBUG_TO_SCREEN + if (debug_enable) { + return; + } +#endif + + struct CharacterMatrix matrix; + + matrix_clear(&matrix); + matrix_write_P(&matrix, PSTR("USB: ")); +#ifdef PROTOCOL_LUFA + switch (USB_DeviceState) { + case DEVICE_STATE_Unattached: + matrix_write_P(&matrix, PSTR("Unattached")); + break; + case DEVICE_STATE_Suspended: + matrix_write_P(&matrix, PSTR("Suspended")); + break; + case DEVICE_STATE_Configured: + matrix_write_P(&matrix, PSTR("Connected")); + break; + case DEVICE_STATE_Powered: + matrix_write_P(&matrix, PSTR("Powered")); + break; + case DEVICE_STATE_Default: + matrix_write_P(&matrix, PSTR("Default")); + break; + case DEVICE_STATE_Addressed: + matrix_write_P(&matrix, PSTR("Addressed")); + break; + default: + matrix_write_P(&matrix, PSTR("Invalid")); + } +#endif + +// Define layers here, Have not worked out how to have text displayed for each layer. Copy down the number you see and add a case for it below + + char buf[40]; + snprintf(buf,sizeof(buf), "Undef-%ld", layer_state); + matrix_write_P(&matrix, PSTR("\n\nLayer: ")); + switch (layer_state) { + case _BASE: + matrix_write_P(&matrix, PSTR("Default")); + break; + case _RAISE: + matrix_write_P(&matrix, PSTR("Raise")); + break; + case _LOWER: + matrix_write_P(&matrix, PSTR("Lower")); + break; + case _ADJUST: + matrix_write_P(&matrix, PSTR("ADJUST")); + break; + default: + matrix_write(&matrix, buf); + } + + // Host Keyboard LED Status + char led[40]; + snprintf(led, sizeof(led), "\n%s %s %s", + (host_keyboard_leds() & (1<<USB_LED_NUM_LOCK)) ? "NUMLOCK" : " ", + (host_keyboard_leds() & (1<<USB_LED_CAPS_LOCK)) ? "CAPS" : " ", + (host_keyboard_leds() & (1<<USB_LED_SCROLL_LOCK)) ? "SCLK" : " "); + matrix_write(&matrix, led); + matrix_update(&display, &matrix); +} + +void iota_gfx_task(void) { + render_status_info(); + + if (display.dirty) { + iota_gfx_flush(); + } + + if (timer_elapsed(last_flush) > ScreenOffInterval) { + iota_gfx_off(); + } +} +#endif diff --git a/keyboards/orthodox/ssd1306.h b/keyboards/orthodox/ssd1306.h new file mode 100644 index 0000000000..b0c74f987e --- /dev/null +++ b/keyboards/orthodox/ssd1306.h @@ -0,0 +1,17 @@ +#ifndef SSD1306_H +#define SSD1306_H + +#include <stdbool.h> +#include <stdio.h> + +bool iota_gfx_init(void); +void iota_gfx_task(void); +bool iota_gfx_off(void); +bool iota_gfx_on(void); +void iota_gfx_flush(void); +void iota_gfx_write_char(uint8_t c); +void iota_gfx_write(const char *data); +void iota_gfx_write_P(const char *data); +void iota_gfx_clear_screen(void); + +#endif diff --git a/keyboards/planck/readme.md b/keyboards/planck/readme.md index 4b24a690e0..b1a8c23b2e 100644 --- a/keyboards/planck/readme.md +++ b/keyboards/planck/readme.md @@ -1,33 +1,16 @@ -Planck keyboard firmware -====================== -DIY/Assembled compact ortholinear 40% keyboard by [Ortholinear Keyboards](http://ortholinearkeyboards.com). +Planck +=== -## Quantum MK Firmware +![Planck](http://i.imgur.com/q2M3uEU.jpg) -For the full Quantum feature list, see [the parent readme.md](/readme.md). +A compact 40% (12x4) ortholinear keyboard kit made and sold by OLKB and Massdrop. [More info on qmk.fm](http://qmk.fm/planck/) -## Building +Keyboard Maintainer: [Jack Humbert](https://github.com/jackhumbert) +Hardware Supported: Planck PCB rev1, rev2, rev3, rev4, Teensy 2.0 +Hardware Availability: [OLKB.com](https://olkb.com), [Massdrop](https://www.massdrop.com/buy/planck-mechanical-keyboard?mode=guest_open) -Download or clone the whole firmware and navigate to the keyboards/planck folder. Once your dev env is setup, you'll be able to type `make` to generate your .hex - you can then use `make dfu` to program your PCB once you hit the reset button. +Make example for this keyboard (after setting up your build environment): -Depending on which keymap you would like to use, you will have to compile slightly differently. + make planck-rev4-default -### Default -To build with the default keymap, simply run `make default`. - -### Other Keymaps -Several version of keymap are available in advance but you are recommended to define your favorite layout yourself. To define your own keymap create file named `<name>.c` in the keymaps folder, and see keymap document (you can find in top readme.md) and existent keymap files. - -To build the firmware binary hex file with a keymap just do `make` with a keymap like this: - -``` -$ make [default|jack|<name>] -``` - -Keymaps follow the format **__\<name\>.c__** and are stored in the `keymaps` folder. - -### Notable forks (which some of the keymap files are from) -- [Shane's Fork](https://github.com/shanecelis/tmk_keyboard/tree/master/keyboard/planck) -- [Pierre's Fork](https://github.com/pcarrier/tmk_keyboard/blob/pcarrier/planck/keyboard/gh60/keymap_planck.c) -- [Nathan's Fork](https://github.com/nathanrosspowell/tmk_keyboard/tree/planck-jack/keyboard/planck) -- [Matthew's Fork](https://github.com/pepers/tmk_keyboard/tree/master/keyboard/planck_grid) +See [build environment setup](https://docs.qmk.fm/build_environment_setup.html) then the [make instructions](https://docs.qmk.fm/make_instructions.html) for more information.
\ No newline at end of file diff --git a/keyboards/preonic/readme.md b/keyboards/preonic/readme.md index 10763ee97a..2a4ccd84dc 100644 --- a/keyboards/preonic/readme.md +++ b/keyboards/preonic/readme.md @@ -1,27 +1,16 @@ -Preonic keyboard firmware -====================== -DIY/Assembled compact ortholinear 50% keyboard by [Ortholinear Keyboards](http://ortholinearkeyboards.com). +Preonic +=== -## Quantum MK Firmware +![Preonic](http://i.imgur.com/EDWQbB0.jpg) -For the full Quantum feature list, see [the parent readme.md](/readme.md). +A compact 50% (12x5) ortholinear keyboard kit made and sold by OLKB and Massdrop. [More info on qmk.fm](http://qmk.fm/preonic/) -## Building +Keyboard Maintainer: [Jack Humbert](https://github.com/jackhumbert) +Hardware Supported: Preonic PCB rev1, Teensy 2.0 +Hardware Availability: [OLKB.com](https://olkb.com/preonic/), [Massdrop](https://www.massdrop.com/buy/preonic-mechanical-keyboard?mode=guest_open) -Download or clone the whole firmware and navigate to the keyboards/preonic folder. Once your dev env is setup, you'll be able to type `make` to generate your .hex - you can then use `make dfu` to program your PCB once you hit the reset button. +Make example for this keyboard (after setting up your build environment): -Depending on which keymap you would like to use, you will have to compile slightly differently. + make preonic-default -### Default -To build with the default keymap, simply run `make default`. - -### Other Keymaps -Several version of keymap are available in advance but you are recommended to define your favorite layout yourself. To define your own keymap, create a file in the keymaps folder named `<name>.c` and see keymap document (you can find in top readme.md) and existent keymap files. - -To build the firmware binary hex file with a keymap just do `make` with a keymap like this: - -``` -$ make [default|jack|<name>] -``` - -Keymaps follow the format **__\<name\>.c__** and are stored in the `keymaps` folder. +See [build environment setup](https://docs.qmk.fm/build_environment_setup.html) then the [make instructions](https://docs.qmk.fm/make_instructions.html) for more information.
\ No newline at end of file diff --git a/keyboards/whitefox/animations.c b/keyboards/whitefox/animations.c new file mode 100644 index 0000000000..ed1d75efb8 --- /dev/null +++ b/keyboards/whitefox/animations.c @@ -0,0 +1,128 @@ +/* Copyright 2017 Fred Sundvik + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#if defined(VISUALIZER_ENABLE) + +#include "animations.h" +#include "visualizer.h" + +#ifdef BACKLIGHT_ENABLE +#include "led_keyframes.h" +#endif + +#include "visualizer_keyframes.h" + + +#if defined(LCD_ENABLE) || defined(LCD_BACKLIGHT_ENABLE) || defined(BACKLIGHT_ENABLE) + +static bool keyframe_enable(keyframe_animation_t* animation, visualizer_state_t* state) { +#ifdef BACKLIGHT_ENABLE + led_keyframe_enable(animation, state); +#endif + return false; +} + +static bool keyframe_disable(keyframe_animation_t* animation, visualizer_state_t* state) { +#ifdef BACKLIGHT_ENABLE + led_keyframe_disable(animation, state); +#endif + return false; +} + +static bool keyframe_fade_in(keyframe_animation_t* animation, visualizer_state_t* state) { + bool ret = false; +#ifdef BACKLIGHT_ENABLE + ret |= led_keyframe_fade_in_all(animation, state); +#endif + return ret; +} + +static bool keyframe_fade_out(keyframe_animation_t* animation, visualizer_state_t* state) { + bool ret = false; +#ifdef BACKLIGHT_ENABLE + ret |= led_keyframe_fade_out_all(animation, state); +#endif + return ret; +} + + +// Don't worry, if the startup animation is long, you can use the keyboard like normal +// during that time +keyframe_animation_t default_startup_animation = { + .num_frames = 2, + .loop = false, + .frame_lengths = {0, gfxMillisecondsToTicks(5000)}, + .frame_functions = { + keyframe_enable, + keyframe_fade_in, + }, +}; + +keyframe_animation_t default_suspend_animation = { + .num_frames = 2, + .loop = false, + .frame_lengths = {gfxMillisecondsToTicks(1000), 0}, + .frame_functions = { + keyframe_fade_out, + keyframe_disable, + }, +}; +#endif + +#if defined(BACKLIGHT_ENABLE) +#define CROSSFADE_TIME 1000 +#define GRADIENT_TIME 3000 + +keyframe_animation_t led_test_animation = { + .num_frames = 14, + .loop = true, + .frame_lengths = { + gfxMillisecondsToTicks(1000), // fade in + gfxMillisecondsToTicks(1000), // no op (leds on) + gfxMillisecondsToTicks(1000), // fade out + gfxMillisecondsToTicks(CROSSFADE_TIME), // crossfade + gfxMillisecondsToTicks(GRADIENT_TIME), // left to rigt (outside in) + gfxMillisecondsToTicks(CROSSFADE_TIME), // crossfade + gfxMillisecondsToTicks(GRADIENT_TIME), // top_to_bottom + 0, // mirror leds + gfxMillisecondsToTicks(CROSSFADE_TIME), // crossfade + gfxMillisecondsToTicks(GRADIENT_TIME), // left_to_right (mirrored, so inside out) + gfxMillisecondsToTicks(CROSSFADE_TIME), // crossfade + gfxMillisecondsToTicks(GRADIENT_TIME), // top_to_bottom + 0, // normal leds + gfxMillisecondsToTicks(CROSSFADE_TIME), // crossfade + + }, + .frame_functions = { + led_keyframe_fade_in_all, + keyframe_no_operation, + led_keyframe_fade_out_all, + led_keyframe_crossfade, + led_keyframe_left_to_right_gradient, + led_keyframe_crossfade, + led_keyframe_top_to_bottom_gradient, + led_keyframe_mirror_orientation, + led_keyframe_crossfade, + led_keyframe_left_to_right_gradient, + led_keyframe_crossfade, + led_keyframe_top_to_bottom_gradient, + led_keyframe_normal_orientation, + led_keyframe_crossfade, + }, +}; +#endif + +#endif diff --git a/keyboards/whitefox/animations.h b/keyboards/whitefox/animations.h new file mode 100644 index 0000000000..6d8b9830d9 --- /dev/null +++ b/keyboards/whitefox/animations.h @@ -0,0 +1,30 @@ +/* Copyright 2017 Fred Sundvik + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef KEYBOARDS_ERGODOX_INFINITY_ANIMATIONS_H_ +#define KEYBOARDS_ERGODOX_INFINITY_ANIMATIONS_H_ + +#include "visualizer.h" + +// You can use these default animations, but of course you can also write your own custom ones instead +extern keyframe_animation_t default_startup_animation; +extern keyframe_animation_t default_suspend_animation; + +// An animation for testing and demonstrating the led support, should probably not be used for real world +// cases +extern keyframe_animation_t led_test_animation; + +#endif /* KEYBOARDS_ERGODOX_INFINITY_ANIMATIONS_H_ */ diff --git a/keyboards/whitefox/config.h b/keyboards/whitefox/config.h index b7116341ff..08de9b9aa8 100644 --- a/keyboards/whitefox/config.h +++ b/keyboards/whitefox/config.h @@ -35,6 +35,12 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. #define MATRIX_ROWS 9 #define MATRIX_COLS 8 +/* number of backlight levels */ +#define BACKLIGHT_LEVELS 3 + +#define LED_BRIGHTNESS_LO 100 +#define LED_BRIGHTNESS_HI 255 + /* define if matrix has ghost */ //#define MATRIX_HAS_GHOST @@ -76,3 +82,11 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. //#define NO_ACTION_FUNCTION #endif + +// The visualizer needs gfx thread priorities +#define LED_DISPLAY_NUMBER 0 + +#define LED_NUM_ROWS 5 +#define LED_NUM_COLS 16 + +#define VISUALIZER_THREAD_PRIORITY (NORMAL_PRIORITY - 2) diff --git a/keyboards/whitefox/drivers/gdisp/IS31FL3731C/board_IS31FL3731C.h b/keyboards/whitefox/drivers/gdisp/IS31FL3731C/board_IS31FL3731C.h new file mode 100644 index 0000000000..3dc5327a58 --- /dev/null +++ b/keyboards/whitefox/drivers/gdisp/IS31FL3731C/board_IS31FL3731C.h @@ -0,0 +1,109 @@ +/* +Copyright 2016 Fred Sundvik <fsundvik@gmail.com> + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef _GDISP_LLD_BOARD_H +#define _GDISP_LLD_BOARD_H + +static const I2CConfig i2ccfg = { + 400000 // clock speed (Hz); 400kHz max for IS31 +}; + +#define GDISP_SCREEN_WIDTH 16 +#define GDISP_SCREEN_HEIGHT 5 + +static const uint8_t led_mask[] = { + 0xFF, 0x00, /* C1-1 -> C1-16 */ + 0xFF, 0x00, /* C2-1 -> C2-16 */ + 0xFF, 0x00, /* C3-1 -> C3-16 */ + 0xFF, 0x00, /* C4-1 -> C4-16 */ + 0xFF, 0x00, /* C5-1 -> C5-16 */ + 0xFF, 0x00, /* C6-1 -> C6-16 */ + 0xFF, 0x00, /* C7-1 -> C7-16 */ + 0xFF, 0x00, /* C8-1 -> C8-16 */ + 0xFE, 0x00, /* C9-1 -> C9-16 */ +}; + +// The address of the LED +#define LA(c, r) (c + r * 16 ) +// Need to be an address that is not mapped, but inside the range of the controller matrix +#define NA LA(8, 8) + +// The numbers in the comments are the led numbers DXX on the PCB +// The mapping is taken from the schematic of left hand side +static const uint8_t led_mapping[GDISP_SCREEN_HEIGHT][GDISP_SCREEN_WIDTH] = { +// 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 + { LA(0, 0), LA(1, 0), LA(2, 0), LA(3, 0), LA(4, 0), LA(5, 0), LA(6, 0), LA(7, 0), LA(0, 1), LA(1, 1), LA(2, 1), LA(3, 1), LA(4, 1), LA(5, 1), LA(6, 1), LA(7, 1)}, +// 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 + { LA(0, 2), LA(1, 2), LA(2, 2), LA(3, 2), LA(4, 2), LA(5, 2), LA(6, 2), LA(7, 2), LA(0, 3), LA(1, 3), NA, LA(2, 3), LA(3, 3), LA(4, 3), LA(5, 3), LA(6, 3)}, +// 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 + { LA(7, 3), LA(0, 4), LA(1, 4), LA(2, 4), LA(3, 4), LA(4, 4), LA(5, 4), LA(6, 4), LA(7, 4), LA(0, 5), NA, LA(1, 5), LA(2, 5), LA(3, 5), LA(4, 5), LA(5, 5)}, +// 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 + { LA(6, 5), LA(7, 5), LA(0, 6), LA(1, 6), LA(2, 6), LA(3, 6), LA(4, 6), LA(5, 6), LA(6, 6), LA(7, 6), NA, LA(0, 7), LA(1, 7), LA(2, 7), LA(3, 7), LA(4, 7)}, +// 62 63 64 65 66 67 68 69 70 71 + { LA(5, 7), LA(6, 7), LA(7, 7), NA, NA, NA, LA(0, 8), NA, NA, NA, LA(1, 8), LA(2, 8), LA(3, 8), LA(4, 8), LA(5, 8), LA(6, 8)}, +}; + + +#define IS31_ADDR_DEFAULT 0x74 // AD connected to GND +#define IS31_TIMEOUT 5000 + +static GFXINLINE void init_board(GDisplay *g) { + (void) g; + /* I2C pins */ + palSetPadMode(GPIOB, 0, PAL_MODE_ALTERNATIVE_2); // PTB0/I2C0/SCL + palSetPadMode(GPIOB, 1, PAL_MODE_ALTERNATIVE_2); // PTB1/I2C0/SDA + palSetPadMode(GPIOB, 16, PAL_MODE_OUTPUT_PUSHPULL); + palClearPad(GPIOB, 16); + /* start I2C */ + i2cStart(&I2CD1, &i2ccfg); + // try high drive (from kiibohd) + I2CD1.i2c->C2 |= I2Cx_C2_HDRS; + // try glitch fixing (from kiibohd) + I2CD1.i2c->FLT = 4; +} + +static GFXINLINE void post_init_board(GDisplay *g) { + (void) g; +} + +static GFXINLINE const uint8_t* get_led_mask(GDisplay* g) { + (void) g; + return led_mask; +} + +static GFXINLINE uint8_t get_led_address(GDisplay* g, uint16_t x, uint16_t y) +{ + (void) g; + return led_mapping[y][x]; +} + +static GFXINLINE void set_hardware_shutdown(GDisplay* g, bool shutdown) { + (void) g; + if(!shutdown) { + palSetPad(GPIOB, 16); + } + else { + palClearPad(GPIOB, 16); + } +} + +static GFXINLINE void write_data(GDisplay *g, uint8_t* data, uint16_t length) { + (void) g; + i2cMasterTransmitTimeout(&I2CD1, IS31_ADDR_DEFAULT, data, length, 0, 0, US2ST(IS31_TIMEOUT)); +} + +#endif /* _GDISP_LLD_BOARD_H */ diff --git a/keyboards/whitefox/drivers/gdisp/IS31FL3731C/driver.mk b/keyboards/whitefox/drivers/gdisp/IS31FL3731C/driver.mk new file mode 100644 index 0000000000..f32d0d8685 --- /dev/null +++ b/keyboards/whitefox/drivers/gdisp/IS31FL3731C/driver.mk @@ -0,0 +1,2 @@ +GFXINC += drivers/gdisp/IS31FL3731C +GFXSRC += drivers/gdisp/IS31FL3731C/gdisp_IS31FL3731C.c diff --git a/keyboards/whitefox/drivers/gdisp/IS31FL3731C/gdisp_IS31FL3731C.c b/keyboards/whitefox/drivers/gdisp/IS31FL3731C/gdisp_IS31FL3731C.c new file mode 100644 index 0000000000..c807cbd1e2 --- /dev/null +++ b/keyboards/whitefox/drivers/gdisp/IS31FL3731C/gdisp_IS31FL3731C.c @@ -0,0 +1,312 @@ +/* +Copyright 2016 Fred Sundvik <fsundvik@gmail.com> + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "gfx.h" + +#if GFX_USE_GDISP + +#define GDISP_DRIVER_VMT GDISPVMT_IS31FL3731C_WHITEFOX +#include "drivers/gdisp/IS31FL3731C/gdisp_lld_config.h" +#include "src/gdisp/gdisp_driver.h" + +#include "board_IS31FL3731C.h" + + +// Can't include led_tables from here +extern const uint8_t CIE1931_CURVE[]; + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +#ifndef GDISP_SCREEN_HEIGHT + #define GDISP_SCREEN_HEIGHT 9 +#endif +#ifndef GDISP_SCREEN_WIDTH + #define GDISP_SCREEN_WIDTH 16 +#endif +#ifndef GDISP_INITIAL_CONTRAST + #define GDISP_INITIAL_CONTRAST 0 +#endif +#ifndef GDISP_INITIAL_BACKLIGHT + #define GDISP_INITIAL_BACKLIGHT 0 +#endif + +#define GDISP_FLG_NEEDFLUSH (GDISP_FLG_DRIVER<<0) + +#define IS31_ADDR_DEFAULT 0x74 + +#define IS31_REG_CONFIG 0x00 +// bits in reg +#define IS31_REG_CONFIG_PICTUREMODE 0x00 +#define IS31_REG_CONFIG_AUTOPLAYMODE 0x08 +#define IS31_REG_CONFIG_AUDIOPLAYMODE 0x18 +// D2:D0 bits are starting frame for autoplay mode + +#define IS31_REG_PICTDISP 0x01 // D2:D0 frame select for picture mode + +#define IS31_REG_AUTOPLAYCTRL1 0x02 +// D6:D4 number of loops (000=infty) +// D2:D0 number of frames to be used + +#define IS31_REG_AUTOPLAYCTRL2 0x03 // D5:D0 delay time (*11ms) + +#define IS31_REG_DISPLAYOPT 0x05 +#define IS31_REG_DISPLAYOPT_INTENSITY_SAME 0x20 // same intensity for all frames +#define IS31_REG_DISPLAYOPT_BLINK_ENABLE 0x8 +// D2:D0 bits blink period time (*0.27s) + +#define IS31_REG_AUDIOSYNC 0x06 +#define IS31_REG_AUDIOSYNC_ENABLE 0x1 + +#define IS31_REG_FRAMESTATE 0x07 + +#define IS31_REG_BREATHCTRL1 0x08 +// D6:D4 fade out time (26ms*2^i) +// D2:D0 fade in time (26ms*2^i) + +#define IS31_REG_BREATHCTRL2 0x09 +#define IS31_REG_BREATHCTRL2_ENABLE 0x10 +// D2:D0 extinguish time (3.5ms*2^i) + +#define IS31_REG_SHUTDOWN 0x0A +#define IS31_REG_SHUTDOWN_OFF 0x0 +#define IS31_REG_SHUTDOWN_ON 0x1 + +#define IS31_REG_AGCCTRL 0x0B +#define IS31_REG_ADCRATE 0x0C + +#define IS31_COMMANDREGISTER 0xFD +#define IS31_FUNCTIONREG 0x0B // helpfully called 'page nine' +#define IS31_FUNCTIONREG_SIZE 0xD + +#define IS31_FRAME_SIZE 0xB4 + +#define IS31_PWM_REG 0x24 +#define IS31_PWM_SIZE 0x90 + +#define IS31_LED_MASK_SIZE 0x12 +#define IS31_SCREEN_WIDTH 16 + +#define IS31 + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +typedef struct{ + uint8_t write_buffer_offset; + uint8_t write_buffer[IS31_FRAME_SIZE]; + uint8_t frame_buffer[GDISP_SCREEN_HEIGHT * GDISP_SCREEN_WIDTH]; + uint8_t page; +}__attribute__((__packed__)) PrivData; + +// Some common routines and macros +#define PRIV(g) ((PrivData*)g->priv) + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +static GFXINLINE void write_page(GDisplay* g, uint8_t page) { + uint8_t tx[2] __attribute__((aligned(2))); + tx[0] = IS31_COMMANDREGISTER; + tx[1] = page; + write_data(g, tx, 2); +} + +static GFXINLINE void write_register(GDisplay* g, uint8_t page, uint8_t reg, uint8_t data) { + uint8_t tx[2] __attribute__((aligned(2))); + tx[0] = reg; + tx[1] = data; + write_page(g, page); + write_data(g, tx, 2); +} + +static GFXINLINE void write_ram(GDisplay *g, uint8_t page, uint16_t offset, uint16_t length) { + PRIV(g)->write_buffer_offset = offset; + write_page(g, page); + write_data(g, (uint8_t*)PRIV(g), length + 1); +} + +LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { + // The private area is the display surface. + g->priv = gfxAlloc(sizeof(PrivData)); + __builtin_memset(PRIV(g), 0, sizeof(PrivData)); + PRIV(g)->page = 0; + + // Initialise the board interface + init_board(g); + gfxSleepMilliseconds(10); + + // zero function page, all registers (assuming full_page is all zeroes) + write_ram(g, IS31_FUNCTIONREG, 0, IS31_FUNCTIONREG_SIZE); + set_hardware_shutdown(g, false); + gfxSleepMilliseconds(10); + // software shutdown + write_register(g, IS31_FUNCTIONREG, IS31_REG_SHUTDOWN, IS31_REG_SHUTDOWN_OFF); + gfxSleepMilliseconds(10); + // zero function page, all registers + write_ram(g, IS31_FUNCTIONREG, 0, IS31_FUNCTIONREG_SIZE); + gfxSleepMilliseconds(10); + + + // zero all LED registers on all 8 pages, and enable the mask + __builtin_memcpy(PRIV(g)->write_buffer, get_led_mask(g), IS31_LED_MASK_SIZE); + for(uint8_t i=0; i<8; i++) { + write_ram(g, i, 0, IS31_FRAME_SIZE); + gfxSleepMilliseconds(1); + } + + // software shutdown disable (i.e. turn stuff on) + write_register(g, IS31_FUNCTIONREG, IS31_REG_SHUTDOWN, IS31_REG_SHUTDOWN_OFF); + gfxSleepMilliseconds(10); + + // Finish Init + post_init_board(g); + + /* Initialise the GDISP structure */ + g->g.Width = GDISP_SCREEN_WIDTH; + g->g.Height = GDISP_SCREEN_HEIGHT; + g->g.Orientation = GDISP_ROTATE_0; + g->g.Powermode = powerOff; + g->g.Backlight = GDISP_INITIAL_BACKLIGHT; + g->g.Contrast = GDISP_INITIAL_CONTRAST; + return TRUE; +} + +#if GDISP_HARDWARE_FLUSH + LLDSPEC void gdisp_lld_flush(GDisplay *g) { + // Don't flush if we don't need it. + if (!(g->flags & GDISP_FLG_NEEDFLUSH)) + return; + + PRIV(g)->page++; + PRIV(g)->page %= 2; + // TODO: some smarter algorithm for this + // We should run only one physical page at a time + // This way we don't need to send so much data, and + // we could use slightly less memory + uint8_t* src = PRIV(g)->frame_buffer; + for (int y=0;y<GDISP_SCREEN_HEIGHT;y++) { + for (int x=0;x<GDISP_SCREEN_WIDTH;x++) { + uint8_t val = (uint16_t)*src * g->g.Backlight / 100; + PRIV(g)->write_buffer[get_led_address(g, x, y)]=CIE1931_CURVE[val]; + ++src; + } + } + write_ram(g, PRIV(g)->page, IS31_PWM_REG, IS31_PWM_SIZE); + gfxSleepMilliseconds(1); + write_register(g, IS31_FUNCTIONREG, IS31_REG_PICTDISP, PRIV(g)->page); + + g->flags &= ~GDISP_FLG_NEEDFLUSH; + } +#endif + +#if GDISP_HARDWARE_DRAWPIXEL + LLDSPEC void gdisp_lld_draw_pixel(GDisplay *g) { + coord_t x, y; + + switch(g->g.Orientation) { + default: + case GDISP_ROTATE_0: + x = g->p.x; + y = g->p.y; + break; + case GDISP_ROTATE_180: + x = GDISP_SCREEN_WIDTH-1 - g->p.x; + y = g->p.y; + break; + } + PRIV(g)->frame_buffer[y * GDISP_SCREEN_WIDTH + x] = gdispColor2Native(g->p.color); + g->flags |= GDISP_FLG_NEEDFLUSH; + } +#endif + +#if GDISP_HARDWARE_PIXELREAD + LLDSPEC color_t gdisp_lld_get_pixel_color(GDisplay *g) { + coord_t x, y; + + switch(g->g.Orientation) { + default: + case GDISP_ROTATE_0: + x = g->p.x; + y = g->p.y; + break; + case GDISP_ROTATE_180: + x = GDISP_SCREEN_WIDTH-1 - g->p.x; + y = g->p.y; + break; + } + return gdispNative2Color(PRIV(g)->frame_buffer[y * GDISP_SCREEN_WIDTH + x]); + } +#endif + +#if GDISP_NEED_CONTROL && GDISP_HARDWARE_CONTROL + LLDSPEC void gdisp_lld_control(GDisplay *g) { + switch(g->p.x) { + case GDISP_CONTROL_POWER: + if (g->g.Powermode == (powermode_t)g->p.ptr) + return; + switch((powermode_t)g->p.ptr) { + case powerOff: + case powerSleep: + case powerDeepSleep: + write_register(g, IS31_FUNCTIONREG, IS31_REG_SHUTDOWN, IS31_REG_SHUTDOWN_OFF); + break; + case powerOn: + write_register(g, IS31_FUNCTIONREG, IS31_REG_SHUTDOWN, IS31_REG_SHUTDOWN_ON); + break; + default: + return; + } + g->g.Powermode = (powermode_t)g->p.ptr; + return; + + case GDISP_CONTROL_ORIENTATION: + if (g->g.Orientation == (orientation_t)g->p.ptr) + return; + switch((orientation_t)g->p.ptr) { + /* Rotation is handled by the drawing routines */ + case GDISP_ROTATE_0: + case GDISP_ROTATE_180: + g->g.Height = GDISP_SCREEN_HEIGHT; + g->g.Width = GDISP_SCREEN_WIDTH; + break; + case GDISP_ROTATE_90: + case GDISP_ROTATE_270: + g->g.Height = GDISP_SCREEN_WIDTH; + g->g.Width = GDISP_SCREEN_HEIGHT; + break; + default: + return; + } + g->g.Orientation = (orientation_t)g->p.ptr; + return; + + case GDISP_CONTROL_BACKLIGHT: + if (g->g.Backlight == (unsigned)g->p.ptr) + return; + unsigned val = (unsigned)g->p.ptr; + g->g.Backlight = val > 100 ? 100 : val; + g->flags |= GDISP_FLG_NEEDFLUSH; + return; + } + } +#endif // GDISP_NEED_CONTROL + +#endif // GFX_USE_GDISP diff --git a/keyboards/whitefox/drivers/gdisp/IS31FL3731C/gdisp_lld_config.h b/keyboards/whitefox/drivers/gdisp/IS31FL3731C/gdisp_lld_config.h new file mode 100644 index 0000000000..bb28ad775e --- /dev/null +++ b/keyboards/whitefox/drivers/gdisp/IS31FL3731C/gdisp_lld_config.h @@ -0,0 +1,36 @@ +/* +Copyright 2016 Fred Sundvik <fsundvik@gmail.com> + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef _GDISP_LLD_CONFIG_H +#define _GDISP_LLD_CONFIG_H + +#if GFX_USE_GDISP + +/*===========================================================================*/ +/* Driver hardware support. */ +/*===========================================================================*/ + +#define GDISP_HARDWARE_FLUSH TRUE // This controller requires flushing +#define GDISP_HARDWARE_DRAWPIXEL TRUE +#define GDISP_HARDWARE_PIXELREAD TRUE +#define GDISP_HARDWARE_CONTROL TRUE + +#define GDISP_LLD_PIXELFORMAT GDISP_PIXELFORMAT_GRAY256 + +#endif /* GFX_USE_GDISP */ + +#endif /* _GDISP_LLD_CONFIG_H */ diff --git a/keyboards/whitefox/gfxconf.h b/keyboards/whitefox/gfxconf.h new file mode 100644 index 0000000000..890317a0f4 --- /dev/null +++ b/keyboards/whitefox/gfxconf.h @@ -0,0 +1,329 @@ +/** + * This file has a different license to the rest of the uGFX system. + * You can copy, modify and distribute this file as you see fit. + * You do not need to publish your source modifications to this file. + * The only thing you are not permitted to do is to relicense it + * under a different license. + */ + +/** + * Copy this file into your project directory and rename it as gfxconf.h + * Edit your copy to turn on the uGFX features you want to use. + * The values below are the defaults. + * + * Only remove the comments from lines where you want to change the + * default value. This allows definitions to be included from + * driver makefiles when required and provides the best future + * compatibility for your project. + * + * Please use spaces instead of tabs in this file. + */ + +#ifndef _GFXCONF_H +#define _GFXCONF_H + + +/////////////////////////////////////////////////////////////////////////// +// GOS - One of these must be defined, preferably in your Makefile // +/////////////////////////////////////////////////////////////////////////// +//#define GFX_USE_OS_CHIBIOS TRUE +//#define GFX_USE_OS_FREERTOS FALSE +// #define GFX_FREERTOS_USE_TRACE FALSE +//#define GFX_USE_OS_WIN32 FALSE +//#define GFX_USE_OS_LINUX FALSE +//#define GFX_USE_OS_OSX FALSE +//#define GFX_USE_OS_ECOS FALSE +//#define GFX_USE_OS_RAWRTOS FALSE +//#define GFX_USE_OS_ARDUINO FALSE +//#define GFX_USE_OS_KEIL FALSE +//#define GFX_USE_OS_CMSIS FALSE +//#define GFX_USE_OS_RAW32 FALSE +// #define INTERRUPTS_OFF() optional_code +// #define INTERRUPTS_ON() optional_code +// These are not defined by default for some reason +#define GOS_NEED_X_THREADS FALSE +#define GOS_NEED_X_HEAP FALSE + +// Options that (should where relevant) apply to all operating systems + #define GFX_NO_INLINE FALSE +// #define GFX_COMPILER GFX_COMPILER_UNKNOWN +// #define GFX_CPU GFX_CPU_UNKNOWN +// #define GFX_OS_HEAP_SIZE 0 +// #define GFX_OS_NO_INIT FALSE +// #define GFX_OS_INIT_NO_WARNING FALSE +// #define GFX_OS_PRE_INIT_FUNCTION myHardwareInitRoutine +// #define GFX_OS_EXTRA_INIT_FUNCTION myOSInitRoutine +// #define GFX_OS_EXTRA_DEINIT_FUNCTION myOSDeInitRoutine + + +/////////////////////////////////////////////////////////////////////////// +// GDISP // +/////////////////////////////////////////////////////////////////////////// +#define GFX_USE_GDISP TRUE + +//#define GDISP_NEED_AUTOFLUSH FALSE +//#define GDISP_NEED_TIMERFLUSH FALSE +//#define GDISP_NEED_VALIDATION TRUE +//#define GDISP_NEED_CLIP TRUE +#define GDISP_NEED_CIRCLE TRUE +#define GDISP_NEED_ELLIPSE TRUE +#define GDISP_NEED_ARC TRUE +#define GDISP_NEED_ARCSECTORS TRUE +#define GDISP_NEED_CONVEX_POLYGON TRUE +//#define GDISP_NEED_SCROLL FALSE +#define GDISP_NEED_PIXELREAD TRUE +#define GDISP_NEED_CONTROL TRUE +//#define GDISP_NEED_QUERY FALSE +//#define GDISP_NEED_MULTITHREAD FALSE +//#define GDISP_NEED_STREAMING FALSE +#define GDISP_NEED_TEXT TRUE +// #define GDISP_NEED_TEXT_WORDWRAP FALSE +// #define GDISP_NEED_ANTIALIAS FALSE +// #define GDISP_NEED_UTF8 FALSE + #define GDISP_NEED_TEXT_KERNING TRUE +// #define GDISP_INCLUDE_FONT_UI1 FALSE +// #define GDISP_INCLUDE_FONT_UI2 FALSE // The smallest preferred font. +// #define GDISP_INCLUDE_FONT_LARGENUMBERS FALSE +// #define GDISP_INCLUDE_FONT_DEJAVUSANS10 FALSE +// #define GDISP_INCLUDE_FONT_DEJAVUSANS12 FALSE +// #define GDISP_INCLUDE_FONT_DEJAVUSANS16 FALSE +// #define GDISP_INCLUDE_FONT_DEJAVUSANS20 FALSE +// #define GDISP_INCLUDE_FONT_DEJAVUSANS24 FALSE +// #define GDISP_INCLUDE_FONT_DEJAVUSANS32 FALSE + #define GDISP_INCLUDE_FONT_DEJAVUSANSBOLD12 TRUE +// #define GDISP_INCLUDE_FONT_FIXED_10X20 FALSE +// #define GDISP_INCLUDE_FONT_FIXED_7X14 FALSE + #define GDISP_INCLUDE_FONT_FIXED_5X8 TRUE +// #define GDISP_INCLUDE_FONT_DEJAVUSANS12_AA FALSE +// #define GDISP_INCLUDE_FONT_DEJAVUSANS16_AA FALSE +// #define GDISP_INCLUDE_FONT_DEJAVUSANS20_AA FALSE +// #define GDISP_INCLUDE_FONT_DEJAVUSANS24_AA FALSE +// #define GDISP_INCLUDE_FONT_DEJAVUSANS32_AA FALSE +// #define GDISP_INCLUDE_FONT_DEJAVUSANSBOLD12_AA FALSE +// #define GDISP_INCLUDE_USER_FONTS FALSE + +//#define GDISP_NEED_IMAGE FALSE +// #define GDISP_NEED_IMAGE_NATIVE FALSE +// #define GDISP_NEED_IMAGE_GIF FALSE +// #define GDISP_NEED_IMAGE_BMP FALSE +// #define GDISP_NEED_IMAGE_BMP_1 FALSE +// #define GDISP_NEED_IMAGE_BMP_4 FALSE +// #define GDISP_NEED_IMAGE_BMP_4_RLE FALSE +// #define GDISP_NEED_IMAGE_BMP_8 FALSE +// #define GDISP_NEED_IMAGE_BMP_8_RLE FALSE +// #define GDISP_NEED_IMAGE_BMP_16 FALSE +// #define GDISP_NEED_IMAGE_BMP_24 FALSE +// #define GDISP_NEED_IMAGE_BMP_32 FALSE +// #define GDISP_NEED_IMAGE_JPG FALSE +// #define GDISP_NEED_IMAGE_PNG FALSE +// #define GDISP_NEED_IMAGE_ACCOUNTING FALSE +#ifdef EMULATOR +#define GDISP_NEED_PIXMAP TRUE +#endif +// #define GDISP_NEED_PIXMAP_IMAGE FALSE + +//#define GDISP_DEFAULT_ORIENTATION GDISP_ROTATE_LANDSCAPE // If not defined the native hardware orientation is used. +//#define GDISP_LINEBUF_SIZE 128 +//#define GDISP_STARTUP_COLOR Black +#define GDISP_NEED_STARTUP_LOGO FALSE + +//#define GDISP_TOTAL_DISPLAYS 2 + +#ifndef EMULATOR +#define GDISP_DRIVER_LIST GDISPVMT_IS31FL3731C_WHITEFOX +#endif + + #ifdef GDISP_DRIVER_LIST + // For code and speed optimization define as TRUE or FALSE if all controllers have the same capability + #define GDISP_HARDWARE_STREAM_WRITE FALSE + #define GDISP_HARDWARE_STREAM_READ FALSE + #define GDISP_HARDWARE_STREAM_POS FALSE + #define GDISP_HARDWARE_DRAWPIXEL TRUE + #define GDISP_HARDWARE_CLEARS FALSE + #define GDISP_HARDWARE_FILLS FALSE + //#define GDISP_HARDWARE_BITFILLS FALSE + #define GDISP_HARDWARE_SCROLL FALSE + #define GDISP_HARDWARE_PIXELREAD TRUE + #define GDISP_HARDWARE_CONTROL TRUE + #define GDISP_HARDWARE_QUERY FALSE + #define GDISP_HARDWARE_CLIP FALSE + + #define GDISP_PIXELFORMAT GDISP_PIXELFORMAT_RGB888 + #endif + +// The custom format is not defined for some reason, so define it as error +// so we don't get compiler warnings +#define GDISP_PIXELFORMAT_CUSTOM GDISP_PIXELFORMAT_ERROR + +#define GDISP_USE_GFXNET FALSE +// #define GDISP_GFXNET_PORT 13001 +// #define GDISP_GFXNET_CUSTOM_LWIP_STARTUP FALSE +// #define GDISP_DONT_WAIT_FOR_NET_DISPLAY FALSE +// #define GDISP_GFXNET_UNSAFE_SOCKETS FALSE + + +/////////////////////////////////////////////////////////////////////////// +// GWIN // +/////////////////////////////////////////////////////////////////////////// +#define GFX_USE_GWIN FALSE + +//#define GWIN_NEED_WINDOWMANAGER FALSE +// #define GWIN_REDRAW_IMMEDIATE FALSE +// #define GWIN_REDRAW_SINGLEOP FALSE +// #define GWIN_NEED_FLASHING FALSE +// #define GWIN_FLASHING_PERIOD 250 + +//#define GWIN_NEED_CONSOLE FALSE +// #define GWIN_CONSOLE_USE_HISTORY FALSE +// #define GWIN_CONSOLE_HISTORY_AVERAGING FALSE +// #define GWIN_CONSOLE_HISTORY_ATCREATE FALSE +// #define GWIN_CONSOLE_ESCSEQ FALSE +// #define GWIN_CONSOLE_USE_BASESTREAM FALSE +// #define GWIN_CONSOLE_USE_FLOAT FALSE +//#define GWIN_NEED_GRAPH FALSE +//#define GWIN_NEED_GL3D FALSE + +//#define GWIN_NEED_WIDGET FALSE +//#define GWIN_FOCUS_HIGHLIGHT_WIDTH 1 +// #define GWIN_NEED_LABEL FALSE +// #define GWIN_LABEL_ATTRIBUTE FALSE +// #define GWIN_NEED_BUTTON FALSE +// #define GWIN_BUTTON_LAZY_RELEASE FALSE +// #define GWIN_NEED_SLIDER FALSE +// #define GWIN_SLIDER_NOSNAP FALSE +// #define GWIN_SLIDER_DEAD_BAND 5 +// #define GWIN_SLIDER_TOGGLE_INC 20 +// #define GWIN_NEED_CHECKBOX FALSE +// #define GWIN_NEED_IMAGE FALSE +// #define GWIN_NEED_IMAGE_ANIMATION FALSE +// #define GWIN_NEED_RADIO FALSE +// #define GWIN_NEED_LIST FALSE +// #define GWIN_NEED_LIST_IMAGES FALSE +// #define GWIN_NEED_PROGRESSBAR FALSE +// #define GWIN_PROGRESSBAR_AUTO FALSE +// #define GWIN_NEED_KEYBOARD FALSE +// #define GWIN_KEYBOARD_DEFAULT_LAYOUT VirtualKeyboard_English1 +// #define GWIN_NEED_KEYBOARD_ENGLISH1 TRUE +// #define GWIN_NEED_TEXTEDIT FALSE +// #define GWIN_FLAT_STYLING FALSE +// #define GWIN_WIDGET_TAGS FALSE + +//#define GWIN_NEED_CONTAINERS FALSE +// #define GWIN_NEED_CONTAINER FALSE +// #define GWIN_NEED_FRAME FALSE +// #define GWIN_NEED_TABSET FALSE +// #define GWIN_TABSET_TABHEIGHT 18 + + +/////////////////////////////////////////////////////////////////////////// +// GEVENT // +/////////////////////////////////////////////////////////////////////////// +#define GFX_USE_GEVENT TRUE + +//#define GEVENT_ASSERT_NO_RESOURCE FALSE +//#define GEVENT_MAXIMUM_SIZE 32 +//#define GEVENT_MAX_SOURCE_LISTENERS 32 + + +/////////////////////////////////////////////////////////////////////////// +// GTIMER // +/////////////////////////////////////////////////////////////////////////// +#define GFX_USE_GTIMER FALSE + +//#define GTIMER_THREAD_PRIORITY HIGH_PRIORITY +//#define GTIMER_THREAD_WORKAREA_SIZE 2048 + + +/////////////////////////////////////////////////////////////////////////// +// GQUEUE // +/////////////////////////////////////////////////////////////////////////// +#define GFX_USE_GQUEUE FALSE + +//#define GQUEUE_NEED_ASYNC FALSE +//#define GQUEUE_NEED_GSYNC FALSE +//#define GQUEUE_NEED_FSYNC FALSE +//#define GQUEUE_NEED_BUFFERS FALSE + +/////////////////////////////////////////////////////////////////////////// +// GINPUT // +/////////////////////////////////////////////////////////////////////////// +#define GFX_USE_GINPUT FALSE + +//#define GINPUT_NEED_MOUSE FALSE +// #define GINPUT_TOUCH_STARTRAW FALSE +// #define GINPUT_TOUCH_NOTOUCH FALSE +// #define GINPUT_TOUCH_NOCALIBRATE FALSE +// #define GINPUT_TOUCH_NOCALIBRATE_GUI FALSE +// #define GINPUT_MOUSE_POLL_PERIOD 25 +// #define GINPUT_MOUSE_CLICK_TIME 300 +// #define GINPUT_TOUCH_CXTCLICK_TIME 700 +// #define GINPUT_TOUCH_USER_CALIBRATION_LOAD FALSE +// #define GINPUT_TOUCH_USER_CALIBRATION_SAVE FALSE +// #define GMOUSE_DRIVER_LIST GMOUSEVMT_Win32, GMOUSEVMT_Win32 +//#define GINPUT_NEED_KEYBOARD FALSE +// #define GINPUT_KEYBOARD_POLL_PERIOD 200 +// #define GKEYBOARD_DRIVER_LIST GKEYBOARDVMT_Win32, GKEYBOARDVMT_Win32 +// #define GKEYBOARD_LAYOUT_OFF FALSE +// #define GKEYBOARD_LAYOUT_SCANCODE2_US FALSE +//#define GINPUT_NEED_TOGGLE FALSE +//#define GINPUT_NEED_DIAL FALSE + + +/////////////////////////////////////////////////////////////////////////// +// GFILE // +/////////////////////////////////////////////////////////////////////////// +#define GFX_USE_GFILE FALSE + +//#define GFILE_NEED_PRINTG FALSE +//#define GFILE_NEED_SCANG FALSE +//#define GFILE_NEED_STRINGS FALSE +//#define GFILE_NEED_FILELISTS FALSE +//#define GFILE_NEED_STDIO FALSE +//#define GFILE_NEED_NOAUTOMOUNT FALSE +//#define GFILE_NEED_NOAUTOSYNC FALSE + +//#define GFILE_NEED_MEMFS FALSE +//#define GFILE_NEED_ROMFS FALSE +//#define GFILE_NEED_RAMFS FALSE +//#define GFILE_NEED_FATFS FALSE +//#define GFILE_NEED_NATIVEFS FALSE +//#define GFILE_NEED_CHBIOSFS FALSE + +//#define GFILE_ALLOW_FLOATS FALSE +//#define GFILE_ALLOW_DEVICESPECIFIC FALSE +//#define GFILE_MAX_GFILES 3 + +/////////////////////////////////////////////////////////////////////////// +// GADC // +/////////////////////////////////////////////////////////////////////////// +#define GFX_USE_GADC FALSE + +//#define GADC_MAX_LOWSPEED_DEVICES 4 + + +/////////////////////////////////////////////////////////////////////////// +// GAUDIO // +/////////////////////////////////////////////////////////////////////////// +#define GFX_USE_GAUDIO FALSE +// There seems to be a bug in the ugfx code, the wrong define is used +// So define it in order to avoid warnings +#define GFX_USE_GAUDIN GFX_USE_GAUDIO +// #define GAUDIO_NEED_PLAY FALSE +// #define GAUDIO_NEED_RECORD FALSE + + +/////////////////////////////////////////////////////////////////////////// +// GMISC // +/////////////////////////////////////////////////////////////////////////// +#define GFX_USE_GMISC TRUE + +//#define GMISC_NEED_ARRAYOPS FALSE +//#define GMISC_NEED_FASTTRIG FALSE +//#define GMISC_NEED_FIXEDTRIG FALSE +//#define GMISC_NEED_INVSQRT FALSE +// #define GMISC_INVSQRT_MIXED_ENDIAN FALSE +// #define GMISC_INVSQRT_REAL_SLOW FALSE +#define GMISC_NEED_MATRIXFLOAT2D TRUE +#define GMISC_NEED_MATRIXFIXED2D FALSE + +#endif /* _GFXCONF_H */ diff --git a/keyboards/whitefox/halconf.h b/keyboards/whitefox/halconf.h index 46b37a4f46..b380315298 100644 --- a/keyboards/whitefox/halconf.h +++ b/keyboards/whitefox/halconf.h @@ -76,7 +76,7 @@ * @brief Enables the I2C subsystem. */ #if !defined(HAL_USE_I2C) || defined(__DOXYGEN__) -#define HAL_USE_I2C FALSE +#define HAL_USE_I2C TRUE #endif /** diff --git a/keyboards/whitefox/keymaps/jetpacktuxedo/Makefile b/keyboards/whitefox/keymaps/jetpacktuxedo/Makefile new file mode 100644 index 0000000000..8eb483103c --- /dev/null +++ b/keyboards/whitefox/keymaps/jetpacktuxedo/Makefile @@ -0,0 +1,5 @@ +ifndef QUANTUM_DIR + include ../../../Makefile +endif + +BACKLIGHT_ENABLE = yes diff --git a/keyboards/whitefox/keymaps/jetpacktuxedo/keymap.c b/keyboards/whitefox/keymaps/jetpacktuxedo/keymap.c index 09f6ca34df..82de171733 100644 --- a/keyboards/whitefox/keymaps/jetpacktuxedo/keymap.c +++ b/keyboards/whitefox/keymaps/jetpacktuxedo/keymap.c @@ -31,11 +31,11 @@ const uint16_t keymaps[][MATRIX_ROWS][MATRIX_COLS] = { * `---------------------------------------------------------------' */ [0] = KEYMAP( \ - KC_ESC, KC_1, KC_2, KC_3, KC_4, KC_5, KC_6, KC_7, KC_8, KC_9, KC_0, KC_MINS,KC_EQL,KC_NO,KC_BSPC,KC_INS, \ - KC_TAB, KC_Q, KC_W, KC_E, KC_R, KC_T, KC_Y, KC_U, KC_I, KC_O, KC_P, KC_LBRC,KC_RBRC, KC_BSLS, KC_DEL, \ - MO(1), KC_A, KC_S, KC_D, KC_F, KC_G, KC_H, KC_J, KC_K, KC_L, KC_SCLN,KC_QUOT,KC_NUHS, KC_ENT, KC_PGUP,\ - KC_LSFT,KC_NUBS,KC_Z, KC_X, KC_C, KC_V, KC_B, KC_N, KC_M, KC_COMM,KC_DOT, KC_SLSH, KC_RSFT, KC_UP, KC_PGDN,\ - KC_LCTL,KC_LGUI,KC_LALT, KC_SPC, KC_RALT,KC_RCTL,KC_NO, KC_LEFT,KC_DOWN,KC_RGHT \ + KC_GESC, KC_1, KC_2, KC_3, KC_4, KC_5, KC_6, KC_7, KC_8, KC_9, KC_0, KC_MINS,KC_EQL,KC_NO,KC_BSPC,KC_INS, \ + KC_TAB, KC_Q, KC_W, KC_E, KC_R, KC_T, KC_Y, KC_U, KC_I, KC_O, KC_P, KC_LBRC,KC_RBRC, KC_BSLS, KC_DEL, \ + MO(1), KC_A, KC_S, KC_D, KC_F, KC_G, KC_H, KC_J, KC_K, KC_L, KC_SCLN,KC_QUOT,KC_NUHS, KC_ENT, KC_PGUP,\ + KC_LSFT, KC_NUBS,KC_Z, KC_X, KC_C, KC_V, KC_B, KC_N, KC_M, KC_COMM,KC_DOT, KC_SLSH, KC_RSFT, KC_UP, KC_PGDN,\ + KC_LCTL, KC_LGUI,KC_LALT, KC_SPC, KC_RALT,KC_RCTL,KC_NO, KC_LEFT,KC_DOWN,KC_RGHT \ ), /* Layer 1: FN Layer * ,---------------------------------------------------------------. @@ -52,8 +52,8 @@ const uint16_t keymaps[][MATRIX_ROWS][MATRIX_COLS] = { */ [1] = KEYMAP( \ KC_GRV, KC_F1, KC_F2, KC_F3, KC_F4, KC_F5, KC_F6, KC_F7, KC_F8, KC_F9, KC_F10, KC_F11, KC_F12, KC_TRNS,KC_TRNS,KC_MUTE,\ - KC_TRNS,KC_TRNS,KC_TRNS,KC_TRNS,KC_TRNS,KC_TRNS,KC_TRNS,KC_TRNS,KC_TRNS,KC_TRNS,KC_PSCR,KC_SLCK,KC_PAUS,KC_TRNS, KC_TRNS,\ - KC_TRNS,KC_TRNS,KC_TRNS,KC_TRNS,KC_TRNS,KC_TRNS,KC_TRNS,KC_TRNS,KC_TRNS,KC_TRNS,KC_TRNS,KC_TRNS,KC_TRNS,KC_TRNS, KC_VOLU,\ + KC_TRNS,KC_TRNS,KC_TRNS,KC_TRNS,KC_TRNS,BL_TOGG,KC_TRNS,KC_TRNS,BL_INC, KC_TRNS,KC_PSCR,KC_SLCK,KC_PAUS,KC_TRNS, KC_TRNS,\ + KC_TRNS,KC_TRNS,KC_TRNS,BL_DEC, KC_TRNS,KC_TRNS,KC_TRNS,KC_TRNS,KC_TRNS,KC_TRNS,KC_TRNS,KC_TRNS,KC_TRNS,KC_TRNS, KC_VOLU,\ KC_TRNS,KC_TRNS,KC_TRNS,KC_TRNS,KC_TRNS,KC_TRNS,KC_TRNS,KC_TRNS,KC_TRNS,KC_TRNS,KC_TRNS,KC_TRNS,KC_TRNS, KC_PGUP,KC_VOLD,\ KC_TRNS,KC_TRNS,KC_TRNS, KC_TRNS, KC_TRNS,KC_TRNS,KC_TRNS, KC_HOME,KC_PGDN,KC_END \ ), diff --git a/keyboards/whitefox/rules.mk b/keyboards/whitefox/rules.mk index 18b690f492..565381e16b 100644 --- a/keyboards/whitefox/rules.mk +++ b/keyboards/whitefox/rules.mk @@ -1,6 +1,7 @@ # project specific files SRC = matrix.c \ - led.c + led.c \ + animations.c ## chip/board settings # - the next two should match the directories in @@ -66,3 +67,7 @@ COMMAND_ENABLE ?= yes # Commands for debug and configuration #SLEEP_LED_ENABLE ?= yes # Breathing sleep LED during USB suspend NKRO_ENABLE ?= yes # USB Nkey Rollover CUSTOM_MATRIX ?= yes # Custom matrix file +BACKLIGHT_ENABLE ?= yes +VISUALIZER_ENABLE ?= yes + +include $(KEYBOARD_PATH)/drivers/gdisp/IS31FL3731C/driver.mk diff --git a/keyboards/whitefox/visualizer.c b/keyboards/whitefox/visualizer.c new file mode 100644 index 0000000000..167e0ec4de --- /dev/null +++ b/keyboards/whitefox/visualizer.c @@ -0,0 +1,60 @@ +/* Copyright 2017 Fred Sundvik + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef KEYBOARDS_WHITEFOX_SIMPLE_VISUALIZER_H_ +#define KEYBOARDS_WHITEFOX_SIMPLE_VISUALIZER_H_ + +#include "visualizer.h" +#include "visualizer_keyframes.h" +#include "led.h" +#include "animations.h" + + +static bool initial_update = true; + +// Feel free to modify the animations below, or even add new ones if needed + +void initialize_user_visualizer(visualizer_state_t* state) { + // The brightness will be dynamically adjustable in the future + // But for now, change it here. + initial_update = true; + start_keyframe_animation(&default_startup_animation); +} + + +void update_user_visualizer_state(visualizer_state_t* state, visualizer_keyboard_status_t* prev_status) { + // Add more tests, change the colors and layer texts here + // Usually you want to check the high bits (higher layers first) + // because that's the order layers are processed for keypresses + // You can for check for example: + // state->status.layer + // state->status.default_layer + // state->status.leds (see led.h for available statuses) + + if (initial_update) { initial_update=false; start_keyframe_animation(&led_test_animation); } +} + + +void user_visualizer_suspend(visualizer_state_t* state) { + start_keyframe_animation(&default_suspend_animation); +} + +void user_visualizer_resume(visualizer_state_t* state) { + initial_update = true; + start_keyframe_animation(&default_startup_animation); +} + +#endif /* KEYBOARDS_WHITEFOX_SIMPLE_VISUALIZER_H_ */ |