From f4a1bef7dc03c8d03d03a22e2b0812894eabc9e5 Mon Sep 17 00:00:00 2001 From: cuu Date: Fri, 14 Mar 2025 13:28:19 +0800 Subject: [PATCH] Add picocalc stm32 i2c keyboard code --- Code/picocalc_keyboard/README.md | 5 + Code/picocalc_keyboard/backlight.h | 9 + Code/picocalc_keyboard/backlight.ino | 59 ++ Code/picocalc_keyboard/battery.h | 11 + Code/picocalc_keyboard/battery.ino | 74 +++ Code/picocalc_keyboard/conf_app.h | 31 ++ Code/picocalc_keyboard/fifo.h | 18 + Code/picocalc_keyboard/fifo.ino | 58 ++ Code/picocalc_keyboard/keyboard.h | 83 +++ Code/picocalc_keyboard/keyboard.ino | 453 +++++++++++++++ Code/picocalc_keyboard/picocalc_keyboard.ino | 547 +++++++++++++++++++ Code/picocalc_keyboard/pins.h | 21 + Code/picocalc_keyboard/port.h | 44 ++ Code/picocalc_keyboard/port.ino | 39 ++ Code/picocalc_keyboard/reg.h | 55 ++ Code/picocalc_keyboard/reg.ino | 45 ++ 16 files changed, 1552 insertions(+) create mode 100644 Code/picocalc_keyboard/README.md create mode 100644 Code/picocalc_keyboard/backlight.h create mode 100644 Code/picocalc_keyboard/backlight.ino create mode 100644 Code/picocalc_keyboard/battery.h create mode 100644 Code/picocalc_keyboard/battery.ino create mode 100644 Code/picocalc_keyboard/conf_app.h create mode 100644 Code/picocalc_keyboard/fifo.h create mode 100644 Code/picocalc_keyboard/fifo.ino create mode 100644 Code/picocalc_keyboard/keyboard.h create mode 100644 Code/picocalc_keyboard/keyboard.ino create mode 100644 Code/picocalc_keyboard/picocalc_keyboard.ino create mode 100644 Code/picocalc_keyboard/pins.h create mode 100644 Code/picocalc_keyboard/port.h create mode 100644 Code/picocalc_keyboard/port.ino create mode 100644 Code/picocalc_keyboard/reg.h create mode 100644 Code/picocalc_keyboard/reg.ino diff --git a/Code/picocalc_keyboard/README.md b/Code/picocalc_keyboard/README.md new file mode 100644 index 0000000..4338fd2 --- /dev/null +++ b/Code/picocalc_keyboard/README.md @@ -0,0 +1,5 @@ +# picocalc keyboard + * STM32F103R8T6 + +## Libraries +* https://github.com/stm32duino/Arduino_Core_STM32/ diff --git a/Code/picocalc_keyboard/backlight.h b/Code/picocalc_keyboard/backlight.h new file mode 100644 index 0000000..047c9ea --- /dev/null +++ b/Code/picocalc_keyboard/backlight.h @@ -0,0 +1,9 @@ +#ifndef BACKLIGHT_H +#define BACKLIGHT_H + +void lcd_backlight_update_reg(); + +void lcd_backlight_update(int); +void kbd_backlight_update(int); + +#endif diff --git a/Code/picocalc_keyboard/backlight.ino b/Code/picocalc_keyboard/backlight.ino new file mode 100644 index 0000000..b531267 --- /dev/null +++ b/Code/picocalc_keyboard/backlight.ino @@ -0,0 +1,59 @@ + +#include "backlight.h" + +#define KBD_BACKLIGHT_SEG 4 +uint8_t kbd_backlight_segs[KBD_BACKLIGHT_SEG] = {20,40,80,110}; +uint8_t kbd_backlight_offset = 0; + +void lcd_backlight_update_reg() { + + uint8_t val; + + val = reg_get_value(REG_ID_BKL); + val = val & 0xff; + + analogWriteFrequency(10000); + analogWrite(PA8, val); + +} + +void lcd_backlight_update(int v) { + int val; + + val = reg_get_value(REG_ID_BKL); + val += v; + if(val < 0) val = 0; + if(val > 0xff) val = 0xff; + + analogWriteFrequency(10000); + analogWrite(PA8, val); + reg_set_value(REG_ID_BKL,val); +} + +void kbd_backlight_update(int v){ + int val; + + val = reg_get_value(REG_ID_BK2); + val += v; + if(val < 20 ) val = 0; + if(val > 0xff) val = 0; + + analogWriteFrequency(10000); + analogWrite(PC8, val); + reg_set_value(REG_ID_BK2,val); +} + +void kbd_backlight_update_offset(){ + int val; + kbd_backlight_offset++; + kbd_backlight_offset = kbd_backlight_offset % KBD_BACKLIGHT_SEG; + + val = reg_get_value(REG_ID_BK2); + val += kbd_backlight_segs[kbd_backlight_offset]; + if(val < 20 ) val = 0; + if(val > 0xff) val = 0; + + analogWriteFrequency(10000); + analogWrite(PC8, val); + reg_set_value(REG_ID_BK2,val); +} diff --git a/Code/picocalc_keyboard/battery.h b/Code/picocalc_keyboard/battery.h new file mode 100644 index 0000000..80a5cb3 --- /dev/null +++ b/Code/picocalc_keyboard/battery.h @@ -0,0 +1,11 @@ +#ifndef BATTERY_H +#define BATTERY_H + +void show_bat_segs(); + +void low_bat(); + +void start_chg(); +void stop_chg(); + +#endif diff --git a/Code/picocalc_keyboard/battery.ino b/Code/picocalc_keyboard/battery.ino new file mode 100644 index 0000000..f450af8 --- /dev/null +++ b/Code/picocalc_keyboard/battery.ino @@ -0,0 +1,74 @@ +#include "battery.h" + + +void indicator_led_on(){ + digitalWrite(PC13, LOW); +} + +void indicator_led_off(){ + digitalWrite(PC13, HIGH); +} + +void flash_one_time(int ts,int restore_status) { + for(int i=0;i0 && pcnt < 33) { + //show one time + flash_one_time(1,last_d201_status); + }else if(pcnt >= 33 && pcnt <66){ + //show 2 times + flash_one_time(2,last_d201_status); + }else if(pcnt >=66 && pcnt <= 100){ + //show 3 times + flash_one_time(3,last_d201_status); + } + + if(PMU.isCharging()){ + start_chg(); + } + +} + +void low_bat(){ + if(PMU.isBatteryConnect() && !PMU.isCharging()){ + int pcnt = PMU.getBatteryPercent(); + if(pcnt <= LOW_BAT_VAL){ + //This is related to the battery charging and discharging logic. If you're not sure what you're doing, please don't modify it, as it could damage the battery. + indicator_led_off(); + if(pcnt <= 1) {//This is related to the battery charging and discharging logic. If you're not sure what you're doing, please don't modify it, as it could damage the battery. + PMU.setChargingLedMode(XPOWERS_CHG_LED_BLINK_4HZ); + if(pcnt==0){//This is related to the battery charging and discharging logic. If you're not sure what you're doing, please don't modify it, as it could damage the battery. + PMU.shutdown();//This is related to the battery charging and discharging logic. If you're not sure what you're doing, please don't modify it, as it could damage the battery. + } + }else{ + PMU.setChargingLedMode(XPOWERS_CHG_LED_ON); + } + }else{ + indicator_led_on(); + PMU.setChargingLedMode(XPOWERS_CHG_LED_OFF); + } + } +} + +void start_chg(){ + indicator_led_on(); + PMU.setChargingLedMode(XPOWERS_CHG_LED_BLINK_1HZ); +} + +void stop_chg(){ + PMU.setChargingLedMode(XPOWERS_CHG_LED_OFF); + low_bat(); +} diff --git a/Code/picocalc_keyboard/conf_app.h b/Code/picocalc_keyboard/conf_app.h new file mode 100644 index 0000000..9c023eb --- /dev/null +++ b/Code/picocalc_keyboard/conf_app.h @@ -0,0 +1,31 @@ +#ifndef CONF_APP_H +#define CONF_APP_H + +#define SLAVE_ADDRESS 0x1F +#define FIFO_SIZE 31 + +#define INT_DURATION_MS 1 + +#ifndef CONFIG_PMU_SDA +#define CONFIG_PMU_SDA PB11 +#endif + +#ifndef CONFIG_PMU_SCL +#define CONFIG_PMU_SCL PB10 +#endif + +#ifndef CONFIG_PMU_IRQ +#define CONFIG_PMU_IRQ PC9 +#endif + + +#define LOW_BAT_VAL 20 +#define LCD_BACKLIGHT_STEP 10 + + +#define bitRead(value, bit) (((value) >> (bit)) & 0x01) +#define bitSet(value, bit) ((value) |= (1 << (bit))) +#define bitClear(value, bit) ((value) &= ~(1 << (bit))) +#define bitWrite(value, bit, bitvalue) ((bitvalue) ? bitSet((value), (bit)) : bitClear((value), (bit) )) + +#endif diff --git a/Code/picocalc_keyboard/fifo.h b/Code/picocalc_keyboard/fifo.h new file mode 100644 index 0000000..10adb74 --- /dev/null +++ b/Code/picocalc_keyboard/fifo.h @@ -0,0 +1,18 @@ +#ifndef FIFO_H +#define FIFO_H + +#include "keyboard.h" + +struct fifo_item { + char key; + enum key_state state; +}; + +uint8_t fifo_count(void); +void fifo_flush(void); +bool fifo_enqueue(const struct fifo_item item); +void fifo_enqueue_force(const struct fifo_item item); +struct fifo_item fifo_dequeue(void); + + +#endif diff --git a/Code/picocalc_keyboard/fifo.ino b/Code/picocalc_keyboard/fifo.ino new file mode 100644 index 0000000..978645e --- /dev/null +++ b/Code/picocalc_keyboard/fifo.ino @@ -0,0 +1,58 @@ +#include "fifo.h" + +static struct { + struct fifo_item fifo[FIFO_SIZE]; + uint8_t count; + uint8_t read_idx; + uint8_t write_idx; +} fifo_self; + +uint8_t fifo_count(void) +{ + return fifo_self.count; +} + +void fifo_flush(void) +{ + fifo_self.write_idx = 0; + fifo_self.read_idx = 0; + fifo_self.count = 0; +} + +bool fifo_enqueue(const struct fifo_item item) +{ + if (fifo_self.count >= FIFO_SIZE) + return false; + + fifo_self.fifo[fifo_self.write_idx++] = item; + + fifo_self.write_idx %= FIFO_SIZE; + ++fifo_self.count; + + return true; +} + +void fifo_enqueue_force(const struct fifo_item item) +{ + if (fifo_enqueue(item)) + return; + + fifo_self.fifo[fifo_self.write_idx++] = item; + fifo_self.write_idx %= FIFO_SIZE; + + fifo_self.read_idx++; + fifo_self.read_idx %= FIFO_SIZE; +} + +struct fifo_item fifo_dequeue(void) +{ + struct fifo_item item = { 0 }; + if (fifo_self.count == 0) + return item; + + item = fifo_self.fifo[fifo_self.read_idx++]; + fifo_self.read_idx %= FIFO_SIZE; + --fifo_self.count; + + return item; +} diff --git a/Code/picocalc_keyboard/keyboard.h b/Code/picocalc_keyboard/keyboard.h new file mode 100644 index 0000000..69e5653 --- /dev/null +++ b/Code/picocalc_keyboard/keyboard.h @@ -0,0 +1,83 @@ +#ifndef KEYBOARD_H +#define KEYBOARD_H + +enum key_state +{ + KEY_STATE_IDLE = 0, + KEY_STATE_PRESSED, + KEY_STATE_HOLD, + KEY_STATE_RELEASED, +}; + +#define KEY_JOY_UP 0x01 +#define KEY_JOY_DOWN 0x02 +#define KEY_JOY_LEFT 0x03 +#define KEY_JOY_RIGHT 0x04 +#define KEY_JOY_CENTER 0x05 +#define KEY_BTN_LEFT1 0x06 +#define KEY_BTN_RIGHT1 0x07 + +#define KEY_BACKSPACE 0x08 +#define KEY_TAB 0x09 +#define KEY_ENTER 0x0A +// 0x0D - CARRIAGE RETURN +#define KEY_BTN_LEFT2 0x11 +#define KEY_BTN_RIGHT2 0x12 + + +#define KEY_MOD_ALT 0xA1 +#define KEY_MOD_SHL 0xA2 +#define KEY_MOD_SHR 0xA3 +#define KEY_MOD_SYM 0xA4 +#define KEY_MOD_CTRL 0xA5 + +#define KEY_ESC 0xB1 +#define KEY_UP 0xb5 +#define KEY_DOWN 0xb6 +#define KEY_LEFT 0xb4 +#define KEY_RIGHT 0xb7 + +#define KEY_BREAK 0xd0 // == KEY_PAUSE +#define KEY_INSERT 0xD1 +#define KEY_HOME 0xD2 +#define KEY_DEL 0xD4 +#define KEY_END 0xD5 +#define KEY_PAGE_UP 0xd6 +#define KEY_PAGE_DOWN 0xd7 + +#define KEY_CAPS_LOCK 0xC1 + +#define KEY_F1 0x81 +#define KEY_F2 0x82 +#define KEY_F3 0x83 +#define KEY_F4 0x84 +#define KEY_F5 0x85 +#define KEY_F6 0x86 +#define KEY_F7 0x87 +#define KEY_F8 0x88 +#define KEY_F9 0x89 +#define KEY_F10 0x90 + +typedef void (*key_callback)(char, enum key_state); +typedef void (*lock_callback)(bool, bool); + +void keyboard_process(void); +void keyboard_set_key_callback(key_callback callback); +void keyboard_set_lock_callback(lock_callback callback); +bool keyboard_get_capslock(void); +bool keyboard_get_numlock(void); +void keyboard_init(void); + +#define NUM_OF_COLS 8 +#define NUM_OF_ROWS 7 + +#define NUM_OF_BTNS 12 + +#define KEY_POLL_TIME 16 + +#define KEY_LIST_SIZE 10 + + +#define KEY_HOLD_TIME 300 + +#endif diff --git a/Code/picocalc_keyboard/keyboard.ino b/Code/picocalc_keyboard/keyboard.ino new file mode 100644 index 0000000..a7d57ff --- /dev/null +++ b/Code/picocalc_keyboard/keyboard.ino @@ -0,0 +1,453 @@ + + +#include "port.h" +#include "keyboard.h" + + + +enum mod +{ + MOD_NONE = 0, + MOD_SYM, + MOD_ALT, + MOD_SHL, + MOD_SHR, + MOD_CTRL, + MOD_LAST, +}; + +struct entry +{ + char chr; + char symb; + enum mod mod; +}; + +struct list_item +{ + const struct entry *p_entry; + uint32_t hold_start_time; + uint32_t last_repeat_time; + enum key_state state; + bool mods[MOD_LAST]; +}; + + + +static const struct entry kbd_entries[][NUM_OF_COLS] = +{ + {{KEY_F5,KEY_F10}, {KEY_F4,KEY_F9}, {KEY_F3,KEY_F8},{KEY_F2,KEY_F7}, {KEY_F1,KEY_F6}, {'`','~'},{'3','#'}, {'2','@'}}, + {{KEY_BACKSPACE}, {KEY_DEL,KEY_END},{KEY_CAPS_LOCK},{KEY_TAB,KEY_HOME},{KEY_ESC,KEY_BREAK},{'4','$'},{'E'}, {'W'}}, + {{'P'}, {'=','+'}, {'-','_'}, {'\\','|'}, {'/','?'}, {'R'}, {'S'}, {'1','!'}}, + {{KEY_ENTER,KEY_INSERT},{'8','*'}, {'7','&'}, {'6','^'}, {'5','%'}, {'F'}, {'X'}, {'Q'}}, + {{'.','>'}, {'I'}, {'U'}, {'Y'}, {'T'}, {'V'}, {';',':'}, {'A'}}, + {{'L'}, {'K'}, {'J'}, {'H'}, {'G'}, {'C'}, {'\'','"'},{'Z'}}, + {{'O'}, {',','<'}, {'M'}, {'N'}, {'B'}, {'D'}, {' '}, { }}, + +}; + +static const struct entry btn_entries[NUM_OF_BTNS] = +{ + {.mod = MOD_ALT}, + {.mod = MOD_CTRL}, + {.mod = MOD_SHL}, + {.mod = MOD_SHR}, + {'0',')'}, + {'9','('}, + {']','}'}, + {'[','{'}, + {KEY_RIGHT}, + {KEY_UP,KEY_PAGE_UP}, + {KEY_DOWN,KEY_PAGE_DOWN}, + {KEY_LEFT} + +}; + +static struct { + lock_callback _lock_callback; + key_callback _key_callback; + + struct list_item list[KEY_LIST_SIZE]; + + uint32_t last_process_time; + + bool mods[MOD_LAST]; + + bool capslock_changed; + bool capslock; + + bool numlock_changed; + bool numlock; +} self; + +void output_string(char*str){ + if (!self._key_callback) return; + + while(*str){ + self._key_callback(*str, KEY_STATE_PRESSED); + str++; + } +} +static void transition_to(struct list_item * const p_item, const enum key_state next_state) +{ + bool output = true; + const struct entry * const p_entry = p_item->p_entry; + + p_item->state = next_state; + + if (!self._key_callback || !p_entry) + return; + + char chr = p_entry->chr; + + switch (p_entry->mod) { + case MOD_ALT: + if (reg_is_bit_set(REG_ID_CFG, CFG_REPORT_MODS)) + chr = KEY_MOD_ALT; + break; + + case MOD_SHL: + if (reg_is_bit_set(REG_ID_CFG, CFG_REPORT_MODS)) + chr = KEY_MOD_SHL; + break; + + case MOD_SHR: + if (reg_is_bit_set(REG_ID_CFG, CFG_REPORT_MODS)) + chr = KEY_MOD_SHR; + break; + + case MOD_SYM: + if (reg_is_bit_set(REG_ID_CFG, CFG_REPORT_MODS)) + chr = KEY_MOD_SYM; + break; + case MOD_CTRL: + if (reg_is_bit_set(REG_ID_CFG, CFG_REPORT_MODS)) + chr = KEY_MOD_CTRL; + break; + + default: + { + //toggle operation + if(chr == KEY_CAPS_LOCK && next_state == KEY_STATE_PRESSED ){ + if(self.capslock == true){ + self.capslock = false; + }else{ + self.capslock = true; + } + self.capslock_changed = true; + } + + if (reg_is_bit_set(REG_ID_CFG, CFG_USE_MODS)) { + const bool shift = (self.mods[MOD_SHL] || self.mods[MOD_SHR]); + const bool alt = self.mods[MOD_ALT] | self.numlock; + const bool ctrl = self.mods[MOD_CTRL];//shortcuts control + + if (shift && (chr <'A' || chr >'Z')) { + chr = p_entry->symb; + }else if(self.capslock && (chr >= 'A' && chr <= 'Z')){ + //pass + } + else if(alt){ + //ctrl for operators + if(next_state == KEY_STATE_PRESSED) { + if(chr == ',' || chr == '.' || chr == ' ' || chr == 'B'){ + output = false; + } + if(chr == 'I'){ + output = true; + chr = KEY_INSERT; + } + } + + if( next_state == KEY_STATE_RELEASED ) { + if(chr == ',' || chr == '.' || chr == ' ' || chr == 'B'){ + output = false; + } + if(chr == 'I'){ + output = true; + chr = KEY_INSERT; + } + } + + if(next_state == KEY_STATE_RELEASED) { + if(chr ==','){ + lcd_backlight_update(-LCD_BACKLIGHT_STEP); + }else if(chr =='.'){ + lcd_backlight_update(LCD_BACKLIGHT_STEP); + }else if(chr == ' '){ + //loop update keyboard backlight + kbd_backlight_update_offset(); + }else if(chr == 'B'){ + show_bat_segs(); + } + } + } + else if (!shift && (chr >= 'A' && chr <= 'Z')) { + chr = (chr + ' ');// uppercase to lowercase for a to z + } + } + + break; + } + } + + if (chr != 0 && output==true) { + if(next_state == KEY_STATE_HOLD){ + if( (chr >= 32 && chr <= 127) || chr == KEY_ENTER || chr == KEY_TAB || chr == KEY_DEL || chr == KEY_BACKSPACE || chr == KEY_UP || chr == KEY_DOWN || chr == KEY_RIGHT || chr == KEY_LEFT ) { + self._key_callback(chr, KEY_STATE_PRESSED); + }else{ + self._key_callback(chr, next_state); + } + }else{ + self._key_callback(chr, next_state); + } + } +} + +static void next_item_state(struct list_item * const p_item, const bool pressed) +{ + switch (p_item->state) { + case KEY_STATE_IDLE: + if (pressed) { + if (p_item->p_entry->mod != MOD_NONE) + self.mods[p_item->p_entry->mod] = true; + + if (!self.capslock_changed && self.mods[MOD_SHR] && self.mods[MOD_ALT]) { + self.capslock = true; + self.capslock_changed = true; + } + + if (!self.numlock_changed && self.mods[MOD_SHL] && self.mods[MOD_ALT]) { + self.numlock = true; + self.numlock_changed = true; + } + + if (!self.capslock_changed && (self.mods[MOD_SHL] || self.mods[MOD_SHR])) { + self.capslock = false; + self.capslock_changed = true; + } + + if (!self.numlock_changed && (self.mods[MOD_SHL] || self.mods[MOD_SHR])) { + self.numlock = false; + self.numlock_changed = true; + } + + if (!self.mods[MOD_ALT]) { + self.capslock_changed = false; + self.numlock_changed = false; + } + + if (self._lock_callback && (self.capslock_changed || self.numlock_changed)) + self._lock_callback(self.capslock_changed, self.numlock_changed); + + transition_to(p_item, KEY_STATE_PRESSED); + + p_item->hold_start_time = time_uptime_ms(); + p_item->last_repeat_time = 0; + } + break; + + case KEY_STATE_PRESSED: + if ((time_uptime_ms() - p_item->hold_start_time) > KEY_HOLD_TIME) { + transition_to(p_item, KEY_STATE_HOLD); + } else if(!pressed) { + transition_to(p_item, KEY_STATE_RELEASED); + } + break; + + case KEY_STATE_HOLD: + if (!pressed){ + transition_to(p_item, KEY_STATE_RELEASED); + }else{ + if ((time_uptime_ms() - p_item->hold_start_time) > KEY_HOLD_TIME) { + if(time_uptime_ms() - p_item->last_repeat_time > 100) { + transition_to(p_item, KEY_STATE_HOLD); + p_item->last_repeat_time = time_uptime_ms(); + } + } + } + break; + case KEY_STATE_RELEASED: + { + if (p_item->p_entry->mod != MOD_NONE) + self.mods[p_item->p_entry->mod] = false; + + p_item->p_entry = NULL; + transition_to(p_item, KEY_STATE_IDLE); + break; + } + } +} + + + +void keyboard_process(void) +{ + struct port_config port_init; + js_bits = 0xff; + + if ((time_uptime_ms() - self.last_process_time) <= KEY_POLL_TIME) + return; + + port_get_config_defaults(&port_init); + + for (uint8_t c = 0; c < NUM_OF_COLS; ++c) { + uint8_t col_value = 0; + port_init.direction = PORT_PIN_DIR_OUTPUT; + port_pin_set_config(col_pins[c], &port_init); + port_pin_set_output_level(col_pins[c], 0); + + for (uint8_t r = 0; r < NUM_OF_ROWS; ++r) { + uint8_t pin_value = port_pin_get_input_level(row_pins[r]); + const bool pressed = (pin_value == 0); + uint8_t row_bit = (1< -1) { + next_item_state(&self.list[list_idx], pressed); + continue; + } + + if (!pressed) + continue; + + for (uint32_t i = 0 ; i < KEY_LIST_SIZE; ++i) { + if (self.list[i].p_entry != NULL) + continue; + + self.list[i].p_entry = &((const struct entry*)kbd_entries)[key_idx]; + self.list[i].state = KEY_STATE_IDLE; + next_item_state(&self.list[i], pressed); + + break; + } + } + io_matrix[c] = col_value; + port_pin_set_output_level(col_pins[c], 1); + + port_init.direction = PORT_PIN_DIR_INPUT; + port_init.input_pull = PORT_PIN_PULL_NONE; + port_pin_set_config(col_pins[c], &port_init); + } + +#if NUM_OF_BTNS > 0 + for (uint8_t b = 0; b < NUM_OF_BTNS; ++b) { + uint8_t pin_value = port_pin_get_input_level(btn_pins[b]); + const bool pressed = (pin_value == 0); + if( b < 8 ) {// read BTN1->BTN8 + + if(pressed){ + io_matrix[b] &= ~(1 << 7); + }else{ + io_matrix[b] |= ( 1 << 7); + } + }else{//c64 joystick arrow keys + //B12=left,, B11=down,B10 = up,B9 = right + uint8_t btn_bts = b-8; + if(pressed){ + js_bits &= ~(1< -1) { + next_item_state(&self.list[list_idx], pressed); + continue; + } + + if (!pressed) + continue; + + for (uint8_t i = 0 ; i < KEY_LIST_SIZE; ++i) { + if (self.list[i].p_entry != NULL) + continue; + + self.list[i].p_entry = &((const struct entry*)btn_entries)[b]; + self.list[i].state = KEY_STATE_IDLE; + next_item_state(&self.list[i], pressed); + + break; + } + } +#endif + io_matrix[8] = 0xFF; + self.last_process_time = time_uptime_ms(); +} + +void keyboard_set_key_callback(key_callback callback) +{ + self._key_callback = callback; +} + +void keyboard_set_lock_callback(lock_callback callback) +{ + self._lock_callback = callback; +} + +bool keyboard_get_capslock(void) +{ + return self.capslock; +} + +bool keyboard_get_numlock(void) +{ + return self.numlock; +} + +void keyboard_init(void) +{ + struct port_config port_init; + port_get_config_defaults(&port_init); + + for (int i = 0; i < MOD_LAST; ++i) + self.mods[i] = false; + + // Rows + port_init.direction = PORT_PIN_DIR_INPUT; + port_init.input_pull = PORT_PIN_PULL_UP; + for (uint32_t i = 0; i < NUM_OF_ROWS; ++i) + port_pin_set_config(row_pins[i], &port_init); + + // Cols + port_init.direction = PORT_PIN_DIR_INPUT; + port_init.input_pull = PORT_PIN_PULL_NONE; + for(uint32_t i = 0; i < NUM_OF_COLS; ++i) + port_pin_set_config(col_pins[i], &port_init); + + // Btns +#if NUM_OF_BTNS > 0 + port_init.direction = PORT_PIN_DIR_INPUT; + port_init.input_pull = PORT_PIN_PULL_UP; + for(uint32_t i = 0; i < NUM_OF_BTNS; ++i) + port_pin_set_config(btn_pins[i], &port_init); +#endif +} diff --git a/Code/picocalc_keyboard/picocalc_keyboard.ino b/Code/picocalc_keyboard/picocalc_keyboard.ino new file mode 100644 index 0000000..a27a9d6 --- /dev/null +++ b/Code/picocalc_keyboard/picocalc_keyboard.ino @@ -0,0 +1,547 @@ +#include + +#define XPOWERS_CHIP_AXP2101 + +#include + +#include "XPowersLib.h" +//--------------------------------------- +#include "backlight.h" +#include "conf_app.h" +#include "fifo.h" +#include "keyboard.h" +#include "pins.h" +#include "port.h" +#include "reg.h" +#include "battery.h" + +#define DEBUG_UART +TwoWire Wire2 = TwoWire(CONFIG_PMU_SDA, CONFIG_PMU_SCL); +bool pmu_flag = 0; +bool pmu_online = 0; +uint8_t pmu_status = 0; +uint8_t keycb_start = 0; + +uint8_t head_phone_status=LOW; + +XPowersPMU PMU; + +const uint8_t i2c_sda = CONFIG_PMU_SDA; +const uint8_t i2c_scl = CONFIG_PMU_SCL; +const uint8_t pmu_irq_pin = CONFIG_PMU_IRQ; + +unsigned long run_time; + +void set_pmu_flag(void) { pmu_flag = true; } + +HardwareSerial Serial1(PA10, PA9); + +uint8_t write_buffer[10]; +uint8_t write_buffer_len = 0; + +uint8_t io_matrix[9];//for IO matrix,last bytye is the restore key(c64 only) +uint8_t js_bits=0xff;// c64 joystick bits + +unsigned long time_uptime_ms() { return millis(); } + +void lock_cb(bool caps_changed, bool num_changed) { + bool do_int = false; + + if (caps_changed && reg_is_bit_set(REG_ID_CFG, CFG_CAPSLOCK_INT)) { + reg_set_bit(REG_ID_INT, INT_CAPSLOCK); + do_int = true; + } + + if (num_changed && reg_is_bit_set(REG_ID_CFG, CFG_NUMLOCK_INT)) { + reg_set_bit(REG_ID_INT, INT_NUMLOCK); + do_int = true; + } + + /* // int_pin can be a LED + if (do_int) { + port_pin_set_output_level(int_pin, 0); + delay_ms(INT_DURATION_MS); + port_pin_set_output_level(int_pin, 1); + }*/ +} + +static void key_cb(char key, enum key_state state) { + bool do_int = false; + + if(keycb_start == 0){ + fifo_flush(); + return; + } + + if (reg_is_bit_set(REG_ID_CFG, CFG_KEY_INT)) { + reg_set_bit(REG_ID_INT, INT_KEY); + do_int = true; + } + +#ifdef DEBUG + // Serial1.println("key: 0x%02X/%d/%c, state: %d, blk: %d\r\n", key, key, key, + // state, reg_get_value(REG_ID_BKL)); +#endif + + const struct fifo_item item = {key, state}; + if (!fifo_enqueue(item)) { + if (reg_is_bit_set(REG_ID_CFG, CFG_OVERFLOW_INT)) { + reg_set_bit(REG_ID_INT, INT_OVERFLOW); // INT_OVERFLOW The interrupt was + // generated by FIFO overflow. + do_int = true; + } + + if (reg_is_bit_set(REG_ID_CFG, CFG_OVERFLOW_ON)) fifo_enqueue_force(item); + } + + //Serial1.println(key); +} + +void receiveEvent(int howMany) { + uint8_t rcv_data[2]; // max size 2, protocol defined + uint8_t rcv_idx; + + if (Wire.available() < 1) return; + + rcv_idx = 0; + while (Wire.available()) // loop through all but the last + { + uint8_t c = Wire.read(); // receive byte as a character + rcv_data[rcv_idx] = c; + rcv_idx++; + if (rcv_idx >= 2) { + rcv_idx = 0; + } + } + + const bool is_write = (rcv_data[0] & WRITE_MASK); + const uint8_t reg = (rcv_data[0] & ~WRITE_MASK); + + write_buffer[0] = 0; + write_buffer[1] = 0; + write_buffer_len = 2; + + switch (reg) { + case REG_ID_FIF: { + const struct fifo_item item = fifo_dequeue(); + write_buffer[0] = (uint8_t)item.state; + write_buffer[1] = (uint8_t)item.key; + } break; + case REG_ID_BKL: { + reg_set_value(REG_ID_BKL, rcv_data[1]); + lcd_backlight_update_reg(); + write_buffer[0] = reg; + write_buffer[1] = reg_get_value(REG_ID_BKL); + } break; + case REG_ID_BAT:{ + write_buffer[0] = reg; + if (PMU.isBatteryConnect()) { + write_buffer[1] = PMU.getBatteryPercent(); + }else{ + write_buffer[1] = 0x00; + } + }break; + case REG_ID_KEY: { + write_buffer[0] = fifo_count(); + write_buffer[0] |= keyboard_get_numlock() ? KEY_NUMLOCK : 0x00; + write_buffer[0] |= keyboard_get_capslock() ? KEY_CAPSLOCK : 0x00; + + }break; + case REG_ID_C64_MTX:{ + write_buffer[0] = reg; + memcpy(write_buffer + 1, io_matrix, sizeof(io_matrix)); + write_buffer_len = 10; + }break; + case REG_ID_C64_JS:{ + write_buffer[0] = reg; + write_buffer[1] = js_bits; + write_buffer_len = 2; + }break; + default: { + write_buffer[0] = 0; + write_buffer[1] = 0; + + write_buffer_len = 2; + } break; + } +} + +//-this is after receiveEvent------------------------------- +void requestEvent() { Wire.write(write_buffer,write_buffer_len ); } + +void report_bat(){ + if (PMU.isBatteryConnect()) { + write_buffer[0] = REG_ID_BAT; + write_buffer[1] = PMU.getBatteryPercent(); + + write_buffer_len = 2; + requestEvent(); + } +} + +void printPMU() { + Serial1.print("isCharging:"); + Serial1.println(PMU.isCharging() ? "YES" : "NO"); + Serial1.print("isDischarge:"); + Serial1.println(PMU.isDischarge() ? "YES" : "NO"); + Serial1.print("isStandby:"); + Serial1.println(PMU.isStandby() ? "YES" : "NO"); + Serial1.print("isVbusIn:"); + Serial1.println(PMU.isVbusIn() ? "YES" : "NO"); + Serial1.print("isVbusGood:"); + Serial1.println(PMU.isVbusGood() ? "YES" : "NO"); + Serial1.print("getChargerStatus:"); + uint8_t charge_status = PMU.getChargerStatus(); + if (charge_status == XPOWERS_AXP2101_CHG_TRI_STATE) { + Serial1.println("tri_charge"); + } else if (charge_status == XPOWERS_AXP2101_CHG_PRE_STATE) { + Serial1.println("pre_charge"); + } else if (charge_status == XPOWERS_AXP2101_CHG_CC_STATE) { + Serial1.println("constant charge"); + } else if (charge_status == XPOWERS_AXP2101_CHG_CV_STATE) { + Serial1.println("constant voltage"); + } else if (charge_status == XPOWERS_AXP2101_CHG_DONE_STATE) { + Serial1.println("charge done"); + } else if (charge_status == XPOWERS_AXP2101_CHG_STOP_STATE) { + Serial1.println("not chargin"); + } + + Serial1.print("getBattVoltage:"); + Serial1.print(PMU.getBattVoltage()); + Serial1.println("mV"); + Serial1.print("getVbusVoltage:"); + Serial1.print(PMU.getVbusVoltage()); + Serial1.println("mV"); + Serial1.print("getSystemVoltage:"); + Serial1.print(PMU.getSystemVoltage()); + Serial1.println("mV"); + + // The battery percentage may be inaccurate at first use, the PMU will + // automatically learn the battery curve and will automatically calibrate the + // battery percentage after a charge and discharge cycle + if (PMU.isBatteryConnect()) { + Serial1.print("getBatteryPercent:"); + Serial1.print(PMU.getBatteryPercent()); + Serial1.println("%"); + } + + Serial1.println(); +} + +void check_pmu_int() { + /// 40 secs check battery percent + + int pcnt; + + if (!pmu_online) return; + + if (time_uptime_ms() - run_time > 40000) { + run_time = millis(); // reset time + pcnt = PMU.getBatteryPercent(); + if (pcnt < 0) { // disconnect + pcnt = 0; + pmu_status = 0xff; + } else { // battery connected + if (PMU.isCharging()) { + pmu_status = bitSet(pcnt, 7); + } else { + pmu_status = pcnt; + } + low_bat(); + } + } + + if (pmu_flag) { + pmu_flag = false; + + // Get PMU Interrupt Status Register + uint32_t status = PMU.getIrqStatus(); + Serial1.print("STATUS => HEX:"); + Serial1.print(status, HEX); + Serial1.print(" BIN:"); + Serial1.println(status, BIN); + + + // When the set low-voltage battery percentage warning threshold is reached, + // set the threshold through getLowBatWarnThreshold( 5% ~ 20% ) + if (PMU.isDropWarningLevel2Irq()) { + Serial1.println("isDropWarningLevel2"); + report_bat(); + } + + // When the set low-voltage battery percentage shutdown threshold is reached + // set the threshold through setLowBatShutdownThreshold() + //This is related to the battery charging and discharging logic. If you're not sure what you're doing, please don't modify it, as it could damage the battery. + if (PMU.isDropWarningLevel1Irq()) { + report_bat(); + // + PMU.shutdown(); + } + if (PMU.isGaugeWdtTimeoutIrq()) { + Serial1.println("isWdtTimeout"); + } + if (PMU.isBatChargerOverTemperatureIrq()) { + Serial1.println("isBatChargeOverTemperature"); + } + if (PMU.isBatWorkOverTemperatureIrq()) { + Serial1.println("isBatWorkOverTemperature"); + } + if (PMU.isBatWorkUnderTemperatureIrq()) { + Serial1.println("isBatWorkUnderTemperature"); + } + if (PMU.isVbusInsertIrq()) { + Serial1.println("isVbusInsert"); + } + if (PMU.isVbusRemoveIrq()) { + Serial1.println("isVbusRemove"); + stop_chg(); + } + if (PMU.isBatInsertIrq()) { + pcnt = PMU.getBatteryPercent(); + if (pcnt < 0) { // disconnect + pcnt = 0; + pmu_status = 0xff; + } else { + pmu_status = pcnt; + } + + Serial1.println("isBatInsert"); + } + if (PMU.isBatRemoveIrq()) { + pmu_status = 0xff; + Serial1.println("isBatRemove"); + stop_chg(); + } + + if (PMU.isPekeyShortPressIrq()) { + Serial1.println("isPekeyShortPress"); + // enterPmuSleep(); + + Serial1.print("Read pmu data buffer ."); + uint8_t data[4] = {0}; + PMU.readDataBuffer(data, XPOWERS_AXP2101_DATA_BUFFER_SIZE); + for (int i = 0; i < 4; ++i) { + Serial1.print(data[i]); + Serial1.print(","); + } + Serial1.println(); + + printPMU(); + } + + if (PMU.isPekeyLongPressIrq()) { + Serial1.println("isPekeyLongPress"); + //Serial1.println("write pmu data buffer ."); + //uint8_t data[4] = {1, 2, 3, 4}; + //PMU.writeDataBuffer(data, XPOWERS_AXP2101_DATA_BUFFER_SIZE); + digitalWrite(PA13, LOW); + digitalWrite(PA14, LOW); + PMU.setChargingLedMode(XPOWERS_CHG_LED_CTRL_CHG); + PMU.shutdown(); + } + + if (PMU.isPekeyNegativeIrq()) { + Serial1.println("isPekeyNegative"); + } + if (PMU.isPekeyPositiveIrq()) { + Serial1.println("isPekeyPositive"); + } + + if (PMU.isLdoOverCurrentIrq()) { + Serial1.println("isLdoOverCurrentIrq"); + } + if (PMU.isBatfetOverCurrentIrq()) { + Serial1.println("isBatfetOverCurrentIrq"); + } + if (PMU.isBatChagerDoneIrq()) { + pcnt = PMU.getBatteryPercent(); + if (pcnt < 0) { // disconnect + pcnt = 0; + pmu_status = 0xff; + } + pmu_status = bitClear(pcnt, 7); + Serial1.println("isBatChagerDone"); + stop_chg(); + } + if (PMU.isBatChagerStartIrq()) { + pcnt = PMU.getBatteryPercent(); + if (pcnt < 0) { // disconnect + pcnt = 0; + pmu_status = 0xff; + } + pmu_status = bitSet(pcnt, 7); + Serial1.println("isBatChagerStart"); + if(PMU.isBatteryConnect()) { + start_chg(); + } + } + if (PMU.isBatDieOverTemperatureIrq()) { + Serial1.println("isBatDieOverTemperature"); + } + if (PMU.isChagerOverTimeoutIrq()) { + Serial1.println("isChagerOverTimeout"); + } + if (PMU.isBatOverVoltageIrq()) { + Serial1.println("isBatOverVoltage"); + } + // Clear PMU Interrupt Status Register + PMU.clearIrqStatus(); + } + + reg_set_value(REG_ID_BAT, (uint8_t)pmu_status); +} + +/* + * PA8 lcd_bl + * PC8 keyboard_bl + */ +void setup() { + pinMode(PA13, OUTPUT); // pico enable + digitalWrite(PA13, LOW); + reg_init(); + + Serial1.begin(115200); + + Wire.setSDA(PB9); + Wire.setSCL(PB8); + Wire.begin(SLAVE_ADDRESS); + Wire.setClock(10000);//It is important to set to 10Khz + Wire.onReceive(receiveEvent); // register event + Wire.onRequest(requestEvent); + + // no delay here + + bool result = PMU.begin(Wire2, AXP2101_SLAVE_ADDRESS, i2c_sda, i2c_scl); + + if (result == false) { + Serial1.println("PMU is not online..."); + } else { + pmu_online = 1; + Serial1.printf("getID:0x%x\n", PMU.getChipID()); + } + + pinMode(PC12, INPUT); // HP_DET + + pinMode(PC13, OUTPUT); // indicator led + + digitalWrite(PC13, LOW); + + pinMode(PA14, OUTPUT); // PA_EN + digitalWrite(PA14, HIGH); + + int pin = PC8; + + /* + RCC->APB2ENR |= RCC_APB2ENR_AFIOEN; + // 重映射Timer3的部分映射到PC6-PC9 + AFIO->MAPR &= ~AFIO_MAPR_TIM3_REMAP; + AFIO->MAPR |= AFIO_MAPR_TIM3_REMAP_PARTIALREMAP; + */ + /* + pinMode(pin,OUTPUT); + + TIM_TypeDef *Instance = (TIM_TypeDef + *)pinmap_peripheral(digitalPinToPinName(pin), PinMap_PWM); uint32_t channel = + STM_PIN_CHANNEL(pinmap_function(digitalPinToPinName(pin), PinMap_PWM)); + // Instantiate HardwareTimer object. Thanks to 'new' instantiation, + HardwareTimer is not destructed when setup() function is finished. + HardwareTimer *MyTim = new HardwareTimer(Instance); + + // Configure and start PWM + // MyTim->setPWM(channel, pin, 5, 10, NULL, NULL); // No callback required, we + can simplify the function call MyTim->setPWM(channel, pin, 80000, 1); // + Hertz, dutycycle + */ + /* + * data records: + * 500,10 === nightlight watch level + */ + /* + analogWriteFrequency(80000); + analogWrite(pin, 10); + */ + + pin = PA8; + analogWriteFrequency(10000); + analogWrite(pin, 100); + + keyboard_init(); + keyboard_set_key_callback(key_cb); + lcd_backlight_update(-223); + + digitalWrite(PA13, HIGH); + + + // It is necessary to disable the detection function of the TS pin on the + // board without the battery temperature detection function, otherwise it will + // cause abnormal charging + PMU.setSysPowerDownVoltage(2800); + PMU.disableTSPinMeasure(); + // PMU.enableTemperatureMeasure(); + PMU.enableBattDetection(); + PMU.enableVbusVoltageMeasure(); + PMU.enableBattVoltageMeasure(); + PMU.enableSystemVoltageMeasure(); + + PMU.setChargingLedMode(XPOWERS_CHG_LED_CTRL_CHG); + + pinMode(pmu_irq_pin, INPUT_PULLUP); + attachInterrupt(pmu_irq_pin, set_pmu_flag, FALLING); + + PMU.disableIRQ(XPOWERS_AXP2101_ALL_IRQ); + PMU.clearIrqStatus(); + PMU.enableIRQ(XPOWERS_AXP2101_BAT_INSERT_IRQ | + XPOWERS_AXP2101_BAT_REMOVE_IRQ | // BATTERY + XPOWERS_AXP2101_VBUS_INSERT_IRQ | + XPOWERS_AXP2101_VBUS_REMOVE_IRQ | // VBUS + XPOWERS_AXP2101_PKEY_SHORT_IRQ | + XPOWERS_AXP2101_PKEY_LONG_IRQ | // POWER KEY + XPOWERS_AXP2101_BAT_CHG_DONE_IRQ | + XPOWERS_AXP2101_BAT_CHG_START_IRQ // CHARGE + // XPOWERS_AXP2101_PKEY_NEGATIVE_IRQ | + // XPOWERS_AXP2101_PKEY_POSITIVE_IRQ | //POWER KEY + ); + // setLowBatWarnThreshold Range: 5% ~ 20% + // The following data is obtained from actual testing , Please see the description below for the test method. + // 20% ~= 3.7v + // 15% ~= 3.6v + // 10% ~= 3.55V + // 5% ~= 3.5V + // 1% ~= 3.4V + PMU.setLowBatWarnThreshold(5); // Set to trigger interrupt when reaching 5% + + // setLowBatShutdownThreshold Range: 0% ~ 15% + // The following data is obtained from actual testing , Please see the description below for the test method. + // 15% ~= 3.6v + // 10% ~= 3.55V + // 5% ~= 3.5V + // 1% ~= 3.4V + PMU.setLowBatShutdownThreshold(1); //This is related to the battery charging and discharging logic. If you're not sure what you're doing, please don't modify it, as it could damage the battery. + + + run_time = 0; + keycb_start = 1; + low_bat(); + //printf("Start pico"); +} + +//hp headphone +void check_hp_det(){ + int v = digitalRead(PC12); + if(v == HIGH) { + if( head_phone_status != v ) { + Serial1.println("HeadPhone detected"); + } + digitalWrite(PA14,LOW); + }else{ + digitalWrite(PA14,HIGH); + } + head_phone_status = v; + +} +void loop() { + check_pmu_int(); + keyboard_process(); + check_hp_det(); + delay(10); +} diff --git a/Code/picocalc_keyboard/pins.h b/Code/picocalc_keyboard/pins.h new file mode 100644 index 0000000..d8ed0be --- /dev/null +++ b/Code/picocalc_keyboard/pins.h @@ -0,0 +1,21 @@ +#ifndef PINS_H +#define PINS_H + +#include "keyboard.h" + +const uint8_t row_pins[NUM_OF_ROWS] = +{ + PA0,PA1,PA2,PA3,PA4,PA5,PA6 +}; + +const uint8_t col_pins[NUM_OF_COLS] = +{ + PC0,PC1,PC2,PC3,PC4,PC5,PC6,PC7 +}; + +const uint8_t btn_pins[NUM_OF_BTNS] = +{ + PB0,PB1,PB2,PB3,PB4,PB5,PB6,PB7,PB12,PB13,PB14,PB15 +}; + +#endif diff --git a/Code/picocalc_keyboard/port.h b/Code/picocalc_keyboard/port.h new file mode 100644 index 0000000..7313e3f --- /dev/null +++ b/Code/picocalc_keyboard/port.h @@ -0,0 +1,44 @@ +#ifndef PORT_H +#define PORT_H + +enum port_pin_dir { + /** The pin's input buffer should be enabled, so that the pin state can + * be read */ + PORT_PIN_DIR_INPUT = INPUT, + /** The pin's output buffer should be enabled, so that the pin state can + * be set */ + PORT_PIN_DIR_OUTPUT = OUTPUT, + +}; + +/** + * \brief Port pin input pull configuration enum. + * + * Enum for the possible pin pull settings of the port pin configuration + * structure, to indicate the type of logic level pull the pin should use. + */ +enum port_pin_pull { + /** No logical pull should be applied to the pin */ + PORT_PIN_PULL_NONE = INPUT_FLOATING, + /** Pin should be pulled up when idle */ + PORT_PIN_PULL_UP = INPUT_PULLUP, + /** Pin should be pulled down when idle */ + PORT_PIN_PULL_DOWN = INPUT_PULLDOWN, +}; + + +struct port_config { + /** Port buffer input/output direction */ + enum port_pin_dir direction; + + /** Port pull-up/pull-down for input pins */ + enum port_pin_pull input_pull; +}; + + +void port_get_config_defaults(struct port_config *const config); +void port_pin_set_config(const uint8_t gpio_pin,const struct port_config *const config); +void port_pin_set_output_level(const uint8_t gpio_pin, const bool level); +bool port_pin_get_input_level(const uint8_t gpio_pin); + +#endif diff --git a/Code/picocalc_keyboard/port.ino b/Code/picocalc_keyboard/port.ino new file mode 100644 index 0000000..12db553 --- /dev/null +++ b/Code/picocalc_keyboard/port.ino @@ -0,0 +1,39 @@ +#include "port.h" + +void port_get_config_defaults(struct port_config *const config) +{ + + /* Default configuration values */ + config->direction = PORT_PIN_DIR_INPUT; + config->input_pull = PORT_PIN_PULL_UP; + +} + +void port_pin_set_config(const uint8_t gpio_pin,const struct port_config *const config) +{ + if(config->direction == PORT_PIN_DIR_OUTPUT){ + pinMode(gpio_pin,OUTPUT); + return; + } + + if(config->direction == PORT_PIN_DIR_INPUT){ + + if(config->input_pull != PORT_PIN_PULL_NONE){ + pinMode(gpio_pin,config->input_pull); + }else{ + pinMode(gpio_pin,config->direction); + } + } +} + +void port_pin_set_output_level(const uint8_t gpio_pin, const bool level) +{ + digitalWrite(gpio_pin,level); +} + + +bool port_pin_get_input_level(const uint8_t gpio_pin){ + + return digitalRead(gpio_pin); + +} diff --git a/Code/picocalc_keyboard/reg.h b/Code/picocalc_keyboard/reg.h new file mode 100644 index 0000000..35f76b9 --- /dev/null +++ b/Code/picocalc_keyboard/reg.h @@ -0,0 +1,55 @@ +#ifndef REG_H +#define REG_H + +#include +#include + +enum reg_id +{ + REG_ID_VER = 0x01, // fw version + REG_ID_CFG = 0x02, // config + REG_ID_INT = 0x03, // interrupt status + REG_ID_KEY = 0x04, // key status + REG_ID_BKL = 0x05, // backlight + REG_ID_DEB = 0x06, // debounce cfg + REG_ID_FRQ = 0x07, // poll freq cfg + REG_ID_RST = 0x08, // reset + REG_ID_FIF = 0x09, // fifo + REG_ID_BK2 = 0x0A, //keyboard backlight + REG_ID_BAT = 0x0b,// battery + REG_ID_C64_MTX = 0x0c,// read c64 matrix + REG_ID_C64_JS = 0x0d, // joystick io bits + REG_ID_LAST, +}; + +#define CFG_OVERFLOW_ON (1 << 0) //When a FIFO overflow happens, should the new entry still be pushed, overwriting the oldest one. If 0 then new entry is lost. +#define CFG_OVERFLOW_INT (1 << 1) //Should an interrupt be generated when a FIFO overflow happens +#define CFG_CAPSLOCK_INT (1 << 2) //Should an interrupt be generated when Caps Lock is toggled. +#define CFG_NUMLOCK_INT (1 << 3) //Should an interrupt be generated when Num Lock is toggled. +#define CFG_KEY_INT (1 << 4) +#define CFG_PANIC_INT (1 << 5) +#define CFG_REPORT_MODS (1 << 6) // Should Alt, Sym and Shifts be reported as well +#define CFG_USE_MODS (1 << 7) // Should Alt, Sym and Shifts modify the keys reported +// CFG_STICKY_MODS // Pressing and releasing a mod affects next key pressed + +#define INT_OVERFLOW (1 << 0) +#define INT_CAPSLOCK (1 << 1) +#define INT_NUMLOCK (1 << 2) +#define INT_KEY (1 << 3) +#define INT_PANIC (1 << 4) + +#define KEY_CAPSLOCK (1 << 5) +#define KEY_NUMLOCK (1 << 6) +#define KEY_COUNT_MASK 0x1F //0x1F == 31 + +#define VER_VAL ((VERSION_MAJOR << 4) | (VERSION_MINOR << 0)) + +#define WRITE_MASK (1<<7) + +uint8_t reg_get_value(enum reg_id reg); +void reg_set_value(enum reg_id reg, uint8_t value); +bool reg_is_bit_set(enum reg_id reg, uint8_t bit); +void reg_set_bit(enum reg_id reg, uint8_t bit); +void reg_init(void); + +#endif diff --git a/Code/picocalc_keyboard/reg.ino b/Code/picocalc_keyboard/reg.ino new file mode 100644 index 0000000..b60d4c9 --- /dev/null +++ b/Code/picocalc_keyboard/reg.ino @@ -0,0 +1,45 @@ +#include "reg.h" + +static uint8_t regs[REG_ID_LAST]; + +uint8_t reg_get_value(enum reg_id reg) +{ + return regs[reg]; +} + +void reg_set_value(enum reg_id reg, uint8_t value) +{ + regs[reg] = value; +} + +bool reg_is_bit_set(enum reg_id reg, uint8_t bit) +{ + return regs[reg] & bit; +} + +void reg_set_bit(enum reg_id reg, uint8_t bit) +{ + regs[reg] |= bit; +} + +/* + * | Bit | Name | Description | +| ------ |:----------------:| ------------------------------------------------------------------:| +| 7 | CFG_USE_MODS | Should Alt, Sym and the Shift keys modify the keys being reported. | +| 6 | CFG_REPORT_MODS | Should Alt, Sym and the Shift keys be reported as well. | +| 5 | CFG_PANIC_INT | Currently not implemented. | +| 4 | CFG_KEY_INT | Should an interrupt be generated when a key is pressed. | +| 3 | CFG_NUMLOCK_INT | Should an interrupt be generated when Num Lock is toggled. | +| 2 | CFG_CAPSLOCK_INT | Should an interrupt be generated when Caps Lock is toggled. | +| 1 | CFG_OVERFLOW_INT | Should an interrupt be generated when a FIFO overflow happens. | +| 0 | CFG_OVERFLOW_ON | When a FIFO overflow happens, should the new entry still be pushed, overwriting the oldest one. If 0 then new entry is lost. | + */ +void reg_init(void) +{ + regs[REG_ID_CFG] = CFG_OVERFLOW_INT | CFG_KEY_INT | CFG_USE_MODS|CFG_REPORT_MODS ; + regs[REG_ID_DEB] = 10; + regs[REG_ID_FRQ] = 5; + regs[REG_ID_BKL] = 255;//100%duty + regs[REG_ID_BK2] = 0; + regs[REG_ID_BAT] = 0xff; //default .no battery +}