aboutsummaryrefslogtreecommitdiffstats
path: root/protocol/iwrap
diff options
context:
space:
mode:
Diffstat (limited to 'protocol/iwrap')
-rw-r--r--protocol/iwrap/iWRAP.txt376
-rw-r--r--protocol/iwrap/iwrap.c467
-rw-r--r--protocol/iwrap/iwrap.h49
-rw-r--r--protocol/iwrap/main.c378
-rw-r--r--protocol/iwrap/suart.S156
-rw-r--r--protocol/iwrap/suart.h8
-rw-r--r--protocol/iwrap/wd.h159
7 files changed, 1593 insertions, 0 deletions
diff --git a/protocol/iwrap/iWRAP.txt b/protocol/iwrap/iWRAP.txt
new file mode 100644
index 000000000..2a062d9d9
--- /dev/null
+++ b/protocol/iwrap/iWRAP.txt
@@ -0,0 +1,376 @@
+Bulegiga WT12
+=============
+WT12 is a bluetooth module from Bluegiga. http://www.bluegiga.com/
+
+iWRAP
+ higher layer interface for bluetooth firmware
+ communicate with UART
+
+iWRAP HID
+default setting
+ 115200 8bit/n/1/n
+
+
+TODO
+----
+KiCAD circuit/PCB design
+power saving
+ AVR sleep(15ms by watch dog timer)
+ WT12 sleep
+ measuring current consumption
+ measuring battery life of normal usage/idle/intensive usage
+software reset/bootloarder
+LED indicator(chaging/paring/connecting)
+license confirmation of suart.c
+consumer page is not working
+authenticate method/SSP
+SPP keyboard support
+SPP debug console support
+mouse wheel feature request to Bluegiga
+
+
+Problems
+--------
+power consumption
+no consumer page support(bug?)
+no mouse wheel support
+no paring management
+no interactive auth method
+
+
+UART hardware flow control
+--------------------------
+(iWRAP4 User Guide 9.5)
+Hardware flow control is enabled by default and it should not be disabled unless mandatory, because without the hardware flow control the data transmission may not be reliable.
+If the hardware flow control is enabled from PS-keys, but no flow control is used, the following steps should be implemented in the hardware design:
+- CTS pin must be grounded
+- RTS pin must be left floating
+
+
+Power Saving
+------------
+power consume
+ without opimization: 4hr to shutdown(310mAh)
+ 2011/08/25: 9hr(310mAh) SNIFF MASTER sleep/WDTO_120MS
+
+measure current consumption
+ HHKB keyswitch matrix board
+ idle
+ scanning
+ Bluegiga WT12 module
+ SLEEP command
+ deep sleep on/off in config bits
+
+HHKB keyswich
+ how to power off
+ I/O pin configuration when sleeping
+ FET switch for 5V regulator
+
+Bluetooth module
+ power off when in USB mode
+ power off by FET switch
+
+AVR configuration
+ unused pins
+ ADC
+
+
+
+SET CONTROL CONFIG
+------------------
+ SET CONTROL CONFIG 4810
+ SET CONTROL CONFIG LIST
+ SET CONTROL CONFIG 0000 0000 4910 DEEP_SLEEP KLUDGE INTERACTIVE_PIN UART_LATENCY
+
+ Bit14 UART low latency
+ Bit11 Interactive pairing mode
+ Bit04 Deep sleep
+
+
+Reconnection
+------------
+SET CONTROL AUTOCALL 1124 5000 HID
+ 1124 HID service class
+ 5000 interval ms
+
+HID profile
+-----------
+This is needed to configure only once.
+ SET PROFILE HID ON
+ RESET
+
+HID class
+---------
+ SET BT CLASS 005C0 // keyboard/mouse combined devie
+
+Pairing Security
+----------------
+Secure Simple Pairing(SSP)
+ SET BT SSP 2 0 // Enables SSP for keyboard and Man-in-the-middle protection
+ SET BT SSP 3 0 // Enables SSP just works mode
+
+for keyboard with SSP
+ SET BT AUTH * 0000
+ SET BT SSP 2 0
+ SET CONTROL CONFIG 800
+ RESET
+
+for keyboard without SSP
+ SET BT AUTH * 0000
+ SET CONTROL CONFIG 800
+ RESET
+
+AUTH
+ AUTH xx:xx:xx:xx:xx:xx? // Pairing request event
+ AUTH xx:xx:xx:xx:xx:xx 0000
+
+ SSP PASSKEY 78:dd:08:b7:e4:a2 ?
+ SSP PASSKEY 78:dd:08:b7:e4:a2 xxxxx
+ (SSP COMPLETE 78:dd:08:b7:e4:a2 HCI_ERROR_AUTH_FAIL // failed)
+ RING 0 78:dd:08:b7:e4:a2 11 HID
+
+Connecton
+ RING xx:xx:xx:xx:xx:xx xx HID // connection event
+
+ KILL xx:xx:xx:xx:xx:xx
+
+Mode
+----
+Command mode
+Data mode
+ Raw mode
+ (Simple mode not for a real keyboard)
+
+Raw mode
+ Keyboard:
+ 0x9f, length(10), 0xa1, 0x01, mods, 0x00, key1, key2, key3, key4, key5, key6
+
+ Mouse:
+ 0x9f, length(5), 0xa1, 0x02, buttons, X, Y
+
+ Consumer page:
+ 0x9f, length(5), 0xa1, 0x03, bitfield1, bitfield2, bitfield3
+
+ consumer page suage
+ Bitfield 1:
+ 0x01 Volume Increment
+ 0x02 Volume Decrement
+ 0x04 Mute
+ 0x08 Play/Pause
+ 0x10 Scan Next Track
+ 0x20 Scan Previous Track
+ 0x40 Stop
+ 0x80 Eject
+ Bitfield 2:
+ 0x01 Email Reader
+ 0x02 Application Control Search
+ 0x04 AC Bookmarks
+ 0x08 AC Home
+ 0x10 AC Back
+ 0x20 AC Forward
+ 0x40 AC Stop
+ 0x80 AC Refresh
+ Bitfield 3:
+ 0x01 Application Launch Generic Consumer Control
+ 0x02 AL Internet Browser
+ 0x04 AL Calculator
+ 0x08 AL Terminal Lock / Screensaver
+ 0x10 AL Local Machine Browser
+ 0x20 AC Minimize
+ 0x40 Record
+ 0x80 Rewind
+
+
+
+
+
+2011/07/13
+set
+SET BT BDADDR 00:07:80:47:22:14
+SET BT NAME HHKB pro BT
+SET BT CLASS 0005c0
+SET BT AUTH * 0000
+SET BT IDENT BT:47 f000 4.1.0 Bluegiga iWRAP
+SET BT LAP 9e8b33
+SET BT PAGEMODE 4 2000 1
+SET BT PAIR 78:dd:08:b7:e4:a2 a191189cd7e51030ad6a07848ce879bb
+SET BT POWER 3 3 3
+SET BT ROLE 0 f 7d00
+SET BT SNIFF 0 20 1 8
+SET BT SSP 2 1
+SET BT MTU 667
+SET CONTROL AUTOCALL 1124 3000 HID
+SET CONTROL BAUD 38400,8n1
+SET CONTROL CD 00 0
+SET CONTROL ECHO 7
+SET CONTROL ESCAPE 43 00 1
+SET CONTROL GAIN 0 5
+SET CONTROL INIT SET CONTROL MUX 0
+SET CONTROL MSC DTE 00 00 00 00 00 00
+SET CONTROL MUX 1
+SET CONTROL PIO 00 00
+SET CONTROL READY 00
+SET PROFILE HID f HID
+SET
+
+info config
+
+!!! THIS IS BETA RELEASE AND MAY BE USED FOR EVALUATION PURPOSES ONLY !!!
+
+WRAP THOR AI (4.1.0 build 435)
+Copyright (c) 2003-2011 Bluegiga Technologies Inc.
+Compiled on Jun 28 2011 17:19:51, running on WT12-A module, psr v31
+ AVRCP BGIO FTP HFP HFP_AG HID HID_CONSUMER_PAGE HSP LEDS MAP OTA PBAP PIO=0x00fc SSP SUBRATE TEST VOLUME
+ - BOCK3 version 435 (Jun 28 2011 17:19:37) (max acl/sco 7/1)
+ - Bluetooth version 2.1, Power class 2
+ - Loader 4279, firmware 6297 (56-bit encryption), native execution mode
+ - up 0 days, 06:23, 2 connections (pool 2)
+ - User configuration:
+&028a = 0001 0000 0000 0011 0024 0000 0000 0010 0000 0080 0000 0000 0080 005f 009b 0034 00fb 0006
+&028b = 0000 0bb8
+&028d = 0001
+&0295 = 0000 0005 000b 0000 0003 0000 0000 0000 0000 0000 0000
+&0298 = a006
+&0299 = 0000 0000
+&02a3 = 0030 0030 0030 0030
+&02a4 = 009d 0000
+&02a5 = 0053 0045 0054 0020 0043 004f 004e 0054 0052 004f 004c 0020 004d 0055 0058 0020 0030
+&02a7 = 0000 05c0
+&02a8 = 4910 0000 0000
+&02aa = 0004 2000 0001 0033 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000
+&02ac = 0000 0000 002b 0000 0000 0000 0000 0000 0000 0000 0002 0000 0000 0000 0010 0000 0000 0000 0000 029b 0000 0000 0000 0000
+&02ad = 4848 424b 7020 6f72 4220 0054
+&02b3 = 0005 0003 0003 0003 0003 0003 0003 0003 0003 0003 0003 0003 0003 0003 0003 0003
+&02b7 = 000f 4948 0044
+&02bb = 8000
+READY.
+
+
+
+
+2011/07/07 settings:
+set
+SET BT BDADDR 00:07:80:47:22:14
+SET BT NAME HHKB Pro BT
+SET BT CLASS 0005c0
+SET BT AUTH * 000
+SET BT IDENT BT:47 f000 4.0.0 Bluegiga iWRAP
+SET BT LAP 9e8b33
+SET BT PAGEMODE 4 2000 1
+SET BT PAIR 78:dd:08:b7:e4:a2 9e54d0aabb1b4d73cfccddb1ea4ef2d6
+SET BT POWER 3 3 3
+SET BT ROLE 0 f 7d00
+SET BT SNIFF 0 20 1 8
+SET BT SSP 3 0
+SET BT MTU 667
+SET CONTROL BAUD 38400,8n1
+SET CONTROL CD 00 0
+SET CONTROL ECHO 7
+SET CONTROL ESCAPE 255 00 1
+SET CONTROL GAIN 0 5
+SET CONTROL INIT set control mux 0
+SET CONTROL MSC DTE 00 00 00 00 00 00
+SET CONTROL PREAMP 1 1
+SET CONTROL READY 00
+SET PROFILE HID HID
+SET PROFILE SPP Bluetooth Serial Port
+SET
+
+info config
+WRAP THOR AI (4.0.0 build 317)
+Copyright (c) 2003-2010 Bluegiga Technologies Inc.
+Compiled on Apr 20 2010 16:44:28, running on WT12-A module, psr v31
+ AVRCP FTP PBAP PIO=0x00fc SSP SUBRATE VOLUME
+ - BOCK3 version 317 (Apr 20 2010 16:44:21) (max acl/sco 7/1)
+ - Bluetooth version 2.1, Power class 2
+ - Loader 4279, firmware 6297 (56-bit encryption), native execution mode
+ - up 0 days, 00:00, 0 connections (pool 1)
+ - User configuration:
+&028c = 0001 0020 0000 0001 0008 0000
+&028d = 0000
+&0296 = 0047 0001 f000 0400 6c42 6575 6967 6167 6920 5257 5041
+&0298 = c006
+&02a3 = 0030 0030 0030
+&02a4 = 009d 0000
+&02a5 = 0073 0065 0074 0020 0063 006f 006e 0074 0072 006f 006c 0020 006d 0075 0078 0020 0030
+&02a7 = 0000 05c0
+&02a8 = 0800 0000 0000
+&02ac = 0000 0000 00ff 0000 0000 0000 0000 0000 0000 0000 0002 0000 0000 0000 0010 0000 0000 0000 0000 029b 0000 0000 0000 0000
+&02ad = 4848 424b 5020 6f72 4220 0054
+&02b3 = 0004 0003 0003 0003 0003 0003 0003 0003 0003 0003 0003 0003 0003 0003 0003 0003
+&02b7 = 0000
+&02bb = 6c42 6575 6f74 746f 2068 6553 6972 6c61 5020 726f 0074
+READY.
+
+
+
+2011/08/23:
+SET BT BDADDR 00:07:80:47:22:14
+SET BT NAME HHKB pro BT
+SET BT CLASS 0005c0
+SET BT AUTH * 0000
+SET BT IDENT BT:47 f000 4.1.0 Bluegiga iWRAP
+SET BT LAP 9e8b33
+SET BT PAGEMODE 4 2000 1
+SET BT PAIRCOUNT 4
+SET BT POWER 3 3 3
+SET BT ROLE 1 f 12c0
+SET BT SNIFF 10 2 1 8
+SET BT SSP 3 0
+SET BT MTU 667
+SET CONTROL BAUD 38400,8n1
+SET CONTROL CD 00 0
+SET CONTROL ECHO 7
+SET CONTROL ESCAPE 43 00 1
+SET CONTROL GAIN 0 5
+SET CONTROL INIT SET CONTROL MUX 0
+SET CONTROL MSC DTE 00 00 00 00 00 00
+SET CONTROL MUX 1
+SET CONTROL PIO 00 00
+SET CONTROL READY 00
+SET PROFILE HID 7 HIDKeyboardMouse
+SET
+
+SET CONTROL CONFIG 0000 0004 481e CLOCK_CACHE INTERLACED_INQ INTERLACED_PAGE DEEP_SLEEP INTERACTIVE_PIN UART_LATENCY 23D_NOKLUDGE
+
+
+
+2011/08/25:
+SET BT BDADDR 00:07:80:47:22:14
+SET BT NAME HHKB pro BT
+SET BT CLASS 0005c0
+
+SET BT IDENT BT:47 f000 4.1.0 Bluegiga iWRAP
+SET BT LAP 9e8b33
+SET BT PAGEMODE 4 2000 1
+SET BT PAIRCOUNT 4
+SET BT PAIR 78:dd:08:b7:e4:a2 0be83335a03fed8ededae42e99554e28
+SET BT POWER 3 3 3
+SET BT ROLE 1 f 12c0
+SET BT SNIFF 100 20 1 8
+SET BT SSP 3 0
+SET BT MTU 667
+SET CONTROL BAUD 38400,8n1
+SET CONTROL CD 00 0
+SET CONTROL ECHO 7
+SET CONTROL ESCAPE - 20 1
+SET CONTROL GAIN 0 5
+SET CONTROL INIT SET CONTROL MUX 0
+SET CONTROL MSC DTE 00 00 00 00 00 00
+SET CONTROL MUX 1
+SET CONTROL PIO 00 00
+SET CONTROL READY 00
+SET PROFILE HID f HIDKeyboardMouse
+SET
+
+
+SET CONTROL CONFIG 0000 0000 490e CLOCK_CACHE INTERLACED_INQ INTERLACED_PAGE KLUDGE INTERACTIVE_PIN UART_LATENCY
+
+
+2011/09/08:
+SET CONTROL CONFIG 0000 0000 410e CLOCK_CACHE INTERLACED_INQ INTERLACED_PAGE KLUDGE UART_LATENCY
+
+ Removed INTERACTIVE_PIN to avoid interactive auth and use SET BT AUTH pin(0000).
+
+
+EOF
diff --git a/protocol/iwrap/iwrap.c b/protocol/iwrap/iwrap.c
new file mode 100644
index 000000000..9c68761bf
--- /dev/null
+++ b/protocol/iwrap/iwrap.c
@@ -0,0 +1,467 @@
+/*
+Copyright 2011 Jun Wako <wakojun@gmail.com>
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/* host driver for Bulegiga iWRAP */
+/* Bluegiga BT12
+ * Connections
+ * Hardware UART Software UART BlueTooth
+ * PC=====UART=======AVR=====SUART====iWRAP(BT12)-----------PC
+ *
+ * - Hardware UART for Debug Console to communicate iWRAP
+ * - Software UART for iWRAP control to send keyboard/mouse data
+ */
+
+#include <stdint.h>
+#include <string.h>
+#include <avr/interrupt.h>
+#include <util/delay.h>
+#include "usb_keycodes.h"
+#include "suart.h"
+#include "uart.h"
+#include "report.h"
+#include "host_driver.h"
+#include "iwrap.h"
+#include "print.h"
+
+
+/* iWRAP MUX mode utils. 3.10 HID raw mode(iWRAP_HID_Application_Note.pdf) */
+#define MUX_HEADER(LINK, LENGTH) do { \
+ xmit(0xbf); /* SOF */ \
+ xmit(LINK); /* Link */ \
+ xmit(0x00); /* Flags */ \
+ xmit(LENGTH); /* Length */ \
+} while (0)
+#define MUX_FOOTER(LINK) xmit(LINK^0xff)
+
+
+static uint8_t connected = 0;
+//static uint8_t channel = 1;
+
+/* iWRAP buffer */
+#define MUX_BUF_SIZE 64
+static char buf[MUX_BUF_SIZE];
+static uint8_t snd_pos = 0;
+
+#define MUX_RCV_BUF_SIZE 256
+static char rcv_buf[MUX_RCV_BUF_SIZE];
+static uint8_t rcv_head = 0;
+static uint8_t rcv_tail = 0;
+
+
+/* receive buffer */
+static void rcv_enq(char c)
+{
+ uint8_t next = (rcv_head + 1) % MUX_RCV_BUF_SIZE;
+ if (next != rcv_tail) {
+ rcv_buf[rcv_head] = c;
+ rcv_head = next;
+ }
+}
+
+static char rcv_deq(void)
+{
+ char c = 0;
+ if (rcv_head != rcv_tail) {
+ c = rcv_buf[rcv_tail++];
+ rcv_tail %= MUX_RCV_BUF_SIZE;
+ }
+ return c;
+}
+
+/*
+static char rcv_peek(void)
+{
+ if (rcv_head == rcv_tail)
+ return 0;
+ return rcv_buf[rcv_tail];
+}
+*/
+
+static void rcv_clear(void)
+{
+ rcv_tail = rcv_head = 0;
+}
+
+/* iWRAP response */
+ISR(PCINT1_vect, ISR_BLOCK) // recv() runs away in case of ISR_NOBLOCK
+{
+ if ((SUART_IN_PIN & (1<<SUART_IN_BIT)))
+ return;
+
+ static volatile uint8_t mux_state = 0xff;
+ static volatile uint8_t mux_link = 0xff;
+ uint8_t c = recv();
+ switch (mux_state) {
+ case 0xff: // SOF
+ if (c == 0xbf)
+ mux_state--;
+ break;
+ case 0xfe: // Link
+ mux_state--;
+ mux_link = c;
+ break;
+ case 0xfd: // Flags
+ mux_state--;
+ break;
+ case 0xfc: // Length
+ mux_state = c;
+ break;
+ case 0x00:
+ mux_state = 0xff;
+ mux_link = 0xff;
+ break;
+ default:
+ if (mux_state--) {
+ uart_putchar(c);
+ rcv_enq(c);
+ }
+ }
+}
+
+
+/*------------------------------------------------------------------*
+ * iWRAP communication
+ *------------------------------------------------------------------*/
+void iwrap_init(void)
+{
+ // reset iWRAP if in already MUX mode after AVR software-reset
+ iwrap_send("RESET");
+ iwrap_mux_send("RESET");
+ _delay_ms(3000);
+ iwrap_send("\r\nSET CONTROL MUX 1\r\n");
+ _delay_ms(500);
+ iwrap_check_connection();
+}
+
+void iwrap_mux_send(const char *s)
+{
+ rcv_clear();
+ MUX_HEADER(0xff, strlen((char *)s));
+ iwrap_send(s);
+ MUX_FOOTER(0xff);
+}
+
+void iwrap_send(const char *s)
+{
+ while (*s)
+ xmit(*s++);
+}
+
+/* send buffer */
+void iwrap_buf_add(uint8_t c)
+{
+ // need space for '\0'
+ if (snd_pos < MUX_BUF_SIZE-1)
+ buf[snd_pos++] = c;
+}
+
+void iwrap_buf_del(void)
+{
+ if (snd_pos)
+ snd_pos--;
+}
+
+void iwrap_buf_send(void)
+{
+ buf[snd_pos] = '\0';
+ snd_pos = 0;
+ iwrap_mux_send(buf);
+}
+
+void iwrap_call(void)
+{
+ char *p;
+
+ iwrap_mux_send("SET BT PAIR");
+ _delay_ms(500);
+
+ p = rcv_buf + rcv_tail;
+ while (!strncmp(p, "SET BT PAIR", 11)) {
+ p += 7;
+ strncpy(p, "CALL", 4);
+ strncpy(p+22, " 11 HID\n\0", 9);
+ print_S(p);
+ iwrap_mux_send(p);
+ // TODO: skip to next line
+ p += 57;
+
+ DEBUG_LED_CONFIG;
+ DEBUG_LED_ON;
+ _delay_ms(500);
+ DEBUG_LED_OFF;
+ _delay_ms(500);
+ DEBUG_LED_ON;
+ _delay_ms(500);
+ DEBUG_LED_OFF;
+ _delay_ms(500);
+ DEBUG_LED_ON;
+ _delay_ms(500);
+ DEBUG_LED_OFF;
+ _delay_ms(500);
+ DEBUG_LED_ON;
+ _delay_ms(500);
+ DEBUG_LED_OFF;
+ _delay_ms(500);
+ DEBUG_LED_ON;
+ _delay_ms(500);
+ DEBUG_LED_OFF;
+ _delay_ms(500);
+ }
+ iwrap_check_connection();
+}
+
+void iwrap_kill(void)
+{
+ char c;
+ iwrap_mux_send("LIST");
+ _delay_ms(500);
+
+ while ((c = rcv_deq()) && c != '\n') ;
+ if (strncmp(rcv_buf + rcv_tail, "LIST ", 5)) {
+ print("no connection to kill.\n");
+ return;
+ }
+ // skip 10 'space' chars
+ for (uint8_t i = 10; i; i--)
+ while ((c = rcv_deq()) && c != ' ') ;
+
+ char *p = rcv_buf + rcv_tail - 5;
+ strncpy(p, "KILL ", 5);
+ strncpy(p + 22, "\n\0", 2);
+ print_S(p);
+ iwrap_mux_send(p);
+ _delay_ms(500);
+
+ iwrap_check_connection();
+}
+
+void iwrap_unpair(void)
+{
+ iwrap_mux_send("SET BT PAIR");
+ _delay_ms(500);
+
+ char *p = rcv_buf + rcv_tail;
+ if (!strncmp(p, "SET BT PAIR", 11)) {
+ strncpy(p+29, "\n\0", 2);
+ print_S(p);
+ iwrap_mux_send(p);
+ }
+}
+
+void iwrap_sleep(void)
+{
+ iwrap_mux_send("SLEEP");
+}
+
+void iwrap_sniff(void)
+{
+}
+
+void iwrap_subrate(void)
+{
+}
+
+bool iwrap_failed(void)
+{
+ if (strncmp(rcv_buf, "SYNTAX ERROR", 12))
+ return true;
+ else
+ return false;
+}
+
+uint8_t iwrap_connected(void)
+{
+ return connected;
+}
+
+uint8_t iwrap_check_connection(void)
+{
+ iwrap_mux_send("LIST");
+ _delay_ms(100);
+
+ if (strncmp(rcv_buf, "LIST ", 5) || !strncmp(rcv_buf, "LIST 0", 6))
+ connected = 0;
+ else
+ connected = 1;
+ return connected;
+}
+
+
+/*------------------------------------------------------------------*
+ * Host driver
+ *------------------------------------------------------------------*/
+static uint8_t keyboard_leds(void);
+static void send_keyboard(report_keyboard_t *report);
+static void send_mouse(report_mouse_t *report);
+static void send_system(uint16_t data);
+static void send_consumer(uint16_t data);
+
+static host_driver_t driver = {
+ keyboard_leds,
+ send_keyboard,
+ send_mouse,
+ send_system,
+ send_consumer
+};
+
+host_driver_t *iwrap_driver(void)
+{
+ return &driver;
+}
+
+static uint8_t keyboard_leds(void) {
+ return 0;
+}
+
+static void send_keyboard(report_keyboard_t *report)
+{
+ if (!iwrap_connected() && !iwrap_check_connection()) return;
+ MUX_HEADER(0x01, 0x0c);
+ // HID raw mode header
+ xmit(0x9f);
+ xmit(0x0a); // Length
+ xmit(0xa1); // keyboard report
+ xmit(0x01);
+ xmit(report->mods);
+ xmit(0x00); // reserved byte(always 0)
+ xmit(report->keys[0]);
+ xmit(report->keys[1]);
+ xmit(report->keys[2]);
+ xmit(report->keys[3]);
+ xmit(report->keys[4]);
+ xmit(report->keys[5]);
+ MUX_FOOTER(0x01);
+}
+
+static void send_mouse(report_mouse_t *report)
+{
+#if defined(MOUSEKEY_ENABLE) || defined(PS2_MOUSE_ENABLE)
+ if (!iwrap_connected() && !iwrap_check_connection()) return;
+ MUX_HEADER(0x01, 0x07);
+ // HID raw mode header
+ xmit(0x9f);
+ xmit(0x05); // Length
+ xmit(0xa1); // mouse report
+ xmit(0x02);
+ xmit(report->buttons);
+ xmit(report->x);
+ xmit(report->y);
+ MUX_FOOTER(0x01);
+#endif
+}
+
+static void send_system(uint16_t data)
+{
+ /* not supported */
+}
+
+static void send_consumer(uint16_t data)
+{
+#ifdef EXTRAKEY_ENABLE
+ static uint16_t last_data = 0;
+ uint8_t bits1 = 0;
+ uint8_t bits2 = 0;
+ uint8_t bits3 = 0;
+
+ if (!iwrap_connected() && !iwrap_check_connection()) return;
+ if (data == last_data) return;
+ last_data = data;
+
+ // 3.10 HID raw mode(iWRAP_HID_Application_Note.pdf)
+ switch (data) {
+ case AUDIO_VOL_UP:
+ bits1 = 0x01;
+ break;
+ case AUDIO_VOL_DOWN:
+ bits1 = 0x02;
+ break;
+ case AUDIO_MUTE:
+ bits1 = 0x04;
+ break;
+ case TRANSPORT_PLAY_PAUSE:
+ bits1 = 0x08;
+ break;
+ case TRANSPORT_NEXT_TRACK:
+ bits1 = 0x10;
+ break;
+ case TRANSPORT_PREV_TRACK:
+ bits1 = 0x20;
+ break;
+ case TRANSPORT_STOP:
+ bits1 = 0x40;
+ break;
+ case TRANSPORT_EJECT:
+ bits1 = 0x80;
+ break;
+ case AL_EMAIL:
+ bits2 = 0x01;
+ break;
+ case AC_SEARCH:
+ bits2 = 0x02;
+ break;
+ case AC_BOOKMARKS:
+ bits2 = 0x04;
+ break;
+ case AC_HOME:
+ bits2 = 0x08;
+ break;
+ case AC_BACK:
+ bits2 = 0x10;
+ break;
+ case AC_FORWARD:
+ bits2 = 0x20;
+ break;
+ case AC_STOP:
+ bits2 = 0x40;
+ break;
+ case AC_REFRESH:
+ bits2 = 0x80;
+ break;
+ case AL_CC_CONFIG:
+ bits3 = 0x01;
+ break;
+ case AL_CALCULATOR:
+ bits3 = 0x04;
+ break;
+ case AL_LOCK:
+ bits3 = 0x08;
+ break;
+ case AL_LOCAL_BROWSER:
+ bits3 = 0x10;
+ break;
+ case AC_MINIMIZE:
+ bits3 = 0x20;
+ break;
+ case TRANSPORT_RECORD:
+ bits3 = 0x40;
+ break;
+ case TRANSPORT_REWIND:
+ bits3 = 0x80;
+ break;
+ }
+
+ MUX_HEADER(0x01, 0x07);
+ xmit(0x9f);
+ xmit(0x05); // Length
+ xmit(0xa1); // consumer report
+ xmit(0x03);
+ xmit(bits1);
+ xmit(bits2);
+ xmit(bits3);
+ MUX_FOOTER(0x01);
+#endif
+}
diff --git a/protocol/iwrap/iwrap.h b/protocol/iwrap/iwrap.h
new file mode 100644
index 000000000..ffaad9395
--- /dev/null
+++ b/protocol/iwrap/iwrap.h
@@ -0,0 +1,49 @@
+/*
+Copyright 2011 Jun Wako <wakojun@gmail.com>
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef IWRAP_H
+#define IWRAP_H
+
+#include <stdint.h>
+#include <stdbool.h>
+#include "host_driver.h"
+
+
+/* enable iWRAP MUX mode */
+#define MUX_MODE
+
+
+host_driver_t *iwrap_driver(void);
+
+void iwrap_init(void);
+void iwrap_send(const char *s);
+void iwrap_mux_send(const char *s);
+void iwrap_buf_send(void);
+void iwrap_buf_add(uint8_t c);
+void iwrap_buf_del(void);
+
+void iwrap_call(void);
+void iwrap_kill(void);
+void iwrap_unpair(void);
+void iwrap_sleep(void);
+void iwrap_sniff(void);
+void iwrap_subrate(void);
+bool iwrap_failed(void);
+uint8_t iwrap_connected(void);
+uint8_t iwrap_check_connection(void);
+
+#endif
diff --git a/protocol/iwrap/main.c b/protocol/iwrap/main.c
new file mode 100644
index 000000000..a552afb67
--- /dev/null
+++ b/protocol/iwrap/main.c
@@ -0,0 +1,378 @@
+/*
+Copyright 2011 Jun Wako <wakojun@gmail.com>
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+#include <stdint.h>
+#include <avr/interrupt.h>
+#include <avr/io.h>
+//#include <avr/wdt.h>
+#include "wd.h" // in order to use watchdog in interrupt mode
+#include <avr/sleep.h>
+#include <util/delay.h>
+#include <avr/power.h>
+#include "keyboard.h"
+#include "matrix.h"
+#include "host.h"
+#include "iwrap.h"
+#ifdef HOST_VUSB
+# include "vusb.h"
+# include "usbdrv.h"
+#endif
+#include "uart.h"
+#include "suart.h"
+#include "timer.h"
+#include "debug.h"
+#include "usb_keycodes.h"
+#include "command.h"
+
+
+static void sleep(uint8_t term);
+static bool console(void);
+static uint8_t console_command(uint8_t c);
+static uint8_t key2asc(uint8_t key);
+
+
+/*
+static void set_prr(void)
+{
+ power_adc_disable();
+ power_spi_disable();
+ power_twi_disable();
+#ifndef TIMER_H
+ //power_timer0_disable(); // used in timer.c
+#endif
+ power_timer1_disable();
+ power_timer2_disable();
+}
+*/
+
+/*
+static void pullup_pins(void)
+{
+ // DDRs are set to 0(input) by default.
+#ifdef PORTA
+ PORTA = 0xFF;
+#endif
+ PORTB = 0xFF;
+ PORTC = 0xFF;
+ PORTD = 0xFF;
+#ifdef PORTE
+ PORTE = 0xFF;
+#endif
+#ifdef PORTE
+ PORTF = 0xFF;
+#endif
+}
+*/
+
+
+#ifdef HOST_VUSB
+static void disable_vusb(void)
+{
+ // disable interrupt & disconnect to prevent host from enumerating
+ USB_INTR_ENABLE &= ~(1 << USB_INTR_ENABLE_BIT);
+ usbDeviceDisconnect();
+}
+
+static void enable_vusb(void)
+{
+ USB_INTR_ENABLE |= (1 << USB_INTR_ENABLE_BIT);
+ usbDeviceConnect();
+}
+
+static void init_vusb(void)
+{
+ uint8_t i = 0;
+
+ usbInit();
+ disable_vusb();
+ /* fake USB disconnect for > 250 ms */
+ while(--i){
+ _delay_ms(1);
+ }
+ enable_vusb();
+}
+#endif
+
+void change_driver(host_driver_t *driver)
+{
+ host_clear_keyboard_report();
+ host_swap_keyboard_report();
+ host_clear_keyboard_report();
+ host_send_keyboard_report();
+ _delay_ms(1000);
+ host_set_driver(driver);
+}
+
+
+static bool sleeping = false;
+static bool insomniac = false; // TODO: should be false for power saving
+static uint16_t last_timer = 0;
+
+int main(void)
+{
+ MCUSR = 0;
+ clock_prescale_set(clock_div_1);
+ WD_SET(WD_OFF);
+
+ // power saving: the result is worse than nothing... why?
+ //pullup_pins();
+ //set_prr();
+
+ print_enable = true;
+ debug_enable = false;
+
+#ifdef HOST_VUSB
+ disable_vusb();
+#endif
+ uart_init(115200);
+ keyboard_init();
+ print("\nSend BREAK for UART Console Commands.\n");
+
+ // TODO: move to iWRAP/suart file
+ print("suart init\n");
+ // suart init
+ // PC4: Tx Output IDLE(Hi)
+ PORTC |= (1<<4);
+ DDRC |= (1<<4);
+ // PC5: Rx Input(pull-up)
+ PORTC |= (1<<5);
+ DDRC &= ~(1<<5);
+ // suart receive interrut(PC5/PCINT13)
+ PCMSK1 = 0b00100000;
+ PCICR = 0b00000010;
+
+ host_set_driver(iwrap_driver());
+
+ print("iwrap_init()\n");
+ iwrap_init();
+ iwrap_call();
+
+ last_timer = timer_read();
+ while (true) {
+#ifdef HOST_VUSB
+ if (host_get_driver() == vusb_driver())
+ usbPoll();
+#endif
+ keyboard_proc();
+#ifdef HOST_VUSB
+ if (host_get_driver() == vusb_driver())
+ vusb_transfer_keyboard();
+#endif
+ if (matrix_is_modified() || console()) {
+ last_timer = timer_read();
+ sleeping = false;
+ } else if (!sleeping && timer_elapsed(last_timer) > 4000) {
+ sleeping = true;
+ iwrap_check_connection();
+ }
+
+ if (host_get_driver() == iwrap_driver()) {
+ if (sleeping && !insomniac) {
+ _delay_ms(1); // wait for UART to send
+ iwrap_sleep();
+ sleep(WDTO_60MS);
+ }
+ }
+ }
+}
+
+static void sleep(uint8_t term)
+{
+ WD_SET(WD_IRQ, term);
+
+ cli();
+ set_sleep_mode(SLEEP_MODE_PWR_DOWN);
+ sleep_enable();
+ sleep_bod_disable();
+ sei();
+ sleep_cpu();
+ sleep_disable();
+
+ WD_SET(WD_OFF);
+}
+
+ISR(WDT_vect)
+{
+ // wake up
+}
+
+static bool console(void)
+{
+ // Send to Bluetoot module WT12
+ static bool breaked = false;
+ if (!uart_available())
+ return false;
+ else {
+ uint8_t c;
+ c = uart_getchar();
+ uart_putchar(c);
+ switch (c) {
+ case 0x00: // BREAK signal
+ if (!breaked) {
+ print("break(? for help): ");
+ breaked = true;
+ }
+ break;
+ case '\r':
+ uart_putchar('\n');
+ iwrap_buf_send();
+ break;
+ case '\b':
+ iwrap_buf_del();
+ break;
+ default:
+ if (breaked) {
+ print("\n");
+ console_command(c);
+ breaked = false;
+ } else {
+ iwrap_buf_add(c);
+ }
+ break;
+ }
+ return true;
+ }
+}
+
+uint8_t command_extra()
+{
+ return console_command(key2asc(host_get_first_key()));
+}
+
+static uint8_t console_command(uint8_t c)
+{
+ switch (c) {
+ case 'h':
+ case '?':
+ print("\nCommands for Bluetooth(WT12/iWRAP):\n");
+ print("r: reset. software reset by watchdog\n");
+ print("i: insomniac. prevent KB from sleeping\n");
+ print("c: iwrap_call. CALL for BT connection.\n");
+#ifdef HOST_VUSB
+ print("u: USB mode. switch to USB.\n");
+ print("w: BT mode. switch to Bluetooth.\n");
+#endif
+ print("k: kill first connection.\n");
+ print("Del: unpair first pairing.\n");
+ print("\n");
+ return 0;
+ case 'r':
+ print("reset\n");
+ WD_AVR_RESET();
+ return 1;
+ case 'i':
+ insomniac = !insomniac;
+ if (insomniac)
+ print("insomniac\n");
+ else
+ print("not insomniac\n");
+ return 1;
+ case 'c':
+ print("iwrap_call()\n");
+ iwrap_call();
+ return 1;
+#ifdef HOST_VUSB
+ case 'u':
+ print("USB mode\n");
+ init_vusb();
+ change_driver(vusb_driver());
+ //iwrap_kill();
+ //iwrap_sleep();
+ // disable suart receive interrut(PC5/PCINT13)
+ PCMSK1 &= ~(0b00100000);
+ PCICR &= ~(0b00000010);
+ return 1;
+ case 'w':
+ print("iWRAP mode\n");
+ change_driver(iwrap_driver());
+ disable_vusb();
+ // enable suart receive interrut(PC5/PCINT13)
+ PCMSK1 |= 0b00100000;
+ PCICR |= 0b00000010;
+ return 1;
+#endif
+ case 'k':
+ print("kill\n");
+ iwrap_kill();
+ return 1;
+ case 0x7F: // DELETE
+ print("unpair\n");
+ iwrap_unpair();
+ return 1;
+ }
+ return 0;
+}
+
+// convert keycode into ascii charactor
+static uint8_t key2asc(uint8_t key)
+{
+ switch (key) {
+ case KB_A: return 'a';
+ case KB_B: return 'b';
+ case KB_C: return 'c';
+ case KB_D: return 'd';
+ case KB_E: return 'e';
+ case KB_F: return 'f';
+ case KB_G: return 'g';
+ case KB_H: return 'h';
+ case KB_I: return 'i';
+ case KB_J: return 'j';
+ case KB_K: return 'k';
+ case KB_L: return 'l';
+ case KB_M: return 'm';
+ case KB_N: return 'n';
+ case KB_O: return 'o';
+ case KB_P: return 'p';
+ case KB_Q: return 'q';
+ case KB_R: return 'r';
+ case KB_S: return 's';
+ case KB_T: return 't';
+ case KB_U: return 'u';
+ case KB_V: return 'v';
+ case KB_W: return 'w';
+ case KB_X: return 'x';
+ case KB_Y: return 'y';
+ case KB_Z: return 'z';
+ case KB_1: return '1';
+ case KB_2: return '2';
+ case KB_3: return '3';
+ case KB_4: return '4';
+ case KB_5: return '5';
+ case KB_6: return '6';
+ case KB_7: return '7';
+ case KB_8: return '8';
+ case KB_9: return '9';
+ case KB_0: return '0';
+ case KB_ENTER: return '\n';
+ case KB_ESCAPE: return 0x1B;
+ case KB_BSPACE: return '\b';
+ case KB_TAB: return '\t';
+ case KB_SPACE: return ' ';
+ case KB_MINUS: return '-';
+ case KB_EQUAL: return '=';
+ case KB_LBRACKET: return '[';
+ case KB_RBRACKET: return ']';
+ case KB_BSLASH: return '\\';
+ case KB_NONUS_HASH: return '\\';
+ case KB_SCOLON: return ';';
+ case KB_QUOTE: return '\'';
+ case KB_GRAVE: return '`';
+ case KB_COMMA: return ',';
+ case KB_DOT: return '.';
+ case KB_SLASH: return '/';
+ default: return 0x00;
+ }
+}
diff --git a/protocol/iwrap/suart.S b/protocol/iwrap/suart.S
new file mode 100644
index 000000000..1b0290963
--- /dev/null
+++ b/protocol/iwrap/suart.S
@@ -0,0 +1,156 @@
+;---------------------------------------------------------------------------;
+; Software implemented UART module ;
+; (C)ChaN, 2005 (http://elm-chan.org/) ;
+;---------------------------------------------------------------------------;
+; Bit rate settings:
+;
+; 1MHz 2MHz 4MHz 6MHz 8MHz 10MHz 12MHz 16MHz 20MHz
+; 2.4kbps 138 - - - - - - - -
+; 4.8kbps 68 138 - - - - - - -
+; 9.6kbps 33 68 138 208 - - - - -
+; 19.2kbps - 33 68 102 138 173 208 - -
+; 38.4kbps - - 33 50 68 85 102 138 172
+; 57.6kbps - - 21 33 44 56 68 91 114
+; 115.2kbps - - - - 21 27 33 44 56
+
+.nolist
+#include <avr/io.h>
+.list
+
+#define BPS 102 /* Bit delay. (see above table) */
+#define BIDIR 0 /* 0:Separated Tx/Rx, 1:Shared Tx/Rx */
+
+#define OUT_1 sbi _SFR_IO_ADDR(SUART_OUT_PORT), SUART_OUT_BIT /* Output 1 */
+#define OUT_0 cbi _SFR_IO_ADDR(SUART_OUT_PORT), SUART_OUT_BIT /* Output 0 */
+#define SKIP_IN_1 sbis _SFR_IO_ADDR(SUART_IN_PIN), SUART_IN_BIT /* Skip if 1 */
+#define SKIP_IN_0 sbic _SFR_IO_ADDR(SUART_IN_PIN), SUART_IN_BIT /* Skip if 0 */
+
+
+
+#ifdef SPM_PAGESIZE
+.macro _LPMI reg
+ lpm \reg, Z+
+.endm
+.macro _MOVW dh,dl, sh,sl
+ movw \dl, \sl
+.endm
+#else
+.macro _LPMI reg
+ lpm
+ mov \reg, r0
+ adiw ZL, 1
+.endm
+.macro _MOVW dh,dl, sh,sl
+ mov \dl, \sl
+ mov \dh, \sh
+.endm
+#endif
+
+
+
+;---------------------------------------------------------------------------;
+; Transmit a byte in serial format of N81
+;
+;Prototype: void xmit (uint8_t data);
+;Size: 16 words
+
+.global xmit
+.func xmit
+xmit:
+#if BIDIR
+ ldi r23, BPS-1 ;Pre-idle time for bidirectional data line
+5: dec r23 ;
+ brne 5b ;/
+#endif
+ in r0, _SFR_IO_ADDR(SREG) ;Save flags
+
+ com r24 ;C = start bit
+ ldi r25, 10 ;Bit counter
+ cli ;Start critical section
+
+1: ldi r23, BPS-1 ;----- Bit transferring loop
+2: dec r23 ;Wait for a bit time
+ brne 2b ;/
+ brcs 3f ;MISO = bit to be sent
+ OUT_1 ;
+3: brcc 4f ;
+ OUT_0 ;/
+4: lsr r24 ;Get next bit into C
+ dec r25 ;All bits sent?
+ brne 1b ; no, coutinue
+
+ out _SFR_IO_ADDR(SREG), r0 ;End of critical section
+ ret
+.endfunc
+
+
+
+;---------------------------------------------------------------------------;
+; Receive a byte
+;
+;Prototype: uint8_t rcvr (void);
+;Size: 19 words
+
+.global rcvr
+.func rcvr
+rcvr:
+ in r0, _SFR_IO_ADDR(SREG) ;Save flags
+
+ ldi r24, 0x80 ;Receiving shift reg
+ cli ;Start critical section
+
+1: SKIP_IN_1 ;Wait for idle
+ rjmp 1b
+2: SKIP_IN_0 ;Wait for start bit
+ rjmp 2b
+ ldi r25, BPS/2 ;Wait for half bit time
+3: dec r25
+ brne 3b
+
+4: ldi r25, BPS ;----- Bit receiving loop
+5: dec r25 ;Wait for a bit time
+ brne 5b ;/
+ lsr r24 ;Next bit
+ SKIP_IN_0 ;Get a data bit into r24.7
+ ori r24, 0x80
+ brcc 4b ;All bits received? no, continue
+
+ out _SFR_IO_ADDR(SREG), r0 ;End of critical section
+ ret
+.endfunc
+
+
+; Not wait for start bit. This should be called after detecting start bit.
+.global recv
+.func recv
+recv:
+ in r0, _SFR_IO_ADDR(SREG) ;Save flags
+
+ ldi r24, 0x80 ;Receiving shift reg
+ cli ;Start critical section
+
+;1: SKIP_IN_1 ;Wait for idle
+; rjmp 1b
+;2: SKIP_IN_0 ;Wait for start bit
+; rjmp 2b
+ ldi r25, BPS/2 ;Wait for half bit time
+3: dec r25
+ brne 3b
+
+4: ldi r25, BPS ;----- Bit receiving loop
+5: dec r25 ;Wait for a bit time
+ brne 5b ;/
+ lsr r24 ;Next bit
+ SKIP_IN_0 ;Get a data bit into r24.7
+ ori r24, 0x80
+ brcc 4b ;All bits received? no, continue
+
+ ldi r25, BPS/2 ;Wait for half bit time
+6: dec r25
+ brne 6b
+7: SKIP_IN_1 ;Wait for stop bit
+ rjmp 7b
+
+ out _SFR_IO_ADDR(SREG), r0 ;End of critical section
+ ret
+.endfunc
diff --git a/protocol/iwrap/suart.h b/protocol/iwrap/suart.h
new file mode 100644
index 000000000..72725b998
--- /dev/null
+++ b/protocol/iwrap/suart.h
@@ -0,0 +1,8 @@
+#ifndef SUART
+#define SUART
+
+void xmit(uint8_t);
+uint8_t rcvr(void);
+uint8_t recv(void);
+
+#endif /* SUART */
diff --git a/protocol/iwrap/wd.h b/protocol/iwrap/wd.h
new file mode 100644
index 000000000..99058f033
--- /dev/null
+++ b/protocol/iwrap/wd.h
@@ -0,0 +1,159 @@
+/* This is from http://www.mtcnet.net/~henryvm/wdt/ */
+#ifndef _AVR_WD_H_
+#define _AVR_WD_H_
+
+#include <avr/io.h>
+
+/*
+Copyright (c) 2009, Curt Van Maanen
+
+Permission to use, copy, modify, and/or distribute this software for any
+purpose with or without fee is hereby granted, provided that the above
+copyright notice and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+
+include usage-
+ #include "wd.h" //if in same directory as project
+ #include <avr/wd.h> //if wd.h is in avr directory
+
+set watchdog modes and prescale
+
+usage-
+ WD_SET(mode,[timeout]); //prescale always set
+
+modes-
+ WD_OFF disabled
+ WD_RST normal reset mode
+ WD_IRQ interrupt only mode (if supported)
+ WD_RST_IRQ interrupt+reset mode (if supported)
+
+timeout-
+ WDTO_15MS default if no timeout provided
+ WDTO_30MS
+ WDTO_60MS
+ WDTO_120MS
+ WDTO_250MS
+ WDTO_500MS
+ WDTO_1S
+ WDTO_2S
+ WDTO_4S (if supported)
+ WDTO_8S (if supported)
+
+examples-
+ WD_SET(WD_RST,WDTO_1S); //reset mode, 1s timeout
+ WD_SET(WD_OFF); //watchdog disabled (if not fused on)
+ WD_SET(WD_RST); //reset mode, 15ms (default timeout)
+ WD_SET(WD_IRQ,WDTO_120MS); //interrupt only mode, 120ms timeout
+ WD_SET(WD_RST_IRQ,WDTO_2S); //interrupt+reset mode, 2S timeout
+
+
+for enhanced watchdogs, if the watchdog is not being used WDRF should be
+cleared on every power up or reset, along with disabling the watchdog-
+ WD_DISABLE(); //clear WDRF, then turn off watchdog
+
+*/
+
+//reset registers to the same name (MCUCSR)
+#if !defined(MCUCSR)
+#define MCUCSR MCUSR
+#endif
+
+//watchdog registers to the same name (WDTCSR)
+#if !defined(WDTCSR)
+#define WDTCSR WDTCR
+#endif
+
+//if enhanced watchdog, define irq values, create disable macro
+#if defined(WDIF)
+#define WD_IRQ 0xC0
+#define WD_RST_IRQ 0xC8
+#define WD_DISABLE() do{ \
+ MCUCSR &= ~(1<<WDRF); \
+ WD_SET(WD_OFF); \
+ }while(0)
+#endif
+
+//all watchdogs
+#define WD_RST 8
+#define WD_OFF 0
+
+//prescale values
+#define WDTO_15MS 0
+#define WDTO_30MS 1
+#define WDTO_60MS 2
+#define WDTO_120MS 3
+#define WDTO_250MS 4
+#define WDTO_500MS 5
+#define WDTO_1S 6
+#define WDTO_2S 7
+
+//prescale values for avrs with WDP3
+#if defined(WDP3)
+#define WDTO_4S 0x20
+#define WDTO_8S 0x21
+#endif
+
+//watchdog reset
+#define WDR() __asm__ __volatile__("wdr")
+
+//avr reset using watchdog
+#define WD_AVR_RESET() do{ \
+ __asm__ __volatile__("cli"); \
+ WD_SET_UNSAFE(WD_RST); \
+ while(1); \
+ }while(0)
+
+/*set the watchdog-
+1. save SREG
+2. turn off irq's
+3. reset watchdog timer
+4. enable watchdog change
+5. write watchdog value
+6. restore SREG (restoring irq status)
+*/
+#define WD_SET(val,...) \
+ __asm__ __volatile__( \
+ "in __tmp_reg__,__SREG__" "\n\t" \
+ "cli" "\n\t" \
+ "wdr" "\n\t" \
+ "sts %[wdreg],%[wden]" "\n\t" \
+ "sts %[wdreg],%[wdval]" "\n\t" \
+ "out __SREG__,__tmp_reg__" "\n\t" \
+ : \
+ : [wdreg] "M" (&WDTCSR), \
+ [wden] "r" ((uint8_t)(0x18)), \
+ [wdval] "r" ((uint8_t)(val|(__VA_ARGS__+0))) \
+ : "r0" \
+)
+
+/*set the watchdog when I bit in SREG known to be clear-
+1. reset watchdog timer
+2. enable watchdog change
+5. write watchdog value
+*/
+#define WD_SET_UNSAFE(val,...) \
+ __asm__ __volatile__( \
+ "wdr" "\n\t" \
+ "sts %[wdreg],%[wden]" "\n\t" \
+ "sts %[wdreg],%[wdval]" "\n\t" \
+ : \
+ : [wdreg] "M" (&WDTCSR), \
+ [wden] "r" ((uint8_t)(0x18)), \
+ [wdval] "r" ((uint8_t)(val|(__VA_ARGS__+0))) \
+)
+
+
+//for compatibility with avr/wdt.h
+#define wdt_enable(val) WD_SET(WD_RST,val)
+#define wdt_disable() WD_SET(WD_OFF)
+
+
+#endif /* _AVR_WD_H_ */