first working prototype

Signed-off-by: Szymon Łopaciuk <szymon@lopaciuk.eu>
This commit is contained in:
Szymon Łopaciuk
2021-02-10 01:01:02 +00:00
parent 05dc2bf824
commit 5ae2e71abd
14 changed files with 965 additions and 272 deletions
+14 -5
View File
@@ -1,16 +1,25 @@
# stm32-adb2usb [WIP]
# stm32-adb2usb
A simple implementation of an ADB to USB converter for the STM32F103 'Blue Pill'.
This is work in progress and is not yet functional.
It is currently functional, but there are many ways in which it could be improved upon (see TODO).
Testing done on an STM32F103 (or rather actually a Chinese clone), but in the end should be compatible with other STM32 microcontrollers/boards.
This code is a Platform IO project reliant on ST's stm32duino, although I am sure it could be easily converted to something else.
## Useful resources
I aim to make the code as easy to follow as it is possible in this case, especially the part relating to the ADB protocol.
However, there are some resources that are very useful in understanding how the protocol works, and which I used:
By far the best and most comprehensive description of the ADB protocol and devices is Apple's [Guide to the Macintosh&copy; Family Hardware (2nd ed.)](https://archive.org/details/apple-guide-macintosh-family-hardware) (chapter 8, p. 287).
Some other resources that were useful to me as well:
- [ADB - The Untold Story: Space Aliens Ate My Mouse'](https://developer.apple.com/library/archive/technotes/hw/hw_01.html#//apple_ref/doc/uid/DTS10002470) by Apple, the most 'authoritative' source, but lacks some key spec features
- [ADB - The Untold Story: Space Aliens Ate My Mouse'](https://developer.apple.com/library/archive/technotes/hw/hw_01.html#//apple_ref/doc/uid/DTS10002470) by Apple, quick introduction to what ADB is about, but lacks some key spec features
- https://web.archive.org/save/http://85.226.187.247/_pdf/Processor_Memory/PIC1617/MIDRANGE/00591A.PDF
- Inside Macintosh volume V, pages 191-192, for the keycodes
- Inside Macintosh volume V, pages 191-192, for keycodes
- [This blog post](https://www.bigmessowires.com/2016/03/30/understanding-the-adb-service-request-signal/) which explains `Srq` and `Tlt`
## TODO
- [x] Make the keyboard work
- [ ] Make the mouse work
- [ ] Ditch bitfields as the ordering of bytes/bits is confusing and not super portable (see tests failing; passing around uint16_t and then casting to bitfield structs is really dodgy and I shouldn't be doing that)
- [ ] Handle SRQs and multiple devices of the same type properly
- [ ] Make the layout easier to customise (swap a control, or num lock, for fn?)
+4 -1
View File
@@ -19,8 +19,10 @@ build_flags =
-D USBD_VID=0x0483
-D USBD_PID=0x5711
-D USB_MANUFACTURER="STMicroelectronics"
-D USB_PRODUCT="Apple Desktop Bus Device"
-D USB_PRODUCT="Apple Desktop Bus Device"
-D HAL_PCD_MODULE_ENABLED
;-D PIO_FRAMEWORK_ARDUINO_ENABLE_CDC
;-D PIO_FRAMEWORK_ARDUINO_USB_FULLSPEED_FULLMODE
upload_flags = -c set CPUTAPID 0x2ba01477 ; Chinese clone, genuine is 0x1ba01477
debug_tool = stlink
upload_protocol = stlink
@@ -39,5 +41,6 @@ platform = native
build_flags =
-D USBCON
-D USBD_USE_HID_COMPOSITE
-D PIO_FRAMEWORK_ARDUINO_ENABLE_HID
-I $PROJECT_DIR/test/test_desktop/include
test_build_project_src = true
+29 -16
View File
@@ -2,21 +2,20 @@
#define ADB_h
#include <Arduino.h>
#include <stm32f1xx_hal_gpio.h>
#define ADB_DATA_PIN PB4
#define ADB_DATA_PORT GPIOB
#define ADB_DATA_PIN_NO 4
#define ADB_WRITE(bit) digitalWrite(ADB_DATA_PIN, bit)
//#define ADB_WRITE(bit) HAL_GPIO_WritePin(ADB_DATA_PORT, ADB_DATA_PIN_NO, (GPIO_PinState)(bit));
#define ADB_READ() (digitalRead(ADB_DATA_PIN))
//#define ADB_READ() HAL_GPIO_ReadPin(ADB_DATA_PORT, ADB_DATA_PIN_NO)
#define ADB_ADDRESS(addr) (addr << 4)
#define ADB_REGISTER(reg) (reg)
#define ADB_CMD_TALK 0b1100
#define ADB_CMD_LISTEN 0b1000
#define ADB_CMD_FLUSH 0b0001
#define ADB_CMD_TALK (0b11 << 2)
#define ADB_CMD_LISTEN (0b10 << 2)
#define ADB_CMD_FLUSH (0b01 << 2)
#define ADB_BIT_ERROR 0xFF
// Reset: signal low for 3 ms.
static void adb_reset() {
@@ -69,6 +68,13 @@ static void adb_write_bits(uint16_t bits, uint8_t length) {
}
}
// Like adb_write_bits, but add start and stop bits
static void adb_write_data_packet(uint16_t bits, uint8_t length) {
adb_write_bit(1);
adb_write_bits(bits, length);
adb_write_bit(0);
}
// Send the '0' stop bit, and listen for an SRQ.
// ``If a device in need of service issues a service request,
// it must do so within the 65 μs of the Stop Bits low time
@@ -92,13 +98,17 @@ void adb_write_command(uint8_t command_byte) {
adb_stop_bit_srq_listen(); // TODO: Handle the SRQ
}
// Stop-to-start time: period of 160 - 240 μs before device's
// Stop-to-start time: period of 140 - 260 μs before device's
// response when the bus is held high.
// Returns: true if the response is starting, false if timeout
static bool adb_wait_tlt() {
// spec says 160 μs, but it seems that Macintoshes allowed 140 μs,
// (see `ADB - The Untold Story: Space Aliens Ate My Mouse'):
static bool adb_wait_tlt(bool response_expected) {
ADB_WRITE(HIGH);
delayMicroseconds(140);
uint8_t i = 0;
while (ADB_READ() == HIGH && i < 240 && response_expected) {
delayMicroseconds(1);
i++;
}
return true;
}
@@ -111,7 +121,7 @@ static uint8_t adb_read_bit() {
// devices need to stick to 30% precision, 65 * 1.3 = 85 μs
// if this time is exceeded assume timeout
if (micros() - time_start > 85)
return 0xFF;
return ADB_BIT_ERROR;
}
auto low_time = micros() - time_start;
@@ -119,7 +129,7 @@ static uint8_t adb_read_bit() {
// devices need to stick to 30% precision, 65 * 1.3 = 85 μs
// if this time is exceeded assume timeout
if (micros() - time_start - low_time > 85)
return 0xFF;
return ADB_BIT_ERROR;
}
auto high_time = micros() - time_start - low_time;
@@ -129,14 +139,17 @@ static uint8_t adb_read_bit() {
// Read `length` bits from the bus into `buffer`.
bool adb_read_data_packet(uint16_t* buffer, uint8_t length)
{
uint8_t start_bit = adb_read_bit(); // should equal to '1'
if (start_bit != 0x1) {return false;}
if (adb_read_bit() != 0x1) { // start bit should equal to '1'
return false;
}
*buffer = 0;
for (uint8_t i = 0; i < length; i++)
{
uint8_t current_bit = adb_read_bit();
if (current_bit == 0xFF) return false;
if (current_bit == ADB_BIT_ERROR) {
return false;
}
*buffer <<= 1;
*buffer |= current_bit;
}
@@ -147,7 +160,7 @@ bool adb_read_data_packet(uint16_t* buffer, uint8_t length)
void adb_init() {
pinMode(ADB_DATA_PIN, OUTPUT_OPEN_DRAIN);
digitalWrite(ADB_DATA_PIN, HIGH);
ADB_WRITE(HIGH);
while (ADB_READ() == LOW); // wait for the bus
+72
View File
@@ -0,0 +1,72 @@
#ifndef ADB_DEVICES_h
#define ADB_DEVICES_h
#include <cstdint>
#include "adb.h"
#include "hid_keyboard.h"
#include "adb_structures.h"
adb_kb_data<adb_kb_modifiers> adb_keyboard_read_modifiers(bool* error) {
adb_kb_data<adb_kb_modifiers> modifiers = {0};
adb_write_command(ADB_CMD_TALK | ADB_ADDRESS(2) | ADB_REGISTER(2));
adb_wait_tlt(true);
*error = !adb_read_data_packet(&modifiers.raw, 16);
return modifiers;
}
adb_kb_data<adb_kb_keypress> adb_keyboard_read_key_press(bool* error) {
adb_kb_data<adb_kb_keypress> key_press = {0};
adb_write_command(ADB_CMD_TALK | ADB_ADDRESS(2) | ADB_REGISTER(0));
adb_wait_tlt(true);
*error = !adb_read_data_packet(&key_press.raw, 16);
return key_press;
}
adb_kb_data<adb_register3> adb_keyboard_read_register3(bool* error) {
adb_kb_data<adb_register3> reg3 = {0};
adb_write_command(ADB_CMD_TALK | ADB_ADDRESS(2) | ADB_REGISTER(3));
adb_wait_tlt(true);
*error = !adb_read_data_packet(&reg3.raw, 16);
return reg3;
}
bool adb_keyboard_update_register3(adb_kb_data<adb_register3> new_reg3, uint16_t mask, bool* error) {
// Read the initial value
adb_kb_data<adb_register3> reg3 = adb_keyboard_read_register3(error);
if (*error) return false;
delay(ADB_POLL_DELAY);
// Apply the change
reg3.raw = (reg3.raw & ~mask) | (new_reg3.raw & mask);
// Write the new value
adb_write_command(ADB_CMD_LISTEN | ADB_ADDRESS(2) | ADB_REGISTER(3));
adb_wait_tlt(false);
adb_write_data_packet(reg3.raw, 16);
delay(ADB_POLL_DELAY);
// Read the current value
reg3 = adb_keyboard_read_register3(error);
if (*error) return false;
// Check if update worked, return true
if ((reg3.raw & mask) == (new_reg3.raw & mask))
return true;
return false;
}
void adb_keyboard_write_leds(bool scroll, bool caps, bool num) {
adb_kb_data<adb_kb_modifiers> modifiers = {0};
modifiers.data.led_scroll = !scroll;
modifiers.data.led_caps = !caps;
modifiers.data.led_num = !num;
adb_write_command(ADB_CMD_LISTEN | ADB_ADDRESS(2) | ADB_REGISTER(2));
adb_wait_tlt(false);
adb_write_data_packet(modifiers.raw, 16);
}
#endif
+63
View File
@@ -0,0 +1,63 @@
#ifndef ADB_STRUCTURES_h
#define ADB_STRUCTURES_h
#include <cstdint>
#define KEY_POWER 0x66
#define ADB_KEY_POWER_DOWN 0x7F7F
#define ADB_KEY_POWER_UP 0xFFFF
#define ADB_KEY_LEFT_SHIFT 0x38
#define ADB_KEY_RIGHT_SHIFT 0x7B
#define ADB_KEY_LEFT_CONTROL 0x36
#define ADB_KEY_RIGHT_CONTROL 0x7D
#define ADB_KEY_LEFT_OPTION 0x3A
#define ADB_KEY_RIGHT_OPTION 0x7C
#define ADB_KEY_LEFT_COMMAND 0x37
#define ADB_KEY_RIGHT_COMMAND 0x37
#define ADB_KEY_CAPS_LOCK 0x39
struct adb_kb_keypress {
uint8_t key1 : 7;
bool released1 : 1;
uint8_t key0 : 7;
bool released0 : 1;
};
struct adb_kb_modifiers {
// Only on Apple Extended Keyboard:
bool led_num : 1; // 0, ditto
bool led_caps : 1; // 1, ditto
bool led_scroll : 1; // 2, changeable with `listen' command
uint8_t reserved1 : 3; // 53
bool scroll_lock : 1; // 6
bool num_lock : 1; // 7
// Apple Standard Keyboard:
bool command : 1; // 8
bool option : 1; // 9
bool shift : 1; // 10
bool control : 1; // 11
bool reset : 1; // 12
bool caps_lock : 1; // 13
bool backspace : 1; // 14
uint8_t reserved0 : 1; // 15
};
// Contains device info and params
struct adb_register3 {
uint8_t device_handler_id : 8;
uint8_t device_address : 4;
uint8_t reserved1 : 1; // must be 0
uint8_t srq_enable : 1;
uint8_t exceptional_event : 1; // device specific, always 1 if not used
uint8_t reserved0 : 1; // must be 0
};
template <typename T>
union adb_kb_data {
uint16_t raw;
T data;
};
#endif
+129
View File
@@ -0,0 +1,129 @@
#include "hid_keyboard.h"
#include "usbd_hid_composite_if.h"
#include <Arduino.h>
#include "keymap.h"
void hid_keyboard_init()
{
HID_Composite_Init(HID_KEYBOARD);
}
void hid_keyboard_close()
{
HID_Composite_DeInit(HID_KEYBOARD);
}
void hid_keyboard_send_report(hid_key_report* report)
{
uint8_t buf[8] = {report->modifiers, 0, report->keys[0],
report->keys[1], report->keys[2], report->keys[3], report->keys[4],
report->keys[5]
};
HID_Composite_keyboard_sendReport(buf, 8);
}
bool hid_keyboard_set_keys_from_adb_register(
hid_key_report* report, adb_kb_data<adb_kb_keypress> key_press) {
// Power button is a special case, residing in both octets:
if (key_press.raw == ADB_KEY_POWER_DOWN)
return hid_keyboard_update_key_in_report(report, KEY_POWER, false);
else if (key_press.raw == ADB_KEY_POWER_UP)
return hid_keyboard_update_key_in_report(report, KEY_POWER, true);
// Other keys:
bool report_changed = false;
// Higher octet key:
uint8_t key0 = key_press.data.key0;
if (adb_keymap_is_modifier(key0))
report_changed = hid_keyboard_update_modifier_in_report(
report, key0, key_press.data.released0);
else
report_changed = hid_keyboard_update_key_in_report(
report, adb_keycode_to_hid[key0], key_press.data.released0);
// Lower octet key:
uint8_t key1 = key_press.data.key1;
if (adb_keymap_is_modifier(key1))
report_changed = hid_keyboard_update_modifier_in_report(
report, key1, key_press.data.released1) || report_changed;
else
report_changed = hid_keyboard_update_key_in_report(
report, adb_keycode_to_hid[key1], key_press.data.released1) || report_changed;
return report_changed;
}
bool hid_keyboard_set_modifiers_from_adb_register(
hid_key_report* report, adb_kb_data<adb_kb_keypress> reg) {
// TODO: don't seem necessary, as modifiers still register normal keypresses
return false;
}
bool hid_keyboard_update_key_in_report(hid_key_report* report, uint8_t hid_keycode, bool released) {
// Sometimes the response from the ADB keyboard is rubbish:
// either an invalid key, or lifting a key that's not been pressed.
// This detects the first case, so we don't waste time processing it.
if (hid_keycode == KEY_NONE) return false;
if (released)
return hid_keyboard_remove_key_from_report(report, hid_keycode);
else
return hid_keyboard_add_key_to_report(report, hid_keycode);
}
bool hid_keyboard_update_modifier_in_report(hid_key_report* report, uint8_t adb_keycode, bool released) {
auto put_key = [released, report](uint8_t mask) mutable {
// no change if the modifier is already set
if (released == !(report->modifiers & mask)) return false;
// flip the modifier
if (!released) report->modifiers |= mask;
else report->modifiers &= ~mask;
return true;
};
if (adb_keycode == ADB_KEY_LEFT_SHIFT) return put_key(KEY_MOD_LSHIFT);
if (adb_keycode == ADB_KEY_RIGHT_SHIFT) return put_key(KEY_MOD_RSHIFT);
if (adb_keycode == ADB_KEY_LEFT_CONTROL) return put_key(KEY_MOD_LCTRL);
if (adb_keycode == ADB_KEY_RIGHT_CONTROL) return put_key(KEY_MOD_RCTRL);
if (adb_keycode == ADB_KEY_LEFT_OPTION) return put_key(KEY_MOD_LALT);
if (adb_keycode == ADB_KEY_RIGHT_OPTION) return put_key(KEY_MOD_RALT);
if (adb_keycode == ADB_KEY_LEFT_COMMAND) return put_key(KEY_MOD_LMETA);
if (adb_keycode == ADB_KEY_RIGHT_COMMAND) return put_key(KEY_MOD_RMETA);
return false; // unreachable
}
// Returns true if after execution the key is in the report
// in other words, returns false if insertion unsuccessful (report unchanged)
bool hid_keyboard_add_key_to_report(hid_key_report* report, uint8_t hid_keycode) {
int8_t free_slot = -1;
for (uint8_t i = 0; i < KEY_REPORT_KEYS_COUNT; i++) {
if (report->keys[i] == hid_keycode)
return true; // key is already in the report
if (report->keys[i] == 0 && free_slot == -1)
free_slot = i; // memorise empty entry idx
}
if (free_slot == -1)
return false; // key report is full
report->keys[free_slot] = hid_keycode;
return true;
}
bool hid_keyboard_remove_key_from_report(hid_key_report* report, uint8_t hid_keycode) {
bool report_changed = false;
for (uint8_t i = 0; i < KEY_REPORT_KEYS_COUNT; i++) {
if (report->keys[i] == hid_keycode) {
report->keys[i] = 0;
report_changed = true;
}
}
return report_changed;
}
//#endif
+24
View File
@@ -0,0 +1,24 @@
#ifndef HID_KEYBOARD_h
#define HID_KEYBOARD_h
#include <cstdint>
#include "adb_structures.h"
#define KEY_REPORT_KEYS_COUNT 6
struct hid_key_report {
uint8_t modifiers;
uint8_t keys[KEY_REPORT_KEYS_COUNT];
};
void hid_keyboard_init();
void hid_keyboard_close();
void hid_keyboard_send_report(hid_key_report* report);
bool hid_keyboard_set_keys_from_adb_register(hid_key_report* report, adb_kb_data<adb_kb_keypress> reg);
bool hid_keyboard_set_modifiers_from_adb_register(hid_key_report* report, adb_kb_data<adb_kb_keypress> reg);
bool hid_keyboard_update_key_in_report(hid_key_report* report, uint8_t hid_keycode, bool released);
bool hid_keyboard_update_modifier_in_report(hid_key_report* report, uint8_t adb_keycode, bool released);
bool hid_keyboard_add_key_to_report(hid_key_report* report, uint8_t hid_keycode);
bool hid_keyboard_remove_key_from_report(hid_key_report* report, uint8_t hid_keycode);
#endif
+274
View File
@@ -0,0 +1,274 @@
// https://www.usb.org/sites/default/files/documents/hut1_12v2.pdf, pp. 53
// adapted from https://gist.github.com/MightyPork/6da26e382a7ad91b5496ee55fdc73db2
#ifndef HID_TABLES_h
#define HID_TABLES_h
#define KEY_MOD_LCTRL 0x01
#define KEY_MOD_LSHIFT 0x02
#define KEY_MOD_LALT 0x04
#define KEY_MOD_LMETA 0x08
#define KEY_MOD_RCTRL 0x10
#define KEY_MOD_RSHIFT 0x20
#define KEY_MOD_RALT 0x40
#define KEY_MOD_RMETA 0x80
/**
* 0x00 if no key pressed.
*
* If more than N keys are pressed, the HID reports
* KEY_ERR_OVF in all slots to indicate this condition.
*/
#define KEY_NONE 0x00 // No key pressed
#define KEY_ERR_OVF 0x01 // Keyboard Error Roll Over - used for all slots if too many keys are pressed ("Phantom key")
// 0x02 // Keyboard POST Fail
// 0x03 // Keyboard Error Undefined
#define KEY_A 0x04 // Keyboard a and A
#define KEY_B 0x05 // Keyboard b and B
#define KEY_C 0x06 // Keyboard c and C
#define KEY_D 0x07 // Keyboard d and D
#define KEY_E 0x08 // Keyboard e and E
#define KEY_F 0x09 // Keyboard f and F
#define KEY_G 0x0a // Keyboard g and G
#define KEY_H 0x0b // Keyboard h and H
#define KEY_I 0x0c // Keyboard i and I
#define KEY_J 0x0d // Keyboard j and J
#define KEY_K 0x0e // Keyboard k and K
#define KEY_L 0x0f // Keyboard l and L
#define KEY_M 0x10 // Keyboard m and M
#define KEY_N 0x11 // Keyboard n and N
#define KEY_O 0x12 // Keyboard o and O
#define KEY_P 0x13 // Keyboard p and P
#define KEY_Q 0x14 // Keyboard q and Q
#define KEY_R 0x15 // Keyboard r and R
#define KEY_S 0x16 // Keyboard s and S
#define KEY_T 0x17 // Keyboard t and T
#define KEY_U 0x18 // Keyboard u and U
#define KEY_V 0x19 // Keyboard v and V
#define KEY_W 0x1a // Keyboard w and W
#define KEY_X 0x1b // Keyboard x and X
#define KEY_Y 0x1c // Keyboard y and Y
#define KEY_Z 0x1d // Keyboard z and Z
#define KEY_1 0x1e // Keyboard 1 and !
#define KEY_2 0x1f // Keyboard 2 and @
#define KEY_3 0x20 // Keyboard 3 and #
#define KEY_4 0x21 // Keyboard 4 and $
#define KEY_5 0x22 // Keyboard 5 and %
#define KEY_6 0x23 // Keyboard 6 and ^
#define KEY_7 0x24 // Keyboard 7 and &
#define KEY_8 0x25 // Keyboard 8 and *
#define KEY_9 0x26 // Keyboard 9 and (
#define KEY_0 0x27 // Keyboard 0 and )
#define KEY_ENTER 0x28 // Keyboard Return (ENTER)
#define KEY_ESC 0x29 // Keyboard ESCAPE
#define KEY_BACKSPACE 0x2a // Keyboard DELETE (Backspace)
#define KEY_TAB 0x2b // Keyboard Tab
#define KEY_SPACE 0x2c // Keyboard Spacebar
#define KEY_MINUS 0x2d // Keyboard - and _
#define KEY_EQUAL 0x2e // Keyboard = and +
#define KEY_LEFTBRACE 0x2f // Keyboard [ and {
#define KEY_RIGHTBRACE 0x30 // Keyboard ] and }
#define KEY_BACKSLASH 0x31 // Keyboard \ and |
#define KEY_HASHTILDE 0x32 // Keyboard Non-US # and ~
#define KEY_SEMICOLON 0x33 // Keyboard ; and :
#define KEY_APOSTROPHE 0x34 // Keyboard ' and "
#define KEY_GRAVE 0x35 // Keyboard ` and ~
#define KEY_COMMA 0x36 // Keyboard , and <
#define KEY_DOT 0x37 // Keyboard . and >
#define KEY_SLASH 0x38 // Keyboard / and ?
#define KEY_CAPSLOCK 0x39 // Keyboard Caps Lock
#define KEY_F1 0x3a // Keyboard F1
#define KEY_F2 0x3b // Keyboard F2
#define KEY_F3 0x3c // Keyboard F3
#define KEY_F4 0x3d // Keyboard F4
#define KEY_F5 0x3e // Keyboard F5
#define KEY_F6 0x3f // Keyboard F6
#define KEY_F7 0x40 // Keyboard F7
#define KEY_F8 0x41 // Keyboard F8
#define KEY_F9 0x42 // Keyboard F9
#define KEY_F10 0x43 // Keyboard F10
#define KEY_F11 0x44 // Keyboard F11
#define KEY_F12 0x45 // Keyboard F12
#define KEY_SYSRQ 0x46 // Keyboard Print Screen
#define KEY_SCROLLLOCK 0x47 // Keyboard Scroll Lock
#define KEY_PAUSE 0x48 // Keyboard Pause
#define KEY_INSERT 0x49 // Keyboard Insert
#define KEY_HOME 0x4a // Keyboard Home
#define KEY_PAGEUP 0x4b // Keyboard Page Up
#define KEY_DELETE 0x4c // Keyboard Delete Forward
#define KEY_END 0x4d // Keyboard End
#define KEY_PAGEDOWN 0x4e // Keyboard Page Down
#define KEY_RIGHT 0x4f // Keyboard Right Arrow
#define KEY_LEFT 0x50 // Keyboard Left Arrow
#define KEY_DOWN 0x51 // Keyboard Down Arrow
#define KEY_UP 0x52 // Keyboard Up Arrow
#define KEY_NUMLOCK 0x53 // Keyboard Num Lock and Clear
#define KEY_KPSLASH 0x54 // Keypad /
#define KEY_KPASTERISK 0x55 // Keypad *
#define KEY_KPMINUS 0x56 // Keypad -
#define KEY_KPPLUS 0x57 // Keypad +
#define KEY_KPENTER 0x58 // Keypad ENTER
#define KEY_KP1 0x59 // Keypad 1 and End
#define KEY_KP2 0x5a // Keypad 2 and Down Arrow
#define KEY_KP3 0x5b // Keypad 3 and PageDn
#define KEY_KP4 0x5c // Keypad 4 and Left Arrow
#define KEY_KP5 0x5d // Keypad 5
#define KEY_KP6 0x5e // Keypad 6 and Right Arrow
#define KEY_KP7 0x5f // Keypad 7 and Home
#define KEY_KP8 0x60 // Keypad 8 and Up Arrow
#define KEY_KP9 0x61 // Keypad 9 and Page Up
#define KEY_KP0 0x62 // Keypad 0 and Insert
#define KEY_KPDOT 0x63 // Keypad . and Delete
#define KEY_102ND 0x64 // Keyboard Non-US \ and |
#define KEY_COMPOSE 0x65 // Keyboard Application
#define KEY_POWER 0x66 // Keyboard Power
#define KEY_KPEQUAL 0x67 // Keypad =
#define KEY_F13 0x68 // Keyboard F13
#define KEY_F14 0x69 // Keyboard F14
#define KEY_F15 0x6a // Keyboard F15
#define KEY_F16 0x6b // Keyboard F16
#define KEY_F17 0x6c // Keyboard F17
#define KEY_F18 0x6d // Keyboard F18
#define KEY_F19 0x6e // Keyboard F19
#define KEY_F20 0x6f // Keyboard F20
#define KEY_F21 0x70 // Keyboard F21
#define KEY_F22 0x71 // Keyboard F22
#define KEY_F23 0x72 // Keyboard F23
#define KEY_F24 0x73 // Keyboard F24
#define KEY_OPEN 0x74 // Keyboard Execute
#define KEY_HELP 0x75 // Keyboard Help
#define KEY_PROPS 0x76 // Keyboard Menu
#define KEY_FRONT 0x77 // Keyboard Select
#define KEY_STOP 0x78 // Keyboard Stop
#define KEY_AGAIN 0x79 // Keyboard Again
#define KEY_UNDO 0x7a // Keyboard Undo
#define KEY_CUT 0x7b // Keyboard Cut
#define KEY_COPY 0x7c // Keyboard Copy
#define KEY_PASTE 0x7d // Keyboard Paste
#define KEY_FIND 0x7e // Keyboard Find
#define KEY_MUTE 0x7f // Keyboard Mute
#define KEY_VOLUMEUP 0x80 // Keyboard Volume Up
#define KEY_VOLUMEDOWN 0x81 // Keyboard Volume Down
// 0x82 Keyboard Locking Caps Lock
// 0x83 Keyboard Locking Num Lock
// 0x84 Keyboard Locking Scroll Lock
#define KEY_KPCOMMA 0x85 // Keypad Comma
// 0x86 Keypad Equal Sign
#define KEY_RO 0x87 // Keyboard International1
#define KEY_KATAKANAHIRAGANA 0x88 // Keyboard International2
#define KEY_YEN 0x89 // Keyboard International3
#define KEY_HENKAN 0x8a // Keyboard International4
#define KEY_MUHENKAN 0x8b // Keyboard International5
#define KEY_KPJPCOMMA 0x8c // Keyboard International6
// 0x8d Keyboard International7
// 0x8e Keyboard International8
// 0x8f Keyboard International9
#define KEY_HANGEUL 0x90 // Keyboard LANG1
#define KEY_HANJA 0x91 // Keyboard LANG2
#define KEY_KATAKANA 0x92 // Keyboard LANG3
#define KEY_HIRAGANA 0x93 // Keyboard LANG4
#define KEY_ZENKAKUHANKAKU 0x94 // Keyboard LANG5
// 0x95 Keyboard LANG6
// 0x96 Keyboard LANG7
// 0x97 Keyboard LANG8
// 0x98 Keyboard LANG9
// 0x99 Keyboard Alternate Erase
// 0x9a Keyboard SysReq/Attention
// 0x9b Keyboard Cancel
// 0x9c Keyboard Clear
// 0x9d Keyboard Prior
// 0x9e Keyboard Return
// 0x9f Keyboard Separator
// 0xa0 Keyboard Out
// 0xa1 Keyboard Oper
// 0xa2 Keyboard Clear/Again
// 0xa3 Keyboard CrSel/Props
// 0xa4 Keyboard ExSel
// 0xb0 Keypad 00
// 0xb1 Keypad 000
// 0xb2 Thousands Separator
// 0xb3 Decimal Separator
// 0xb4 Currency Unit
// 0xb5 Currency Sub-unit
#define KEY_KPLEFTPAREN 0xb6 // Keypad (
#define KEY_KPRIGHTPAREN 0xb7 // Keypad )
// 0xb8 Keypad {
// 0xb9 Keypad }
// 0xba Keypad Tab
// 0xbb Keypad Backspace
// 0xbc Keypad A
// 0xbd Keypad B
// 0xbe Keypad C
// 0xbf Keypad D
// 0xc0 Keypad E
// 0xc1 Keypad F
// 0xc2 Keypad XOR
// 0xc3 Keypad ^
// 0xc4 Keypad %
// 0xc5 Keypad <
// 0xc6 Keypad >
// 0xc7 Keypad &
// 0xc8 Keypad &&
// 0xc9 Keypad |
// 0xca Keypad ||
// 0xcb Keypad :
// 0xcc Keypad #
// 0xcd Keypad Space
// 0xce Keypad @
// 0xcf Keypad !
// 0xd0 Keypad Memory Store
// 0xd1 Keypad Memory Recall
// 0xd2 Keypad Memory Clear
// 0xd3 Keypad Memory Add
// 0xd4 Keypad Memory Subtract
// 0xd5 Keypad Memory Multiply
// 0xd6 Keypad Memory Divide
// 0xd7 Keypad +/-
// 0xd8 Keypad Clear
// 0xd9 Keypad Clear Entry
// 0xda Keypad Binary
// 0xdb Keypad Octal
// 0xdc Keypad Decimal
// 0xdd Keypad Hexadecimal
#define KEY_LEFTCTRL 0xe0 // Keyboard Left Control
#define KEY_LEFTSHIFT 0xe1 // Keyboard Left Shift
#define KEY_LEFTALT 0xe2 // Keyboard Left Alt
#define KEY_LEFTMETA 0xe3 // Keyboard Left GUI
#define KEY_RIGHTCTRL 0xe4 // Keyboard Right Control
#define KEY_RIGHTSHIFT 0xe5 // Keyboard Right Shift
#define KEY_RIGHTALT 0xe6 // Keyboard Right Alt
#define KEY_RIGHTMETA 0xe7 // Keyboard Right GUI
#define KEY_MEDIA_PLAYPAUSE 0xe8
#define KEY_MEDIA_STOPCD 0xe9
#define KEY_MEDIA_PREVIOUSSONG 0xea
#define KEY_MEDIA_NEXTSONG 0xeb
#define KEY_MEDIA_EJECTCD 0xec
#define KEY_MEDIA_VOLUMEUP 0xed
#define KEY_MEDIA_VOLUMEDOWN 0xee
#define KEY_MEDIA_MUTE 0xef
#define KEY_MEDIA_WWW 0xf0
#define KEY_MEDIA_BACK 0xf1
#define KEY_MEDIA_FORWARD 0xf2
#define KEY_MEDIA_STOP 0xf3
#define KEY_MEDIA_FIND 0xf4
#define KEY_MEDIA_SCROLLUP 0xf5
#define KEY_MEDIA_SCROLLDOWN 0xf6
#define KEY_MEDIA_EDIT 0xf7
#define KEY_MEDIA_SLEEP 0xf8
#define KEY_MEDIA_COFFEE 0xf9
#define KEY_MEDIA_REFRESH 0xfa
#define KEY_MEDIA_CALC 0xfb
#endif
+142 -5
View File
@@ -1,12 +1,149 @@
#ifndef KEYMAP_h
#define KEYMAP_h
#include <cstdint>
#include "hid_tables.h"
#define KEY_POWER 0x66
bool adb_keymap_is_modifier(uint8_t key) {
return \
(key == ADB_KEY_LEFT_SHIFT) ||
(key == ADB_KEY_RIGHT_SHIFT) ||
(key == ADB_KEY_LEFT_OPTION) ||
(key == ADB_KEY_RIGHT_OPTION) ||
(key == ADB_KEY_LEFT_COMMAND) ||
(key == ADB_KEY_RIGHT_COMMAND) ||
(key == ADB_KEY_LEFT_CONTROL) ||
(key == ADB_KEY_RIGHT_CONTROL);
}
#define ADB_KEY_POWER_DOWN 0x7F7F
#define ADB_KEY_POWER_UP 0xFFFF
uint8_t* adb_keycode_to_hid = {0x0}; // TODO
uint8_t adb_keycode_to_hid[128] = {
/* 0x00 = */ KEY_A,
/* 0x01 = */ KEY_S,
/* 0x02 = */ KEY_D,
/* 0x03 = */ KEY_F,
/* 0x04 = */ KEY_H,
/* 0x05 = */ KEY_G,
/* 0x06 = */ KEY_Z,
/* 0x07 = */ KEY_X,
/* 0x08 = */ KEY_C,
/* 0x09 = */ KEY_V,
/* 0x0a = */ KEY_102ND,
/* 0x0b = */ KEY_B,
/* 0x0c = */ KEY_Q,
/* 0x0d = */ KEY_W,
/* 0x0e = */ KEY_E,
/* 0x0f = */ KEY_R,
/* 0x10 = */ KEY_Y,
/* 0x11 = */ KEY_T,
/* 0x12 = */ KEY_1,
/* 0x13 = */ KEY_2,
/* 0x14 = */ KEY_3,
/* 0x15 = */ KEY_4,
/* 0x16 = */ KEY_6,
/* 0x17 = */ KEY_5,
/* 0x18 = */ KEY_EQUAL,
/* 0x19 = */ KEY_9,
/* 0x1a = */ KEY_7,
/* 0x1b = */ KEY_MINUS,
/* 0x1c = */ KEY_8,
/* 0x1d = */ KEY_0,
/* 0x1e = */ KEY_RIGHTBRACE,
/* 0x1f = */ KEY_O,
/* 0x20 = */ KEY_U,
/* 0x21 = */ KEY_LEFTBRACE,
/* 0x22 = */ KEY_I,
/* 0x23 = */ KEY_P,
/* 0x24 = */ KEY_ENTER,
/* 0x25 = */ KEY_L,
/* 0x26 = */ KEY_J,
/* 0x27 = */ KEY_APOSTROPHE,
/* 0x28 = */ KEY_K,
/* 0x29 = */ KEY_SEMICOLON,
/* 0x2a = */ KEY_HASHTILDE,
/* 0x2b = */ KEY_COMMA,
/* 0x2c = */ KEY_SLASH,
/* 0x2d = */ KEY_N,
/* 0x2e = */ KEY_M,
/* 0x2f = */ KEY_DOT,
/* 0x30 = */ KEY_TAB,
/* 0x31 = */ KEY_SPACE,
/* 0x32 = */ KEY_GRAVE,
/* 0x33 = */ KEY_BACKSPACE,
/* 0x34 = */ 0,
/* 0x35 = */ KEY_ESC,
/* 0x36 = */ KEY_LEFTCTRL,
/* 0x37 = */ KEY_LEFTMETA,
/* 0x38 = */ KEY_LEFTSHIFT,
/* 0x39 = */ KEY_CAPSLOCK,
/* 0x3a = */ KEY_LEFTALT,
/* 0x3b = */ KEY_LEFT,
/* 0x3c = */ KEY_RIGHT,
/* 0x3d = */ KEY_DOWN,
/* 0x3e = */ KEY_UP,
/* 0x3f = */ 0,
/* 0x40 = */ 0,
/* 0x41 = */ KEY_KPDOT,
/* 0x42 = */ 0,
/* 0x43 = */ KEY_KPASTERISK,
/* 0x44 = */ 0,
/* 0x45 = */ KEY_KPPLUS,
/* 0x46 = */ 0,
/* 0x47 = */ KEY_NUMLOCK,
/* 0x48 = */ 0,
/* 0x49 = */ 0,
/* 0x4a = */ 0,
/* 0x4b = */ KEY_KPSLASH,
/* 0x4c = */ KEY_KPENTER,
/* 0x4d = */ 0,
/* 0x4e = */ KEY_KPMINUS,
/* 0x4f = */ 0,
/* 0x50 = */ 0,
/* 0x51 = */ KEY_KPEQUAL,
/* 0x52 = */ KEY_KP0,
/* 0x53 = */ KEY_KP1,
/* 0x54 = */ KEY_KP2,
/* 0x55 = */ KEY_KP3,
/* 0x56 = */ KEY_KP4,
/* 0x57 = */ KEY_KP5,
/* 0x58 = */ KEY_KP6,
/* 0x59 = */ KEY_KP7,
/* 0x5a = */ 0,
/* 0x5b = */ KEY_KP8,
/* 0x5c = */ KEY_KP9,
/* 0x5d = */ 0,
/* 0x5e = */ 0,
/* 0x5f = */ 0,
/* 0x60 = */ KEY_F5,
/* 0x61 = */ KEY_F6,
/* 0x62 = */ KEY_F7,
/* 0x63 = */ KEY_F3,
/* 0x64 = */ KEY_F8,
/* 0x65 = */ KEY_F9,
/* 0x66 = */ 0,
/* 0x67 = */ KEY_VOLUMEDOWN, //KEY_F11,
/* 0x68 = */ 0,
/* 0x69 = */ KEY_F13,
/* 0x6a = */ 0,
/* 0x6b = */ KEY_F14,
/* 0x6c = */ 0,
/* 0x6d = */ KEY_MUTE, //KEY_F10,
/* 0x6e = */ 0,
/* 0x6f = */ KEY_VOLUMEUP, //KEY_F12,
/* 0x70 = */ 0,
/* 0x71 = */ KEY_F15,
/* 0x72 = */ KEY_HELP, // or KEY_INSERT
/* 0x73 = */ KEY_HOME,
/* 0x74 = */ KEY_PAGEUP,
/* 0x75 = */ KEY_DELETE,
/* 0x76 = */ KEY_F4,
/* 0x77 = */ KEY_END,
/* 0x78 = */ KEY_F2,
/* 0x79 = */ KEY_PAGEDOWN,
/* 0x7a = */ KEY_F1,
/* 0x7b = */ KEY_RIGHTSHIFT,
/* 0x7c = */ KEY_RIGHTALT,
/* 0x7d = */ KEY_RIGHTCTRL,
/* 0x7e = */ 0,
/* 0x7f = */ KEY_POWER, // Special key, repeated in both bytes of the register
};
#endif
+98 -44
View File
@@ -2,66 +2,120 @@
#include <Arduino.h>
#include <stm32f1xx_hal_gpio.h>
#include <Keyboard.h>
#include "adb.h"
#include "hid_tables.h"
#include "adb_structures.h"
#include "hid_keyboard.h"
#include "adb_devices.h"
void setup() {
Keyboard.begin();
pinMode(PC13, OUTPUT);
digitalWrite(PC13, LOW);
#define POLL_DELAY 5
delay(5000);
digitalWrite(PC13, HIGH);
Keyboard.print("Setting up IO...\n");
pinMode(ADB_DATA_PIN, OUTPUT_OPEN_DRAIN);
ADB_WRITE(HIGH);
Keyboard.print("Waiting for ADB high... ");
while(LOW == ADB_READ());
Keyboard.print("Ready.\n");
Keyboard.print("Resetting... ");
adb_reset();
delay(500); // A wait for good measure, apparently AEKII can take a moment to reset
Keyboard.print("Ready.\n");
}
bool apple_extended_detected = false;
#ifdef PIO_FRAMEWORK_ARDUINO_ENABLE_CDC
void print16b(uint16_t buff) {
uint16_t mask = (1 << 15);
for (uint8_t i = 0; i < 16; i++)
{
Keyboard.write(buff & mask ? '1' : '0');
Serial.write(buff & mask ? '1' : '0');
mask >>= 1;
}
Serial.write('\n');
Serial.flush();
}
void printkbresp(uint16_t buff) {
void printkbresp(adb_kb_keypress buff) {
//Keyboard.print(" key1 ");
Keyboard.print(buff & (1 << 15) ? "u" : "d");
Keyboard.print((buff & (0x7F << 8)) >> 8, 16);
//Keyboard.print(" key2 ");
//Keyboard.print(buff & (1 << 7) ? "up \t" : "down\t");
//Keyboard.print(buff & 0x7F, 16);
Keyboard.print("\n");
Serial.print(buff.released0 ? "u" : "d");
Serial.print(buff.key0, 16);
Serial.print(", ");
Serial.print(buff.released1 ? "u" : "d");
Serial.print(buff.key1, 16);
Serial.print("\n");
Serial.flush();
}
#endif
void setup() {
// Turn the led on at the beginning of setup
pinMode(PC13, OUTPUT);
digitalWrite(PC13, LOW);
#ifdef PIO_FRAMEWORK_ARDUINO_ENABLE_CDC
Serial.begin(115200);
#endif
// Set up HID
hid_keyboard_init();
// Set up the ADB bus
adb_init();
delay(1000); // A wait for good measure, apparently AEKII can take a moment to reset
// Initialise the ADB devices
// Switch the keyboard to Apple Extended if available
bool error = false;
adb_kb_data<adb_register3> reg3 = {0}, mask = {0};
reg3.data.device_handler_id = 0x03;
mask.data.device_handler_id = 0xFF;
apple_extended_detected = adb_keyboard_update_register3(reg3, mask.raw, &error);
// Set-up successful, turn of the LED
digitalWrite(PC13, HIGH);
}
void loop() {
//Keyboard.print("Talk addr 3 reg 0... ");
//noInterrupts();
uint16_t buffer = 0;
adb_write_command(ADB_CMD_TALK | ADB_ADDRESS(2) | ADB_REGISTER(0));
adb_wait_tlt();
bool success = adb_read_data_packet(&buffer, 17);
//interrupts();
if (success) {
//print16b(buffer);
printkbresp(buffer);
// TODO: Add proper polling based on SRQ
static bool led_caps = false;
static hid_key_report key_report = {0};
bool error = false;
auto key_press = adb_keyboard_read_key_press(&error);
if (error) return; // don't continue changing the hid report if there was
// an error reading from ADB most often it's a timeout
bool report_changed = hid_keyboard_set_keys_from_adb_register(&key_report, key_press);
// Handle the `toggle' caps lock key.
// Every action reported by an ADB keyboard on the caps lock key
// should be interpreted as key down, followed by key released,
// unless the keypress was so fast, that it was pressed and depressed
// within the same `register'. Then ignore.
bool caps_lock_action = key_press.data.key0 == ADB_KEY_CAPS_LOCK ||
key_press.data.key1 == ADB_KEY_CAPS_LOCK;
bool caps_lock_twice_in_register = key_press.data.key0 == ADB_KEY_CAPS_LOCK &&
key_press.data.key1 == ADB_KEY_CAPS_LOCK &&
key_press.data.released0 != key_press.data.released1;
if (caps_lock_action && !caps_lock_twice_in_register)
{
hid_keyboard_add_key_to_report(&key_report, KEY_CAPSLOCK);
// Send the preliminary report, with caps lock down
hid_keyboard_send_report(&key_report);
led_caps = !led_caps;
adb_keyboard_write_leds(0, led_caps, 0);
// Wait a little bit
delay(80);
// Now just release the caps lock key, and continue as before
hid_keyboard_remove_key_from_report(&key_report, KEY_CAPSLOCK);
report_changed = true;
}
//else
// Keyboard.print("timeout.\n");
delay(5);
// Send the finished report
if (report_changed)
hid_keyboard_send_report(&key_report);
// Wait a tiny bit before polling again,
// while ADB seems fairly tolarent of quick requests
// we don't want to overwhelm USB either
delay(POLL_DELAY);
}
#endif
-94
View File
@@ -1,94 +0,0 @@
#include <Arduino.h>
#include "raw_keyboard.h"
#include "keymap.h"
#if defined(USBCON)
#include "usbd_hid_composite_if.h"
RawKeyboard::RawKeyboard() {
keyReport = (KeyReport) {0};
}
void RawKeyboard::begin(void)
{
HID_Composite_Init(HID_KEYBOARD);
}
void RawKeyboard::end(void)
{
HID_Composite_DeInit(HID_KEYBOARD);
}
void RawKeyboard::sendReport()
{
uint8_t buf[8] = {keyReport.modifiers, keyReport.reserved, keyReport.keys[0],
keyReport.keys[1], keyReport.keys[2], keyReport.keys[3], keyReport.keys[4],
keyReport.keys[5]
};
HID_Composite_keyboard_sendReport(buf, 8);
//delay required to prevent persistent key when call print
delay(20);
}
void RawKeyboard::setKeysFromADBRegister(uint16_t reg) {
if (reg == ADB_KEY_POWER_DOWN) // power button is a special case
{ // residing in both octets
updateKeyInReport(KEY_POWER, false);
}
else if (reg == ADB_KEY_POWER_UP) {
updateKeyInReport(KEY_POWER, true);
}
else {
// Higher octet key:
uint8_t key0 = (reg >> 8) & 0x7F;
bool released0 = (reg >> 8) & 0x80;
updateKeyInReport(adb_keycode_to_hid[key0], released0);
// Lower octet key:
uint8_t key1 = reg & 0x7F;
bool released1 = reg & 0x80;
updateKeyInReport(adb_keycode_to_hid[key1], released1);
}
}
void RawKeyboard::setModifiersFromADBRegister(uint16_t reg) {
}
void RawKeyboard::updateKeyInReport(uint8_t hid_keycode, bool released) {
if (released)
removeKeyFromReport(hid_keycode);
else
addKeyToReport(hid_keycode);
}
// Returns true if after execution the key is in the report
bool RawKeyboard::addKeyToReport(uint8_t hid_keycode) {
int8_t free_slot = -1;
for (uint8_t i = 0; i < KEY_REPORT_KEYS_COUNT; i++) {
if (keyReport.keys[i] == hid_keycode)
return true; // key is already in the report
if (keyReport.keys[i] == 0 && free_slot == -1)
free_slot = i; // memorise empty entry idx
}
if (free_slot == -1)
return false; // key report is full
keyReport.keys[free_slot] = hid_keycode;
return true;
}
void RawKeyboard::removeKeyFromReport(uint8_t hid_keycode) {
for (uint8_t i = 0; i < KEY_REPORT_KEYS_COUNT; i++) {
if (keyReport.keys[i] == hid_keycode) {
keyReport.keys[i] = 0;
}
}
}
#endif
-38
View File
@@ -1,38 +0,0 @@
#ifndef RAWKEYBOARD_h
#define RAWKEYBOARD_h
#if !defined(USBCON) || !defined(USBD_USE_HID_COMPOSITE)
#error "USB HID not enabled! Select 'HID' in the 'Tools->USB interface' menu."
#else
#include <cstdint>
#define KEY_REPORT_KEYS_COUNT 6
typedef struct {
uint8_t modifiers;
uint8_t reserved;
uint8_t keys[6];
} KeyReport;
class RawKeyboard {
private:
RawKeyboard();
KeyReport keyReport;
void updateKeyInReport(uint8_t hid_keycode, bool released);
bool addKeyToReport(uint8_t hid_keycode);
void removeKeyFromReport(uint8_t hid_keycode);
public:
void begin();
void end();
void setKeysFromADBRegister(uint16_t);
void setModifiersFromADBRegister(uint16_t);
void sendReport();
};
#endif
#endif
-69
View File
@@ -1,69 +0,0 @@
#define private public
#pragma GCC diagnostic ignored "-Wc++11-extensions"
#include <unity.h>
#include "raw_keyboard.h"
// void setUp(void) {
// // set stuff up here
// }
// void tearDown(void) {
// // clean stuff up here
// }
void test_keyReport_empty(void) {
RawKeyboard k;
for (uint8_t i = 0; i < 6; i++)
TEST_ASSERT_EQUAL(0, k.keyReport.keys[i]);
TEST_ASSERT_EQUAL(0, k.keyReport.reserved);
TEST_ASSERT_EQUAL(0, k.keyReport.modifiers);
}
void test_addKeyToReport(void) {
RawKeyboard k;
TEST_ASSERT_TRUE(k.addKeyToReport(1));
TEST_ASSERT_TRUE(k.addKeyToReport(2));
TEST_ASSERT_TRUE(k.addKeyToReport(3));
TEST_ASSERT_TRUE(k.addKeyToReport(2));
TEST_ASSERT_EQUAL(1, k.keyReport.keys[0]);
TEST_ASSERT_EQUAL(2, k.keyReport.keys[1]);
TEST_ASSERT_EQUAL(3, k.keyReport.keys[2]);
TEST_ASSERT_EQUAL(0, k.keyReport.keys[3]);
TEST_ASSERT_EQUAL(0, k.keyReport.keys[4]);
TEST_ASSERT_EQUAL(0, k.keyReport.keys[5]);
}
void test_removeKeyFromReport(void) {
RawKeyboard k;
uint8_t initial_keys[] = {7, 8, 9, 0, 0, 0};
for (uint8_t i = 0; i < 6; i++) {
k.keyReport.keys[i] = initial_keys[i];
}
k.removeKeyFromReport(7);
k.removeKeyFromReport(9);
k.removeKeyFromReport(7);
TEST_ASSERT_EQUAL(0, k.keyReport.keys[0]);
TEST_ASSERT_EQUAL(8, k.keyReport.keys[1]);
TEST_ASSERT_EQUAL(0, k.keyReport.keys[2]);
TEST_ASSERT_EQUAL(0, k.keyReport.keys[3]);
TEST_ASSERT_EQUAL(0, k.keyReport.keys[4]);
TEST_ASSERT_EQUAL(0, k.keyReport.keys[5]);
}
int main(int argc, char **argv) {
UNITY_BEGIN();
RUN_TEST(test_keyReport_empty);
RUN_TEST(test_addKeyToReport);
RUN_TEST(test_removeKeyFromReport);
UNITY_END();
return 0;
}
+116
View File
@@ -0,0 +1,116 @@
#define private public
#pragma GCC diagnostic ignored "-Wc++11-extensions"
#include <unity.h>
#include "adb_devices.h"
#include "hid_keyboard.h"
// void setUp(void) {
// // set stuff up here
// }
// void tearDown(void) {
// // clean stuff up here
// }
void test_key_report_empty(void) {
hid_key_report k = {0};
for (uint8_t i = 0; i < 6; i++)
TEST_ASSERT_EQUAL(0, k.keys[i]);
TEST_ASSERT_EQUAL(0, k.modifiers);
}
void test_hid_keyboard_add_key_to_report(void) {
hid_key_report k = {0};
TEST_ASSERT_TRUE(hid_keyboard_add_key_to_report(&k, 1));
TEST_ASSERT_TRUE(hid_keyboard_add_key_to_report(&k, 2));
TEST_ASSERT_TRUE(hid_keyboard_add_key_to_report(&k, 3));
TEST_ASSERT_TRUE(hid_keyboard_add_key_to_report(&k, 2));
TEST_ASSERT_EQUAL(1, k.keys[0]);
TEST_ASSERT_EQUAL(2, k.keys[1]);
TEST_ASSERT_EQUAL(3, k.keys[2]);
TEST_ASSERT_EQUAL(0, k.keys[3]);
TEST_ASSERT_EQUAL(0, k.keys[4]);
TEST_ASSERT_EQUAL(0, k.keys[5]);
}
void test_hid_keyboard_remove_key_from_report(void) {
hid_key_report k = {0};
uint8_t initial_keys[] = {7, 8, 9, 0, 0, 0};
for (uint8_t i = 0; i < 6; i++) {
k.keys[i] = initial_keys[i];
}
hid_keyboard_remove_key_from_report(&k, 7);
hid_keyboard_remove_key_from_report(&k, 9);
hid_keyboard_remove_key_from_report(&k, 7);
TEST_ASSERT_EQUAL(0, k.keys[0]);
TEST_ASSERT_EQUAL(8, k.keys[1]);
TEST_ASSERT_EQUAL(0, k.keys[2]);
TEST_ASSERT_EQUAL(0, k.keys[3]);
TEST_ASSERT_EQUAL(0, k.keys[4]);
TEST_ASSERT_EQUAL(0, k.keys[5]);
}
void test_adb_kb_keypress(void) {
uint8_t kp_bin[2] = {0b10000001, 0b00001011};
adb_kb_keypress kp_stru;
kp_stru.released0 = true;
kp_stru.key0 = 1;
kp_stru.released1 = false;
kp_stru.key1 = 11;
uint16_t kp_stru_bin = *((uint16_t*)&kp_stru);
TEST_ASSERT_EQUAL(kp_bin, kp_stru_bin);
}
void test_adb_kb_modifiers() {
uint8_t mod_bin[2] = {0b00110101, 0b11000010};
adb_kb_modifiers mod_stru = *((adb_kb_modifiers*)&mod_bin);
TEST_ASSERT_EQUAL(0, mod_stru.reserved0);
TEST_ASSERT_EQUAL(0, mod_stru.backspace);
TEST_ASSERT_EQUAL(1, mod_stru.caps_lock);
TEST_ASSERT_EQUAL(1, mod_stru.reset);
TEST_ASSERT_EQUAL(0, mod_stru.control);
TEST_ASSERT_EQUAL(1, mod_stru.shift);
TEST_ASSERT_EQUAL(0, mod_stru.option);
TEST_ASSERT_EQUAL(1, mod_stru.command);
TEST_ASSERT_EQUAL(1, mod_stru.num_lock);
TEST_ASSERT_EQUAL(1, mod_stru.scroll_lock);
TEST_ASSERT_EQUAL(0, mod_stru.reserved1);
TEST_ASSERT_EQUAL(0, mod_stru.led_scroll);
TEST_ASSERT_EQUAL(1, mod_stru.led_caps);
TEST_ASSERT_EQUAL(0, mod_stru.led_num);
}
void test_adb_command() {
uint8_t cmd_bin = 0b01101001;
adb_command cmd_stru = *((adb_command*)&cmd_bin);
TEST_ASSERT_EQUAL(6, cmd_stru.addr);
TEST_ASSERT_EQUAL(2, cmd_stru.cmd);
TEST_ASSERT_EQUAL(1, cmd_stru.reg);
}
int main(int argc, char **argv) {
UNITY_BEGIN();
RUN_TEST(test_key_report_empty);
RUN_TEST(test_hid_keyboard_add_key_to_report);
RUN_TEST(test_hid_keyboard_remove_key_from_report);
RUN_TEST(test_adb_kb_keypress);
RUN_TEST(test_adb_kb_modifiers);
RUN_TEST(test_adb_command);
UNITY_END();
return 0;
}