From aa6c480f40241471d12c317c72acd94c2148a991 Mon Sep 17 00:00:00 2001 From: Robin Haberkorn Date: Thu, 11 Feb 2021 08:10:12 +0100 Subject: added the K7637 firmware --- COPYING | 339 ++++++++++++++++++++++++++++++++++++++++++ Makefile | 107 ++++++++++++++ command.c | 60 ++++++++ config.h | 75 ++++++++++ k7637-beep.sh | 19 +++ k7637.rules | 3 + keyclick.h | 47 ++++++ led.c | 82 +++++++++++ matrix.c | 337 ++++++++++++++++++++++++++++++++++++++++++ pwm.c | 347 +++++++++++++++++++++++++++++++++++++++++++ pwm.h | 34 +++++ song.c | 456 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ song.h | 24 +++ unimap_00.c | 34 +++++ unimap_trans.h | 99 +++++++++++++ usbconfig.h | 381 +++++++++++++++++++++++++++++++++++++++++++++++ 16 files changed, 2444 insertions(+) create mode 100644 COPYING create mode 100644 Makefile create mode 100644 command.c create mode 100644 config.h create mode 100755 k7637-beep.sh create mode 100644 k7637.rules create mode 100644 keyclick.h create mode 100644 led.c create mode 100644 matrix.c create mode 100644 pwm.c create mode 100644 pwm.h create mode 100644 song.c create mode 100644 song.h create mode 100644 unimap_00.c create mode 100644 unimap_trans.h create mode 100644 usbconfig.h diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..d159169 --- /dev/null +++ b/COPYING @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + 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, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..7ed57ed --- /dev/null +++ b/Makefile @@ -0,0 +1,107 @@ +#---------------------------------------------------------------------------- +# On command line: +# +# make all = Make software. +# +# make clean = Clean out built project files. +# +# make coff = Convert ELF to AVR COFF. +# +# make extcoff = Convert ELF to AVR Extended COFF. +# +# make program = Download the hex file to the device. +# Please customize your programmer settings(PROGRAM_CMD) +# +# make teensy = Download the hex file to the device, using teensy_loader_cli. +# (must have teensy_loader_cli installed). +# +# make dfu = Download the hex file to the device, using dfu-programmer (must +# have dfu-programmer installed). +# +# make flip = Download the hex file to the device, using Atmel FLIP (must +# have Atmel FLIP installed). +# +# make dfu-ee = Download the eeprom file to the device, using dfu-programmer +# (must have dfu-programmer installed). +# +# make flip-ee = Download the eeprom file to the device, using Atmel FLIP +# (must have Atmel FLIP installed). +# +# make debug = Start either simulavr or avarice as specified for debugging, +# with avr-gdb or avr-insight as the front end for debugging. +# +# make filename.s = Just compile filename.c into the assembler code only. +# +# make filename.i = Create a preprocessed source file for use in submitting +# bug reports to the GCC project. +# +# To rebuild project do "make clean" then "make all". +#---------------------------------------------------------------------------- + +# Target file name (without extension). +TARGET = k7637 + +# Directory common source filess exist +TMK_DIR = tmk_core + +# Directory keyboard dependent files exist +TARGET_DIR = . + +# project specific files +SRC = unimap_00.c \ + matrix.c \ + led.c \ + command.c \ + pwm.c \ + song.c + +CONFIG_H = config.h + + +# MCU name, you MUST set this to match the board you are using +# type "make clean" after changing this, so all files will be rebuilt +MCU = at90usb1286 + + +# Processor frequency. +# Normally the first thing your program should do is set the clock prescaler, +# so your program will run at the correct speed. You should also set this +# variable to same clock speed. The _delay_ms() macro uses this, and many +# examples use this variable to calculate timings. Do not add a "UL" here. +F_CPU = 16000000 + + +# Boot Section Size in *bytes* +# Teensy halfKay 512 +# Atmel DFU loader 4096 +# LUFA bootloader 4096 +OPT_DEFS += -DBOOTLOADER_SIZE=2048 + + +# Build Options +# comment out to disable the options. +# +#BOOTMAGIC_ENABLE = yes # Virtual DIP switch configuration(+1000) +#MOUSEKEY_ENABLE = yes # Mouse keys(+5000) +EXTRAKEY_ENABLE = yes # Audio control and System control(+600) +CONSOLE_ENABLE = yes # Console for debug (hid_listen) +COMMAND_ENABLE = yes # Commands for debug and configuration +#SLEEP_LED_ENABLE = yes # Breathing sleep LED during USB suspend +NKRO_ENABLE = yes # USB Nkey Rollover(+500) +UNIMAP_ENABLE = yes +KEYMAP_SECTION_ENABLE = yes + +#PS2_MOUSE_ENABLE = yes # PS/2 mouse(TrackPoint) support +#PS2_USE_BUSYWAIT = yes # uses primitive reference code +#PS2_USE_INT = yes # uses external interrupt for falling edge of PS/2 clock pin +#PS2_USE_USART = yes # uses hardware USART engine for PS/2 signal receive(recomened) + + +# Search Path +VPATH += $(TARGET_DIR) +VPATH += $(TMK_DIR) + +include $(TMK_DIR)/common.mk +include $(TMK_DIR)/protocol.mk +include $(TMK_DIR)/protocol/pjrc.mk +include $(TMK_DIR)/rules.mk diff --git a/command.c b/command.c new file mode 100644 index 0000000..6827706 --- /dev/null +++ b/command.c @@ -0,0 +1,60 @@ +/* +Copyright 2021 Robin Haberkorn + +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 . +*/ + +#include +#include + +#include "debug.h" +#include "led.h" +#include "host.h" +#include "keycode.h" +#include "keyclick.h" +#include "pwm.h" +#include "song.h" +#include "command.h" + +enum keyclick_mode keyclick_mode = KEYCLICK_OFF; + +bool command_extra(uint8_t code) +{ + switch (code) { + //case KC_AUDIO_MUTE: + case KC_SPACE: + keyclick_mode = (keyclick_mode+1) % KEYCLICK_MAX; + dprintf("new keyclick mode: %u\n", keyclick_mode); + /* FIXME: Perhaps do this in matrix_scan() */ + keyclick_solenoid_set(false); + pwm_pb5_set_tone(0); + /* update the keyclick mode LED */ + led_set(host_keyboard_leds()); + return true; + + /* + * NOTE: The Fx keys are also used in command_common() + * but do the same as the number keys (switch layers). + * It should therefore be safe to repurpose them. + */ + case KC_F1: + song_play_ruinen(); + return true; + case KC_F2: + song_play_kitt(); + return true; + } + + return false; +} diff --git a/config.h b/config.h new file mode 100644 index 0000000..9821031 --- /dev/null +++ b/config.h @@ -0,0 +1,75 @@ +/* +Copyright 2012 Jun Wako +Copyright 2021 Robin Haberkorn + +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 . +*/ + +#ifndef CONFIG_H +#define CONFIG_H + + +/* USB Device descriptor parameter */ +#define VENDOR_ID 0xFEED +#define PRODUCT_ID 0x1111 +#define DEVICE_VER 0x0001 +#define MANUFACTURER VEB Kombinat Robotron +#define PRODUCT K7637 +#define DESCRIPTION t.m.k. keyboard firmware for Robotron K7637 + +/* key matrix size */ +#define MATRIX_ROWS 8 +#define MATRIX_COLS 16 + +/* define if matrix has ghost */ +//#define MATRIX_HAS_GHOST + +/* Set 0 if debouncing isn't needed */ +#define DEBOUNCE 2 + +/* 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 "magic" commands (LSHIFT+ET2+ET1). + * + * NOTE: This is LSHIFT+RSHIFT default. + * We had to pick something else since we cannot current discern these keys. + * This would be possible to add support for RSHIFT with a simple hardware hack, though. + */ +#define IS_COMMAND() ( \ + keyboard_report->mods == (MOD_BIT(KC_LSHIFT) | MOD_BIT(KC_LCTRL) | MOD_BIT(KC_RALT)) \ +) + +/* + * 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/k7637-beep.sh b/k7637-beep.sh new file mode 100755 index 0000000..03ba3a7 --- /dev/null +++ b/k7637-beep.sh @@ -0,0 +1,19 @@ +#!/bin/sh +#./k7637-beep.sh [duration] +DURATION=${1:-200} + +# `xset led` does not work for me at all, +# so we use sysfs instead. +# This way we can also avoid sending the request to all attached keyboard. +for led in /sys/class/leds/*\:\:kana; do + if [ "`cat $led/device/name`" = "VEB Kombinat Robotron K7637" ]; then + # NOTE: This will usually require root + echo 1 >$led/brightness || break + sleep `printf '%.3f' ${DURATION}e-3` + echo 0 >$led/brightness + exit $? + fi +done + +# Fall back to regular PC speaker beep +exec beep -l $DURATION diff --git a/k7637.rules b/k7637.rules new file mode 100644 index 0000000..27c213f --- /dev/null +++ b/k7637.rules @@ -0,0 +1,3 @@ +# Make sure that all users can write the K7637's LEDs. +# This is important, so that k7637-beep and consequently xkbevd can run without root privilege. +SUBSYSTEM=="leds", ATTRS{name}=="VEB Kombinat Robotron K7637", ACTION=="add", RUN+="/bin/chmod a+rw /sys%p/brightness" diff --git a/keyclick.h b/keyclick.h new file mode 100644 index 0000000..f964230 --- /dev/null +++ b/keyclick.h @@ -0,0 +1,47 @@ +/* +Copyright 2021 Robin Haberkorn + +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 . +*/ + +#ifndef KEYCLICK_H +#define KEYCLICK_H + +#include + +#include + +enum keyclick_mode { + KEYCLICK_OFF = 0, + KEYCLICK_SOLENOID, + KEYCLICK_BUZZER, + /** not a real keyclick mode */ + KEYCLICK_MAX +}; + +extern enum keyclick_mode keyclick_mode; + +static inline void +keyclick_solenoid_set(bool state) +{ + /* + * NOTE: The solenoid/relay is LOW-active. + */ + if (state) + PORTB &= ~(1 << PB3); + else + PORTB |= (1 << PB3); +} + +#endif diff --git a/led.c b/led.c new file mode 100644 index 0000000..c7e5933 --- /dev/null +++ b/led.c @@ -0,0 +1,82 @@ +/* +Copyright 2021 Robin Haberkorn + +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 . +*/ + +#include + +#include + +#include "debug.h" +#include "keyclick.h" +#include "led.h" +#include "pwm.h" + +void led_set(uint8_t usb_led) +{ + dprintf("Set keyboard LEDs: 0x%02X\n", usb_led); + + /* + * All LEDs and the buzzer are output pins obviously, even for PWM operation + */ + DDRD |= 0b00001111; + DDRB |= 0b11110000; + + /* LED right next to the Capslock key (C99) */ + if (usb_led & (1 << USB_LED_CAPS_LOCK)) + PORTD &= ~(1 << PD3); + else + PORTD |= (1 << PD3); + + /* + * 1st LED on first row (G00). + * + * NOTE: This will automatically disable PWM mode, so it will not + * interfere with timer 0 and tmk's timer module. + */ + pwm_pd0_set_led(usb_led & (1 << USB_LED_NUM_LOCK) ? 255 : 0); + + /* 2nd LED on first row (G01): Highlight keyclick mode. */ + pwm_pb7_set_led(keyclick_mode*255/(KEYCLICK_MAX-1)); + + /* 3rd LED on the first row (G02) */ + pwm_pd1_set_led(usb_led & (1 << USB_LED_COMPOSE) ? 255 : 0); + + /* + * 4th LED (G03) are currently not triggerable via USB. + * Could be triggered as the "backlight". + */ + pwm_pb6_set_led(0); + + /* 5th LED on the first row (G04) */ + pwm_pb4_set_led(usb_led & (1 << USB_LED_SCROLL_LOCK) ? 255 : 0); + + /* + * 6th LED on the first row (G53). + * + * Triggering this LED (PD2) will also enable the buzzer (PB5), + * so we have got a way to beep from userspace (see ./k7637-beep.sh). + * + * The original firmware also had the error display on G53 + * (cf. Betriebsdokumentation). + */ + if (usb_led & (1 << USB_LED_KANA)) { + PORTD &= ~(1 << PD2); + pwm_pb5_set_tone(2200); + } else { + PORTD |= (1 << PD2); + pwm_pb5_set_tone(0); + } +} diff --git a/matrix.c b/matrix.c new file mode 100644 index 0000000..8f98afd --- /dev/null +++ b/matrix.c @@ -0,0 +1,337 @@ +/* +Copyright 2021 Robin Haberkorn + +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 . +*/ + +#include +#include +#include + +#include +#include + +#include "print.h" +#include "debug.h" +#include "timer.h" +#include "led.h" +#include "host.h" +#include "pwm.h" +#include "keyclick.h" +#include "matrix.h" + +/* + * NOTE: The "Betriebsdokumentation" mentions that the keyboard matrix + * must not change for two scan cycles. + * The setting below actually means, it must not change for 2ms. + * This has been shown to be sufficient. + * It is still possible for keypresses to be instable but this has only + * been observed with a poor power source. + */ +#ifndef DEBOUNCE +# define DEBOUNCE 2 +#endif + +/* matrix state(1:on, 0:off) */ +static matrix_row_t matrix[MATRIX_ROWS]; +static matrix_row_t matrix_debouncing[MATRIX_ROWS]; + +static void init_pins(void); +static void select_col(uint8_t col); +static void unselect_cols(void); +static bool read_row(uint8_t row); + +void matrix_init(void) +{ + debug_enable = true; + debug_matrix = true; + + /* this also configures all LED pins and brings them into defined states */ + led_set(host_keyboard_leds()); + + init_pins(); + + /* initialize matrix state: all keys off */ + memset(matrix, sizeof(matrix), 0); + memset(matrix_debouncing, sizeof(matrix_debouncing), 0); +} + +/* + * FIXME: If we rotated the matrix (8 columns and 16 rows) + * we could simplify and speed up the code below. + * Unfortunately, we'd also have to rotate the Unimap translation table and + * it would no longer correspond with the "Serviceschaltplan". + */ +uint8_t matrix_scan(void) +{ + static uint16_t debouncing_time = 0, keyclick_time = 0; + /** Number of pressed keys in `matrix_debouncing` */ + uint8_t matrix_debouncing_pressed_keys = 0; + + for (uint8_t col = 0; col < MATRIX_COLS; col++) { + select_col(col); + /* + * Give the signals some time to settle. + * This is not mentioned in the "Betriebsdokumentation" + * but has been tested experimentally. + * 30us is used by all the other controller firmwares as well. + */ + _delay_us(30); + + uint8_t row = 0; + + /* + * The first 4 bits in the 15th column + * are sensed like ordinary keypresses but + * in reality represent a 3-bit "security key" + * (cf. Betriebsdokumentation, p.13f) with + * an actual resolution of 6 encoded into a special + * keylike device that's plugged into the keyboard. + * It makes no sense to map these original bits into + * the keyboard matrix. + * Instead we translate it into one of six key presses + * via unused fields of the keyboard matrix whenever + * the "security" key is removed. + * These pseudo-keypress are mapped to F19-F24 in unimap_trans + * and could be mapped at the OS level, eg. to lock up the screen. + */ + if (col+1 == MATRIX_COLS) { + static uint8_t last_security_key = 0; + uint8_t security_key = (!read_row(0) << 0) | + (!read_row(1) << 1) | + (!read_row(2) << 2); + + for (uint8_t i = 0; i < 6; i++) + matrix_debouncing[i] &= ~(1 << col); + if (security_key != last_security_key && security_key == 0 && + 1 <= last_security_key && last_security_key <= 6) + matrix_debouncing[last_security_key-1] |= (1 << col); + + last_security_key = security_key; + row = 6; + } + + while (row < MATRIX_ROWS) { + matrix_row_t prev_row = matrix_debouncing[row]; + + if (read_row(row)) { + matrix_debouncing[row] |= (1 << col); + matrix_debouncing_pressed_keys++; + } else { + matrix_debouncing[row] &= ~(1 << col); + } + + if (matrix_debouncing[row] != prev_row) + debouncing_time = timer_read(); + + row++; + } + + unselect_cols(); + } + + if (debouncing_time && timer_elapsed(debouncing_time) >= DEBOUNCE) { + /** Number of pressed keys in `matrix` */ + static uint8_t matrix_pressed_keys = 0; + + /* + * Trigger keyclick whenever the keyboard matrix has actually + * changed (ie. `debouncing_time` was set). + * When using the solenoid, the keyclick is supposed to immitate a + * mechanical click, so there should be one sound when pressing down + * the key and another when releasing it. + * If a key is already pressed (ie. you press an additional key), + * we release the solenoid for 50ms. + * We consciously do not _delay_ms(50) here since that would delay + * key event delivery. + * When using the buzzer, a short 50ms beep is played every time + * a new key is pressed. + */ + switch (keyclick_mode) { + case KEYCLICK_SOLENOID: + if (matrix_debouncing_pressed_keys > 1 || + (matrix_debouncing_pressed_keys == 1 && matrix_pressed_keys > 1)) { + keyclick_solenoid_set(false); + keyclick_time = timer_read(); + } else { + keyclick_solenoid_set(matrix_debouncing_pressed_keys); + } + break; + + case KEYCLICK_BUZZER: + if (matrix_debouncing_pressed_keys > matrix_pressed_keys) { + pwm_pb5_set_tone(550); + keyclick_time = timer_read(); + } + break; + + default: + break; + } + + memcpy(matrix, matrix_debouncing, sizeof(matrix)); + matrix_pressed_keys = matrix_debouncing_pressed_keys; + + debouncing_time = 0; + } + + /* + * This is responsible for performing a delayed action depending + * on the keyclick mode (see abovc). + * For solenoids, it reactivates them since they should be on and + * are released when the last key is released. + * When using the buzzer, this is responsible for turning it off + * after a short while. + * Polling here makes sure we do not delay any key delivery. + */ + if (keyclick_time && timer_elapsed(keyclick_time) >= 50) { + switch (keyclick_mode) { + case KEYCLICK_SOLENOID: + keyclick_solenoid_set(true); + break; + + case KEYCLICK_BUZZER: + if (!(host_keyboard_leds() & (1 << USB_LED_KANA))) + pwm_pb5_set_tone(0); + break; + + default: + break; + } + + keyclick_time = 0; + } + + return 1; +} + +inline +matrix_row_t matrix_get_row(uint8_t row) +{ + return matrix[row]; +} + +static void init_pins(void) +{ + /* + * All rows are input pins (DDR:0) and need pull-ups. + * There is a pull-up attached to the EPROM, but I acceidentally + * destroyed it. + * Therefore we enable internal pull-ups (PORT:1). + */ + /* Row 0: PB0 == D7 */ + DDRB &= ~0b1; + PORTB |= 0b1; + /* Row 1-2: PE4-5 == D5-6 (Connected by cable) */ + DDRE &= ~0b110000; + PORTE |= 0b110000; + /* Row 3-4: PF0-1 == D4-3 (NOTE: PF0 == Row 4, PF1 == Row 3) */ + DDRF &= ~0b11; + PORTF |= 0b11; + /* Row 5: PE7 == D2 */ + DDRE &= ~0b10000000; + PORTE |= 0b10000000; + /* Row 6-7: PB1-2 == D0-1 */ + DDRB &= ~0b110; + PORTB |= 0b110; + + /* + * We've got a strobe-sense matrix and we strobe via the column pins. + * Therefore they must be outputs (DDR:1). + */ + /* Column 0-3: PF4-7 == A11-14 */ + DDRF |= 0b11110000; + /* Column 4-11: PC0-7 == A3-10 */ + DDRC |= 0b11111111; + /* Column 12-13: PE0-1 == A1-2 */ + DDRE |= 0b11; + /* Column 14: PD7 == A0 */ + DDRD |= 0b10000000; + + /* + * PF3 == A15 must be LOW since otherwise some NAND gates (IC13) will interfere with D0-3 + * (half of the matrix rows). + * We might also draw this to GND by cable or destroy IC13. + * The latter might even save some power. + * + * FIXME: A15 must actually be triggered for some of the modifiers! + */ + DDRF |= 0b00001000; + PORTF &= ~0b00001000; + + /* + * Solenoid (ie. relay). It's LOW-active. + */ + DDRB |= (1 << PB3); + PORTB |= (1 << PB3); +} + +static void select_col(uint8_t col) +{ + /* + * FIXME: Simplify? Will go at the expense of readability. + */ + switch (col) { + case 0: PORTD |= 0b10000000; break; + case 1: PORTE |= 0b00000001; break; + case 2: PORTE |= 0b00000010; break; + case 3: PORTC |= 0b00000001; break; + case 4: PORTC |= 0b00000010; break; + case 5: PORTC |= 0b00000100; break; + case 6: PORTC |= 0b00001000; break; + case 7: PORTC |= 0b00010000; break; + case 8: PORTC |= 0b00100000; break; + case 9: PORTC |= 0b01000000; break; + case 10: PORTC |= 0b10000000; break; + case 11: PORTF |= 0b10000000; break; + case 12: PORTF |= 0b01000000; break; + case 13: PORTF |= 0b00100000; break; + case 14: PORTF |= 0b00010000; break; + case 15: PORTF |= 0b00001000; break; + } +} + +static void unselect_cols(void) +{ + PORTD &= ~0b10000000; + PORTE &= ~0b11; + PORTC &= ~0b11111111; + PORTF &= ~0b11111000; +} + +static bool read_row(uint8_t row) +{ + /* + * NOTE: The key mechanism pulls the row pin to GND when the key is + * pressed. + * However, the rows are not directly connected to the keyboard matrix + * but through NAND gates. The signal is therefore inverted. + * The NAND gates no longer serve any purpose and could be skipped + * altogether by desoldering them and directly connecting the inputs with + * the outputs. The PIN registers should then be inverted. + */ + switch (row) { + case 0: return PINB & 0b00000010; + case 1: return PINB & 0b00000100; + case 2: return PINE & 0b10000000; + case 3: return PINF & 0b00000001; + case 4: return PINF & 0b00000010; + case 5: return PINE & 0b00100000; + case 6: return PINE & 0b00010000; + case 7: return PINB & 0b00000001; + } + + /* not reached */ + return false; +} diff --git a/pwm.c b/pwm.c new file mode 100644 index 0000000..97c3dac --- /dev/null +++ b/pwm.c @@ -0,0 +1,347 @@ +/* +Copyright 2021 Robin Haberkorn + +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 . +*/ + +#include +#include + +#include +#include +#include + +#include "debug.h" +#include "pwm.h" + +/** + * Translation table from brightness to PWM setting to allow smooth + * fadings (8-bit timers). + * + * This is calculated by the formula: + * ``` + * uint16_t resolution = 0xFF; + * pwm_table8[x] = x ? round(pow((double)x / 255.0, 2.5) * resolution) : 0; + * ``` + */ +static const uint8_t pwm_table8[256] PROGMEM = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03, 0x03, 0x03, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x05, 0x06, 0x06, 0x06, 0x06, 0x07, + 0x07, 0x07, 0x07, 0x08, 0x08, 0x08, 0x09, 0x09, 0x09, 0x0A, 0x0A, 0x0A, + 0x0B, 0x0B, 0x0C, 0x0C, 0x0C, 0x0D, 0x0D, 0x0E, 0x0E, 0x0F, 0x0F, 0x0F, + 0x10, 0x10, 0x11, 0x11, 0x12, 0x12, 0x13, 0x13, 0x14, 0x14, 0x15, 0x16, + 0x16, 0x17, 0x17, 0x18, 0x19, 0x19, 0x1A, 0x1A, 0x1B, 0x1C, 0x1C, 0x1D, + 0x1E, 0x1E, 0x1F, 0x20, 0x21, 0x21, 0x22, 0x23, 0x24, 0x24, 0x25, 0x26, + 0x27, 0x28, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2E, 0x2F, 0x30, + 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, + 0x3D, 0x3E, 0x3F, 0x40, 0x41, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, + 0x4B, 0x4C, 0x4D, 0x4E, 0x50, 0x51, 0x52, 0x53, 0x55, 0x56, 0x57, 0x59, + 0x5A, 0x5B, 0x5D, 0x5E, 0x5F, 0x61, 0x62, 0x63, 0x65, 0x66, 0x68, 0x69, + 0x6B, 0x6C, 0x6E, 0x6F, 0x71, 0x72, 0x74, 0x75, 0x77, 0x79, 0x7A, 0x7C, + 0x7D, 0x7F, 0x81, 0x82, 0x84, 0x86, 0x87, 0x89, 0x8B, 0x8D, 0x8E, 0x90, + 0x92, 0x94, 0x96, 0x97, 0x99, 0x9B, 0x9D, 0x9F, 0xA1, 0xA3, 0xA5, 0xA6, + 0xA8, 0xAA, 0xAC, 0xAE, 0xB0, 0xB2, 0xB4, 0xB6, 0xB8, 0xBA, 0xBD, 0xBF, + 0xC1, 0xC3, 0xC5, 0xC7, 0xC9, 0xCC, 0xCE, 0xD0, 0xD2, 0xD4, 0xD7, 0xD9, + 0xDB, 0xDD, 0xE0, 0xE2, 0xE4, 0xE7, 0xE9, 0xEB, 0xEE, 0xF0, 0xF3, 0xF5, + 0xF8, 0xFA, 0xFD, 0xFF +}; + +/** + * Translation table from brightness to PWM setting to allow smooth + * fadings (16-bit timers). + */ +static const uint16_t pwm_table16[256] PROGMEM = { + 0x0000, 0x0000, 0x0000, 0x0001, 0x0002, 0x0004, 0x0006, 0x0008, 0x000B, + 0x000F, 0x0014, 0x0019, 0x001F, 0x0026, 0x002E, 0x0037, 0x0041, 0x004B, + 0x0057, 0x0063, 0x0071, 0x0080, 0x008F, 0x00A0, 0x00B2, 0x00C5, 0x00DA, + 0x00EF, 0x0106, 0x011E, 0x0137, 0x0152, 0x016E, 0x018B, 0x01A9, 0x01C9, + 0x01EB, 0x020E, 0x0232, 0x0257, 0x027F, 0x02A7, 0x02D2, 0x02FD, 0x032B, + 0x0359, 0x038A, 0x03BC, 0x03EF, 0x0425, 0x045C, 0x0494, 0x04CF, 0x050B, + 0x0548, 0x0588, 0x05C9, 0x060C, 0x0651, 0x0698, 0x06E0, 0x072A, 0x0776, + 0x07C4, 0x0814, 0x0866, 0x08B9, 0x090F, 0x0967, 0x09C0, 0x0A1B, 0x0A79, + 0x0AD8, 0x0B3A, 0x0B9D, 0x0C03, 0x0C6A, 0x0CD4, 0x0D3F, 0x0DAD, 0x0E1D, + 0x0E8F, 0x0F03, 0x0F79, 0x0FF2, 0x106C, 0x10E9, 0x1168, 0x11E9, 0x126C, + 0x12F2, 0x137A, 0x1404, 0x1490, 0x151F, 0x15B0, 0x1643, 0x16D9, 0x1771, + 0x180B, 0x18A7, 0x1946, 0x19E8, 0x1A8B, 0x1B32, 0x1BDA, 0x1C85, 0x1D33, + 0x1DE2, 0x1E95, 0x1F49, 0x2001, 0x20BB, 0x2177, 0x2236, 0x22F7, 0x23BB, + 0x2481, 0x254A, 0x2616, 0x26E4, 0x27B5, 0x2888, 0x295E, 0x2A36, 0x2B11, + 0x2BEF, 0x2CD0, 0x2DB3, 0x2E99, 0x2F81, 0x306D, 0x315A, 0x324B, 0x333F, + 0x3435, 0x352E, 0x3629, 0x3728, 0x3829, 0x392D, 0x3A33, 0x3B3D, 0x3C49, + 0x3D59, 0x3E6B, 0x3F80, 0x4097, 0x41B2, 0x42D0, 0x43F0, 0x4513, 0x463A, + 0x4763, 0x488F, 0x49BE, 0x4AF0, 0x4C25, 0x4D5D, 0x4E97, 0x4FD5, 0x5116, + 0x525A, 0x53A1, 0x54EB, 0x5638, 0x5787, 0x58DA, 0x5A31, 0x5B8A, 0x5CE6, + 0x5E45, 0x5FA7, 0x610D, 0x6276, 0x63E1, 0x6550, 0x66C2, 0x6837, 0x69AF, + 0x6B2B, 0x6CAA, 0x6E2B, 0x6FB0, 0x7139, 0x72C4, 0x7453, 0x75E5, 0x777A, + 0x7912, 0x7AAE, 0x7C4C, 0x7DEF, 0x7F94, 0x813D, 0x82E9, 0x8498, 0x864B, + 0x8801, 0x89BA, 0x8B76, 0x8D36, 0x8EFA, 0x90C0, 0x928A, 0x9458, 0x9629, + 0x97FD, 0x99D4, 0x9BB0, 0x9D8E, 0x9F70, 0xA155, 0xA33E, 0xA52A, 0xA71A, + 0xA90D, 0xAB04, 0xACFE, 0xAEFB, 0xB0FC, 0xB301, 0xB509, 0xB715, 0xB924, + 0xBB37, 0xBD4D, 0xBF67, 0xC184, 0xC3A5, 0xC5CA, 0xC7F2, 0xCA1E, 0xCC4D, + 0xCE80, 0xD0B7, 0xD2F1, 0xD52F, 0xD771, 0xD9B6, 0xDBFE, 0xDE4B, 0xE09B, + 0xE2EF, 0xE547, 0xE7A2, 0xEA01, 0xEC63, 0xEECA, 0xF134, 0xF3A2, 0xF613, + 0xF888, 0xFB02, 0xFD7E, 0xFFFF +}; + +/** + * Configure a PWM pin of Timer 0 (8-bit resolution). + * + * @note Timer 0 is used by tmk's timer module as well. + * You can therefore only temporarilly PWM-modulate using timer 0 + * (ie. NOT during matrix scanning), cannot use any timer module functions + * and should call timer_init() afterwards. + * This can be easily resolved by using pwm_pb5_set_led() for one of the LEDs + * and redistribute all the LED. + * The buzzer can then use the no longer used PD0 since it's manually + * IRQ-triggered anyway. + * + * @param channel Channel to initialize. + * 0 (OC0A/PB7), 1 (OC0B/PD0) + */ +static void pwm_timer0_init(uint8_t channel) +{ + /* Fast PWM on OC0x, inverted duty cycle, TOP = 0xFF */ + TCCR0A |= (0b11 << (3-channel)*2) | 0b11; + /* no prescaling */ + TCCR0B = 0b00000001; +} + +void pwm_pd0_set_led(uint8_t brightness) +{ + switch (brightness) { + case 0: + TCCR0A &= ~0b00110000; + PORTD |= (1 << PD0); + break; + case 255: + TCCR0A &= ~0b00110000; + PORTD &= ~(1 << PD0); + break; + default: + pwm_timer0_init(1); + OCR0B = pgm_read_byte(&pwm_table8[brightness]); + break; + } +} + +/** + * Configure a PWM pin of Timer 1 (16-bit resolution). + * + * @param channel Channel to initialize. + * 0 (OC1A/PB5), 1 (OC1B/PB6), 2 (OC1C/PB7) + */ +static void pwm_timer1_init(uint8_t channel) +{ + /* Fast PWM on OC1x, inverted duty cycle, TOP = ICR1 */ + TCCR1A |= (0b11 << (3-channel)*2) | 0b10; + /* stop timer */ + TCCR1B = 0; + /* TOP for PWM - full 16 Bit */ + ICR1 = 0xFFFF; + /* no prescaling */ + TCCR1B = 0b00011001; +} + +void pwm_pb5_set_led(uint8_t brightness) +{ + switch (brightness) { + case 0: + TCCR1A &= ~0b11000000; + PORTB |= (1 << PB5); + break; + case 255: + TCCR1A &= ~0b11000000; + PORTB &= ~(1 << PB5); + break; + default: + pwm_timer1_init(0); + OCR1A = pgm_read_word(&pwm_table16[brightness]); + break; + } +} + +void pwm_pb6_set_led(uint8_t brightness) +{ + switch (brightness) { + case 0: + TCCR1A &= ~0b00110000; + PORTB |= (1 << PB6); + break; + case 255: + TCCR1A &= ~0b00110000; + PORTB &= ~(1 << PB6); + break; + default: + pwm_timer1_init(1); + OCR1B = pgm_read_word(&pwm_table16[brightness]); + break; + } +} + +void pwm_pb7_set_led(uint8_t brightness) +{ + switch (brightness) { + case 0: + TCCR1A &= ~0b00001100; + PORTB |= (1 << PB7); + break; + case 255: + TCCR1A &= ~0b00001100; + PORTB &= ~(1 << PB7); + break; + default: + pwm_timer1_init(2); + OCR1C = pgm_read_word(&pwm_table16[brightness]); + break; + } +} + +/** + * Configure a PWM pin of Timer 2 (8-bit resolution). + * + * @param channel Channel to initialize. + * 0 (OC2A/PB4), 1 (OC2B/PD1) + */ +static void pwm_timer2_init(uint8_t channel) +{ + /* Fast PWM on OC2x, inverted duty cycle, TOP = 0xFF */ + TCCR2A |= (0b11 << (3-channel)*2) | 0b11; + /* no prescaling */ + TCCR2B = 0b00000001; +} + +void pwm_pb4_set_led(uint8_t brightness) +{ + switch (brightness) { + case 0: + TCCR2A &= ~0b11000000; + PORTB |= (1 << PB4); + break; + case 255: + TCCR2A &= ~0b11000000; + PORTB &= ~(1 << PB4); + break; + default: + pwm_timer2_init(0); + OCR2A = pgm_read_byte(&pwm_table8[brightness]); + break; + } +} + +void pwm_pd1_set_led(uint8_t brightness) +{ + switch (brightness) { + case 0: + TCCR2A &= ~0b00110000; + PORTD |= (1 << PD1); + break; + case 255: + TCCR2A &= ~0b00110000; + PORTD &= ~(1 << PD1); + break; + default: + pwm_timer2_init(1); + OCR2B = pgm_read_byte(&pwm_table8[brightness]); + break; + } +} + +/** + * Set a LED by position in the first row. + * + * @bug The pins used should be rescrambled after we freed PD0. + * + * @param led LED to set (0-4). + * @param brightness Brightness level to set. + */ +void pwm_set_led(uint8_t led, uint8_t brightness) +{ + switch (led) { + case 0: pwm_pd0_set_led(brightness); break; + case 1: pwm_pb7_set_led(brightness); break; + case 2: pwm_pd1_set_led(brightness); break; + case 3: pwm_pb6_set_led(brightness); break; + case 4: pwm_pb4_set_led(brightness); break; + } +} + +/** + * Play a tone on PB5 (the buzzer). + * + * @note This uses timer 3 with an IRQ, even though we cannot + * use one of the Timer 3 PWM pins -- they are required for matrix + * strobing. + * It was problematic to use one of the accessible Timer 0-2 pins as + * a frequency generator for the buzzer, though: + * - Timer 0 (PD0) does not support toggle mode and regular PWM mode would + * leave only a 7-bit frequency resolution. + * - Timer 1 is shared with two other LED pins. + * It is therefore not possible to use toggle mode, but the remaining 15 + * bit are sufficient anyway. Unfortunately, changing the frequency changes + * the timer's TOP value, which requires recalculating the duty cycles of the + * remaining two pins. This calculation is slow and cannot be cached. + * Also, changing the frequency would always introduce some flickering. + * - The same is true for timer 2, just with even less resolution. + * Using timer 3 exclusively for sound has the advantage that we can also + * some day use an IRQ for playing back (bit banging) audio samples eg. + * for a keyclick sounds. + * + * @todo It would be nice, if we could specify the tone's volume. + * This will reduce the effective resolution to 15 bit, but that should be + * sufficient anyway. + * + * @param freq Frequency to play. If 0, disables the buzzer. + */ +void pwm_pb5_set_tone(uint16_t freq) +{ + if (!freq) { + /* + * There should be a way to turn off the buzzer as we would otherwise + * always have some kind of tone. + */ + TIMSK3 = 0; + return; + } + + /* + * CTC mode: Effectively allows us to toggle the pin after OCR3A counts. + * This allows us to use the full 16-bit resolution. + * On the other hand, if we'd like to control volume, we'd have to + * control the cycle length independently, reducing resolution to 15 bit. + */ + TCCR3A = 0b00; + /* + * Prescaling: 8 (0b010). + * This allows for frequencies between 15 Hz and 1 MHz. + * + * FIXME: It may be even better to use 1 if we have frequencies below 122 Hz. + */ + TCCR3B = 0b00001010; + + /* + * The frequency of the resulting signal is calculated as follows: + * F_CPU / PRESCALER / (CYCLE_LENGTH+1) / 2 + */ + OCR3A = (F_CPU/2/8) / freq - 1; + + /* enable TIMER3_COMPA_vect() interrupt */ + TIMSK3 = (1 << OCIE3A); +} + +ISR(TIMER3_COMPA_vect, ISR_NOBLOCK) +{ + PORTB ^= (1 << PB5); +} diff --git a/pwm.h b/pwm.h new file mode 100644 index 0000000..f1e0d3f --- /dev/null +++ b/pwm.h @@ -0,0 +1,34 @@ +/* +Copyright 2021 Robin Haberkorn + +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 . +*/ + +#ifndef PWM_H +#define PWM_H + +#include + +void pwm_pd0_set_led(uint8_t brightness); +void pwm_pd1_set_led(uint8_t brightness); +void pwm_pb4_set_led(uint8_t brightness); +void pwm_pb5_set_led(uint8_t brightness); +void pwm_pb6_set_led(uint8_t brightness); +void pwm_pb7_set_led(uint8_t brightness); + +void pwm_set_led(uint8_t led, uint8_t brightness); + +void pwm_pb5_set_tone(uint16_t freq); + +#endif diff --git a/song.c b/song.c new file mode 100644 index 0000000..cd3b000 --- /dev/null +++ b/song.c @@ -0,0 +1,456 @@ +/* +Copyright 2021 Robin Haberkorn + +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 . +*/ + +#include + +#include +#include + +#include "debug.h" +#include "timer.h" +#include "led.h" +#include "host.h" +#include "pwm.h" +#include "keyclick.h" +#include "song.h" + +static void delay_long(uint16_t ms) +{ + while (ms >= 10) { + _delay_ms(10); + ms -= 10; + } + switch (ms) { + case 9: _delay_ms(9); break; + case 8: _delay_ms(8); break; + case 7: _delay_ms(7); break; + case 6: _delay_ms(6); break; + case 5: _delay_ms(5); break; + case 4: _delay_ms(4); break; + case 3: _delay_ms(3); break; + case 2: _delay_ms(2); break; + case 1: _delay_ms(1); break; + } +} + +struct song_note { + uint16_t freq; + uint16_t dur; +}; + +// midicsv anthem_ddr.mid | perl midicsv2frequency.pl +static const struct song_note song_ruinen[] PROGMEM = { + {440,585}, + {440,459}, + {0,585}, + {0,156}, + {391,500}, + {0,100}, + {349,500}, + {0,100}, + {466,1044}, + {0,156}, + {440,500}, + {0,100}, + {391,500}, + {0,100}, + {523,500}, + {0,100}, + {440,500}, + {0,100}, + {349,500}, + {0,100}, + {523,500}, + {0,100}, + {523,800}, + {0,100}, + {587,294}, + {0,6}, + {466,1044}, + {0,156}, + {440,1044}, + {0,156}, + {391,500}, + {0,100}, + {349,500}, + {0,100}, + {466,1044}, + {0,156}, + {440,500}, + {0,100}, + {391,500}, + {0,100}, + {523,500}, + {0,100}, + {440,500}, + {0,100}, + {587,500}, + {0,100}, + {466,500}, + {0,100}, + {391,800}, + {0,100}, + {329,294}, + {0,6}, + {349,1700}, + {0,100}, + {349,444}, + {0,6}, + {329,144}, + {0,6}, + {293,800}, + {0,100}, + {329,294}, + {0,6}, + {349,800}, + {0,100}, + {440,294}, + {0,6}, + {391,500}, + {0,100}, + {261,1100}, + {0,100}, + {349,444}, + {0,6}, + {329,144}, + {0,6}, + {293,800}, + {0,100}, + {329,294}, + {0,6}, + {349,800}, + {0,100}, + {440,294}, + {0,6}, + {391,1044}, + {0,156}, + {440,500}, + {0,100}, + {440,500}, + {0,100}, + {391,500}, + {0,100}, + {349,500}, + {0,100}, + {466,500}, + {0,100}, + {466,500}, + {0,100}, + {440,500}, + {0,100}, + {391,500}, + {0,100}, + {523,500}, + {0,100}, + {440,500}, + {0,100}, + {349,500}, + {0,100}, + {523,500}, + {0,100}, + {523,800}, + {0,100}, + {587,294}, + {0,6}, + {466,500}, + {0,100}, + {349,294}, + {0,6}, + {391,294}, + {0,6}, + {440,1044}, + {0,156}, + {391,1044}, + {0,156}, + {523,1044}, + {0,156}, + {349,500}, + {0,100}, + {391,500}, + {0,100}, + {440,1044}, + {0,156}, + {391,1044}, + {0,156}, + {349,1044} +}; + +void song_play_ruinen(void) +{ + keyclick_solenoid_set(false); + + uint8_t i = 0; + for (long unsigned int cur_note = 0; cur_note < sizeof(song_ruinen)/sizeof(song_ruinen[0]); cur_note++) { + pwm_pb5_set_tone(pgm_read_word(&song_ruinen[cur_note].freq)); + + uint8_t max_brightness = ((uint32_t)pgm_read_word(&song_ruinen[cur_note].freq)*255)/600; + uint16_t fade_dur = pgm_read_word(&song_ruinen[cur_note].dur)/2/(max_brightness+1); + for (int16_t brightness = 0; brightness <= max_brightness; brightness++) { + pwm_set_led(i % 5, brightness); + delay_long(fade_dur); + } + + /* + * The fade duration is probably not very precise, so compensate for it. + * + * FIXME: Once timer 0 is freed, we should use timer_read() and timer_elapsed() + * which will be more precise. + */ + delay_long(pgm_read_word(&song_ruinen[cur_note].dur) - fade_dur*(max_brightness+1)*2); + + for (int16_t brightness = max_brightness; brightness >= 0; brightness--) { + pwm_set_led(i % 5, brightness); + delay_long(fade_dur); + } + + if (pgm_read_word(&song_ruinen[cur_note].freq)) + i++; + } + + pwm_pb5_set_tone(0); + + /* we screwed up timer 0 settings and they are also used by the timer module */ + timer_init(); + + /* restore the previous lock lights */ + led_set(host_keyboard_leds()); +} + +static const struct song_note song_knight_rider[] PROGMEM = { + // KnightRider:d=4, o=5, b=125:16e, 16p, 16f, 16e, 16e, 16p, 16e, 16e, 16f, 16e, 16e, 16e, + // 16d#, 16e, 16e, 16e, 16e, 16p, 16f, 16e, 16e, 16p, 16f, 16e, 16f, 16e, 16e, 16e, 16d#, + // 16e, 16e, 16e, 16d, 16p, 16e, 16d, 16d, 16p, 16e, 16d, 16e, 16d, 16d, 16d, 16c, 16d, 16d, + // 16d, 16d, 16p, 16e, 16d, 16d, 16p, 16e, 16d, 16e, 16d, 16d, 16d, 16c, 16d, 16d, 16d + {0, 480}, + {330, 480}, + {0, 120}, + {349, 120}, + {330, 120}, + {330, 120}, + {0, 120}, + {330, 120}, + {330, 120}, + {349, 120}, + {330, 120}, + {330, 120}, + {330, 120}, + {311, 120}, + {330, 120}, + {330, 120}, + {330, 120}, + {330, 120}, + {0, 120}, + {349, 120}, + {330, 120}, + {330, 120}, + {0, 120}, + {349, 120}, + {330, 120}, + {349, 120}, + {330, 120}, + {330, 120}, + {330, 120}, + {311, 120}, + {330, 120}, + {330, 120}, + {330, 120}, + {294, 120}, + {0, 120}, + {330, 120}, + {294, 120}, + {294, 120}, + {0, 120}, + {330, 120}, + {294, 120}, + {330, 120}, + {294, 120}, + {294, 120}, + {294, 120}, + {262, 120}, + {294, 120}, + {294, 120}, + {294, 120}, + {294, 120}, + {0, 120}, + {330, 120}, + {294, 120}, + {294, 120}, + {0, 120}, + {330, 120}, + {294, 120}, + {330, 120}, + {294, 120}, + {294, 120}, + {294, 120}, + {262, 120}, + {294, 120}, + {294, 120}, + + // KnightRider:d=4, o=5, b=63:16e, 32f, 32e, 8b, 16e6, 32f6, 32e6, 8b, 16e, 32f, 32e, 16b, + // 16e6, d6, 8p, p, 16e, 32f, 32e, 8b, 16e6, 32f6, 32e6, 8b, 16e, 32f, 32e, 16b, 16e6, f6, p + {0, 952}, + {330, 952}, + {349, 119}, + {330, 119}, + {494, 476}, + {659, 238}, + {698, 119}, + {659, 119}, + {494, 476}, + {330, 238}, + {349, 119}, + {330, 119}, + {494, 238}, + {659, 238}, + {587, 952}, + {0, 476}, + {0, 952}, + {330, 238}, + {349, 119}, + {330, 119}, + {494, 476}, + {659, 238}, + {698, 119}, + {659, 119}, + {494, 476}, + {330, 238}, + {349, 119}, + {330, 119}, + {494, 238}, + {659, 238}, + {698, 952} + +#if 0 + {0, 952}, + {659, 952}, + {698, 119}, + {659, 119}, + {988, 476}, + {1319, 238}, + {1397, 119}, + {1319, 119}, + {988, 476}, + {659, 238}, + {698, 119}, + {659, 119}, + {988, 238}, + {1319, 238}, + {1175, 952}, + {0, 476}, + {0, 952}, + {659, 238}, + {698, 119}, + {659, 119}, + {988, 476}, + {1319, 238}, + {1397, 119}, + {1319, 119}, + {988, 476}, + {659, 238}, + {698, 119}, + {659, 119}, + {988, 238}, + {1319, 238}, + {1397, 952} +#endif +}; + +/** + * Light curve of the Larsen light. + * This is half a period of a sine curve now. + */ +static const uint8_t song_larsen_curve[] PROGMEM = { + 3, 6, 9, 12, 15, 18, 21, 24, 28, 31, 34, 37, 40, 43, 46, 49, 52, 55, 58, 61, 64, 68, + 71, 74, 77, 79, 82, 85, 88, 91, 94, 97, 100, 103, 106, 109, 111, 114, 117, 120, 122, + 125, 128, 131, 133, 136, 139, 141, 144, 146, 149, 151, 154, 156, 159, 161, 164, 166, + 168, 171, 173, 175, 178, 180, 182, 184, 186, 188, 191, 193, 195, 197, 199, 201, 202, + 204, 206, 208, 210, 212, 213, 215, 217, 218, 220, 221, 223, 224, 226, 227, 229, 230, + 231, 233, 234, 235, 236, 237, 239, 240, 241, 242, 243, 244, 244, 245, 246, 247, 248, + 248, 249, 250, 250, 251, 251, 252, 252, 253, 253, 253, 254, 254, 254, 254, 254, 254, + 254, 255, 254, 254, 254, 254, 254, 254, 254, 253, 253, 253, 252, 252, 251, 251, 250, + 250, 249, 248, 248, 247, 246, 245, 244, 244, 243, 242, 241, 240, 239, 237, 236, 235, + 234, 233, 231, 230, 229, 227, 226, 224, 223, 221, 220, 218, 217, 215, 213, 212, 210, + 208, 206, 204, 202, 201, 199, 197, 195, 193, 191, 188, 186, 184, 182, 180, 178, 175, + 173, 171, 168, 166, 164, 161, 159, 156, 154, 151, 149, 146, 144, 141, 139, 136, 133, + 131, 128, 125, 122, 120, 117, 114, 111, 109, 106, 103, 100, 97, 94, 91, 88, 85, 82, + 79, 77, 74, 71, 68, 64, 61, 58, 55, 52, 49, 46, 43, 40, 37, 34, 31, 28, 24, 21, 18, + 15, 12, 9, 6, 3, 0 +}; + +/** + * Step length for the Larsen curve animation. + * This will result in 1024ms per sweep. + */ +#define LARSEN_CURVE_STEP 4 /* ms */ + +static void song_larsen_light(int16_t pos) +{ + for (uint8_t led = 0; led < 5; led++) { + int16_t offset = sizeof(song_larsen_curve)*(2+led)/4 - pos; + pwm_set_led(led, 0 <= offset && offset < sizeof(song_larsen_curve) + ? pgm_read_byte(&song_larsen_curve[offset]) : 0); + } + + _delay_ms(LARSEN_CURVE_STEP); +} + +void song_play_kitt(void) +{ + keyclick_solenoid_set(false); + + int16_t i; + + /* fade in larsen light */ + for (i = (int16_t)sizeof(song_larsen_curve)/-2; i < 0; i++) + song_larsen_light(i); + + long unsigned int cur_note = 0; + uint16_t cur_note_dur = 0; + + int8_t dir = 1; + for (i = 0; cur_note < sizeof(song_knight_rider)/sizeof(song_knight_rider[0]); i += dir) { + /* + * FIXME: Once we freed up timer 0 by rearranging the LED pins, + * it might be more precise to use timer_read()/timer_elapsed() to wait for the next note. + */ + if (cur_note_dur < LARSEN_CURVE_STEP) { + cur_note_dur = pgm_read_word(&song_knight_rider[cur_note].dur); + pwm_pb5_set_tone(pgm_read_word(&song_knight_rider[cur_note].freq)); + } + + song_larsen_light(i); + + cur_note_dur -= LARSEN_CURVE_STEP; + if (cur_note_dur < LARSEN_CURVE_STEP) + cur_note++; + + if (i == sizeof(song_larsen_curve)-1 || (dir < 0 && i == 0)) + dir *= -1; + } + + pwm_pb5_set_tone(0); + + /* fade out larsen light */ + while (i < sizeof(song_larsen_curve)*3/2) + song_larsen_light(i++); + + /* we screwed up timer 0 settings and they are also used by the timer module */ + timer_init(); + + /* restore the previous lock lights */ + led_set(host_keyboard_leds()); +} diff --git a/song.h b/song.h new file mode 100644 index 0000000..53f667f --- /dev/null +++ b/song.h @@ -0,0 +1,24 @@ +/* +Copyright 2021 Robin Haberkorn + +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 . +*/ + +#ifndef SONG_H +#define SONG_H + +void song_play_ruinen(void); +void song_play_kitt(void); + +#endif diff --git a/unimap_00.c b/unimap_00.c new file mode 100644 index 0000000..cd266a7 --- /dev/null +++ b/unimap_00.c @@ -0,0 +1,34 @@ +/* +Copyright 2021 Robin Haberkorn + +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 . +*/ +#include + +#include "action_code.h" +#include "unimap_trans.h" + +#ifdef KEYMAP_SECTION_ENABLE +const action_t actionmaps[][UNIMAP_ROWS][UNIMAP_COLS] __attribute__ ((section (".keymap.keymaps"))) = { +#else +const action_t actionmaps[][UNIMAP_ROWS][UNIMAP_COLS] PROGMEM = { +#endif + [0] = UNIMAP_K7637( + ESC, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, F13, PSCR,SLCK,PAUS, VOLD,VOLU,MUTE, F19, + GRV, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, MINS,EQL, BSPC, END, DEL, NLCK,PSLS, F20, + TAB, Q, W, E, R, T, Y, U, I, O, P, LBRC,RBRC, HOME,PGUP, P7, P8, P9, PPLS, F21, + CAPS,A, S, D, F, G, H, J, K, L, SCLN,QUOT,NUHS, ENT, PGDN, P4, P5, P6, NO, F22, + LSFT,NUBS,Z, X, C, V, B, N, M, COMM,DOT, SLSH, DOWN,UP, P1, P2, P3, PENT, F23, + NO, LCTL, SPC, RALT, NO, LEFT,RGHT, P0, P00, PCMM,NO, F24), +}; diff --git a/unimap_trans.h b/unimap_trans.h new file mode 100644 index 0000000..a616fd1 --- /dev/null +++ b/unimap_trans.h @@ -0,0 +1,99 @@ +/* +Copyright 2021 Robin Haberkorn + +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 . +*/ +#ifndef UNIMAP_TRANS_H +#define UNIMAP_TRANS_H + +#include +#include + +#include "unimap.h" + +#define UNIMAP_K7637( \ + K29,K3A,K3B,K3C,K3D,K3E,K3F,K40,K41,K42,K43,K44,K45,K68, K46,K47,K48, K01,K02,K03, K6E, \ + K35,K1E,K1F,K20,K21,K22,K23,K24,K25,K26,K27,K2D,K2E,K2A, K4A,K4C, K53,K54, K6F, \ + K2B,K14,K1A,K08,K15,K17,K1C,K18,K0C,K12,K13,K2F,K30, K4D,K4B, K5F,K60,K61,K57, K70, \ + K39,K04,K16,K07,K09,K0A,K0B,K0D,K0E,K0F,K33,K34,K32, K28,K4E, K5C,K5D,K5E,K66, K71, \ + K79,K64,K1D,K1B,K06,K19,K05,K11,K10,K36,K37,K38, K51,K52, K59,K5A,K5B,K58, K72, \ + K78, K7A, K2C, K7E, K7C, K50,K4F, K62,K55,K63,K67, K73 \ +) UNIMAP( \ + K68, NO, NO, NO, NO, NO,K6E,K6F,K70,K71,K72,K73, \ + K29, K3A,K3B,K3C,K3D,K3E,K3F,K40,K41,K42,K43,K44,K45, K46,K47,K48, K01,K02,K03, \ + K35,K1E,K1F,K20,K21,K22,K23,K24,K25,K26,K27,K2D,K2E, NO,K2A, NO,K4A,K4B, K53,K54,K55, NO, \ + K2B,K14,K1A,K08,K15,K17,K1C,K18,K0C,K12,K13,K2F,K30, NO, K4C,K4D,K4E, K5F,K60,K61,K57, \ + K39,K04,K16,K07,K09,K0A,K0B,K0D,K0E,K0F,K33,K34, K32,K28, K5C,K5D,K5E,K66, \ + K79,K64,K1D,K1B,K06,K19,K05,K11,K10,K36,K37,K38, NO, NO, K52, K59,K5A,K5B,K58, \ + K78, NO,K7A, NO, K2C, NO, NO,K7E, NO, NO,K7C, K50,K51,K4F, K62,K63,K67 \ +) + +/* Mapping to Universal keyboard layout + * ,-----------------------------------------------. + * |F13|F14|F15|F16|F17|F18|F19|F20|F21|F22|F23|F24| + * ,---. |-----------------------------------------------| ,-----------. ,-----------. + * |Esc| |F1 |F2 |F3 |F4 |F5 |F6 |F7 |F8 |F9 |F10|F11|F12| |PrS|ScL|Pau| |VDn|VUp|Mut| + * `---' `-----------------------------------------------' `-----------' `-----------' + * ,-----------------------------------------------------------. ,-----------. ,---------------. + * | `| 1| 2| 3| 4| 5| 6| 7| 8| 9| 0| -| =|JPY|Bsp| |Ins|Hom|PgU| |NmL| /| *| -| + * |-----------------------------------------------------------| |-----------| |---------------| + * |Tab | Q| W| E| R| T| Y| U| I| O| P| [| ]| \ | |Del|End|PgD| | 7| 8| 9| +| + * |-----------------------------------------------------------| `-----------' |---------------| + * |CapsL | A| S| D| F| G| H| J| K| L| ;| '| #|Retn| | 4| 5| 6|KP,| + * |-----------------------------------------------------------| ,---. |---------------| + * |Shft| <| Z| X| C| V| B| N| M| ,| ,| /| RO|Shift | |Up | | 1| 2| 3|KP=| + * |-----------------------------------------------------------| ,-----------. |---------------| + * |Ctl|Gui|Alt|MHEN| Space |HENK|KANA|Alt|Gui|App|Ctl| |Lef|Dow|Rig| | 0 | .|Ent| + * `-----------------------------------------------------------' `-----------' `---------------' + * + * ,-----------------------------------------------. + * | 68| 69| 6A| 6B| 6C| 6D| 6E| 6F| 70| 71| 72| 73| + * ,---. |-----------------------------------------------| ,-----------. ,-----------. + * | 29| | 3A| 3B| 3C| 3D| 3E| 3F| 40| 41| 42| 43| 44| 45| | 46| 47| 48| | 01| 02| 03| + * `---' `-----------------------------------------------' `-----------' `-----------' + * ,-----------------------------------------------------------. ,-----------. ,---------------. + * | 35| 1E| 1F| 20| 21| 22| 23| 24| 25| 26| 27| 2D| 2E| 74| 2A| | 49| 4A| 4B| | 53| 54| 55| 56| + * |-----------------------------------------------------------| |-----------| |---------------| + * | 2B| 14| 1A| 08| 15| 17| 1C| 18| 0C| 12| 13| 2F| 30| 31| | 4C| 4D| 4E| | 5F| 60| 61| 57| + * |-----------------------------------------------------------| `-----------' |---------------| + * | 39| 04| 16| 07| 09| 0A| 0B| 0D| 0E| 0F| 33| 34| 32| 28| | 5C| 5D| 5E| 66| + * |-----------------------------------------------------------| ,---. |---------------| + * | 79| 64| 1D| 1B| 06| 19| 05| 11| 10| 36| 37| 38| 75| 7D| | 52| | 59| 5A| 5B| 58| + * |-----------------------------------------------------------| ,-----------. |---------------| + * | 78| 7B| 7A| 77| 2C| 76| 00| 7E| 7F| 65| 7C| | 50| 51| 4F| | 62| 63| 67| + * `-----------------------------------------------------------' `-----------' `---------------' + * + * This is a direct adaption of the table in "Serviceschaltplaene", p.3. + * I tried to keep the geometries as close as possible and support keys that my particular model + * does not feature. + * This may have resulted in countrintuitive keycaps, but makes sure that other models will also + * be supported and makes it easier to work with the keymap editor. + * + * NOTE: The first 6 rows in the last column aren't in the original keyboard matrix - they are the + * result of mapping the "security" key. + */ +#define NO UNIMAP_NO +const uint8_t PROGMEM unimap_trans[MATRIX_ROWS][MATRIX_COLS] = { + {0x02, 0x01, 0x48, 0x45, 0x46, 0x44, 0x40, 0x43, 0x3C, 0x29, 0x3D, 0x42, 0x3E, NO, 0x3A, 0x6E}, + { NO, NO, NO, 0x51, 0x47, 0x34, 0x10, 0x38, 0x06, NO, 0x05, 0x37, 0x11, NO, 0x1B, 0x6F}, + {0x61, 0x60, 0x5F, 0x2E, 0x4B, 0x2D, 0x23, 0x12, 0x1F, 0x2B, 0x17, 0x25, 0x22, 0x57, 0x1E, 0x70}, + {0x5B, 0x5A, 0x59, 0x4D, 0x52, 0x30, 0x0D, 0x33, 0x07, 0x64, 0x09, 0x0E, 0x0B, 0x58, 0x14, 0x71}, + {0x5E, 0x5D, 0x5C, 0x2A, 0x4E, 0x2F, 0x18, 0x13, 0x08, 0x04, 0x15, 0x0C, 0x1C, 0x66, 0x1A, 0x72}, + {0x63, 0x55, 0x62, 0x50, 0x4F, 0x7C, NO, 0x7E, 0x2C, 0x7A, NO, NO, NO, 0x67, 0x78, 0x73}, + {0x03, 0x54, 0x53, 0x68, 0x4C, 0x27, 0x24, 0x26, 0x20, NO, 0x21, 0x41, 0x3F, NO, 0x3B, 0x35}, + { NO, NO, NO, 0x28, 0x4A, 0x32, 0x36, 0x39, 0x19, 0x1D, 0x0A, 0x0F, NO, NO, 0x16, 0x79} +}; +#undef NO + +#endif diff --git a/usbconfig.h b/usbconfig.h new file mode 100644 index 0000000..01e5aa6 --- /dev/null +++ b/usbconfig.h @@ -0,0 +1,381 @@ +/* Name: usbconfig.h + * Project: V-USB, virtual USB port for Atmel's(r) AVR(r) microcontrollers + * Author: Christian Starkjohann + * Creation Date: 2005-04-01 + * Tabsize: 4 + * Copyright: (c) 2005 by OBJECTIVE DEVELOPMENT Software GmbH + * License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt) + * This Revision: $Id: usbconfig-prototype.h 785 2010-05-30 17:57:07Z cs $ + */ + +#ifndef __usbconfig_h_included__ +#define __usbconfig_h_included__ + + +/* +General Description: +This file is an example configuration (with inline documentation) for the USB +driver. It configures V-USB for USB D+ connected to Port D bit 2 (which is +also hardware interrupt 0 on many devices) and USB D- to Port D bit 4. You may +wire the lines to any other port, as long as D+ is also wired to INT0 (or any +other hardware interrupt, as long as it is the highest level interrupt, see +section at the end of this file). +*/ + +/* ---------------------------- Hardware Config ---------------------------- */ + +#define USB_CFG_IOPORTNAME B +/* This is the port where the USB bus is connected. When you configure it to + * "B", the registers PORTB, PINB and DDRB will be used. + */ +#define USB_CFG_DMINUS_BIT 1 +/* This is the bit number in USB_CFG_IOPORT where the USB D- line is connected. + * This may be any bit in the port. + */ +#define USB_CFG_DPLUS_BIT 2 +/* This is the bit number in USB_CFG_IOPORT where the USB D+ line is connected. + * This may be any bit in the port. Please note that D+ must also be connected + * to interrupt pin INT0! [You can also use other interrupts, see section + * "Optional MCU Description" below, or you can connect D- to the interrupt, as + * it is required if you use the USB_COUNT_SOF feature. If you use D- for the + * interrupt, the USB interrupt will also be triggered at Start-Of-Frame + * markers every millisecond.] + */ +#define USB_CFG_CLOCK_KHZ (F_CPU/1000) +/* Clock rate of the AVR in kHz. Legal values are 12000, 12800, 15000, 16000, + * 16500, 18000 and 20000. The 12.8 MHz and 16.5 MHz versions of the code + * require no crystal, they tolerate +/- 1% deviation from the nominal + * frequency. All other rates require a precision of 2000 ppm and thus a + * crystal! + * Since F_CPU should be defined to your actual clock rate anyway, you should + * not need to modify this setting. + */ +#define USB_CFG_CHECK_CRC 0 +/* Define this to 1 if you want that the driver checks integrity of incoming + * data packets (CRC checks). CRC checks cost quite a bit of code size and are + * currently only available for 18 MHz crystal clock. You must choose + * USB_CFG_CLOCK_KHZ = 18000 if you enable this option. + */ + +/* ----------------------- Optional Hardware Config ------------------------ */ + +/* #define USB_CFG_PULLUP_IOPORTNAME D */ +/* If you connect the 1.5k pullup resistor from D- to a port pin instead of + * V+, you can connect and disconnect the device from firmware by calling + * the macros usbDeviceConnect() and usbDeviceDisconnect() (see usbdrv.h). + * This constant defines the port on which the pullup resistor is connected. + */ +/* #define USB_CFG_PULLUP_BIT 4 */ +/* This constant defines the bit number in USB_CFG_PULLUP_IOPORT (defined + * above) where the 1.5k pullup resistor is connected. See description + * above for details. + */ + +/* --------------------------- Functional Range ---------------------------- */ + +#define USB_CFG_HAVE_INTRIN_ENDPOINT 1 +/* Define this to 1 if you want to compile a version with two endpoints: The + * default control endpoint 0 and an interrupt-in endpoint (any other endpoint + * number). + */ +#define USB_CFG_HAVE_INTRIN_ENDPOINT3 1 +/* Define this to 1 if you want to compile a version with three endpoints: The + * default control endpoint 0, an interrupt-in endpoint 3 (or the number + * configured below) and a catch-all default interrupt-in endpoint as above. + * You must also define USB_CFG_HAVE_INTRIN_ENDPOINT to 1 for this feature. + */ +#define USB_CFG_EP3_NUMBER 3 +/* If the so-called endpoint 3 is used, it can now be configured to any other + * endpoint number (except 0) with this macro. Default if undefined is 3. + */ +/* #define USB_INITIAL_DATATOKEN USBPID_DATA1 */ +/* The above macro defines the startup condition for data toggling on the + * interrupt/bulk endpoints 1 and 3. Defaults to USBPID_DATA1. + * Since the token is toggled BEFORE sending any data, the first packet is + * sent with the oposite value of this configuration! + */ +#define USB_CFG_IMPLEMENT_HALT 0 +/* Define this to 1 if you also want to implement the ENDPOINT_HALT feature + * for endpoint 1 (interrupt endpoint). Although you may not need this feature, + * it is required by the standard. We have made it a config option because it + * bloats the code considerably. + */ +#define USB_CFG_SUPPRESS_INTR_CODE 0 +/* Define this to 1 if you want to declare interrupt-in endpoints, but don't + * want to send any data over them. If this macro is defined to 1, functions + * usbSetInterrupt() and usbSetInterrupt3() are omitted. This is useful if + * you need the interrupt-in endpoints in order to comply to an interface + * (e.g. HID), but never want to send any data. This option saves a couple + * of bytes in flash memory and the transmit buffers in RAM. + */ +#define USB_CFG_INTR_POLL_INTERVAL 10 +/* If you compile a version with endpoint 1 (interrupt-in), this is the poll + * interval. The value is in milliseconds and must not be less than 10 ms for + * low speed devices. + */ +#define USB_CFG_IS_SELF_POWERED 0 +/* Define this to 1 if the device has its own power supply. Set it to 0 if the + * device is powered from the USB bus. + */ +#define USB_CFG_MAX_BUS_POWER 100 +/* Set this variable to the maximum USB bus power consumption of your device. + * The value is in milliamperes. [It will be divided by two since USB + * communicates power requirements in units of 2 mA.] + */ +#define USB_CFG_IMPLEMENT_FN_WRITE 1 +/* Set this to 1 if you want usbFunctionWrite() to be called for control-out + * transfers. Set it to 0 if you don't need it and want to save a couple of + * bytes. + */ +#define USB_CFG_IMPLEMENT_FN_READ 0 +/* Set this to 1 if you need to send control replies which are generated + * "on the fly" when usbFunctionRead() is called. If you only want to send + * data from a static buffer, set it to 0 and return the data from + * usbFunctionSetup(). This saves a couple of bytes. + */ +#define USB_CFG_IMPLEMENT_FN_WRITEOUT 0 +/* Define this to 1 if you want to use interrupt-out (or bulk out) endpoints. + * You must implement the function usbFunctionWriteOut() which receives all + * interrupt/bulk data sent to any endpoint other than 0. The endpoint number + * can be found in 'usbRxToken'. + */ +#define USB_CFG_HAVE_FLOWCONTROL 0 +/* Define this to 1 if you want flowcontrol over USB data. See the definition + * of the macros usbDisableAllRequests() and usbEnableAllRequests() in + * usbdrv.h. + */ +#define USB_CFG_DRIVER_FLASH_PAGE 0 +/* If the device has more than 64 kBytes of flash, define this to the 64 k page + * where the driver's constants (descriptors) are located. Or in other words: + * Define this to 1 for boot loaders on the ATMega128. + */ +#define USB_CFG_LONG_TRANSFERS 0 +/* Define this to 1 if you want to send/receive blocks of more than 254 bytes + * in a single control-in or control-out transfer. Note that the capability + * for long transfers increases the driver size. + */ +/* #define USB_RX_USER_HOOK(data, len) if(usbRxToken == (uchar)USBPID_SETUP) blinkLED(); */ +/* This macro is a hook if you want to do unconventional things. If it is + * defined, it's inserted at the beginning of received message processing. + * If you eat the received message and don't want default processing to + * proceed, do a return after doing your things. One possible application + * (besides debugging) is to flash a status LED on each packet. + */ +#define USB_RESET_HOOK(resetStarts) if(!resetStarts){hadUsbReset();} +/* http://codeandlife.com/2012/02/22/v-usb-with-attiny45-attiny85-without-a-crystal/ */ +#ifndef __ASSEMBLER__ +extern void hadUsbReset(void); // define the function for usbdrv.c +#endif +/* This macro is a hook if you need to know when an USB RESET occurs. It has + * one parameter which distinguishes between the start of RESET state and its + * end. + */ +/* #define USB_SET_ADDRESS_HOOK() hadAddressAssigned(); */ +/* This macro (if defined) is executed when a USB SET_ADDRESS request was + * received. + */ +#define USB_COUNT_SOF 0 +/* define this macro to 1 if you need the global variable "usbSofCount" which + * counts SOF packets. This feature requires that the hardware interrupt is + * connected to D- instead of D+. + */ +/* #ifdef __ASSEMBLER__ + * macro myAssemblerMacro + * in YL, TCNT0 + * sts timer0Snapshot, YL + * endm + * #endif + * #define USB_SOF_HOOK myAssemblerMacro + * This macro (if defined) is executed in the assembler module when a + * Start Of Frame condition is detected. It is recommended to define it to + * the name of an assembler macro which is defined here as well so that more + * than one assembler instruction can be used. The macro may use the register + * YL and modify SREG. If it lasts longer than a couple of cycles, USB messages + * immediately after an SOF pulse may be lost and must be retried by the host. + * What can you do with this hook? Since the SOF signal occurs exactly every + * 1 ms (unless the host is in sleep mode), you can use it to tune OSCCAL in + * designs running on the internal RC oscillator. + * Please note that Start Of Frame detection works only if D- is wired to the + * interrupt, not D+. THIS IS DIFFERENT THAN MOST EXAMPLES! + */ +#define USB_CFG_CHECK_DATA_TOGGLING 0 +/* define this macro to 1 if you want to filter out duplicate data packets + * sent by the host. Duplicates occur only as a consequence of communication + * errors, when the host does not receive an ACK. Please note that you need to + * implement the filtering yourself in usbFunctionWriteOut() and + * usbFunctionWrite(). Use the global usbCurrentDataToken and a static variable + * for each control- and out-endpoint to check for duplicate packets. + */ +#define USB_CFG_HAVE_MEASURE_FRAME_LENGTH 1 +/* define this macro to 1 if you want the function usbMeasureFrameLength() + * compiled in. This function can be used to calibrate the AVR's RC oscillator. + */ +#define USB_USE_FAST_CRC 0 +/* The assembler module has two implementations for the CRC algorithm. One is + * faster, the other is smaller. This CRC routine is only used for transmitted + * messages where timing is not critical. The faster routine needs 31 cycles + * per byte while the smaller one needs 61 to 69 cycles. The faster routine + * may be worth the 32 bytes bigger code size if you transmit lots of data and + * run the AVR close to its limit. + */ + +/* -------------------------- Device Description --------------------------- */ + +#define USB_CFG_VENDOR_ID (VENDOR_ID & 0xFF), ((VENDOR_ID >> 8) & 0xFF) +/* USB vendor ID for the device, low byte first. If you have registered your + * own Vendor ID, define it here. Otherwise you may use one of obdev's free + * shared VID/PID pairs. Be sure to read USB-IDs-for-free.txt for rules! + * *** IMPORTANT NOTE *** + * This template uses obdev's shared VID/PID pair for Vendor Class devices + * with libusb: 0x16c0/0x5dc. Use this VID/PID pair ONLY if you understand + * the implications! + */ +#define USB_CFG_DEVICE_ID (PRODUCT_ID & 0xFF), ((PRODUCT_ID >> 8) & 0xFF) +/* This is the ID of the product, low byte first. It is interpreted in the + * scope of the vendor ID. If you have registered your own VID with usb.org + * or if you have licensed a PID from somebody else, define it here. Otherwise + * you may use one of obdev's free shared VID/PID pairs. See the file + * USB-IDs-for-free.txt for details! + * *** IMPORTANT NOTE *** + * This template uses obdev's shared VID/PID pair for Vendor Class devices + * with libusb: 0x16c0/0x5dc. Use this VID/PID pair ONLY if you understand + * the implications! + */ +#define USB_CFG_DEVICE_VERSION 0x00, 0x01 +/* Version number of the device: Minor number first, then major number. + */ +#define USB_CFG_VENDOR_NAME 't', '.', 'm', '.', 'k', '.' +#define USB_CFG_VENDOR_NAME_LEN 6 +/* These two values define the vendor name returned by the USB device. The name + * must be given as a list of characters under single quotes. The characters + * are interpreted as Unicode (UTF-16) entities. + * If you don't want a vendor name string, undefine these macros. + * ALWAYS define a vendor name containing your Internet domain name if you use + * obdev's free shared VID/PID pair. See the file USB-IDs-for-free.txt for + * details. + */ +#define USB_CFG_DEVICE_NAME 'O', 'n', 'e', 'k', 'e', 'y' +#define USB_CFG_DEVICE_NAME_LEN 6 +/* Same as above for the device name. If you don't want a device name, undefine + * the macros. See the file USB-IDs-for-free.txt before you assign a name if + * you use a shared VID/PID. + */ +/*#define USB_CFG_SERIAL_NUMBER 'N', 'o', 'n', 'e' */ +/*#define USB_CFG_SERIAL_NUMBER_LEN 0 */ +/* Same as above for the serial number. If you don't want a serial number, + * undefine the macros. + * It may be useful to provide the serial number through other means than at + * compile time. See the section about descriptor properties below for how + * to fine tune control over USB descriptors such as the string descriptor + * for the serial number. + */ +#define USB_CFG_DEVICE_CLASS 0 +#define USB_CFG_DEVICE_SUBCLASS 0 +/* See USB specification if you want to conform to an existing device class. + * Class 0xff is "vendor specific". + */ +#define USB_CFG_INTERFACE_CLASS 3 /* HID */ +#define USB_CFG_INTERFACE_SUBCLASS 1 /* Boot */ +#define USB_CFG_INTERFACE_PROTOCOL 1 /* Keyboard */ +/* See USB specification if you want to conform to an existing device class or + * protocol. The following classes must be set at interface level: + * HID class is 3, no subclass and protocol required (but may be useful!) + * CDC class is 2, use subclass 2 and protocol 1 for ACM + */ +#define USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH 0 +/* Define this to the length of the HID report descriptor, if you implement + * an HID device. Otherwise don't define it or define it to 0. + * If you use this define, you must add a PROGMEM character array named + * "usbHidReportDescriptor" to your code which contains the report descriptor. + * Don't forget to keep the array and this define in sync! + */ + +/* #define USB_PUBLIC static */ +/* Use the define above if you #include usbdrv.c instead of linking against it. + * This technique saves a couple of bytes in flash memory. + */ + +/* ------------------- Fine Control over USB Descriptors ------------------- */ +/* If you don't want to use the driver's default USB descriptors, you can + * provide our own. These can be provided as (1) fixed length static data in + * flash memory, (2) fixed length static data in RAM or (3) dynamically at + * runtime in the function usbFunctionDescriptor(). See usbdrv.h for more + * information about this function. + * Descriptor handling is configured through the descriptor's properties. If + * no properties are defined or if they are 0, the default descriptor is used. + * Possible properties are: + * + USB_PROP_IS_DYNAMIC: The data for the descriptor should be fetched + * at runtime via usbFunctionDescriptor(). If the usbMsgPtr mechanism is + * used, the data is in FLASH by default. Add property USB_PROP_IS_RAM if + * you want RAM pointers. + * + USB_PROP_IS_RAM: The data returned by usbFunctionDescriptor() or found + * in static memory is in RAM, not in flash memory. + * + USB_PROP_LENGTH(len): If the data is in static memory (RAM or flash), + * the driver must know the descriptor's length. The descriptor itself is + * found at the address of a well known identifier (see below). + * List of static descriptor names (must be declared PROGMEM if in flash): + * char usbDescriptorDevice[]; + * char usbDescriptorConfiguration[]; + * char usbDescriptorHidReport[]; + * char usbDescriptorString0[]; + * int usbDescriptorStringVendor[]; + * int usbDescriptorStringDevice[]; + * int usbDescriptorStringSerialNumber[]; + * Other descriptors can't be provided statically, they must be provided + * dynamically at runtime. + * + * Descriptor properties are or-ed or added together, e.g.: + * #define USB_CFG_DESCR_PROPS_DEVICE (USB_PROP_IS_RAM | USB_PROP_LENGTH(18)) + * + * The following descriptors are defined: + * USB_CFG_DESCR_PROPS_DEVICE + * USB_CFG_DESCR_PROPS_CONFIGURATION + * USB_CFG_DESCR_PROPS_STRINGS + * USB_CFG_DESCR_PROPS_STRING_0 + * USB_CFG_DESCR_PROPS_STRING_VENDOR + * USB_CFG_DESCR_PROPS_STRING_PRODUCT + * USB_CFG_DESCR_PROPS_STRING_SERIAL_NUMBER + * USB_CFG_DESCR_PROPS_HID + * USB_CFG_DESCR_PROPS_HID_REPORT + * USB_CFG_DESCR_PROPS_UNKNOWN (for all descriptors not handled by the driver) + * + * Note about string descriptors: String descriptors are not just strings, they + * are Unicode strings prefixed with a 2 byte header. Example: + * int serialNumberDescriptor[] = { + * USB_STRING_DESCRIPTOR_HEADER(6), + * 'S', 'e', 'r', 'i', 'a', 'l' + * }; + */ + +#define USB_CFG_DESCR_PROPS_DEVICE 0 +#define USB_CFG_DESCR_PROPS_CONFIGURATION USB_PROP_IS_DYNAMIC +//#define USB_CFG_DESCR_PROPS_CONFIGURATION 0 +#define USB_CFG_DESCR_PROPS_STRINGS 0 +#define USB_CFG_DESCR_PROPS_STRING_0 0 +#define USB_CFG_DESCR_PROPS_STRING_VENDOR 0 +#define USB_CFG_DESCR_PROPS_STRING_PRODUCT 0 +#define USB_CFG_DESCR_PROPS_STRING_SERIAL_NUMBER 0 +//#define USB_CFG_DESCR_PROPS_HID USB_PROP_IS_DYNAMIC +#define USB_CFG_DESCR_PROPS_HID 0 +#define USB_CFG_DESCR_PROPS_HID_REPORT USB_PROP_IS_DYNAMIC +//#define USB_CFG_DESCR_PROPS_HID_REPORT 0 +#define USB_CFG_DESCR_PROPS_UNKNOWN 0 + +/* ----------------------- Optional MCU Description ------------------------ */ + +/* The following configurations have working defaults in usbdrv.h. You + * usually don't need to set them explicitly. Only if you want to run + * the driver on a device which is not yet supported or with a compiler + * which is not fully supported (such as IAR C) or if you use a differnt + * interrupt than INT0, you may have to define some of these. + */ +/* #define USB_INTR_CFG MCUCR */ +/* #define USB_INTR_CFG_SET ((1 << ISC00) | (1 << ISC01)) */ +/* #define USB_INTR_CFG_CLR 0 */ +/* #define USB_INTR_ENABLE GIMSK */ +/* #define USB_INTR_ENABLE_BIT INT0 */ +/* #define USB_INTR_PENDING GIFR */ +/* #define USB_INTR_PENDING_BIT INTF0 */ +/* #define USB_INTR_VECTOR INT0_vect */ + +#endif /* __usbconfig_h_included__ */ -- cgit v1.2.3