Mkdir rn42
This commit is contained in:
102
keyboard/hhkb_rn42/rn42/main.c
Normal file
102
keyboard/hhkb_rn42/rn42/main.c
Normal file
@@ -0,0 +1,102 @@
|
||||
#include <avr/io.h>
|
||||
#include <avr/power.h>
|
||||
#include <avr/wdt.h>
|
||||
#include "lufa.h"
|
||||
#include "print.h"
|
||||
#include "sendchar.h"
|
||||
#include "rn42.h"
|
||||
#include "rn42_task.h"
|
||||
#include "serial.h"
|
||||
#include "keyboard.h"
|
||||
#include "keycode.h"
|
||||
#include "action.h"
|
||||
#include "action_util.h"
|
||||
#include "wait.h"
|
||||
#include "suart.h"
|
||||
#include "suspend.h"
|
||||
|
||||
static int8_t sendchar_func(uint8_t c)
|
||||
{
|
||||
sendchar(c); // LUFA
|
||||
xmit(c); // SUART
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void SetupHardware(void)
|
||||
{
|
||||
/* Disable watchdog if enabled by bootloader/fuses */
|
||||
MCUSR &= ~(1 << WDRF);
|
||||
wdt_disable();
|
||||
|
||||
/* Disable clock division */
|
||||
clock_prescale_set(clock_div_1);
|
||||
|
||||
// Leonardo needs. Without this USB device is not recognized.
|
||||
USB_Disable();
|
||||
|
||||
USB_Init();
|
||||
|
||||
// for Console_Task
|
||||
USB_Device_EnableSOFEvents();
|
||||
print_set_sendchar(sendchar_func);
|
||||
|
||||
// SUART PD0:output, PD1:input
|
||||
DDRD |= (1<<0);
|
||||
PORTD |= (1<<0);
|
||||
DDRD &= ~(1<<1);
|
||||
PORTD |= (1<<1);
|
||||
}
|
||||
|
||||
int main(void) __attribute__ ((weak));
|
||||
int main(void)
|
||||
{
|
||||
SetupHardware();
|
||||
sei();
|
||||
|
||||
/* wait for USB startup to get ready for debug output */
|
||||
uint8_t timeout = 255; // timeout when USB is not available(Bluetooth)
|
||||
while (timeout-- && USB_DeviceState != DEVICE_STATE_Configured) {
|
||||
wait_ms(4);
|
||||
#if defined(INTERRUPT_CONTROL_ENDPOINT)
|
||||
;
|
||||
#else
|
||||
USB_USBTask();
|
||||
#endif
|
||||
}
|
||||
print("USB configured.\n");
|
||||
|
||||
rn42_init();
|
||||
rn42_task_init();
|
||||
print("RN-42 init\n");
|
||||
|
||||
/* init modules */
|
||||
keyboard_init();
|
||||
|
||||
if (!rn42_rts()) {
|
||||
host_set_driver(&rn42_driver);
|
||||
} else {
|
||||
host_set_driver(&lufa_driver);
|
||||
}
|
||||
|
||||
#ifdef SLEEP_LED_ENABLE
|
||||
sleep_led_init();
|
||||
#endif
|
||||
|
||||
print("Keyboard start.\n");
|
||||
while (1) {
|
||||
while (USB_DeviceState == DEVICE_STATE_Suspended) {
|
||||
suspend_power_down();
|
||||
if (USB_Device_RemoteWakeupEnabled && suspend_wakeup_condition()) {
|
||||
USB_Device_SendRemoteWakeup();
|
||||
}
|
||||
}
|
||||
|
||||
keyboard_task();
|
||||
|
||||
#if !defined(INTERRUPT_CONTROL_ENDPOINT)
|
||||
USB_USBTask();
|
||||
#endif
|
||||
|
||||
rn42_task();
|
||||
}
|
||||
}
|
192
keyboard/hhkb_rn42/rn42/rn42.c
Normal file
192
keyboard/hhkb_rn42/rn42/rn42.c
Normal file
@@ -0,0 +1,192 @@
|
||||
#include <avr/io.h>
|
||||
#include "host.h"
|
||||
#include "host_driver.h"
|
||||
#include "serial.h"
|
||||
#include "rn42.h"
|
||||
#include "print.h"
|
||||
#include "wait.h"
|
||||
|
||||
|
||||
/* 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);
|
||||
|
||||
host_driver_t rn42_driver = {
|
||||
keyboard_leds,
|
||||
send_keyboard,
|
||||
send_mouse,
|
||||
send_system,
|
||||
send_consumer
|
||||
};
|
||||
|
||||
|
||||
void rn42_init(void)
|
||||
{
|
||||
// PF7: BT connection control(HiZ: connect, low: disconnect)
|
||||
// JTAG disable for PORT F. write JTD bit twice within four cycles.
|
||||
MCUCR |= (1<<JTD);
|
||||
MCUCR |= (1<<JTD);
|
||||
rn42_autoconnect();
|
||||
|
||||
// PF1: RTS(low: allowed to send, high: not allowed)
|
||||
DDRF &= ~(1<<1);
|
||||
PORTF &= ~(1<<1);
|
||||
|
||||
// PD5: CTS(low: allow to send, high:not allow)
|
||||
DDRD |= (1<<5);
|
||||
PORTD &= ~(1<<5);
|
||||
|
||||
serial_init();
|
||||
}
|
||||
|
||||
void rn42_putc(uint8_t c)
|
||||
{
|
||||
serial_send(c);
|
||||
}
|
||||
|
||||
bool rn42_autoconnecting(void)
|
||||
{
|
||||
// GPIO6 for control connection(high: auto connect, low: disconnect)
|
||||
// Note that this needs config: SM,4(Auto-Connect DTR Mode)
|
||||
return (PORTF & (1<<7) ? true : false);
|
||||
}
|
||||
|
||||
void rn42_autoconnect(void)
|
||||
{
|
||||
// hi to auto connect
|
||||
DDRF |= (1<<7);
|
||||
PORTF |= (1<<7);
|
||||
}
|
||||
|
||||
void rn42_disconnect(void)
|
||||
{
|
||||
// low to disconnect
|
||||
DDRF |= (1<<7);
|
||||
PORTF &= ~(1<<7);
|
||||
}
|
||||
|
||||
bool rn42_rts(void)
|
||||
{
|
||||
// low when RN-42 is powered and ready to receive
|
||||
return PINF&(1<<1);
|
||||
}
|
||||
|
||||
void rn42_cts_hi(void)
|
||||
{
|
||||
// not allow to send
|
||||
PORTD |= (1<<5);
|
||||
}
|
||||
|
||||
void rn42_cts_lo(void)
|
||||
{
|
||||
// allow to send
|
||||
PORTD &= ~(1<<5);
|
||||
}
|
||||
|
||||
|
||||
static uint8_t keyboard_leds(void) { return 0; }
|
||||
|
||||
static void send_keyboard(report_keyboard_t *report)
|
||||
{
|
||||
// wake from deep sleep
|
||||
/*
|
||||
PORTD |= (1<<5); // high
|
||||
wait_ms(5);
|
||||
PORTD &= ~(1<<5); // low
|
||||
*/
|
||||
|
||||
serial_send(0xFD); // Raw report mode
|
||||
serial_send(9); // length
|
||||
serial_send(1); // descriptor type
|
||||
serial_send(report->mods);
|
||||
serial_send(0x00);
|
||||
serial_send(report->keys[0]);
|
||||
serial_send(report->keys[1]);
|
||||
serial_send(report->keys[2]);
|
||||
serial_send(report->keys[3]);
|
||||
serial_send(report->keys[4]);
|
||||
serial_send(report->keys[5]);
|
||||
}
|
||||
|
||||
static void send_mouse(report_mouse_t *report)
|
||||
{
|
||||
// wake from deep sleep
|
||||
/*
|
||||
PORTD |= (1<<5); // high
|
||||
wait_ms(5);
|
||||
PORTD &= ~(1<<5); // low
|
||||
*/
|
||||
|
||||
serial_send(0xFD); // Raw report mode
|
||||
serial_send(5); // length
|
||||
serial_send(2); // descriptor type
|
||||
serial_send(report->buttons);
|
||||
serial_send(report->x);
|
||||
serial_send(report->y);
|
||||
serial_send(report->v);
|
||||
}
|
||||
|
||||
static void send_system(uint16_t data)
|
||||
{
|
||||
// Table 5-6 of RN-BT-DATA-UB
|
||||
// 81,82,83 scan codes can be used?
|
||||
}
|
||||
|
||||
|
||||
static uint16_t usage2bits(uint16_t usage)
|
||||
{
|
||||
switch (usage) {
|
||||
case AC_HOME: return 0x01;
|
||||
case AL_EMAIL: return 0x02;
|
||||
case AC_SEARCH: return 0x04;
|
||||
//case AL_KBD_LAYOUT: return 0x08; // Apple virtual keybaord toggle
|
||||
case AUDIO_VOL_UP: return 0x10;
|
||||
case AUDIO_VOL_DOWN: return 0x20;
|
||||
case AUDIO_MUTE: return 0x40;
|
||||
case TRANSPORT_PLAY_PAUSE: return 0x80;
|
||||
case TRANSPORT_NEXT_TRACK: return 0x100;
|
||||
case TRANSPORT_PREV_TRACK: return 0x200;
|
||||
case TRANSPORT_STOP: return 0x400;
|
||||
case TRANSPORT_STOP_EJECT: return 0x800;
|
||||
//case return 0x1000; // Fast forward
|
||||
//case return 0x2000; // Rewind
|
||||
//case return 0x4000; // Stop/eject
|
||||
//case return 0x8000; // Internet browser
|
||||
};
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void send_consumer(uint16_t data)
|
||||
{
|
||||
uint16_t bits = usage2bits(data);
|
||||
serial_send(0xFD); // Raw report mode
|
||||
serial_send(3); // length
|
||||
serial_send(3); // descriptor type
|
||||
serial_send(bits&0xFF);
|
||||
serial_send((bits>>8)&0xFF);
|
||||
}
|
||||
|
||||
|
||||
/* Null driver for config_mode */
|
||||
static uint8_t config_keyboard_leds(void);
|
||||
static void config_send_keyboard(report_keyboard_t *report);
|
||||
static void config_send_mouse(report_mouse_t *report);
|
||||
static void config_send_system(uint16_t data);
|
||||
static void config_send_consumer(uint16_t data);
|
||||
|
||||
host_driver_t rn42_config_driver = {
|
||||
config_keyboard_leds,
|
||||
config_send_keyboard,
|
||||
config_send_mouse,
|
||||
config_send_system,
|
||||
config_send_consumer
|
||||
};
|
||||
|
||||
static uint8_t config_keyboard_leds(void) { return 0; }
|
||||
static void config_send_keyboard(report_keyboard_t *report) {}
|
||||
static void config_send_mouse(report_mouse_t *report) {}
|
||||
static void config_send_system(uint16_t data) {}
|
||||
static void config_send_consumer(uint16_t data) {}
|
18
keyboard/hhkb_rn42/rn42/rn42.h
Normal file
18
keyboard/hhkb_rn42/rn42/rn42.h
Normal file
@@ -0,0 +1,18 @@
|
||||
#ifndef RN42_H
|
||||
#define RN42_H
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
host_driver_t rn42_driver;
|
||||
host_driver_t rn42_config_driver;
|
||||
|
||||
void rn42_init(void);
|
||||
void rn42_putc(uint8_t c);
|
||||
bool rn42_autoconnecting(void);
|
||||
void rn42_autoconnect(void);
|
||||
void rn42_disconnect(void);
|
||||
bool rn42_rts(void);
|
||||
void rn42_cts_hi(void);
|
||||
void rn42_cts_lo(void);
|
||||
|
||||
#endif
|
255
keyboard/hhkb_rn42/rn42/rn42_task.c
Normal file
255
keyboard/hhkb_rn42/rn42/rn42_task.c
Normal file
@@ -0,0 +1,255 @@
|
||||
#include <stdint.h>
|
||||
#include "keycode.h"
|
||||
#include "serial.h"
|
||||
#include "host.h"
|
||||
#include "action.h"
|
||||
#include "action_util.h"
|
||||
#include "lufa.h"
|
||||
#include "rn42_task.h"
|
||||
#include "print.h"
|
||||
#include "timer.h"
|
||||
#include "command.h"
|
||||
|
||||
static bool config_mode = false;
|
||||
static bool force_usb = false;
|
||||
|
||||
static void battery_adc_init(void)
|
||||
{
|
||||
ADMUX = (1<<REFS1) | (1<<REFS0); // Ref:2.56V band-gap, Input:ADC0(PF0)
|
||||
ADCSRA = (1<<ADPS2) | (1<<ADPS1) | (1<<ADPS0); // Prescale:128 16MHz/128=125KHz
|
||||
ADCSRA |= (1<<ADEN); // enable ADC
|
||||
}
|
||||
|
||||
static uint16_t battery_adc(void)
|
||||
{
|
||||
volatile uint16_t bat;
|
||||
ADCSRA |= (1<<ADEN);
|
||||
|
||||
// discard first result
|
||||
ADCSRA |= (1<<ADSC);
|
||||
while (ADCSRA & (1<<ADSC)) ;
|
||||
bat = ADC;
|
||||
|
||||
// discard second result
|
||||
ADCSRA |= (1<<ADSC);
|
||||
while (ADCSRA & (1<<ADSC)) ;
|
||||
bat = ADC;
|
||||
|
||||
ADCSRA |= (1<<ADSC);
|
||||
while (ADCSRA & (1<<ADSC)) ;
|
||||
bat = ADC;
|
||||
|
||||
ADCSRA &= ~(1<<ADEN);
|
||||
return bat;
|
||||
}
|
||||
|
||||
|
||||
void rn42_task_init(void)
|
||||
{
|
||||
battery_adc_init();
|
||||
}
|
||||
|
||||
void rn42_task(void)
|
||||
{
|
||||
int16_t c;
|
||||
if (config_mode) {
|
||||
// Config mode: print output from RN-42
|
||||
while ((c = serial_recv2()) != -1) {
|
||||
// without flow control it'll fail to receive data when flooded
|
||||
rn42_cts_hi();
|
||||
xprintf("%c", c);
|
||||
rn42_cts_lo();
|
||||
}
|
||||
} else {
|
||||
// Raw mode: interpret output report of LED state
|
||||
while ((c = serial_recv2()) != -1) {
|
||||
// LED Out report: 0xFE, 0x02, 0x01, <leds>
|
||||
// To get the report over UART set bit3 with SH, command.
|
||||
static enum {LED_INIT, LED_FE, LED_02, LED_01} state = LED_INIT;
|
||||
xprintf("%02X\n", c);
|
||||
switch (state) {
|
||||
case LED_INIT:
|
||||
if (c == 0xFE) state = LED_FE;
|
||||
else state = LED_INIT;
|
||||
break;
|
||||
case LED_FE:
|
||||
if (c == 0x02) state = LED_02;
|
||||
else state = LED_INIT;
|
||||
break;
|
||||
case LED_02:
|
||||
if (c == 0x01) state = LED_01;
|
||||
else state = LED_INIT;
|
||||
break;
|
||||
case LED_01:
|
||||
// TODO: move to rn42.c and make accessible with keyboard_leds()
|
||||
xprintf("LED status: %02X\n", c);
|
||||
state = LED_INIT;
|
||||
break;
|
||||
default:
|
||||
state = LED_INIT;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Bluetooth mode when ready */
|
||||
if (!config_mode && !force_usb) {
|
||||
if (!rn42_rts() && host_get_driver() != &rn42_driver) {
|
||||
clear_keyboard();
|
||||
host_set_driver(&rn42_driver);
|
||||
} else if (rn42_rts() && host_get_driver() != &lufa_driver) {
|
||||
clear_keyboard();
|
||||
host_set_driver(&lufa_driver);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* Command
|
||||
******************************************************************************/
|
||||
bool command_extra(uint8_t code)
|
||||
{
|
||||
static host_driver_t *prev_driver = &rn42_driver;
|
||||
switch (code) {
|
||||
case KC_H:
|
||||
case KC_SLASH: /* ? */
|
||||
print("\n\n----- Bluetooth RN-42 Help -----\n");
|
||||
print("Del: enter/exit config mode(auto_connect/disconnect)\n");
|
||||
print("i: RN-42 info\n");
|
||||
print("b: battery voltage\n");
|
||||
|
||||
if (config_mode) {
|
||||
return true;
|
||||
} else {
|
||||
print("u: Force USB mode\n");
|
||||
return false; // to display default command help
|
||||
}
|
||||
case KC_DELETE:
|
||||
if (rn42_autoconnecting()) {
|
||||
prev_driver = host_get_driver();
|
||||
clear_keyboard();
|
||||
_delay_ms(500);
|
||||
host_set_driver(&rn42_config_driver); // null driver; not to send a key to host
|
||||
rn42_disconnect();
|
||||
print("\nRN-42: disconnect\n");
|
||||
print("Enter config mode\n");
|
||||
print("type $$$ to start and + for local echo\n");
|
||||
command_state = CONSOLE;
|
||||
config_mode = true;
|
||||
} else {
|
||||
rn42_autoconnect();
|
||||
print("\nRN-42: auto_connect\n");
|
||||
print("Exit config mode\n");
|
||||
command_state = ONESHOT;
|
||||
config_mode = false;
|
||||
//clear_keyboard();
|
||||
host_set_driver(prev_driver);
|
||||
}
|
||||
return true;
|
||||
case KC_U:
|
||||
if (config_mode) return false;
|
||||
if (force_usb) {
|
||||
print("Auto mode\n");
|
||||
force_usb = false;
|
||||
} else {
|
||||
print("USB mode\n");
|
||||
force_usb = true;
|
||||
clear_keyboard();
|
||||
host_set_driver(&lufa_driver);
|
||||
}
|
||||
return true;
|
||||
case KC_I:
|
||||
print("\n----- RN-42 info -----\n");
|
||||
xprintf("protocol: %s\n", (host_get_driver() == &rn42_driver) ? "RN-42" : "LUFA");
|
||||
xprintf("force_usb: %X\n", force_usb);
|
||||
xprintf("rn42_autoconnecting(): %X\n", rn42_autoconnecting());
|
||||
xprintf("rn42_rts(): %X\n", rn42_rts());
|
||||
xprintf("config_mode: %X\n", config_mode);
|
||||
return true;
|
||||
case KC_B:
|
||||
// battery monitor
|
||||
xprintf("BAT: %04X(%08lX)\n", battery_adc(), timer_read32());
|
||||
return true;
|
||||
default:
|
||||
if (config_mode)
|
||||
return true;
|
||||
else
|
||||
return false; // exec default command
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static uint8_t code2asc(uint8_t code);
|
||||
bool command_console_extra(uint8_t code)
|
||||
{
|
||||
switch (code) {
|
||||
default:
|
||||
rn42_putc(code2asc(code));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// convert keycode into ascii charactor
|
||||
static uint8_t code2asc(uint8_t code)
|
||||
{
|
||||
bool shifted = (get_mods() & (MOD_BIT(KC_LSHIFT)|MOD_BIT(KC_RSHIFT))) ? true : false;
|
||||
switch (code) {
|
||||
case KC_A: return (shifted ? 'A' : 'a');
|
||||
case KC_B: return (shifted ? 'B' : 'b');
|
||||
case KC_C: return (shifted ? 'C' : 'c');
|
||||
case KC_D: return (shifted ? 'D' : 'd');
|
||||
case KC_E: return (shifted ? 'E' : 'e');
|
||||
case KC_F: return (shifted ? 'F' : 'f');
|
||||
case KC_G: return (shifted ? 'G' : 'g');
|
||||
case KC_H: return (shifted ? 'H' : 'h');
|
||||
case KC_I: return (shifted ? 'I' : 'i');
|
||||
case KC_J: return (shifted ? 'J' : 'j');
|
||||
case KC_K: return (shifted ? 'K' : 'k');
|
||||
case KC_L: return (shifted ? 'L' : 'l');
|
||||
case KC_M: return (shifted ? 'M' : 'm');
|
||||
case KC_N: return (shifted ? 'N' : 'n');
|
||||
case KC_O: return (shifted ? 'O' : 'o');
|
||||
case KC_P: return (shifted ? 'P' : 'p');
|
||||
case KC_Q: return (shifted ? 'Q' : 'q');
|
||||
case KC_R: return (shifted ? 'R' : 'r');
|
||||
case KC_S: return (shifted ? 'S' : 's');
|
||||
case KC_T: return (shifted ? 'T' : 't');
|
||||
case KC_U: return (shifted ? 'U' : 'u');
|
||||
case KC_V: return (shifted ? 'V' : 'v');
|
||||
case KC_W: return (shifted ? 'W' : 'w');
|
||||
case KC_X: return (shifted ? 'X' : 'x');
|
||||
case KC_Y: return (shifted ? 'Y' : 'y');
|
||||
case KC_Z: return (shifted ? 'Z' : 'z');
|
||||
case KC_1: return (shifted ? '!' : '1');
|
||||
case KC_2: return (shifted ? '@' : '2');
|
||||
case KC_3: return (shifted ? '#' : '3');
|
||||
case KC_4: return (shifted ? '$' : '4');
|
||||
case KC_5: return (shifted ? '%' : '5');
|
||||
case KC_6: return (shifted ? '^' : '6');
|
||||
case KC_7: return (shifted ? '&' : '7');
|
||||
case KC_8: return (shifted ? '*' : '8');
|
||||
case KC_9: return (shifted ? '(' : '9');
|
||||
case KC_0: return (shifted ? ')' : '0');
|
||||
case KC_ENTER: return '\n';
|
||||
case KC_ESCAPE: return 0x1B;
|
||||
case KC_BSPACE: return '\b';
|
||||
case KC_TAB: return '\t';
|
||||
case KC_SPACE: return ' ';
|
||||
case KC_MINUS: return (shifted ? '_' : '-');
|
||||
case KC_EQUAL: return (shifted ? '+' : '=');
|
||||
case KC_LBRACKET: return (shifted ? '{' : '[');
|
||||
case KC_RBRACKET: return (shifted ? '}' : ']');
|
||||
case KC_BSLASH: return (shifted ? '|' : '\\');
|
||||
case KC_NONUS_HASH: return (shifted ? '|' : '\\');
|
||||
case KC_SCOLON: return (shifted ? ':' : ';');
|
||||
case KC_QUOTE: return (shifted ? '"' : '\'');
|
||||
case KC_GRAVE: return (shifted ? '~' : '`');
|
||||
case KC_COMMA: return (shifted ? '<' : ',');
|
||||
case KC_DOT: return (shifted ? '>' : '.');
|
||||
case KC_SLASH: return (shifted ? '?' : '/');
|
||||
case KC_DELETE: return '\0'; // Delete to disconnect
|
||||
default: return ' ';
|
||||
}
|
||||
}
|
10
keyboard/hhkb_rn42/rn42/rn42_task.h
Normal file
10
keyboard/hhkb_rn42/rn42/rn42_task.h
Normal file
@@ -0,0 +1,10 @@
|
||||
#ifndef RN42_TASK_H
|
||||
#define RN42_TASK_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include "rn42.h"
|
||||
|
||||
void rn42_task_init(void);
|
||||
void rn42_task(void);
|
||||
|
||||
#endif
|
156
keyboard/hhkb_rn42/rn42/suart.S
Normal file
156
keyboard/hhkb_rn42/rn42/suart.S
Normal file
@@ -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 44 /* 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
|
8
keyboard/hhkb_rn42/rn42/suart.h
Normal file
8
keyboard/hhkb_rn42/rn42/suart.h
Normal file
@@ -0,0 +1,8 @@
|
||||
#ifndef SUART
|
||||
#define SUART
|
||||
|
||||
void xmit(uint8_t);
|
||||
uint8_t rcvr(void);
|
||||
uint8_t recv(void);
|
||||
|
||||
#endif /* SUART */
|
Reference in New Issue
Block a user