diff options
-rw-r--r-- | COPYING | 339 | ||||
-rw-r--r-- | Makefile | 107 | ||||
-rw-r--r-- | command.c | 60 | ||||
-rw-r--r-- | config.h | 75 | ||||
-rwxr-xr-x | k7637-beep.sh | 19 | ||||
-rw-r--r-- | k7637.rules | 3 | ||||
-rw-r--r-- | keyclick.h | 47 | ||||
-rw-r--r-- | led.c | 82 | ||||
-rw-r--r-- | matrix.c | 337 | ||||
-rw-r--r-- | pwm.c | 347 | ||||
-rw-r--r-- | pwm.h | 34 | ||||
-rw-r--r-- | song.c | 456 | ||||
-rw-r--r-- | song.h | 24 | ||||
-rw-r--r-- | unimap_00.c | 34 | ||||
-rw-r--r-- | unimap_trans.h | 99 | ||||
-rw-r--r-- | usbconfig.h | 381 |
16 files changed, 2444 insertions, 0 deletions
@@ -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. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + 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. + + <signature of Ty Coon>, 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 <robin.haberkorn@googlemail.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 <stdbool.h> +#include <stdint.h> + +#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 <wakojun@gmail.com> +Copyright 2021 Robin Haberkorn <robin.haberkorn@googlemail.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 + + +/* 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 <robin.haberkorn@googlemail.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 KEYCLICK_H +#define KEYCLICK_H + +#include <stdbool.h> + +#include <avr/io.h> + +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 @@ -0,0 +1,82 @@ +/* +Copyright 2021 Robin Haberkorn <robin.haberkorn@googlemail.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 <stdint.h> + +#include <avr/io.h> + +#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 <robin.haberkorn@googlemail.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 <stdint.h> +#include <stdbool.h> +#include <string.h> + +#include <avr/io.h> +#include <util/delay.h> + +#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; +} @@ -0,0 +1,347 @@ +/* +Copyright 2021 Robin Haberkorn <robin.haberkorn@googlemail.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 <stdint.h> +#include <math.h> + +#include <avr/io.h> +#include <avr/interrupt.h> +#include <avr/pgmspace.h> + +#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); +} @@ -0,0 +1,34 @@ +/* +Copyright 2021 Robin Haberkorn <robin.haberkorn@googlemail.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 PWM_H +#define PWM_H + +#include <stdint.h> + +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 @@ -0,0 +1,456 @@ +/* +Copyright 2021 Robin Haberkorn <robin.haberkorn@googlemail.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 <stdint.h> + +#include <avr/pgmspace.h> +#include <util/delay.h> + +#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()); +} @@ -0,0 +1,24 @@ +/* +Copyright 2021 Robin Haberkorn <robin.haberkorn@googlemail.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 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 <robin.haberkorn@googlemail.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 <avr/pgmspace.h> + +#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 <robin.haberkorn@googlemail.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 UNIMAP_TRANS_H +#define UNIMAP_TRANS_H + +#include <stdint.h> +#include <avr/pgmspace.h> + +#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__ */ |