Added source code, MZ6500 module still not complete

This commit is contained in:
Philip Smart
2022-09-04 14:51:38 +01:00
parent 8bba3b0e92
commit 96a69cc86d
74 changed files with 30544 additions and 69 deletions

View File

@@ -1 +0,0 @@
../../sharpkey/main/BT.cpp

788
main/BT.cpp Normal file
View File

@@ -0,0 +1,788 @@
/////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Name: BT.cpp
// Created: Mar 2022
// Version: v1.0
// Author(s): Philip Smart
// Description: Bluetooth base class.
// This source file contains the class to encapsulate the Bluetooth ESP API. Both
// BLE and BT Classic are supported. Allows for scanning, pairing and connection
// to a peripheral device such as a Keyboard or Mouse.
//
// The application uses the Espressif Development environment with Arduino components.
// This is necessary as the class uses the Arduino methods for GPIO manipulation. I
// was considering using pure Espressif IDF methods but considered the potential
// of also using this class on an Arduino project.
//
// Credits:
// Copyright: (c) 2022 Philip Smart <philip.smart@net2net.org>
//
// History: Mar 2022 - Initial write.
//
// Notes: See Makefile to enable/disable conditional components
//
/////////////////////////////////////////////////////////////////////////////////////////////////////////
// This source file is free software: you can redistribute it and#or modify
// it under the terms of the GNU General Public License as published
// by the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This source file is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
/////////////////////////////////////////////////////////////////////////////////////////////////////////
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_log.h"
#include "esp_bt.h"
#include "esp_bt_main.h"
#include "esp_gap_bt_api.h"
#include "esp_bt_device.h"
#include "esp_spp_api.h"
#include "Arduino.h"
#include "driver/gpio.h"
#include "soc/timer_group_struct.h"
#include "soc/timer_group_reg.h"
#include "BT.h"
#define SIZEOF_ARRAY(a) (sizeof(a) / sizeof(*a))
// Out of object pointer to a singleton class for use in the ESP IDF API callback routines which werent written for C++. Other methods can be used but this one is the simplest
// to understand and the class can only ever be singleton.
BT *pBTThis = NULL;
// Method to locate a valid scan entry in the results list.
//
BT::t_scanListItem* BT::findValidScannedDevice(esp_bd_addr_t bda, std::vector<t_scanListItem> &scanList)
{
// Locals.
//
// Loop through the scan results list looking for a valid entry, return entry if found.
for(std::size_t idx = 0; idx < scanList.size(); idx++)
{
if (memcmp(bda, scanList[idx].bda, sizeof(esp_bd_addr_t)) == 0)
{
return &scanList[idx];
}
}
return(nullptr);
}
#ifdef CONFIG_CLASSIC_BT_ENABLED
// Method to add a valid BT Classic device onto the scan list.
//
void BT::addBTScanDevice(esp_bd_addr_t bda, esp_bt_cod_t *cod, esp_bt_uuid_t *uuid, uint8_t *name, uint8_t name_len, int rssi)
{
// Locals.
t_scanListItem item;
// Find a valid device in the BT Classic scan results. If a device is found then this callback is with new data.
t_scanListItem* result = findValidScannedDevice(bda, btCtrl.btScanList);
if(result)
{
// Information can be updated through several calls.
if(result->name.length() == 0 && name && name_len)
{
result->name.assign((char *)name, name_len);
}
if(result->bt.uuid.len == 0 && uuid->len)
{
memcpy(&result->bt.uuid, uuid, sizeof(esp_bt_uuid_t));
}
if(rssi != 0)
{
result->rssi = rssi;
}
return;
}
// Populate new list item with device results.
item.transport = ESP_HID_TRANSPORT_BT;
memcpy(item.bda, bda, sizeof(esp_bd_addr_t));
memcpy(&item.bt.cod, cod, sizeof(esp_bt_cod_t));
memcpy(&item.bt.uuid, uuid, sizeof(esp_bt_uuid_t));
item.usage = esp_hid_usage_from_cod((uint32_t)cod);
item.rssi = rssi;
item.name = "";
// Store device name if present. This is possibly provided in a seperate callback.
if(name_len && name)
{
item.name.assign((char *)name, name_len);
}
// Add new item onto list.
btCtrl.btScanList.push_back(item);
return;
}
#endif
// Method to add a valid BLE device to our scan list.
//
void BT::addBLEScanDevice(esp_bd_addr_t bda, esp_ble_addr_type_t addr_type, uint16_t appearance, uint8_t *name, uint8_t name_len, int rssi)
{
// Locals.
//
t_scanListItem item;
// See if the device is already in the list, exit if found as data updates with seperate callbacks not normal under BLE.
if(findValidScannedDevice(bda, btCtrl.bleScanList))
{
ESP_LOGW(TAG, "Result already exists!");
return;
}
// Populate the item with data.
item.transport = ESP_HID_TRANSPORT_BLE;
memcpy(item.bda, bda, sizeof(esp_bd_addr_t));
item.ble.appearance = appearance;
item.ble.addr_type = addr_type;
item.usage = esp_hid_usage_from_appearance(appearance);
item.rssi = rssi;
item.name = "";
// Store device name if present.
if(name_len && name)
{
item.name.assign((char *)name, name_len);
}
// Add new item onto list.
btCtrl.bleScanList.push_back(item);
return;
}
#ifdef CONFIG_CLASSIC_BT_ENABLED
// Method to process a device data resulting from a BT scan.
//
void BT::processBTDeviceScanResult(esp_bt_gap_cb_param_t * param)
{
// Locals
//
uint32_t codv = 0;
esp_bt_cod_t *cod = (esp_bt_cod_t *)&codv;
int8_t rssi = 0;
uint8_t *name = nullptr;
uint8_t name_len = 0;
esp_bt_uuid_t uuid;
uint8_t len = 0;
uint8_t *data = 0;
uuid.len = ESP_UUID_LEN_16;
uuid.uuid.uuid16 = 0;
for (int i = 0; i < param->disc_res.num_prop; i++)
{
esp_bt_gap_dev_prop_t * prop = &param->disc_res.prop[i];
if(prop->type != ESP_BT_GAP_DEV_PROP_EIR)
{
}
if(prop->type == ESP_BT_GAP_DEV_PROP_BDNAME)
{
name = (uint8_t *) prop->val;
name_len = strlen((const char *)name);
}
else if(prop->type == ESP_BT_GAP_DEV_PROP_RSSI)
{
rssi = *((int8_t *) prop->val);
}
else if(prop->type == ESP_BT_GAP_DEV_PROP_COD)
{
memcpy(&codv, prop->val, sizeof(uint32_t));
}
else if(prop->type == ESP_BT_GAP_DEV_PROP_EIR)
{
data = esp_bt_gap_resolve_eir_data((uint8_t *) prop->val, ESP_BT_EIR_TYPE_CMPL_16BITS_UUID, &len);
if(data == nullptr)
{
data = esp_bt_gap_resolve_eir_data((uint8_t *) prop->val, ESP_BT_EIR_TYPE_INCMPL_16BITS_UUID, &len);
}
if(data && len == ESP_UUID_LEN_16)
{
uuid.len = ESP_UUID_LEN_16;
uuid.uuid.uuid16 = data[0] + (data[1] << 8);
continue;
}
data = esp_bt_gap_resolve_eir_data((uint8_t *) prop->val, ESP_BT_EIR_TYPE_CMPL_32BITS_UUID, &len);
if(data == nullptr)
{
data = esp_bt_gap_resolve_eir_data((uint8_t *) prop->val, ESP_BT_EIR_TYPE_INCMPL_32BITS_UUID, &len);
}
if(data && len == ESP_UUID_LEN_32)
{
uuid.len = len;
memcpy(&uuid.uuid.uuid32, data, sizeof(uint32_t));
continue;
}
data = esp_bt_gap_resolve_eir_data((uint8_t *) prop->val, ESP_BT_EIR_TYPE_CMPL_128BITS_UUID, &len);
if(data == nullptr)
{
data = esp_bt_gap_resolve_eir_data((uint8_t *) prop->val, ESP_BT_EIR_TYPE_INCMPL_128BITS_UUID, &len);
}
if(data && len == ESP_UUID_LEN_128)
{
uuid.len = len;
memcpy(uuid.uuid.uuid128, (uint8_t *)data, len);
continue;
}
//try to find a name
if (name == nullptr)
{
data = esp_bt_gap_resolve_eir_data((uint8_t *) prop->val, ESP_BT_EIR_TYPE_CMPL_LOCAL_NAME, &len);
if (data == nullptr)
{
data = esp_bt_gap_resolve_eir_data((uint8_t *) prop->val, ESP_BT_EIR_TYPE_SHORT_LOCAL_NAME, &len);
}
if (data && len)
{
name = data;
name_len = len;
}
}
}
}
// If the found device is a peripheral or a second call on an existing device, add/update the device.
if ((cod->major == ESP_BT_COD_MAJOR_DEV_PERIPHERAL) || (findValidScannedDevice(param->disc_res.bda, btCtrl.btScanList) != nullptr))
{
addBTScanDevice(param->disc_res.bda, cod, &uuid, name, name_len, rssi);
}
}
#endif
#ifdef CONFIG_CLASSIC_BT_ENABLED
// BT GAP Event Handler.
//
void BT::processBTGapEvent(esp_bt_gap_cb_event_t event, esp_bt_gap_cb_param_t *param)
{
// Locals.
//
switch(event)
{
case ESP_BT_GAP_DISC_STATE_CHANGED_EVT:
{
ESP_LOGI(TAG, "BT GAP DISC_STATE %s", (param->disc_st_chg.state == ESP_BT_GAP_DISCOVERY_STARTED) ? "START" : "STOP");
if (param->disc_st_chg.state == ESP_BT_GAP_DISCOVERY_STOPPED)
{
// Release semaphore on which the initiator is waiting, this signals processing complete and results ready.
xSemaphoreGive(pBTThis->btCtrl.bt_hidh_cb_semaphore);
}
break;
}
case ESP_BT_GAP_DISC_RES_EVT:
{
pBTThis->processBTDeviceScanResult(param);
break;
}
case ESP_BT_GAP_KEY_NOTIF_EVT:
ESP_LOGI(TAG, "BT GAP KEY_NOTIF passkey:%d", param->key_notif.passkey);
if(pBTThis->btCtrl.pairingHandler != nullptr) (*pBTThis->btCtrl.pairingHandler)(param->key_notif.passkey, 1);
break;
case ESP_BT_GAP_MODE_CHG_EVT:
ESP_LOGI(TAG, "BT GAP MODE_CHG_EVT mode:%d", param->mode_chg.mode);
break;
case ESP_BT_GAP_AUTH_CMPL_EVT:
ESP_LOGI(TAG, "BT GAP MODE AUTH_CMPL:%s (%d)", param->auth_cmpl.device_name, param->auth_cmpl.stat);
if(pBTThis->btCtrl.pairingHandler != nullptr) (*pBTThis->btCtrl.pairingHandler)((uint32_t)param->auth_cmpl.stat, 2);
break;
default:
ESP_LOGI(TAG, "BT GAP EVENT %s", pBTThis->bt_gap_evt_str(event));
break;
}
}
#endif
// Method to process a device data resulting from a BLE scan.
//
void BT::processBLEDeviceScanResult(esp_ble_gap_cb_param_t *param)
{
// Locals.
//
uint16_t uuid = 0;
uint16_t appearance = 0;
char name[64] = "";
uint8_t uuid_len = 0;
uint8_t *uuid_d = esp_ble_resolve_adv_data(param->scan_rst.ble_adv, ESP_BLE_AD_TYPE_16SRV_CMPL, &uuid_len);
uint8_t appearance_len = 0;
uint8_t *appearance_d = esp_ble_resolve_adv_data(param->scan_rst.ble_adv, ESP_BLE_AD_TYPE_APPEARANCE, &appearance_len);
uint8_t adv_name_len = 0;
uint8_t *adv_name = esp_ble_resolve_adv_data(param->scan_rst.ble_adv, ESP_BLE_AD_TYPE_NAME_CMPL, &adv_name_len);
if (uuid_d != nullptr && uuid_len)
{
uuid = uuid_d[0] + (uuid_d[1] << 8);
}
if (appearance_d != nullptr && appearance_len)
{
appearance = appearance_d[0] + (appearance_d[1] << 8);
}
if (adv_name == nullptr)
{
adv_name = esp_ble_resolve_adv_data(param->scan_rst.ble_adv, ESP_BLE_AD_TYPE_NAME_SHORT, &adv_name_len);
}
if (adv_name != nullptr && adv_name_len)
{
memcpy(name, adv_name, adv_name_len);
name[adv_name_len] = 0;
}
if (uuid == ESP_GATT_UUID_HID_SVC)
{
addBLEScanDevice(param->scan_rst.bda,
param->scan_rst.ble_addr_type,
appearance, adv_name, adv_name_len,
param->scan_rst.rssi);
}
}
// BLE GAP Event Handler.
//
void BT::processBLEGapEvent(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t * param)
{
switch(event)
{
// SCAN
case ESP_GAP_BLE_SCAN_PARAM_SET_COMPLETE_EVT:
{
ESP_LOGI(TAG, "BLE GAP EVENT SCAN_PARAM_SET_COMPLETE");
// Release semaphore, this releases the caller who initiated the scan as we are now complete.
xSemaphoreGive(pBTThis->btCtrl.ble_hidh_cb_semaphore);
break;
}
case ESP_GAP_BLE_SCAN_RESULT_EVT:
{
switch (param->scan_rst.search_evt)
{
case ESP_GAP_SEARCH_INQ_RES_EVT:
{
pBTThis->processBLEDeviceScanResult(param);
break;
}
case ESP_GAP_SEARCH_INQ_CMPL_EVT:
ESP_LOGI(TAG, "BLE GAP EVENT SCAN DONE: %d", param->scan_rst.num_resps);
// Release semaphore, this releases the caller who initiated the scan as we are now complete.
xSemaphoreGive(pBTThis->btCtrl.ble_hidh_cb_semaphore);
break;
default:
break;
}
break;
}
case ESP_GAP_BLE_SCAN_STOP_COMPLETE_EVT:
{
ESP_LOGI(TAG, "BLE GAP EVENT SCAN CANCELED");
break;
}
// ADVERTISEMENT
case ESP_GAP_BLE_ADV_DATA_SET_COMPLETE_EVT:
ESP_LOGI(TAG, "BLE GAP ADV_DATA_SET_COMPLETE");
break;
case ESP_GAP_BLE_ADV_START_COMPLETE_EVT:
ESP_LOGI(TAG, "BLE GAP ADV_START_COMPLETE");
break;
// AUTHENTICATION
case ESP_GAP_BLE_AUTH_CMPL_EVT:
if (!param->ble_security.auth_cmpl.success)
{
ESP_LOGE(TAG, "BLE GAP AUTH ERROR: 0x%x", param->ble_security.auth_cmpl.fail_reason);
}
else
{
ESP_LOGI(TAG, "BLE GAP AUTH SUCCESS");
}
break;
case ESP_GAP_BLE_KEY_EVT: //shows the ble key info share with peer device to the user.
ESP_LOGI(TAG, "BLE GAP KEY type = %s", pBTThis->ble_key_type_str(param->ble_security.ble_key.key_type));
break;
case ESP_GAP_BLE_PASSKEY_NOTIF_EVT: // ESP_IO_CAP_OUT
// The app will receive this evt when the IO has Output capability and the peer device IO has Input capability.
// Show the passkey number to the user to input it in the peer device.
ESP_LOGI(TAG, "BLE GAP PASSKEY_NOTIF passkey:%d", param->ble_security.key_notif.passkey);
if(pBTThis->btCtrl.pairingHandler != nullptr) (*pBTThis->btCtrl.pairingHandler)(param->ble_security.key_notif.passkey, 3);
break;
case ESP_GAP_BLE_NC_REQ_EVT: // ESP_IO_CAP_IO
// The app will receive this event when the IO has DisplayYesNO capability and the peer device IO also has DisplayYesNo capability.
// show the passkey number to the user to confirm it with the number displayed by peer device.
ESP_LOGI(TAG, "BLE GAP NC_REQ passkey:%d", param->ble_security.key_notif.passkey);
esp_ble_confirm_reply(param->ble_security.key_notif.bd_addr, true);
break;
case ESP_GAP_BLE_PASSKEY_REQ_EVT: // ESP_IO_CAP_IN
// The app will receive this evt when the IO has Input capability and the peer device IO has Output capability.
// See the passkey number on the peer device and send it back.
ESP_LOGI(TAG, "BLE GAP PASSKEY_REQ");
//esp_ble_passkey_reply(param->ble_security.ble_req.bd_addr, true, 1234);
break;
case ESP_GAP_BLE_SEC_REQ_EVT:
ESP_LOGI(TAG, "BLE GAP SEC_REQ");
// Send the positive(true) security response to the peer device to accept the security request.
// If not accept the security request, should send the security response with negative(false) accept value.
esp_ble_gap_security_rsp(param->ble_security.ble_req.bd_addr, true);
break;
case ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT:
ESP_LOGI(TAG, "update connection params status = %d, min_int = %d, max_int = %d,conn_int = %d,latency = %d, timeout = %d",
param->update_conn_params.status,
param->update_conn_params.min_int,
param->update_conn_params.max_int,
param->update_conn_params.conn_int,
param->update_conn_params.latency,
param->update_conn_params.timeout);
break;
default:
ESP_LOGI(TAG, "BLE GAP EVENT %s", pBTThis->ble_gap_evt_str(event));
break;
}
}
#ifdef CONFIG_CLASSIC_BT_ENABLED
// Method to scan for BT Classic devices.
//
esp_err_t BT::scanForBTDevices(uint32_t timeout)
{
// Locals.
//
esp_err_t result = ESP_OK;
// Start BT GAP Discovery, wait for 'timeout' seconds for a valid result.
if((result = esp_bt_gap_start_discovery(ESP_BT_INQ_MODE_GENERAL_INQUIRY, (int)(timeout / 1.28), 0)) != ESP_OK)
{
ESP_LOGE(TAG, "esp_bt_gap_start_discovery failed: %d", result);
}
return(result);
}
#endif
// Method to scan for BLE Devices.
//
esp_err_t BT::scanForBLEDevices(uint32_t timeout)
{
// Locals.
//
esp_err_t result = ESP_OK;
// Setup BLE scan parameters structure, defined in ESP IDF documentation.
static esp_ble_scan_params_t hid_scan_params = {
.scan_type = BLE_SCAN_TYPE_ACTIVE,
.own_addr_type = BLE_ADDR_TYPE_PUBLIC,
.scan_filter_policy = BLE_SCAN_FILTER_ALLOW_ALL,
.scan_interval = 0x50,
.scan_window = 0x30,
.scan_duplicate = BLE_SCAN_DUPLICATE_ENABLE,
};
// Set scan parameters using populated structure.
if((result = esp_ble_gap_set_scan_params(&hid_scan_params)) != ESP_OK)
{
ESP_LOGE(TAG, "esp_ble_gap_set_scan_params failed: %d", result);
return(result);
}
// Wait for result, this is done by taking possession of a semaphore which is released in the callback when scan complete.
xSemaphoreTake(btCtrl.ble_hidh_cb_semaphore, portMAX_DELAY);
if((result = esp_ble_gap_start_scanning(timeout)) != ESP_OK)
{
ESP_LOGE(TAG, "esp_ble_gap_start_scanning failed: %d", result);
return(result);
}
return(result);
}
// Method to scan for Bluetooth devices.
//
esp_err_t BT::scanForAllDevices(uint32_t timeout, size_t *noDevices, std::vector<t_scanListItem> &scanList)
{
// Locals.
//
// Clear previous lists.
#ifdef CONFIG_CLASSIC_BT_ENABLED
btCtrl.btScanList.clear();
#endif
btCtrl.bleScanList.clear();
// Scan for BLE devices.
if(scanForBLEDevices(timeout) == ESP_OK)
{
// Wait for result, this is done by taking possession of a semaphore which is released in the callback when scan complete.
xSemaphoreTake(btCtrl.ble_hidh_cb_semaphore, portMAX_DELAY);
}
else
{
return(ESP_FAIL);
}
#ifdef CONFIG_CLASSIC_BT_ENABLED
// Scan for BT devices
if(scanForBTDevices(timeout) == ESP_OK)
{
// Wait for result, this is done by taking possession of a semaphore which is released in the callback when scan complete.
xSemaphoreTake(btCtrl.bt_hidh_cb_semaphore, portMAX_DELAY);
}
else
{
return(ESP_FAIL);
}
#endif
//esp_bt_gap_cancel_discovery();
//esp_ble_gap_stop_scanning();
// Process results into a merged list.
#ifdef CONFIG_CLASSIC_BT_ENABLED
for(std::size_t idx = 0; idx < btCtrl.btScanList.size(); idx++)
{
scanList.push_back(btCtrl.btScanList[idx]);
}
#endif
for(std::size_t idx = 0; idx < btCtrl.bleScanList.size(); idx++)
{
scanList.push_back(btCtrl.bleScanList[idx]);
}
// Update the final list with display values.
for(std::size_t idx = 0; idx < scanList.size(); idx++)
{
char buf[50];
sprintf(buf, ESP_BD_ADDR_STR, ESP_BD_ADDR_HEX(scanList[idx].bda));
scanList[idx].deviceAddr = buf;
if(scanList[idx].transport == ESP_HID_TRANSPORT_BLE)
{
scanList[idx].deviceType = "BLE";
}
#ifdef CONFIG_CLASSIC_BT_ENABLED
if(scanList[idx].transport == ESP_HID_TRANSPORT_BT)
{
scanList[idx].deviceType = "BT";
}
#endif
}
// Save number of entries.
*noDevices = scanList.size();
// Clear BT/BLE lists as data no longer needed.
#ifdef CONFIG_CLASSIC_BT_ENABLED
btCtrl.btScanList.clear();
#endif
btCtrl.bleScanList.clear();
return(ESP_OK);
}
// Method to scan and build a list for all available devices.
void BT::getDeviceList(std::vector<t_scanListItem> &scanList, int waitTime)
{
// Locals.
//
size_t devicesFound = 0;
ESP_LOGD(TAG, "SCAN...");
// Clear previous entries.
scanList.clear();
// Start scan for HID devices
scanForAllDevices(waitTime, &devicesFound, scanList);
ESP_LOGD(TAG, "SCAN: %u results", devicesFound);
}
// Method to configure Bluetooth and register required callbacks.
bool BT::setup(t_pairingHandler *handler)
{
// Locals.
//
esp_err_t result;
const esp_bt_mode_t mode = HIDH_BTDM_MODE;
uint8_t key_size = 16;
uint8_t init_key = ESP_BLE_ENC_KEY_MASK | ESP_BLE_ID_KEY_MASK;
uint8_t rsp_key = ESP_BLE_ENC_KEY_MASK | ESP_BLE_ID_KEY_MASK;
uint32_t passkey = 123456;
uint8_t auth_option = ESP_BLE_ONLY_ACCEPT_SPECIFIED_AUTH_DISABLE;
uint8_t oob_support = ESP_BLE_OOB_DISABLE;
// Check for multiple instantiations, only one instance allowed.
if(pBTThis != nullptr)
{
ESP_LOGE(TAG, "Setup called more than once. Only one instance of BT is allowed.");
return false;
}
// Store current object and handlers.
pBTThis = this;
btCtrl.pairingHandler = handler;
// Bluetooth not enabled, exit.
if(mode == HIDH_IDLE_MODE)
{
ESP_LOGE(TAG, "Please turn on BT HID host or BLE!");
return false;
}
#ifdef CONFIG_CLASSIC_BT_ENABLED
// Create BT Classic semaphore, used to halt caller whilst underlying receives and proceses data.
btCtrl.bt_hidh_cb_semaphore = xSemaphoreCreateBinary();
if (btCtrl.bt_hidh_cb_semaphore == nullptr)
{
ESP_LOGE(TAG, "xSemaphoreCreateMutex BT failed!");
return false;
}
#endif
// Create BLE semaphore, used to halt caller whilst underlying receives and proceses data.
btCtrl.ble_hidh_cb_semaphore = xSemaphoreCreateBinary();
if(btCtrl.ble_hidh_cb_semaphore == nullptr)
{
ESP_LOGE(TAG, "xSemaphoreCreateMutex BLE failed!");
#ifdef CONFIG_CLASSIC_BT_ENABLED
// Delete BT semaphore as both BT and BLE need to be active, return fail to caller.
vSemaphoreDelete(btCtrl.bt_hidh_cb_semaphore);
btCtrl.bt_hidh_cb_semaphore = nullptr;
#endif
return false;
}
#ifdef CONFIG_CLASSIC_BT_ENABLED
// Setup default config for BT Classic.
esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
bt_cfg.mode = mode;
bt_cfg.bt_max_acl_conn = 3;
bt_cfg.bt_max_sync_conn = 3;
// Configure Bluetooth controller for BT Classic operation.
if((result = esp_bt_controller_init(&bt_cfg)))
{
ESP_LOGE(TAG, "esp_bt_controller_init failed: %d", result);
return false;
}
// Enable Bluetooth Classic mode.
if((result = esp_bt_controller_enable(mode)))
{
ESP_LOGE(TAG, "esp_bt_controller_enable failed: %d", result);
return false;
}
esp_bredr_tx_power_set(ESP_PWR_LVL_P9, ESP_PWR_LVL_P9);
#endif
// Setup and initialise Bluetooth BLE mode.
if((result = esp_bluedroid_init()))
{
ESP_LOGE(TAG, "esp_bluedroid_init failed: %d", result);
return false;
}
if((result = esp_bluedroid_enable()))
{
ESP_LOGE(TAG, "esp_bluedroid_enable failed: %d", result);
return false;
}
esp_ble_tx_power_set(ESP_BLE_PWR_TYPE_DEFAULT, ESP_PWR_LVL_P9);
#ifdef CONFIG_CLASSIC_BT_ENABLED
// Classic Bluetooth GAP
esp_bt_sp_param_t param_type = ESP_BT_SP_IOCAP_MODE;
esp_bt_io_cap_t iocap = ESP_BT_IO_CAP_IO;
esp_bt_gap_set_security_param(param_type, &iocap, sizeof(uint8_t));
// Set default parameters for Legacy Pairing
// Use fixed pin code
//
esp_bt_pin_type_t pin_type = ESP_BT_PIN_TYPE_FIXED;
esp_bt_pin_code_t pin_code;
pin_code[0] = '1';
pin_code[1] = '2';
pin_code[2] = '3';
pin_code[3] = '4';
esp_bt_gap_set_pin(pin_type, 4, pin_code);
if((result = esp_bt_gap_register_callback(processBTGapEvent)))
{
ESP_LOGE(TAG, "esp_bt_gap_register_callback failed: %d", result);
return false;
}
// Allow BT devices to connect back to us
if((result = esp_bt_gap_set_scan_mode(ESP_BT_CONNECTABLE, ESP_BT_NON_DISCOVERABLE)))
{
ESP_LOGE(TAG, "esp_bt_gap_set_scan_mode failed: %d", result);
return false;
}
#endif
// BLE GAP
if((result = esp_ble_gap_register_callback(processBLEGapEvent)))
{
ESP_LOGE(TAG, "esp_ble_gap_register_callback failed: %d", result);
return false;
}
// Setup security, no password.
esp_ble_auth_req_t auth_req = ESP_LE_AUTH_REQ_SC_MITM_BOND; // Bonding with peer device after authentication
esp_ble_io_cap_t iocapble = ESP_IO_CAP_NONE; // Set the IO capability to No output No input
esp_ble_gap_set_security_param(ESP_BLE_SM_SET_STATIC_PASSKEY, &passkey, sizeof(uint32_t));
esp_ble_gap_set_security_param(ESP_BLE_SM_AUTHEN_REQ_MODE, &auth_req, sizeof(uint8_t));
esp_ble_gap_set_security_param(ESP_BLE_SM_IOCAP_MODE, &iocapble, sizeof(uint8_t));
esp_ble_gap_set_security_param(ESP_BLE_SM_MAX_KEY_SIZE, &key_size, sizeof(uint8_t));
esp_ble_gap_set_security_param(ESP_BLE_SM_ONLY_ACCEPT_SPECIFIED_SEC_AUTH, &auth_option, sizeof(uint8_t));
esp_ble_gap_set_security_param(ESP_BLE_SM_OOB_SUPPORT, &oob_support, sizeof(uint8_t));
esp_ble_gap_set_security_param(ESP_BLE_SM_SET_INIT_KEY, &init_key, sizeof(uint8_t));
esp_ble_gap_set_security_param(ESP_BLE_SM_SET_RSP_KEY, &rsp_key, sizeof(uint8_t));
// Initialise parameters.
btCtrl.batteryLevel = -1;
return true;
}
// Basic constructor, do nothing!
BT::BT(void)
{
btCtrl.hidhDevHdl = NULL;
#ifdef CONFIG_CLASSIC_BT_ENABLED
btCtrl.pairingHandler = nullptr;
btCtrl.bt_hidh_cb_semaphore = nullptr;
#endif
btCtrl.ble_hidh_cb_semaphore = nullptr;
pBTThis = NULL;
//
}
// Basic destructor, do nothing! Only ever called for instantiation of uninitialsed class to prove version data.Used for probing versions etc.
BT::~BT(void)
{
//
}

View File

@@ -1 +0,0 @@
../../sharpkey/main/BTHID.cpp

1011
main/BTHID.cpp Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1 +0,0 @@
../../sharpkey/main/CMakeLists.txt

4
main/CMakeLists.txt Normal file
View File

@@ -0,0 +1,4 @@
set(COMPONENT_SRCS SharpKey.cpp NVS.cpp LED.cpp SWITCH.cpp KeyInterface.cpp MZ2528.cpp X1.cpp X68K.cpp Mouse.cpp MZ5665.cpp PC9801.cpp HID.cpp WiFi.cpp PS2KeyAdvanced.cpp PS2Mouse.cpp BT.cpp BTHID.cpp esp_efuse_custom_table.c)
set(COMPONENT_ADD_INCLUDEDIRS "." "include")
register_component()

View File

@@ -1 +0,0 @@
../../sharpkey/main/HID.cpp

1018
main/HID.cpp Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1 +0,0 @@
../../sharpkey/main/Kconfig.projbuild

309
main/Kconfig.projbuild Normal file
View File

@@ -0,0 +1,309 @@
menu "SharpKey Configuration"
choice BUILD_TARGET
prompt "Build target"
default SHARPKEY
help
Choose the target of the next build, SHARPKEY for the multi-host SharpKey Interface, MZ25KEY_MZ2500 for the mz25key Interface which will be used
with an MZ-2500 or MZ25KEY_MZ2800 for the mz25key Interface which will be used with an MZ-2800.
config SHARPKEY
bool "SharpKey"
help
Target build for the SharpKey multi-host Interface.
config MZ25KEY_MZ2500
bool "mz25key - MZ2500"
help
Target build for the mz25key Interface for use on an MZ-2500
config MZ25KEY_MZ2800
bool "mz25key - MZ2800"
help
Target build for the mz25key Interface for use on an MZ-2800
endchoice
choice FEATURE_SECURITY
prompt "Runtime Feature Security"
default DISABLE_FEATURE_SECURITY
help
Choose wether to enable features in the firmware based on fuse settings or to disable the feature.
config DISABLE_FEATURE_SECURITY
bool "Disable feature security"
help
Disable the feature security, enabling all inbuilt modules of the SharpKey firmware.
config ENABLE_FEATURE_SECURITY
bool "Enable feature security"
help
Enable feature security, modules will only be available if the corresponding eFuse is set.
endchoice
menu "PS2 Keyboard"
config PS2_HW_DATAPIN
int "GPIO pin number used for the PS/2 Keyboard DATA line"
range 0 46
default 14
help
GPIO number (IOxx) used to connect with the PS/2 Keyboard DATA line.
Some GPIOs are used for other purposes (flash connections, etc.) and cannot be used to I2C.
GPIOs 35-39 are input-only so cannot be used as outputs.
config PS2_HW_CLKPIN
int "GPIO pin number used for the PS/2 Keyboard CLK line"
range 0 46
default 13
help
GPIO number (IOxx) used to connect with the PS/2 Keyboard CLK line.
This pin must be interrupt capable.
Some GPIOs are used for other purposes (flash connections, etc.) and cannot be used to I2C.
GPIOs 35-39 are input-only so cannot be used as outputs.
endmenu
menu "Host Interface"
menu "4Bit Strobe Input"
config HOST_KDB0
int "KDB0 GPIO pin number"
range 0 46
default 23
help
GPIO number (IOxx) used to connect the 4bit bidirectional data bus Bit 0 with the ESP32. See schematic for actual used value. May change with revisions.
config HOST_KDB1
int "KDB1 GPIO pin number"
range 0 46
default 25
help
GPIO number (IOxx) used to connect the 4bit bidirectional data bus Bit 1 with the ESP32. See schematic for actual used value. May change with revisions.
config HOST_KDB2
int "KDB2 GPIO pin number"
range 0 46
default 26
help
GPIO number (IOxx) used to connect the 4bit bidirectional data bus Bit 2 with the ESP32. See schematic for actual used value. May change with revisions.
config HOST_KDB3
int "KDB3 GPIO pin number"
range 0 46
default 27
help
GPIO number (IOxx) used to connect the 4bit bidirectional data bus Bit 3 with the ESP32. See schematic for actual used value. May change with revisions.
endmenu
menu "8Bit Scan Data Output"
config HOST_KDO0
int "KDO0 GPIO pin number"
range 0 46
default 14
help
GPIO number (IOxx) used to connect the 8bit scan data output Bit 0 to the 74HCT257 IC. See schematic for actual used value. May change with revisions.
config HOST_KDO1
int "KDO1 GPIO pin number"
range 0 46
default 15
help
GPIO number (IOxx) used to connect the 8bit scan data output Bit 1 to the 74HCT257 IC. See schematic for actual used value. May change with revisions.
config HOST_KDO2
int "KDO2 GPIO pin number"
range 0 46
default 16
help
GPIO number (IOxx) used to connect the 8bit scan data output Bit 2 to the 74HCT257 IC. See schematic for actual used value. May change with revisions.
config HOST_KDO3
int "KDO3 GPIO pin number"
range 0 46
default 17
help
GPIO number (IOxx) used to connect the 8bit scan data output Bit 3 to the 74HCT257 IC. See schematic for actual used value. May change with revisions.
config HOST_KDO4
int "KDO4 GPIO pin number"
range 0 46
default 18
help
GPIO number (IOxx) used to connect the 8bit scan data output Bit 4 to the 74HCT257 IC. See schematic for actual used value. May change with revisions.
config HOST_KDO5
int "KDO5 GPIO pin number"
range 0 46
default 19
help
GPIO number (IOxx) used to connect the 8bit scan data output Bit 5 to the 74HCT257 IC. See schematic for actual used value. May change with revisions.
config HOST_KDO6
int "KDO6 GPIO pin number"
range 0 46
default 21
help
GPIO number (IOxx) used to connect the 8bit scan data output Bit 6 to the 74HCT257 IC. See schematic for actual used value. May change with revisions.
config HOST_KDO7
int "KDO7 GPIO pin number"
range 0 46
default 21
help
GPIO number (IOxx) used to connect the 8bit scan data output Bit 7 to the 74HCT257 IC. See schematic for actual used value. May change with revisions.
endmenu
choice MOUSE_UART_CHOICE
prompt "Mouse host side UART"
default HOST_BITBANG_UART
help
Select the hardware method of sending mouse data to the host. The two possible methods are bitbang (software UART) and UART Hardware.
config HOST_BITBANG_UART
bool "Bitbang UART"
help
Use the Bitbang UART (software).
config HOST_HW_UART
bool "Hardware UART"
help
Use one of the ESP32 Hardware UART's.
endchoice
config HOST_RTSNI
int "RTSNi GPIO pin number"
range 0 46
default 35
help
GPIO number (IOxx) used to connect the RTSN line with the ESP32. See schematic for actual used value. May change with revisions.
config HOST_MPXI
int "MPXi GPIO pin number"
range 0 46
default 12
help
GPIO number (IOxx) used to connect the MPX line with the ESP32. See schematic for actual used value. May change with revisions.
config HOST_KDI4
int "KDI4 GPIO pin number"
range 0 46
default 13
help
GPIO number (IOxx) used to connect the KDI4 line with the ESP32. See schematic for actual used value. May change with revisions.
endmenu
menu "WiFi"
config IF_WIFI_ENABLED
bool "Enable WiFi connectivity"
default false
help
Allow interface to act as an Access Point to allow external connectivity. Once connected the WiFi is intended to be used for making
key mapping changes.
This is an experimental feature and under development.
config IF_WIFI_EN_KEY
int "WiFi Enable GPIO pin number"
range 0 46
default 34
depends on IF_WIFI_ENABLED
help
GPIO number (IOxx) used by the WiFi En switch to enable wifi connectivity.
config IF_WIFI_SSID
string "Default SSID in Access Point Mode"
default "sharpkey"
depends on IF_WIFI_ENABLED
help
The SSID broadcast whilst the sharpkey module advertises wireless connectivity.
config IF_WIFI_DEFAULT_SSID_PWD
string "Default password for initial connection to Access Point Mode"
default "sharpkey"
depends on IF_WIFI_ENABLED
help
The initial password needed to connect and logon to access point.
config IF_WIFI_MAX_RETRIES
int "Maximum number of connection retries."
range 0 100
default 10
depends on IF_WIFI_ENABLED
help
Number of retries allowed for making a wireless connection with a client.
config IF_WIFI_AP_CHANNEL
int "Channel of the Access Point."
range 0 13
default 7
depends on IF_WIFI_ENABLED
help
Channel use by the Access Point, default is 7.
config IF_WIFI_SSID_HIDDEN
int "Broadcast SSID?"
range 0 1
default 0
depends on IF_WIFI_ENABLED
help
Broadcast the SSID (0) or hide it (1).
config IF_WIFI_MAX_CONNECTIONS
int "Maximum simultaneous connections."
range 0 20
default 5
depends on IF_WIFI_ENABLED
help
Maximum number of simultaneous open connections supported.
endmenu
menu "Debug Options"
config DEBUG_SERIAL
bool "Serial debug output"
default false
help
Enable debug output (non ESP logging) on the serial port.
config DEBUG_DISABLE_KDB
bool "Disable input mode actuation of the KDB data bus"
default false
help
Disable the Host KDB input configuration step, useful feature for debugging.
config DEBUG_DISABLE_KDO
bool "Disable output mode actuation of the KDO strobe row"
default false
help
Disable the Host KDO output configuration step, useful feature for debugging.
config DEBUG_DISABLE_RTSNI
bool "Disable input mode actuation of the RTSNi signal"
default false
help
Disable the Host RTSNi input configuration step, useful feature for debugging.
config DEBUG_DISABLE_MPXI
bool "Disable input mode actuation of the MPXi signal"
default false
help
Disable the Host MPXi input configuration step, useful feature for debugging.
config DEBUG_DISABLE_KDI
bool "Disable input mode actuation of the KDI4 signal"
default false
help
Disable the Host KDI input configuration step, useful feature for debugging.
endmenu
config PWRLED
int "GPIO pin number used for Power On and Status LED"
range 0 46
default 25
help
GPIO number (IOxx) used to control the Power On/Status LED.
Some GPIOs are used for other purposes (flash connections, etc.) and cannot be used to I2C.
GPIOs 35-39 are input-only so cannot be used as outputs.
endmenu

View File

@@ -1 +0,0 @@
../../sharpkey/main/KeyInterface.cpp

211
main/KeyInterface.cpp Normal file
View File

@@ -0,0 +1,211 @@
/////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Name: KeyInterface.cpp
// Created: Mar 2022
// Version: v1.0
// Author(s): Philip Smart
// Description: Base class with virtual abstraction of key methods on which all host interfaces,
// instantiated as a singleton, are based. This module comprises all common interface
// code and the header contains the virtual abstraction methods overriden by the
// sub-class which forms an actual interface.
// Credits:
// Copyright: (c) 2019-2022 Philip Smart <philip.smart@net2net.org>
//
// History: Mar 2022 - Initial write.
// v1.01 May 2022 - Initial release version.
//
// Notes: See Makefile to enable/disable conditional components
//
/////////////////////////////////////////////////////////////////////////////////////////////////////////
// This source file is free software: you can redistribute it and#or modify
// it under the terms of the GNU General Public License as published
// by the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This source file is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
/////////////////////////////////////////////////////////////////////////////////////////////////////////
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <iostream>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_log.h"
#include "esp_system.h"
#include "driver/gpio.h"
#include "soc/timer_group_struct.h"
#include "soc/timer_group_reg.h"
#include "driver/timer.h"
#include "PS2KeyAdvanced.h"
#include "PS2Mouse.h"
#include "sdkconfig.h"
#include "KeyInterface.h"
// Method to reconfigure the GPIO on ADC2. This is necessary due to an ESP32 issue regarding WiFi Client mode and ADC2. If the
// pins are input and wrong value the WiFi Client mode wont connect, if they are output it will connect!! A few issues with the
// ESP32 you have to work around, next design, try use ADC2 as outputs only!
void KeyInterface::reconfigADC2Ports(bool setAsOutput)
{
// Locals.
//
gpio_config_t io_conf;
// Configure 4 inputs to be the Strobe Row Number which is used to index the virtual key matrix and the strobe data returned.
#if !defined(CONFIG_DEBUG_DISABLE_KDB)
io_conf.intr_type = GPIO_INTR_DISABLE;
io_conf.mode = (setAsOutput == true ? GPIO_MODE_OUTPUT : GPIO_MODE_INPUT);
io_conf.pin_bit_mask = (1ULL<<CONFIG_HOST_KDB0);
io_conf.pull_down_en = GPIO_PULLDOWN_DISABLE;
io_conf.pull_up_en = (setAsOutput == true ? GPIO_PULLUP_DISABLE : GPIO_PULLUP_ENABLE);
gpio_config(&io_conf);
io_conf.pin_bit_mask = (1ULL<<CONFIG_HOST_KDB1);
gpio_config(&io_conf);
io_conf.pin_bit_mask = (1ULL<<CONFIG_HOST_KDB2);
gpio_config(&io_conf);
io_conf.pin_bit_mask = (1ULL<<CONFIG_HOST_KDB3);
gpio_config(&io_conf);
#endif
#if !defined(CONFIG_DEBUG_DISABLE_KDI)
io_conf.intr_type = GPIO_INTR_DISABLE;
io_conf.mode = (setAsOutput == true ? GPIO_MODE_OUTPUT : GPIO_MODE_INPUT);
io_conf.pin_bit_mask = (1ULL<<CONFIG_HOST_KDI4);
io_conf.pull_down_en = GPIO_PULLDOWN_DISABLE;
io_conf.pull_up_en = (setAsOutput == true ? GPIO_PULLUP_DISABLE : GPIO_PULLUP_ENABLE);
gpio_config(&io_conf);
#endif
#if !defined(CONFIG_DEBUG_DISABLE_MPXI)
io_conf.intr_type = GPIO_INTR_DISABLE;
io_conf.mode = (setAsOutput == true ? GPIO_MODE_OUTPUT : GPIO_MODE_INPUT);
io_conf.pin_bit_mask = (1ULL<<CONFIG_HOST_MPXI);
io_conf.pull_down_en = GPIO_PULLDOWN_DISABLE;
io_conf.pull_up_en = (setAsOutput == true ? GPIO_PULLUP_DISABLE : GPIO_PULLUP_ENABLE);
gpio_config(&io_conf);
#endif
// In output mode set the drive capability to weak so as not to adversely affect the 74LS257.
if(setAsOutput == true)
{
#if !defined(CONFIG_DEBUG_DISABLE_KDB)
gpio_set_drive_capability((gpio_num_t)CONFIG_HOST_KDB0, GPIO_DRIVE_CAP_0);
gpio_set_drive_capability((gpio_num_t)CONFIG_HOST_KDB1, GPIO_DRIVE_CAP_0);
gpio_set_drive_capability((gpio_num_t)CONFIG_HOST_KDB2, GPIO_DRIVE_CAP_0);
gpio_set_drive_capability((gpio_num_t)CONFIG_HOST_KDB3, GPIO_DRIVE_CAP_0);
#endif
#if !defined(CONFIG_DEBUG_DISABLE_KDI)
gpio_set_drive_capability((gpio_num_t)CONFIG_HOST_KDI4, GPIO_DRIVE_CAP_0);
#endif
#if !defined(CONFIG_DEBUG_DISABLE_MPXI)
gpio_set_drive_capability((gpio_num_t)CONFIG_HOST_MPXI, GPIO_DRIVE_CAP_0);
#endif
}
return;
}
// Method to set the suspend flag. This is needed as some sub-class logic (ie. the MZ sub-class) locks and dedicates a core to meet
// required timing. Unfortunately if using some Espressif/Arduino/FreeRTOS API modules (such as WiFi) and a core is held in a spinlock
// it appears the API code has been written to use or attach to a fixed core thus the spinlock blocks its operation. Thus this method is provided
// so that external logic such as WiFi can disable the interface during these situations.
//
void KeyInterface::suspendInterface(bool suspendIf)
{
this->suspend = suspendIf;
}
// Method to test to see if the interface has been suspended.
// Two modes, one just tests and returns the state, the second waits in a loop until the interface suspends.
//
bool KeyInterface::isSuspended(bool waitForSuspend)
{
// If flag set, loop waiting for the suspended flag to be set.
while(waitForSuspend == true && this->suspended == false)
{
vTaskDelay(1);
}
// Return the suspended status.
return(this->suspended);
}
// Method to test to see if the interface is running and not suspended.
// Two modes, one just tests and returns the state, the second waits in a loop until the interface runs.
bool KeyInterface::isRunning(bool waitForRelease)
{
// If flag set, loop waiting for the suspended flag to be set.
while(waitForRelease == true && this->suspended == true)
{
vTaskDelay(1);
}
// Return the suspended status.
return(this->suspended);
}
// Base initialisation for generic hardware used by all sub-classes. The sub-class invokes the init
// method manually from within it's init method.
void KeyInterface::init(const char *subClassName, NVS *hdlNVS, LED *hdlLED, HID *hdlHID, uint32_t ifMode)
{
// Locals
#define INITTAG "init"
// Store the NVS object.
this->nvs = hdlNVS;
// Store the LED object.
this->led = hdlLED;
// Store the HID object.
this->hid = hdlHID;
// Store the sub-class name for later use, ie. NVS key access.
this->subClassName = subClassName;
// Set LED to on.
led->setLEDMode(LED::LED_MODE_ON, LED::LED_DUTY_CYCLE_OFF, 0, 0L, 0L);
// All done, no return code!
return;
}
// Base initialisation for generic hardware used by all sub-classes. The sub-class invokes the init
// method manually from within it's init method.
// This method doesnt initialise hardware, used for objects probing this object data.
void KeyInterface::init(const char *subClassName, NVS *hdlNVS, HID *hdlHID)
{
// Locals
#define INITTAG "init"
// Store the NVS object.
this->nvs = hdlNVS;
// Store the HID object.
this->hid = hdlHID;
// Store the sub-class name for later use, ie. NVS key access.
this->subClassName = subClassName;
// All done, no return code!
return;
}
// Constructor, basically initialise the Singleton interface and let the threads loose.
//KeyInterface::KeyInterface(uint32_t ifMode)
//{
// // init(className(__PRETTY_FUNCTION__), ifMode);
//}
// Basic constructor, do nothing!
//KeyInterface::KeyInterface(void)
//{
// //
//}

View File

@@ -1 +0,0 @@
../../sharpkey/main/LED.cpp

341
main/LED.cpp Normal file
View File

@@ -0,0 +1,341 @@
/////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Name: LED.cpp
// Created: Mar 2022
// Version: v1.0
// Author(s): Philip Smart
// Description: Base class for the encapsulation and control methods of an LED used primarily to
// indicate to users the status of the application.
// Credits:
// Copyright: (c) 2019-2022 Philip Smart <philip.smart@net2net.org>
//
// History: Mar 2022 - Initial write.
// v1.01 May 2022 - Initial release version.
//
// Notes: See Makefile to enable/disable conditional components
//
/////////////////////////////////////////////////////////////////////////////////////////////////////////
// This source file is free software: you can redistribute it and#or modify
// it under the terms of the GNU General Public License as published
// by the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This source file is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
/////////////////////////////////////////////////////////////////////////////////////////////////////////
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <iostream>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_log.h"
#include "esp_system.h"
#include "driver/gpio.h"
#include "soc/timer_group_struct.h"
#include "soc/timer_group_reg.h"
#include "driver/timer.h"
#include "PS2KeyAdvanced.h"
#include "PS2Mouse.h"
#include "sdkconfig.h"
#include "LED.h"
// Method to set the LED mode, duty cycle and duty period. Once the current LED cycle has come to an end, the control
// thread will replace the working configuration with the new configuration set here.
//
bool LED::setLEDMode(enum LED_MODE mode, enum LED_DUTY_CYCLE dutyCycle, uint32_t maxBlinks, uint64_t usDutyPeriod, uint64_t msInterPeriod)
{
// Locals.
//
bool result = true;
// If a setup is already waiting to be processed, exit with fail. This could be stacked into a vector but not really beneficial.
if(ledCtrl.newConfig.updated == false)
{
// Ensure we have exclusive access, the LED can be controlled by numerous threads, so ensure only one can access and setup at a time.
if(xSemaphoreTake(ledCtrl.mutexInternal, (TickType_t)1000) == pdTRUE)
{
ledCtrl.newConfig.mode = mode;
ledCtrl.newConfig.dutyCycle = dutyCycle;
ledCtrl.newConfig.maxBlinks = maxBlinks;
ledCtrl.newConfig.dutyPeriod = usDutyPeriod;
ledCtrl.newConfig.interPeriod = msInterPeriod;
ledCtrl.newConfig.updated = true;
// Release mutex so other threads can set the LED.
xSemaphoreGive(ledCtrl.mutexInternal);
} else
{
result = false;
}
} else
{
result = false;
}
return(result);
}
// Thread method to provide LED control.
IRAM_ATTR void LED::ledInterface(void *pvParameters)
{
// Locals.
//
uint32_t LED_MASK;
uint64_t delayTimer = 0LL;
uint64_t curTime = 0LL;
enum LEDSTATE {
LEDSTATE_IDLE = 0,
LEDSTATE_BLINK_MARK = 1,
LEDSTATE_BLINK_SPACE = 2,
LEDSTATE_BLINK_INTER = 3,
} fsmState = LEDSTATE_IDLE;
#define LEDIFTAG "ledInterface"
// Map the instantiating object so we can access its methods and data.
LED* pThis = (LED*)pvParameters;
// Set the LED GPIO mask according to the defined pin. This code needs updating if GPIO1 pins are used.
LED_MASK = (1 << pThis->ledCtrl.ledPin);
// Sign on.
ESP_LOGW("ledInterface", "Starting LED control thread.");
// Turn off LED.
GPIO.out_w1tc = LED_MASK;
// Loops forever.
for(;;)
{
// Check stack space, report if it is getting low.
if(uxTaskGetStackHighWaterMark(NULL) < 1024)
{
ESP_LOGW(LEDIFTAG, "THREAD STACK SPACE(%d)\n",uxTaskGetStackHighWaterMark(NULL));
}
// If a new configuration is set, then once the running FSM has returned to idle, update the configuration prior to the next FSM run.
//
if(pThis->ledCtrl.newConfig.updated)
{
// Take control of the Mutex so we are able to take on the data without a new setup clashing. If the Mutex is taken then continue on with the state machine logic till next loop.
if(xSemaphoreTake(pThis->ledCtrl.mutexInternal, (TickType_t)1) == pdTRUE)
{
pThis->ledCtrl.currentConfig = pThis->ledCtrl.newConfig;
pThis->ledCtrl.currentConfig.valid = true;
pThis->ledCtrl.newConfig.updated = false;
pThis->ledCtrl.blinkCnt = 0;
// Got new setup so release mutex.
xSemaphoreGive(pThis->ledCtrl.mutexInternal);
}
}
// Only run if we have a valid configuration.
if(pThis->ledCtrl.currentConfig.valid)
{
do {
// Get the current timer value, only run the FSM when the timer is idle.
timer_get_counter_value(TIMER_GROUP_0, TIMER_1, &curTime);
if(curTime >= delayTimer)
{
// Ensure the timer is stopped.
timer_pause(TIMER_GROUP_0, TIMER_1);
delayTimer = 0LL;
// Mini finite state machine for LED control.
switch(fsmState)
{
case LEDSTATE_IDLE:
// For on/off, no need for the FSM, just apply setting to LED and loop.
switch(pThis->ledCtrl.currentConfig.mode)
{
case LED_MODE_ON:
// Turn on LED.
GPIO.out_w1ts = LED_MASK;
delayTimer = 1000UL;
break;
case LED_MODE_BLINK_ONESHOT:
// If the number of blinks is not 0 then on reaching the count, switch to LED off mode.
if(pThis->ledCtrl.currentConfig.maxBlinks > 0 && pThis->ledCtrl.blinkCnt++ >= pThis->ledCtrl.currentConfig.maxBlinks)
{
pThis->ledCtrl.currentConfig.mode = LED_MODE_OFF;
} else
{
fsmState = LEDSTATE_BLINK_MARK;
}
break;
case LED_MODE_BLINK:
// Normal blink mode increments the count which is used for determining inter blink period.
pThis->ledCtrl.blinkCnt++;
fsmState = LEDSTATE_BLINK_MARK;
break;
case LED_MODE_OFF:
default:
// Turn off LED.
GPIO.out_w1tc = LED_MASK;
delayTimer = 1000UL;
break;
}
break;
case LEDSTATE_BLINK_MARK:
// Turn on LED.
GPIO.out_w1ts = LED_MASK;
// Next state, SPACE.
fsmState = LEDSTATE_BLINK_SPACE;
// Calculate time to SPACE.
switch(pThis->ledCtrl.currentConfig.dutyCycle)
{
case LED_DUTY_CYCLE_10:
delayTimer = (pThis->ledCtrl.currentConfig.dutyPeriod / 10);
break;
case LED_DUTY_CYCLE_20:
delayTimer = ((pThis->ledCtrl.currentConfig.dutyPeriod / 10) * 2);
break;
case LED_DUTY_CYCLE_30:
delayTimer = ((pThis->ledCtrl.currentConfig.dutyPeriod / 10) * 3);
break;
case LED_DUTY_CYCLE_40:
delayTimer = ((pThis->ledCtrl.currentConfig.dutyPeriod / 10) * 4);
break;
case LED_DUTY_CYCLE_50:
delayTimer = ((pThis->ledCtrl.currentConfig.dutyPeriod / 10) * 5);
break;
case LED_DUTY_CYCLE_60:
delayTimer = ((pThis->ledCtrl.currentConfig.dutyPeriod / 10) * 6);
break;
case LED_DUTY_CYCLE_70:
delayTimer = ((pThis->ledCtrl.currentConfig.dutyPeriod / 10) * 7);
break;
case LED_DUTY_CYCLE_80:
delayTimer = ((pThis->ledCtrl.currentConfig.dutyPeriod / 10) * 8);
break;
case LED_DUTY_CYCLE_90:
delayTimer = ((pThis->ledCtrl.currentConfig.dutyPeriod / 10) * 9);
break;
// We shouldnt be here if duty cycle is off, so back to idle.
case LED_DUTY_CYCLE_OFF:
default:
GPIO.out_w1tc = LED_MASK;
delayTimer = 0;
fsmState = LEDSTATE_IDLE;
break;
}
break;
case LEDSTATE_BLINK_SPACE:
// Turn off LED.
GPIO.out_w1tc = LED_MASK;
// Calculate time to next MARK.
delayTimer = pThis->ledCtrl.currentConfig.dutyPeriod - delayTimer;
// Now add an interblink delay prior to next blink.
fsmState = LEDSTATE_BLINK_INTER;
break;
case LEDSTATE_BLINK_INTER:
// If we are in normal mode with a blink limit set and limit reached or in limited mode, then add an interblink delay as configured.
if((pThis->ledCtrl.currentConfig.mode == LED_MODE_BLINK && pThis->ledCtrl.currentConfig.maxBlinks > 0 && pThis->ledCtrl.blinkCnt >= pThis->ledCtrl.currentConfig.maxBlinks) ||
(pThis->ledCtrl.currentConfig.mode == LED_MODE_BLINK_ONESHOT))
{
// Interblink delay is given in milli-seconds, so multiply up and set delay.
delayTimer = pThis->ledCtrl.currentConfig.interPeriod * 1000;
// Reset blink counter to trigger next interperiod delay.
if(pThis->ledCtrl.currentConfig.mode == LED_MODE_BLINK)
pThis->ledCtrl.blinkCnt = 0;
}
// We return to IDLE to allow time for reconfiguration if requested.
fsmState = LEDSTATE_IDLE;
break;
// Unknown or not programmed state, return to IDLE.
default:
fsmState = LEDSTATE_IDLE;
break;
}
// If a new delay is requested, reset the value in the timer and start.
if(delayTimer > 0LL)
{
timer_set_counter_value(TIMER_GROUP_0, TIMER_1, 0LL);
timer_start(TIMER_GROUP_0, TIMER_1);
}
}
// Give the OS some time...
taskYIELD();
} while(fsmState != LEDSTATE_IDLE);
}
}
}
// Method to set the GPIO pin to be used for LED output.
void LED::ledInit(uint8_t ledPin)
{
// Initialise variables.
this->ledCtrl.currentConfig.valid = false;
this->ledCtrl.currentConfig.updated = false;
this->ledCtrl.currentConfig.mode = LED_MODE_OFF;
this->ledCtrl.currentConfig.dutyCycle = LED_DUTY_CYCLE_OFF;
this->ledCtrl.currentConfig.dutyPeriod = 0LL;
this->ledCtrl.currentConfig.interPeriod = 0LL;
this->ledCtrl.newConfig = this->ledCtrl.currentConfig;
// Store GPIO pin to which LED is connected.
this->ledCtrl.ledPin = ledPin;
// Configure a timer to be used for the LED blink rate.
timer_config_t timerConfig = {
.alarm_en = TIMER_ALARM_DIS, // No alarm, were not using interrupts as we are in a dedicated thread.
.counter_en = TIMER_PAUSE, // Timer paused until required.
.intr_type = TIMER_INTR_LEVEL, // No interrupts used.
.counter_dir = TIMER_COUNT_UP, // Timing a fixed period.
.auto_reload = TIMER_AUTORELOAD_DIS, // No need for auto reload, fixed time period.
.divider = 80 // 1Mhz operation giving 1uS resolution.
};
ESP_ERROR_CHECK(timer_init(TIMER_GROUP_0, TIMER_1, &timerConfig));
ESP_ERROR_CHECK(timer_set_counter_value(TIMER_GROUP_0, TIMER_1, 0));
// Setup mutex's.
ledCtrl.mutexInternal = xSemaphoreCreateMutex();
// Core 0 - Application
// LED control thread - dedicated thread to control the LED according to set mode.
ESP_LOGW("ledInit", "Starting LEDif thread...");
::xTaskCreatePinnedToCore(&this->ledInterface, "ledif", 4096, this, 0, &this->TaskLEDIF, 0);
}
// Constructor, basically initialise the Singleton interface and let the control thread loose.
LED::LED(uint32_t hwPin)
{
// Store the class name for later use, ie. NVS key access.
this->className = getClassName(__PRETTY_FUNCTION__);
// Configure the Power LED used for activity and user interaction. Initial state is ON until a keyboard is detected when it turns off and only blinks on keyboard activity.
ledInit(hwPin);
// Initial state, turn on LED to indicate LED control is working.
setLEDMode(LED::LED_MODE_ON, LED::LED_DUTY_CYCLE_OFF, 0, 0L, 0L);
}
// Basic constructor, do nothing!
LED::LED(void)
{
// Store the class name for later use, ie. NVS key access.
this->className = getClassName(__PRETTY_FUNCTION__);
}

View File

@@ -1 +0,0 @@
../../sharpkey/main/MZ2528.cpp

1244
main/MZ2528.cpp Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1 +0,0 @@
../../sharpkey/main/MZ5665.cpp

1052
main/MZ5665.cpp Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1 +0,0 @@
../../sharpkey/main/Mouse.cpp

729
main/Mouse.cpp Normal file
View File

@@ -0,0 +1,729 @@
/////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Name: Mouse.cpp
// Created: Mar 2022
// Version: v1.0
// Author(s): Philip Smart
// Description: PS/2 Mouse to Sharp Host Interface logic.
// This source file contains the singleton class containing logic to obtain
// PS/2 mouse data (position, keys etc), map them into Sharp compatible codes and
// transmit the data to the connected host.
//
// The whole application of which this class is a member, uses the Espressif Development
// environment with Arduino components.
//
// Credits:
// Copyright: (c) 2022 Philip Smart <philip.smart@net2net.org>
//
// History: Mar 2022 - Initial write.
// v1.01 May 2022 - Initial release version.
// v1.02 Jun 2022 - Updates to reflect changes realised in other modules due to addition of
// bluetooth and suspend logic due to NVS issues using both cores.
// Updates to reflect moving functionality into the HID and to support
// Bluetooth as a primary mouse or secondary mouse.
//
// Notes: See Makefile to enable/disable conditional components
//
/////////////////////////////////////////////////////////////////////////////////////////////////////////
// This source file is free software: you can redistribute it and#or modify
// it under the terms of the GNU General Public License as published
// by the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This source file is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
/////////////////////////////////////////////////////////////////////////////////////////////////////////
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <bitset>
#include <iostream>
#include <sstream>
#include <functional>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "driver/uart.h"
#include "driver/gpio.h"
#include "esp_log.h"
#include "Arduino.h"
#include "soc/timer_group_struct.h"
#include "soc/timer_group_reg.h"
#include "driver/timer.h"
#include "sdkconfig.h"
#include "Mouse.h"
// Tag for ESP main application logging.
#define MAINTAG "Mouse"
// Mouse Protocol
// --------------
//
//
// The Sharp (X68000/X1/MZ-2500/MZ-2800) mouse uses an asynchronous serial protocol over two wires (MSDATA/MSCTRL).
// The MSCTRL signal is an enable signal, idle state = HIGH, it goes low prior to transmission of data by at least 1mS and goes high after
// transmission of last bit by ~2.56mS.
// The MSDATA signal is a standard asynchronous signal, idle = HIGH, 1 start bit, 8 data bits, 2 stop bits @ 4800baud.
//
// Protocol:
// Idle State (MSDATA/MSCTRL) = High.
// Transmission: MSCTRL -> LOW
// 1ms delay
// MSDATA -> low, first start bit.
// 3 bytes transmitted in a <1xStart><8xdata><2xstop> format.
// MSDATA -> high
// 2.56ms delay.
// MSCTRL -> HIGH
// Data bytes: <CTRL><POS X><POS Y>
// CTRL = [7] - Mouse rolling forward when high, backward when low.
// [6]
// [5] - Mouse rolling left, right when low.
// [4]
// [3]
// [2]
// [1] - Right button pressed = HIGH.
// [0] - Left button pressed = HIGH.
// POS X [7:0] - X Position data.
// POS Y [7:0] - Y Position data.
// Method to realise the Sharp host Mouse protocol.
// This method uses Core 1 and it will hold it in a spinlock as necessary to ensure accurate timing.
// Mouse data is passed into the method via a direct object, using the FreeRTOS Queue creates a time lag resulting in the mouse data being out of sync with hand movement.
IRAM_ATTR void Mouse::hostInterface( void * pvParameters )
{
// Locals.
//
Mouse* pThis = (Mouse*)pvParameters; // Retrieve pointer to object in order to access data.
bool msctrlEdge = false;
uint8_t txBuf[4];
uint32_t MSCTRL_MASK;
uint32_t MSDATA_MASK;
#ifdef CONFIG_HOST_BITBANG_UART
int txPos;
int txCnt;
uint32_t shiftReg;
uint64_t delayTimer = 0LL;
uint64_t curTime = 0LL;
uint32_t bitCount = 0;
enum HOSTXMITSTATE {
FSM_IDLE = 0,
FSM_STARTXMIT = 1,
FSM_STARTBIT = 2,
FSM_DATA = 3,
FSM_STOP = 4,
FSM_ENDXMIT = 5
} state = FSM_IDLE;
#endif
// Initialise the MUTEX which prevents this core from being released to other tasks.
pThis->x1Mutex = portMUX_INITIALIZER_UNLOCKED;
if(pThis->hostControl.secondaryIf == false)
{
MSCTRL_MASK = (1 << CONFIG_HOST_KDB0);
MSDATA_MASK = (1 << CONFIG_HOST_KDB1);
} else
{
MSCTRL_MASK = (1 << CONFIG_HOST_KDB0);
MSDATA_MASK = (1 << CONFIG_HOST_KDI4);
}
gpio_config_t ioConf;
ioConf.intr_type = GPIO_INTR_DISABLE;
ioConf.mode = GPIO_MODE_INPUT;
ioConf.pull_down_en = GPIO_PULLDOWN_DISABLE;
ioConf.pull_up_en = GPIO_PULLUP_ENABLE;
// Both Hardware UART and bitbang need MSCTRL setting as an input.
if(pThis->hostControl.secondaryIf == false)
{
ioConf.pin_bit_mask = (1ULL<<CONFIG_HOST_KDB0);
gpio_config(&ioConf);
}
// Bitbang mode also needs MSDATA setting as an output.
#ifdef CONFIG_HOST_BITBANG_UART
ioConf.pull_up_en = GPIO_PULLUP_DISABLE;
ioConf.mode = GPIO_MODE_OUTPUT;
if(pThis->hostControl.secondaryIf == false)
{
ioConf.pin_bit_mask = (1ULL<<CONFIG_HOST_KDB1);
} else
{
ioConf.pin_bit_mask = (1ULL<<CONFIG_HOST_KDI4);
}
gpio_config(&ioConf);
// Set MSDATA to default state which is high.
GPIO.out_w1ts = MSDATA_MASK;
#endif
// Configure a timer to be used for the host mouse asynchronous protocol spacing with 1uS resolution. The default clock source is the APB running at 80MHz.
timer_config_t timerConfig = {
.alarm_en = TIMER_ALARM_DIS, // No alarm, were not using interrupts as we are in a dedicated thread.
.counter_en = TIMER_PAUSE, // Timer paused until required.
.intr_type = TIMER_INTR_LEVEL, // No interrupts used.
.counter_dir = TIMER_COUNT_UP, // Timing a fixed period.
.auto_reload = TIMER_AUTORELOAD_DIS, // No need for auto reload, fixed time period.
.divider = 80 // 1Mhz operation giving 1uS resolution.
};
ESP_ERROR_CHECK(timer_init(TIMER_GROUP_0, TIMER_0, &timerConfig));
ESP_ERROR_CHECK(timer_set_counter_value(TIMER_GROUP_0, TIMER_0, 0));
// Sign on.
ESP_LOGW(MAINTAG, "Starting Host side Mouse thread.");
// Permanent loop, wait for an incoming message on the key to send queue, read it then transmit to the host, repeat!
for(;;)
{
#ifdef CONFIG_HOST_BITBANG_UART
// Get the current timer value, only run the FSM when the timer is idle.
timer_get_counter_value(TIMER_GROUP_0, TIMER_0, &curTime);
if((state == FSM_IDLE && pThis->hostControl.secondaryIf == false) || curTime >= delayTimer)
{
// Ensure the timer is stopped.
timer_pause(TIMER_GROUP_0, TIMER_0);
delayTimer = 0LL;
// Finite state machine to retrieve a key for transmission then serialise it according to the X1 protocol.
switch(state)
{
case FSM_IDLE:
// Yield if the suspend flag is set.
pThis->yield(0);
// Check stack space, report if it is getting low.
if(uxTaskGetStackHighWaterMark(NULL) < 1024)
{
ESP_LOGW(MAINTAG, "THREAD STACK SPACE(%d)\n",uxTaskGetStackHighWaterMark(NULL));
}
if(pThis->hostControl.secondaryIf == false)
{
// Detect high to low edge. On mouse primary mode the MSCTRL signal forces the tempo. On mouse secondary mode (operating in tandem to keyboard),
// the timer forces the tempo.
//
msctrlEdge = (REG_READ(GPIO_IN_REG) & MSCTRL_MASK) != 0 ? true : msctrlEdge;
}
// Wait for a window when MSCTRL goes low.
if(pThis->hostControl.secondaryIf == true || (msctrlEdge == true && (REG_READ(GPIO_IN_REG) & MSCTRL_MASK) == 0))
{
// Wait for incoming mouse movement message.
if(pThis->xmitMsg.valid)
{
txBuf[0] = (uint8_t)pThis->xmitMsg.status;
txBuf[1] = (uint8_t)pThis->xmitMsg.xPos;
txBuf[2] = (uint8_t)pThis->xmitMsg.yPos;
pThis->xmitMsg.valid = false; // Shouldnt be a race state here but consider a mutex if mouse gets out of sync.
txBuf[3] = 0x00;
txPos = 0;
txCnt = 3;
} else
{
// Sharp host protocol requires us to send zero change messages on a regular period regardless of new data.
txBuf[0] = 0x00;
txBuf[1] = 0x00;
txBuf[2] = 0x00;
txBuf[3] = 0x00;
txPos = 0;
txCnt = 3;
}
// Advance to first start bit.
state = FSM_STARTXMIT;
// Clear edge detect for next loop.
msctrlEdge = false;
}
break;
case FSM_STARTXMIT:
// Ensure all variables and states correct before entering serialisation.
GPIO.out_w1ts = MSDATA_MASK;
state = FSM_STARTBIT;
bitCount = 8;
shiftReg = txBuf[txPos++];
txCnt--;
// Create, initialise and hold a spinlock so the current core is bound to this one method.
portENTER_CRITICAL(&pThis->x1Mutex);
break;
case FSM_STARTBIT:
// Send out the start bit by bringing MSDATA low for 208us (4800 baud 1bit time period).
GPIO.out_w1tc = MSDATA_MASK;
delayTimer = BITBANG_UART_BIT_TIME;
state = FSM_DATA;
break;
case FSM_DATA:
if(bitCount > 0)
{
// Setup the bit on MSDATA
if(shiftReg & 0x00000001)
{
GPIO.out_w1ts = MSDATA_MASK;
} else
{
GPIO.out_w1tc = MSDATA_MASK;
}
// Shift the data to the next bit for transmission.
shiftReg = shiftReg >> 1;
// 1 bit period.
delayTimer = BITBANG_UART_BIT_TIME;
// 1 Less bit in frame.
bitCount--;
} else
{
state = FSM_STOP;
}
break;
case FSM_STOP:
// Send out the stop bit, 2 are needed so just adjust the time delay.
GPIO.out_w1ts = MSDATA_MASK;
delayTimer = BITBANG_UART_BIT_TIME * 2;
state = FSM_ENDXMIT;
break;
case FSM_ENDXMIT:
// End of critical timing loop, release the core so other tasks can run whilst we load up the next byte.
portEXIT_CRITICAL(&pThis->x1Mutex);
// Any more bytes to transmit, loop and send if there are.
if(txCnt > 0)
{
state = FSM_STARTXMIT;
} else
{
// Reset timer for next loop.
delayTimer = 20000UL;
state = FSM_IDLE;
}
break;
}
// If a new delay is requested, set the value into the timer and start.
if(delayTimer > 0LL)
{
timer_set_counter_value(TIMER_GROUP_0, TIMER_0, 0LL);
timer_start(TIMER_GROUP_0, TIMER_0);
}
}
#endif
#ifdef CONFIG_HOST_HW_UART
// Get the current timer value, we need to wait 20ms between transmissions.
timer_get_counter_value(TIMER_GROUP_0, TIMER_0, &curTime);
if(curTime >= delayTimer)
{
// Wait for a window when MSCTRL goes low.
if(pThis->hostControl.secondaryIf == true || (REG_READ(GPIO_IN_REG) & MSCTRL_MASK) == 0)
{
// Ensure the timer is stopped, initialise to 0 and restart.
timer_pause(TIMER_GROUP_0, TIMER_0);
delayTimer = 20000LL;
timer_set_counter_value(TIMER_GROUP_0, TIMER_0, 0LL);
timer_start(TIMER_GROUP_0, TIMER_0);
// Wait for incoming mouse movement message.
if(pThis->xmitMsg.valid)
{
txBuf[0] = (uint8_t)pThis->xmitMsg.status;
txBuf[1] = (uint8_t)pThis->xmitMsg.xPos;
txBuf[2] = (uint8_t)pThis->xmitMsg.yPos;
pThis->xmitMsg.valid = false; // Shouldnt be a race state here but consider a mutex if mouse gets out of sync.
txBuf[3] = 0x00;
txPos = 0;
txCnt = 3;
} else
{
// Sharp host protocol requires us to send zero change messages on a regular period regardless of new data.
txBuf[0] = 0x00;
txBuf[1] = 0x00;
txBuf[2] = 0x00;
txBuf[3] = 0x00;
txPos = 0;
txCnt = 3;
}
// Send the bytes and wait.
uart_write_bytes(pThis->hostControl.uartNum, (const char *)txBuf, 3);
// This method doesnt actually return after the last byte is transmitted, it returns well before, so we tack on a 10ms delay which is the width for 3 bytes at 4800 baud.
uart_wait_tx_done(pThis->hostControl.uartNum, 25000);
vTaskDelay(10);
}
// Check stack space, report if it is getting low.
if(uxTaskGetStackHighWaterMark(NULL) < 1024)
{
ESP_LOGW(MAPKEYTAG, "THREAD STACK SPACE(%d)\n",uxTaskGetStackHighWaterMark(NULL));
}
// Yield if the suspend flag is set.
pThis->yield(0);
}
#endif
// Logic to feed the watchdog if needed. Watchdog disabled in menuconfig but if enabled this will need to be used.
//TIMERG0.wdt_wprotect=TIMG_WDT_WKEY_VALUE; // write enable
//TIMERG0.wdt_feed=1; // feed dog
//TIMERG0.wdt_wprotect=0; // write protect
//TIMERG1.wdt_wprotect=TIMG_WDT_WKEY_VALUE; // write enable
//TIMERG1.wdt_feed=1; // feed dog
//TIMERG1.wdt_wprotect=0; // write protect
}
}
// Primary HID routine.
// This method is responsible for receiving HID (PS/2 or BT) mouse scan data and mapping it into Sharp compatible mouse data.
// The HID mouse data once received is mapped and pushed onto a FIFO queue for transmission to the host.
//
void Mouse::mouseReceiveData(HID::t_mouseMessageElement mouseMessage)
{
// Locals.
uint8_t status;
// Invert Y as the Sharp host is inverted compared to a PS/2 on the Y axis.
mouseMessage.yPos = -mouseMessage.yPos;
// Initialise the status flag, on the Sharp host it is <Y Overflow><Y Underflow><X Overflow><X Underflow><1><0><Right Button><Left Button>
status = (((mouseMessage.xPos >> 8) & 0x01) << 4) | (mouseMessage.status & 0x0F );
// Check bounds and set flags accordingly.
if(mouseMessage.xPos > 127)
{
mouseMessage.xPos = 127; // Maximum resolution of Sharp host X movement.
status |= (1UL << 4); // Set overflow bit.
}
if(mouseMessage.xPos < -128)
{
mouseMessage.xPos = -128; // Minimum resolution of Sharp host X movement.
status |= (1UL << 5); // Set underflow bit.
}
if(mouseMessage.yPos > 127)
{
mouseMessage.yPos = 127; // Maximum resolution of Sharp host Y movement.
status |= (1UL << 6); // Set overflow bit.
}
if(mouseMessage.yPos < -128)
{
mouseMessage.yPos = -128; // Minimum resolution of Sharp host Y movement.
status |= (1UL << 7); // Set underflow bit.
}
// Convert back to 8bit 2's compliment and store in the host message to the host thread.
xmitMsg.xPos = (int8_t)mouseMessage.xPos;
xmitMsg.yPos = (int8_t)mouseMessage.yPos;
xmitMsg.status = status;
xmitMsg.wheel = mouseMessage.wheel;
xmitMsg.valid = true;
return;
}
// A method to return the Type of data for a given column in the KeyMap table.
//
void Mouse::getMouseConfigTypes(std::vector<std::string>& typeList)
{
// Add the types.
//
typeList.push_back(HID_MOUSE_HOST_SCALING_TYPE);
typeList.push_back(HID_MOUSE_SCALING_TYPE);
typeList.push_back(HID_MOUSE_RESOLUTION_TYPE);
typeList.push_back(HID_MOUSE_SAMPLING_TYPE);
return;
}
// Method to return a list of key:value entries for a given config category. This represents the
// feature which can be selected and the value it uses. Features can be combined by ORing the values
// together.
bool Mouse::getMouseSelectList(std::vector<std::pair<std::string, int>>& selectList, std::string option)
{
// Locals.
//
bool result = true;
// Build up a map, depending on the list required, of name to value. This list can then be used
// by a user front end to select an option based on a name and return its value.
if(option.compare(HID_MOUSE_HOST_SCALING_TYPE) == 0)
{
selectList.push_back(std::make_pair("ACTIVE", mouseConfig.host.scaling));
selectList.push_back(std::make_pair(HID_MOUSE_HOST_SCALING_1_1_NAME, HID::HID_MOUSE_HOST_SCALING_1_1));
selectList.push_back(std::make_pair(HID_MOUSE_HOST_SCALING_1_2_NAME, HID::HID_MOUSE_HOST_SCALING_1_2));
selectList.push_back(std::make_pair(HID_MOUSE_HOST_SCALING_1_3_NAME, HID::HID_MOUSE_HOST_SCALING_1_3));
selectList.push_back(std::make_pair(HID_MOUSE_HOST_SCALING_1_4_NAME, HID::HID_MOUSE_HOST_SCALING_1_4));
selectList.push_back(std::make_pair(HID_MOUSE_HOST_SCALING_1_5_NAME, HID::HID_MOUSE_HOST_SCALING_1_5));
}
else if(option.compare(HID_MOUSE_SCALING_TYPE) == 0)
{
selectList.push_back(std::make_pair("ACTIVE", mouseConfig.mouse.scaling));
selectList.push_back(std::make_pair(HID_MOUSE_SCALING_1_1_NAME, HID::HID_MOUSE_SCALING_1_1));
selectList.push_back(std::make_pair(HID_MOUSE_SCALING_2_1_NAME, HID::HID_MOUSE_SCALING_2_1));
}
else if(option.compare(HID_MOUSE_RESOLUTION_TYPE) == 0)
{
selectList.push_back(std::make_pair("ACTIVE", mouseConfig.mouse.resolution));
selectList.push_back(std::make_pair(HID_MOUSE_RESOLUTION_1_1_NAME, HID::HID_MOUSE_RESOLUTION_1_1));
selectList.push_back(std::make_pair(HID_MOUSE_RESOLUTION_1_2_NAME, HID::HID_MOUSE_RESOLUTION_1_2));
selectList.push_back(std::make_pair(HID_MOUSE_RESOLUTION_1_4_NAME, HID::HID_MOUSE_RESOLUTION_1_4));
selectList.push_back(std::make_pair(HID_MOUSE_RESOLUTION_1_8_NAME, HID::HID_MOUSE_RESOLUTION_1_8));
}
else if(option.compare(HID_MOUSE_SAMPLING_TYPE) == 0)
{
selectList.push_back(std::make_pair("ACTIVE", mouseConfig.mouse.sampleRate));
selectList.push_back(std::make_pair(HID_MOUSE_SAMPLE_RATE_10_NAME, HID::HID_MOUSE_SAMPLE_RATE_10));
selectList.push_back(std::make_pair(HID_MOUSE_SAMPLE_RATE_20_NAME, HID::HID_MOUSE_SAMPLE_RATE_20));
selectList.push_back(std::make_pair(HID_MOUSE_SAMPLE_RATE_40_NAME, HID::HID_MOUSE_SAMPLE_RATE_40));
selectList.push_back(std::make_pair(HID_MOUSE_SAMPLE_RATE_60_NAME, HID::HID_MOUSE_SAMPLE_RATE_60));
selectList.push_back(std::make_pair(HID_MOUSE_SAMPLE_RATE_80_NAME, HID::HID_MOUSE_SAMPLE_RATE_80));
selectList.push_back(std::make_pair(HID_MOUSE_SAMPLE_RATE_100_NAME, HID::HID_MOUSE_SAMPLE_RATE_100));
selectList.push_back(std::make_pair(HID_MOUSE_SAMPLE_RATE_200_NAME, HID::HID_MOUSE_SAMPLE_RATE_200));
} else
{
// Not found!
result = false;
}
// Return result, false if the option not found, true otherwise.
//
return(result);
}
// Public method to set the mouse configuration parameters.
//
bool Mouse::setMouseConfigValue(std::string paramName, std::string paramValue)
{
// Locals.
//
bool dataError = false;
int value(0);
std::stringstream testVal(paramValue);
// Match the parameter name to a known mouse parameter, type and data check the parameter value and assign to the config accordingly.
if(paramName.compare(HID_MOUSE_HOST_SCALING_TYPE) == 0)
{
// Exception handling is disabled, stringstream is used to catch bad input.
dataError = (static_cast<bool>(testVal >> value) ? false : true);
if(dataError == false)
{
if(value >= to_underlying(HID::HID_MOUSE_HOST_SCALING_1_1) && value <= to_underlying(HID::HID_MOUSE_HOST_SCALING_1_5))
{
mouseConfig.host.scaling = static_cast<HID::HID_MOUSE_HOST_SCALING>(value);
hid->setMouseHostScaling(mouseConfig.host.scaling);
} else
{
dataError = true;
}
}
}
if(paramName.compare(HID_MOUSE_SCALING_TYPE) == 0)
{
dataError = (static_cast<bool>(testVal >> value) ? false : true);
if(dataError == false)
{
if(value >= to_underlying(HID::HID_MOUSE_SCALING_1_1) && value <= to_underlying(HID::HID_MOUSE_SCALING_2_1))
{
mouseConfig.mouse.scaling = static_cast<HID::HID_MOUSE_SCALING>(value);
hid->setMouseScaling(mouseConfig.mouse.scaling);
} else
{
dataError = true;
}
}
}
if(paramName.compare(HID_MOUSE_RESOLUTION_TYPE) == 0)
{
dataError = (static_cast<bool>(testVal >> value) ? false : true);
if(dataError == false)
{
if(value >= to_underlying(HID::HID_MOUSE_RESOLUTION_1_1) && value <= to_underlying(HID::HID_MOUSE_RESOLUTION_1_8))
{
mouseConfig.mouse.resolution = static_cast<HID::HID_MOUSE_RESOLUTION>(value);
hid->setMouseResolution(mouseConfig.mouse.resolution);
} else
{
dataError = true;
}
}
}
if(paramName.compare(HID_MOUSE_SAMPLING_TYPE) == 0)
{
dataError = (static_cast<bool>(testVal >> value) ? false : true);
if(dataError == false)
{
if(value >= to_underlying(HID::HID_MOUSE_SAMPLE_RATE_10) && value <= to_underlying(HID::HID_MOUSE_SAMPLE_RATE_200))
{
mouseConfig.mouse.sampleRate = static_cast<HID::HID_MOUSE_SAMPLING>(value);
hid->setMouseSampleRate(mouseConfig.mouse.sampleRate);
} else
{
dataError = true;
}
}
}
// Error = true, success = false.
return(dataError);
}
// Method to save (persist) the configuration into NVS RAM.
bool Mouse::persistConfig(void)
{
// Locals.
bool result = true;
// Persist the data for next time.
if(nvs->persistData(getClassName(__PRETTY_FUNCTION__), &this->mouseConfig, sizeof(t_mouseConfig)) == false)
{
ESP_LOGW(MAINTAG, "Persisting Mouse configuration data failed, check NVS setup.\n");
result = false;
}
// Few other updates so make a commit here to ensure data is flushed and written.
else if(nvs->commitData() == false)
{
ESP_LOGW(MAINTAG, "NVS Commit writes operation failed, some previous writes may not persist in future power cycles.");
}
// Request persistence in the HID module.
result |= hid->persistConfig();
// Error = false, success = true.
return(result);
}
// Initialisation routine. Start two threads, one to handle the incoming PS/2 mouse data and map it, the second to handle the host interface.
void Mouse::init(uint32_t ifMode, NVS *hdlNVS, LED *hdlLED, HID *hdlHID)
{
// Initialise control variables.
#ifdef CONFIG_HOST_HW_UART
hostControl.uartNum = UART_NUM_2;
hostControl.uartBufferSize = 256;
hostControl.uartQueueSize = 10;
#endif
// Initialise the basic components.
init(hdlNVS, hdlHID);
// Invoke the prototype init which initialises common variables and devices shared by all subclass.
KeyInterface::init(getClassName(__PRETTY_FUNCTION__), hdlNVS, hdlLED, hdlHID, ifMode);
// There are two build possibilities, hardware UART and BITBANG. I initially coded using hardware but whilst trying to find a bug, wrote a bitbang
// technique and both are fit for purpose, so enabling either yields the same result.
#ifdef CONFIG_HOST_HW_UART
// Prepare the UART to be used for communications with the Sharp host.
// The Sharp host Mouse uses an Asynchronous protocol with 2 stop bits no parity 4800 baud.
//
uart_config_t uartConfig = {
.baud_rate = 4800,
.data_bits = UART_DATA_8_BITS,
.parity = UART_PARITY_DISABLE,
.stop_bits = UART_STOP_BITS_2,
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
.rx_flow_ctrl_thresh = 122,
.source_clk = UART_SCLK_APB,
};
// Configure UART parameters and pin assignments, software flow control, not RTS/CTS.
// The mouse only uses a Tx line, the MSCTRL line is used as a gate signal, so assign the Rx line to an unused pin.
ESP_ERROR_CHECK(uart_param_config(hostControl.uartNum, &uartConfig));
ESP_ERROR_CHECK(uart_set_pin(hostControl.uartNum, CONFIG_HOST_KDB1, CONFIG_HOST_KDB2, -1, -1));
// Install UART driver. Use RX/TX buffers without event queue.
ESP_ERROR_CHECK(uart_driver_install(hostControl.uartNum, hostControl.uartBufferSize, hostControl.uartBufferSize, 0, NULL, 0));
#endif
// Register the streaming callback for the mouse, this will receive data, process it and send to the hostInterface for transmission to the host.
hid->setDataCallback(&Mouse::mouseReceiveData, this);
// Create a task pinned to core 1 which will fulfill the Sharp Mouse host interface. This task has the highest priority
// and it will also hold spinlock and manipulate the watchdog to ensure a scan cycle timing can be met. This means
// all other tasks running on Core 1 will suspend as needed. The HID mouse controller will be serviced with core 0.
//
// Core 1 - Sharp Mouse Host Interface
ESP_LOGW(MAINTAG, "Starting mouseIf thread...");
::xTaskCreatePinnedToCore(&this->hostInterface, "mouseIf", 4096, this, 25, &this->TaskHostIF, 1);
vTaskDelay(500);
}
// Initialisation routine without hardware.
void Mouse::init(NVS *hdlNVS, HID *hdlHID)
{
// Invoke the prototype init which initialises common variables and devices shared by all subclass.
KeyInterface::init(getClassName(__PRETTY_FUNCTION__), hdlNVS, hdlHID);
// Retrieve configuration, if it doesnt exist, set defaults.
//
if(nvs->retrieveData(getClassName(__PRETTY_FUNCTION__), &this->mouseConfig, sizeof(t_mouseConfig)) == false)
{
ESP_LOGW(MAINTAG, "Mouse configuration set to default, no valid config in NVS found.");
mouseConfig.mouse.resolution= HID::HID_MOUSE_RESOLUTION_1_8;
mouseConfig.mouse.scaling = HID::HID_MOUSE_SCALING_1_1;
mouseConfig.mouse.sampleRate= HID::HID_MOUSE_SAMPLE_RATE_60;
mouseConfig.host.scaling = HID::HID_MOUSE_HOST_SCALING_1_2;
// Persist the data for next time.
if(nvs->persistData(getClassName(__PRETTY_FUNCTION__), &this->mouseConfig, sizeof(t_mouseConfig)) == false)
{
ESP_LOGW(MAINTAG, "Persisting Default Mouse configuration data failed, check NVS setup.\n");
}
// Few other updates so make a commit here to ensure data is flushed and written.
else if(nvs->commitData() == false)
{
ESP_LOGW(MAINTAG, "NVS Commit writes operation failed, some previous writes may not persist in future power cycles.");
}
}
}
// Constructor, basically initialise the Singleton interface and let the threads loose.
Mouse::Mouse(uint32_t ifMode, NVS *hdlNVS, LED *hdlLED, HID *hdlHID)
{
// Operating in uni-mode.
hostControl.secondaryIf = false;
// Initialise the interface
init(ifMode, hdlNVS, hdlLED, hdlHID);
}
// Constructor, basic initialisation without hardware.
Mouse::Mouse(NVS *hdlNVS, HID *hdlHID)
{
// Operating in uni-mode.
hostControl.secondaryIf = false;
// Initialise the interface
init(hdlNVS, hdlHID);
}
// Constructor for use when mouse operates in tandem with a keyboard.
Mouse::Mouse(uint32_t ifMode, NVS *hdlNVS, LED *hdlLED, HID *hdlHID, bool secondaryIf)
{
// The interface can act in primary mode, ie. sole interface or secondary mode where it acts in tandem to a keyboard host. Slight processing differences occur
// in secondary mode, for example, the pin used to output mouse data differs.
hostControl.secondaryIf = secondaryIf;
// Initialise the interface
init(ifMode, hdlNVS, hdlLED, hdlHID);
}
// Constructor, used for version reporting so no hardware is initialised.
Mouse::Mouse(void)
{
return;
}
// Destructor - only ever called when the class is used for version reporting.
Mouse::~Mouse(void)
{
return;
}

View File

@@ -1 +0,0 @@
../../sharpkey/main/NVS.cpp

293
main/NVS.cpp Normal file
View File

@@ -0,0 +1,293 @@
/////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Name: NVS.cpp
// Created: Mar 2022
// Version: v1.0
// Author(s): Philip Smart
// Description: Base class for encapsulating the Espressif C API for the Non Volatile Storage.
// Credits:
// Copyright: (c) 2019-2022 Philip Smart <philip.smart@net2net.org>
//
// History: Mar 2022 - Initial write.
// v1.01 May 2022 - Initial release version.
//
// Notes: See Makefile to enable/disable conditional components
//
/////////////////////////////////////////////////////////////////////////////////////////////////////////
// This source file is free software: you can redistribute it and#or modify
// it under the terms of the GNU General Public License as published
// by the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This source file is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
/////////////////////////////////////////////////////////////////////////////////////////////////////////
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <iostream>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/semphr.h"
#include "esp_log.h"
#include "esp_system.h"
#include "nvs_flash.h"
#include "nvs.h"
#include "driver/gpio.h"
#include "soc/timer_group_struct.h"
#include "soc/timer_group_reg.h"
#include "driver/timer.h"
#include "sdkconfig.h"
#include "NVS.h"
// Method to externally take the NVS mutex for situations where another IDF module requires access to the NVS subsystem.
//
bool NVS::takeMutex(void)
{
// Locals.
bool result = false;
// Ensure a handle has been opened to the NVS.
if(nvsCtrl.nvsHandle != (nvs_handle_t)0)
{
// Request exclusive access.
if(xSemaphoreTake(nvsCtrl.mutexInternal, (TickType_t)1000) == pdTRUE)
{
result = true;
}
}
return(result);
}
// Method to release the NVS mutex previously taken.
void NVS::giveMutex(void)
{
// Locals.
// Release mutex, external access now possible to the input devices.
xSemaphoreGive(nvsCtrl.mutexInternal);
}
// Method to persist data into the NVS RAM. This method takes a pointer to any memory object and writes it into the NVS using the handle opened at initialisation time.
//
bool NVS::persistData(const char *key, void *pData, uint32_t size)
{
// Locals.
//
esp_err_t nvsStatus;
bool result = true;
#define NVSPERSISTTAG "persistData"
// Ensure a handle has been opened to the NVS.
if(nvsCtrl.nvsHandle != (nvs_handle_t)0)
{
// Ensure we have exclusive access before accessing NVS.
if(xSemaphoreTake(nvsCtrl.mutexInternal, (TickType_t)1000) == pdTRUE)
{
// Write a binary blob of data straight from memory pointed to by pData for readSize bytes into the NVS. This allows for individual variables or entire structures.
nvsStatus = nvs_set_blob(this->nvsCtrl.nvsHandle, key, pData, size);
if(nvsStatus != ESP_OK)
{
ESP_LOGW(NVSPERSISTTAG, "Failed to persist NVS data, key:%s, size:%d, nvsStatus:%d", key, size, nvsStatus);
result = false;
}
} else
{
result = false;
}
} else
{
result = false;
}
// NB: Mutex only released in COMMIT.
// Return result code.
return(result);
}
// Method to retrieve persisted data from the NVS RAM. This method takes a pointer to a pre-allocated memoery block along with size and retrieves a data block from NVS upto size bytes.
//
bool NVS::retrieveData(const char *key, void *pData, uint32_t size)
{
// Locals.
//
esp_err_t nvsStatus;
size_t readSize = size;
bool result = true;
#define NVSRTRVTAG "retrieveData"
// Ensure a handle has been opened to the NVS.
if(nvsCtrl.nvsHandle != (nvs_handle_t)0)
{
// Ensure we have exclusive access before accessing NVS.
if(xSemaphoreTake(nvsCtrl.mutexInternal, (TickType_t)1000) == pdTRUE)
{
// Get a binary blob of data straight into the memory pointed to by pData for readSize. This allows for individual variables or entire structures.
nvsStatus = nvs_get_blob(this->nvsCtrl.nvsHandle, key, pData, &readSize);
if(nvsStatus != ESP_OK || readSize != size)
{
ESP_LOGW(NVSRTRVTAG, "Failed to retrieve NVS data, key:%s, size:%d, requested size:%d, nvsStatus:%d", key, readSize, size, nvsStatus);
result = false;
}
// Release mutex, external access now possible to the input devices.
xSemaphoreGive(nvsCtrl.mutexInternal);
} else
{
result = false;
}
} else
{
result = false;
}
// Return result code.
return(result);
}
// Method to ensure all data written to NVS is flushed and committed. This step is necessary as a write may be buffered and requires flushing to ensure persistence.
//
bool NVS::commitData(void)
{
// Locals.
//
esp_err_t nvsStatus;
bool result = true;
#define NVSCOMMITTAG "commitData"
// Ensure a handle has been opened to the NVS.
if(nvsCtrl.nvsHandle != (nvs_handle_t)0)
{
// Check that the Mutex has been taken, if we grab it then it hasnt been taken in the persistData method, so exit as a call to persistData is mandatory.
if(xSemaphoreTake(nvsCtrl.mutexInternal, (TickType_t)0) == pdTRUE)
{
xSemaphoreGive(nvsCtrl.mutexInternal);
} else
{
// Request a commit transaction and return response accordingly.
nvsStatus = nvs_commit(this->nvsCtrl.nvsHandle);
if(nvsStatus != ESP_OK)
{
ESP_LOGW(NVSCOMMITTAG, "Failed to commit pending NVS data.");
result = false;
}
// Release mutex, external access now possible to the input devices.
xSemaphoreGive(nvsCtrl.mutexInternal);
}
} else
{
result = false;
}
// Return result code.
return(result);
}
// Method to erase all the NVS and return to factory default state. The method closes any open handle,
// de-initialises the NVS then performs a flash erase.
//
void NVS::eraseAll(void)
{
// Locals.
//
#define NVSERATAG "eraseAll"
// Ensure we have exclusive access before accessing NVS.
while(xSemaphoreTake(nvsCtrl.mutexInternal, (TickType_t)1000) != pdTRUE);
// Ensure a handle has been opened to the NVS.
if(nvsCtrl.nvsHandle != (nvs_handle_t)0)
{
// Close open handle.
nvs_close(nvsCtrl.nvsHandle);
nvsCtrl.nvsHandle = NULL;
}
// Stop the flash driver.
nvs_flash_deinit();
ESP_LOGW(NVSERATAG, "Erasing flash, disable for production!\n");
ESP_ERROR_CHECK(nvs_flash_erase());
// Release mutex, external access now possible to the input devices.
xSemaphoreGive(nvsCtrl.mutexInternal);
return;
}
// Method to initialise the NVS subsystem.
void NVS::init(void)
{
// Locals.
esp_err_t nvsStatus;
#define NVSINITTAG "nvsInit"
// Initialise variables.
nvsCtrl.nvsHandle = (nvs_handle_t)0;
//ESP_LOGW(NVSINITTAG, "Erasing flash, disable for production!\n");
//ESP_ERROR_CHECK(nvs_flash_erase());
// Initialize NVS
ESP_LOGW(NVSINITTAG, "Initialising NVS.");
nvsStatus = nvs_flash_init();
if(nvsStatus == ESP_ERR_NVS_NO_FREE_PAGES || nvsStatus == ESP_ERR_NVS_NEW_VERSION_FOUND)
{
// NVS partition was truncated and needs to be erased
ESP_ERROR_CHECK(nvs_flash_erase());
// Retry nvs_flash_init
nvsStatus = nvs_flash_init();
}
ESP_ERROR_CHECK(nvsStatus);
// Setup mutex's.
nvsCtrl.mutexInternal = xSemaphoreCreateMutex();
return;
}
// Method to open a namespace on the NVS given a key.
//
bool NVS::open(std::string keyName)
{
// Locals.
bool result = true;
#define NVSOPENTAG "nvsOpen"
// Only process if no handle has been opened. Currently only coded for one session at a time.
if(nvsCtrl.nvsHandle == (nvs_handle_t)0)
{
// Store the key name under which all data is stored.
this->nvsCtrl.nvsKeyName = keyName;
// Open handle to persistence using the base-class name as the key which represents the global namespace. Sub-classes and objects accessing the public methods will
// use there own class name as a sub-key which represents the class namespace within NVS. Data is then stored within the class namespace using a key:value pair.
esp_err_t nvsStatus = nvs_open(nvsCtrl.nvsKeyName.c_str(), NVS_READWRITE, &this->nvsCtrl.nvsHandle);
if (nvsStatus != ESP_OK)
{
ESP_LOGW(NVSOPENTAG, "Error (%s) opening NVS handle!\n", esp_err_to_name(nvsStatus));
result = false;
}
} else
{
result = false;
}
return(result);
}
// Basic constructor, init variables!
NVS::NVS(void)
{
// Store the class name for later use, ie. NVS key access.
this->nvsCtrl.nvsClassName = getClassName(__PRETTY_FUNCTION__);
}

View File

@@ -1 +0,0 @@
../../sharpkey/main/PC9801.cpp

1054
main/PC9801.cpp Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1 +0,0 @@
../../sharpkey/main/PS2KeyAdvanced.cpp

1113
main/PS2KeyAdvanced.cpp Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1 +0,0 @@
../../sharpkey/main/PS2Mouse.cpp

682
main/PS2Mouse.cpp Normal file
View File

@@ -0,0 +1,682 @@
/////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Name: PS2Mouse.cpp
// Created: Jan 2022
// Version: v1.0
// Author(s): Philip Smart
// Description: PS/2 Mouse Class.
// This source file contains the class to encapsulate a PS/2 mouse. Given two GPIO
// pins, datapin and clkpin, it is able to communicate, configure and return mouse
// data via a rich set of methods.
//
// This class borrows ideas from the interrupt concept of the PS2KeyAdvanced class
// for communicating via the PS/2 protocol.
// https://github.com/techpaul/PS2KeyAdvanced class from Paul Carpenter.
//
// The application uses the Espressif Development environment with Arduino components.
// This is necessary as the class uses the Arduino methods for GPIO manipulation. I
// was considering using pure Espressif IDF methods but considered the potential
// of also using this class on an Arduino project.
//
// Credits:
// Copyright: (c) 2022 Philip Smart <philip.smart@net2net.org>
//
// History: Mar 2022 - Initial write.
//
// Notes: See Makefile to enable/disable conditional components
//
/////////////////////////////////////////////////////////////////////////////////////////////////////////
// This source file is free software: you can redistribute it and#or modify
// it under the terms of the GNU General Public License as published
// by the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This source file is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
/////////////////////////////////////////////////////////////////////////////////////////////////////////
#include "PS2Mouse.h"
// Global handle to allow the static interrupt routine to access the instantiated object. This does limit this class to being Singleton
// but it is unusual to have more than 1 PS/2 mouse on a project so less of a problem.
PS2Mouse *pThis;
// Constructor. Simple assign the hardware data and clock pins to internal variables and setup
// variables. Actual real initialisation is performed by a public method so re-initialisation can
// be made if required.
//
PS2Mouse::PS2Mouse(int clockPin, int dataPin)
{
ps2Ctrl.clkPin = clockPin;
ps2Ctrl.dataPin = dataPin;
ps2Ctrl.supportsIntelliMouseExtensions = false;
ps2Ctrl.mouseDataCallback = NULL;
}
// Destructor - Detach interrupts and free resources.
//
PS2Mouse::~PS2Mouse()
{
// Disable interrupts.
detachInterrupt( digitalPinToInterrupt( ps2Ctrl.clkPin ) );
}
// The interrupt handler triggered on each falling edge of the clock pin.
// Rx Mode: 11 bits - <start><8 data bits><ODD parity bit><stop bit>
// Tx Mode: 11 bits - <start><8 data bits><ODD parity bit><stop bit>
IRAM_ATTR void PS2Mouse::ps2interrupt( void )
{
// Locals.
//
static uint32_t timeLast = 0;
uint32_t timeCurrent;
uint8_t dataBit;
// Workaround for ESP32 SILICON error see extra/Porting.md
#ifdef PS2_ONLY_CHANGE_IRQ
if( digitalRead( ps2Ctrl.clkPin ) )
return;
#endif
// TRANSMIT MODE.
if( pThis->ps2Ctrl.mode & _TX_MODE )
{
// Received data not valid when transmitting.
pThis->ps2Ctrl.rxPos = 0;
// Now point to next bit
pThis->ps2Ctrl.bitCount++;
// BIT 1 - START BIT
if(pThis->ps2Ctrl.bitCount == 1)
{
#if defined( PS2_CLEAR_PENDING_IRQ )
// Start bit due to Arduino bug
digitalWrite(pThis->ps2Ctrl.dataPin, LOW);
break;
#endif
} else
// BIT 2->9 - DATA BIT MSB->LSB
if(pThis->ps2Ctrl.bitCount >= 2 && pThis->ps2Ctrl.bitCount <= 9)
{
// Data bits
dataBit = pThis->ps2Ctrl.shiftReg & 0x01; // get LSB
digitalWrite(pThis->ps2Ctrl.dataPin, dataBit); // send start bit
pThis->ps2Ctrl.parity += dataBit; // another one received ?
pThis->ps2Ctrl.shiftReg >>= 1; // right _SHIFT one place for next bit
} else
// BIT 10 - PARITY BIT
if(pThis->ps2Ctrl.bitCount == 10)
{
// Parity - Send LSB if 1 = odd number of 1's so ps2Ctrl.parity should be 0
digitalWrite( pThis->ps2Ctrl.dataPin, ( ~pThis->ps2Ctrl.parity & 1 ) );
} else
// BIT 11 - STOP BIT
if(pThis->ps2Ctrl.bitCount == 11)
{
// Stop bit write change to input pull up for high stop bit
digitalWrite( pThis->ps2Ctrl.dataPin, HIGH );
pinMode( pThis->ps2Ctrl.dataPin, INPUT );
} else
// BIT 12 - ACK BIT
if(pThis->ps2Ctrl.bitCount == 12)
{
// Acknowledge bit low we cannot do anything if high instead of low
// clear modes to receive again
pThis->ps2Ctrl.mode &= ~_TX_MODE;
pThis->ps2Ctrl.bitCount = 0; // end of byte
} else
{
// in case of weird error and end of byte reception re-sync
pThis->ps2Ctrl.bitCount = 0;
}
}
// RECEIVE MODE.
else
{
// Read latest bit.
dataBit = digitalRead( pThis->ps2Ctrl.dataPin );
// Get current time.
timeCurrent = millis( );
// Reset the receive byte buffer pointer if the gap from the last received byte to the current time is greater than a packet interbyte delay.
if(timeCurrent - timeLast > 100)
{
pThis->ps2Ctrl.rxPos = 0;
}
// Catch glitches, any clock taking longer than 250ms is either a glitch, an error or start of a new packet.
if( timeCurrent - timeLast > 250 )
{
pThis->ps2Ctrl.bitCount = 0;
pThis->ps2Ctrl.shiftReg = 0;
}
// Store current time for next loop to detect timing issues.
timeLast = timeCurrent;
// Now point to next bit
pThis->ps2Ctrl.bitCount++;
// BIT 1 - START BIT
if(pThis->ps2Ctrl.bitCount == 1)
{
// Start bit
pThis->ps2Ctrl.parity = 0;
pThis->ps2Ctrl.mode |= _PS2_BUSY; // set busy
} else
// BIT 2->9 - DATA BIT MSB->LSB
if(pThis->ps2Ctrl.bitCount >= 2 && pThis->ps2Ctrl.bitCount <= 9)
{
// Data bits
pThis->ps2Ctrl.parity += dataBit; // another one received ?
pThis->ps2Ctrl.shiftReg >>= 1; // right _SHIFT one place for next bit
pThis->ps2Ctrl.shiftReg |= ( dataBit ) ? 0x80 : 0; // or in MSbit
} else
// BIT 10 - PARITY BIT
if(pThis->ps2Ctrl.bitCount == 10)
{
// Parity check
pThis->ps2Ctrl.parity &= 1; // Get LSB if 1 = odd number of 1's so ps2Ctrl.parity bit should be 0
if( pThis->ps2Ctrl.parity == dataBit ) // Both same ps2Ctrl.parity error
pThis->ps2Ctrl.parity = 0xFD; // To ensure at next bit count clear and discard
} else
// BIT 11 - STOP BIT
if(pThis->ps2Ctrl.bitCount == 11)
{
// Streaming mode, assemble the data into the buffer.
if(pThis->ps2Ctrl.streamingEnabled)
{
if(pThis->ps2Ctrl.rxPos == 0 && pThis->streaming.newData == true) pThis->streaming.overrun = true;
if(pThis->ps2Ctrl.rxPos == 0) pThis->streaming.mouseData.status = pThis->ps2Ctrl.shiftReg;
if(pThis->ps2Ctrl.rxPos == 1) pThis->streaming.mouseData.position.x = pThis->ps2Ctrl.shiftReg;
if(pThis->ps2Ctrl.rxPos == 2) pThis->streaming.mouseData.position.y = pThis->ps2Ctrl.shiftReg;
if(pThis->ps2Ctrl.rxPos == 3) pThis->streaming.mouseData.wheel = pThis->ps2Ctrl.shiftReg;
if( (pThis->ps2Ctrl.supportsIntelliMouseExtensions == false && pThis->ps2Ctrl.rxPos == 2) || (pThis->ps2Ctrl.supportsIntelliMouseExtensions == true && pThis->ps2Ctrl.rxPos == 3))
{
pThis->streaming.newData = true;
pThis->streaming.overrun = false;
pThis->ps2Ctrl.rxPos = 0;
} else
{
pThis->ps2Ctrl.rxPos++;
}
} else
{
// Save the received byte and parity, let consumer decide on it's validity.
pThis->ps2Ctrl.rxBuf[pThis->ps2Ctrl.rxPos++] = (pThis->ps2Ctrl.parity << 8 | pThis->ps2Ctrl.shiftReg);
}
// Set mode and status for next receive byte
pThis->ps2Ctrl.mode &= ~( _WAIT_RESPONSE );
pThis->ps2Ctrl.mode &= ~_PS2_BUSY;
pThis->ps2Ctrl.bitCount = 0; // end of byte
} else
{
// in case of weird error and end of byte reception re-sync
pThis->ps2Ctrl.bitCount = 0;
}
}
}
// Method to write a byte (control or parameter) to the Mouse. This method encapsulates the protocol necessary
// to invoke Host -> PS/2 Mouse transmission and the interrupts, on falling clock edge, process the byte to send
// and bitbang accordingly.
//
void PS2Mouse::writeByte(uint8_t command)
{
// Locals.
//
uint32_t currentTime = millis();
// Test to see if a transmission is underway, block until the xmit buffer becomes available or timeout expires (no mouse).
//
while((ps2Ctrl.mode & _TX_MODE) && currentTime+100 > millis());
// If TX_MODE has been reset, interrupt processing has occurred so line up next byte,
//
if((ps2Ctrl.mode & _TX_MODE) == 0)
{
// Initialise the ps2 control variables.
ps2Ctrl.shiftReg = command;
ps2Ctrl.bitCount = 1;
ps2Ctrl.parity = 0;
ps2Ctrl.mode |= _TX_MODE + _PS2_BUSY;
ps2Ctrl.rxPos = 0;
// Initialise the streaming buffer.
streaming.mouseData.valid = false;
streaming.mouseData.status = 0;
streaming.mouseData.position.x = 0;
streaming.mouseData.position.y = 0;
streaming.mouseData.wheel = 0;
streaming.newData = false;
streaming.overrun = false;
// STOP the interrupt handler - Setting pin output low will cause interrupt before ready
detachInterrupt( digitalPinToInterrupt( ps2Ctrl.clkPin ) );
// Set data and clock pins to output and high
digitalWrite(ps2Ctrl.dataPin, HIGH);
pinMode(ps2Ctrl.dataPin, OUTPUT);
digitalWrite(ps2Ctrl.clkPin, HIGH);
pinMode(ps2Ctrl.clkPin, OUTPUT);
// Essential for PS2 spec compliance
delayMicroseconds(10);
// Set Clock LOW - trigger Host -> Mouse transmission. Mouse controls the clock but dragging clock low is used by the mouse to detect a host write and clock
// data in accordingly.
digitalWrite( ps2Ctrl.clkPin, LOW );
// Essential for PS2 spec compliance, set clock low for 60us
delayMicroseconds(60);
// Set data low - Start bit
digitalWrite( ps2Ctrl.dataPin, LOW );
// Set clock to input_pullup data stays output while writing to keyboard
digitalWrite(ps2Ctrl.clkPin, HIGH);
pinMode(ps2Ctrl.clkPin, INPUT);
// Restart interrupt handler
attachInterrupt( digitalPinToInterrupt( ps2Ctrl.clkPin ), ps2interrupt, FALLING );
}
// Everything is now processed in the interrupt handler.
return;
}
// Setup and initialise the running object and Mouse hardware. This method must be called at startup and anytime a full reset is required.
//
void PS2Mouse::initialize()
{
// Setup variables.
ps2Ctrl.mode = 0;
ps2Ctrl.supportsIntelliMouseExtensions = false;
ps2Ctrl.streamingEnabled = false;
ps2Ctrl.bitCount = 0;
ps2Ctrl.shiftReg = 0;
ps2Ctrl.parity = 0;
ps2Ctrl.rxPos = 0;
// Clear the receive buffer.
for(int idx=0; idx < 16; idx++) ps2Ctrl.rxBuf[idx] = 0x00;
// Set data and clock pins to input.
digitalWrite(ps2Ctrl.dataPin, HIGH);
pinMode(ps2Ctrl.dataPin, INPUT);
digitalWrite(ps2Ctrl.clkPin, HIGH);
pinMode(ps2Ctrl.clkPin, INPUT);
// Initialise the control structure.
ps2Ctrl.bitCount = 0;
ps2Ctrl.mode = 0;
ps2Ctrl.rxPos = 0;
// As the interrupt handler is static it wont have reference to the instantiated object methods so we need to store the object in a pointer
// which is then used by the interrupt handler.
pThis = this;
// Attach the clock line to a falling low interrupt trigger and handler. The Mouse toggles the clock line for each bit to be sent/received
// so we interrupt on each falling clock edge.
attachInterrupt( digitalPinToInterrupt( ps2Ctrl.clkPin ), ps2interrupt, FALLING );
// Setup the mouse, make a reset, check and set Intellimouse extensions, set the resolution, scaling, sample rate to defaults and switch to remote (polled) mode.
reset();
checkIntelliMouseExtensions();
setResolution(PS2_MOUSE_RESOLUTION_1_8);
setScaling(PS2_MOUSE_SCALING_1_1);
setSampleRate(PS2_MOUSE_SAMPLE_RATE_40);
setRemoteMode();
// All done.
return;
}
// Public method to force a mouse reset. Used on startup and anytime the client believes the mouse has hungup.
//
bool PS2Mouse::reset(void)
{
// Locals.
//
uint8_t respBuf[5];
bool result = false;
// Send command to reset the mouse, if it returns an ACK then reset succeeded.
//
if(sendCmd(MOUSE_CMD_RESET, 0, respBuf, DEFAULT_MOUSE_TIMEOUT))
{
result = true;
}
// Return result.
return(result);
}
// Private method to check and see if the mouse suports Microsoft Intellimouse extensions. It sets an internal state flag accordingly.
//
bool PS2Mouse::checkIntelliMouseExtensions(void)
{
// Locals.
//
char deviceId;
// IntelliMouse detection sequence, error checking isnt used.
setSampleRate(PS2_MOUSE_SAMPLE_RATE_200);
setSampleRate(PS2_MOUSE_SAMPLE_RATE_100);
setSampleRate(PS2_MOUSE_SAMPLE_RATE_80);
// Get device Id and if the mouse supports Intellimouse extensions, it will reveal itself as an INTELLI_MOUSE.
deviceId = getDeviceId();
ps2Ctrl.supportsIntelliMouseExtensions = (deviceId == INTELLI_MOUSE);
// Return flag to indicate support (true) or no support (false).
return(ps2Ctrl.supportsIntelliMouseExtensions);
}
// Public method to set the automatic sample rate.
//
bool PS2Mouse::setSampleRate(enum PS2_SAMPLING rate)
{
// Locals.
//
uint8_t respBuf[5];
bool result = false;
// Sanity check.
if(rate == PS2_MOUSE_SAMPLE_RATE_10 || rate == PS2_MOUSE_SAMPLE_RATE_20 || rate == PS2_MOUSE_SAMPLE_RATE_40 || rate == PS2_MOUSE_SAMPLE_RATE_60 || rate == PS2_MOUSE_SAMPLE_RATE_80 || rate == PS2_MOUSE_SAMPLE_RATE_100 || rate == PS2_MOUSE_SAMPLE_RATE_200)
{
// Send command to set the mouse resolution.
//
if(sendCmd(MOUSE_CMD_SET_SAMPLE_RATE, 0, respBuf, DEFAULT_MOUSE_TIMEOUT))
{
// Send the rate, if ACK is returned, then resolution set otherwise error.
if(sendCmd((uint8_t)rate, 0, respBuf, DEFAULT_MOUSE_TIMEOUT))
{
result = true;
}
}
}
// Return result.
return(result);
}
// Public method to request the mouse Id which can be used to identify the mouse capabilities.
//
char PS2Mouse::getDeviceId(void)
{
// Locals.
//
uint8_t respBuf[5];
// Send command to set the mouse scaling, either 2:1 or 1:1.
//
if(sendCmd(MOUSE_CMD_GET_DEVICE_ID, 1, respBuf, DEFAULT_MOUSE_TIMEOUT) == false)
{
respBuf[0] = 0xFF;
}
// Return result.
return(respBuf[0]);
}
// Public method to set the mouse scaling, either Normal 1:1 (scaling = 0) or non-linear 2:1 (scaling = 1).
//
bool PS2Mouse::setScaling(enum PS2_SCALING scaling)
{
// Locals.
//
uint8_t respBuf[5];
bool result = false;
// Sanity check.
if(scaling >= PS2_MOUSE_SCALING_1_1 && scaling < PS2_MOUSE_SCALING_2_1)
{
// Send command to set the mouse scaling, either 2:1 or 1:1.
//
if(sendCmd((uint8_t)scaling, 0, respBuf, DEFAULT_MOUSE_TIMEOUT))
{
result = true;
}
}
// Return result.
return(result);
}
// Public method to request the mouse enters remote mode.
//
bool PS2Mouse::setRemoteMode(void)
{
// Locals.
//
uint8_t respBuf[5];
// Simply pass on the request to the mouse to enter remote mode.
return(sendCmd(MOUSE_CMD_SET_REMOTE_MODE, 1, respBuf, DEFAULT_MOUSE_TIMEOUT));
}
// Public method to request the mouse enters stream mode. This mode reports mouse movements as they change, albeit the streaming must also be enabled
// once set to Stream Mode via the enableStreaming method.
//
bool PS2Mouse::setStreamMode(void)
{
// Locals.
//
uint8_t respBuf[5];
// Simply pass on the request to the mouse to enter stream mode.
return(sendCmd(MOUSE_CMD_SET_STREAM_MODE, 1, respBuf, DEFAULT_MOUSE_TIMEOUT));
}
// Public methods to enable and disable streaming (constant rate packet transmission from mouse to host).
// This module accepts the data and updates an in object set which the caller queries. No buffering takes place
// so should the caller fail to read the data then the arrival of the next packet from the mouse will override
// the in object values.
//
bool PS2Mouse::enableStreaming(void)
{
// Locals.
//
uint8_t respBuf[5];
// Sanity check.
if(ps2Ctrl.streamingEnabled == false)
{
if(sendCmd(MOUSE_CMD_ENABLE_STREAMING, 0, respBuf, DEFAULT_MOUSE_TIMEOUT))
{
// Initialise the streaming buffer.
streaming.mouseData.valid = false;
streaming.mouseData.status = 0;
streaming.mouseData.position.x = 0;
streaming.mouseData.position.y = 0;
streaming.mouseData.wheel = 0;
streaming.newData = false;
streaming.overrun = false;
ps2Ctrl.streamingEnabled = true;
}
}
// Return the enabled flag to indicate success.
return(ps2Ctrl.streamingEnabled);
}
bool PS2Mouse::disableStreaming(void)
{
// Locals.
//
uint8_t respBuf[5];
// Sanity check.
if(ps2Ctrl.streamingEnabled == true)
{
if(sendCmd(MOUSE_CMD_DISABLE_STREAMING, 0, respBuf, DEFAULT_MOUSE_TIMEOUT))
{
ps2Ctrl.streamingEnabled = false;
}
}
// Return the enabled flag to indicate success.
return(ps2Ctrl.streamingEnabled);
}
// Public method to set the mouse resolution in pixels per millimeter, valid values are o..3.
//
bool PS2Mouse::setResolution(enum PS2_RESOLUTION resolution)
{
// Locals.
//
uint8_t respBuf[5];
bool result = false;
// Sanity check.
if(resolution >= PS2_MOUSE_RESOLUTION_1_1 && resolution < PS2_MOUSE_RESOLUTION_1_8)
{
// Send command to set the mouse resolution.
//
if(sendCmd(MOUSE_CMD_SET_RESOLUTION, 0, respBuf, DEFAULT_MOUSE_TIMEOUT))
{
// Send the resolution, if ACK is returned, then resolution set otherwise error.
if(sendCmd((uint8_t)resolution, 0, respBuf, DEFAULT_MOUSE_TIMEOUT))
{
result = true;
}
}
}
// Return result.
return(result);
}
// Public method to get the current mouse status. The status code is 3 bytes wide and has the following format:
//
// 7 6 5 4 3 2 1 0
// Byte 1: 0 mode enable scaling 0 left btn middle right btn
// Byte 2: resolution
// Byte 3: sample rate
//
bool PS2Mouse::getStatus(uint8_t *respBuf)
{
// Locals.
//
bool result = false;
// Sanity check.
if(respBuf != NULL)
{
// Send command to set the mouse resolution.
//
if(sendCmd(MOUSE_CMD_GET_STATUS, 3, respBuf, DEFAULT_MOUSE_TIMEOUT))
{
result = true;
}
}
// Return result.
return(result);
}
// Public method to obtain current mouse state data.
//
PS2Mouse::MouseData PS2Mouse::readData(void)
{
// Locals.
MouseData data;
uint8_t dataBuf[8] = {0,0,0,0,0,0,0,0};
// If streaming mode enabled then set values according to data state. Data only valid if a new update has occurred since last call otherwise old data is returned and valid flag
// is cleared.
if(ps2Ctrl.streamingEnabled)
{
data.valid = streaming.newData;
data.overrun = streaming.overrun;
data.status = streaming.mouseData.status;
data.position.x = streaming.mouseData.position.x;
data.position.y = streaming.mouseData.position.y;
data.wheel = ps2Ctrl.supportsIntelliMouseExtensions ? streaming.mouseData.wheel : 0;
streaming.newData = false;
streaming.overrun = false;
// If a data callback has been setup execute it otherwise data is read by caller.
//
if(ps2Ctrl.mouseDataCallback != NULL && data.valid)
ps2Ctrl.mouseDataCallback(data);
} else
// Single on-request data set from mouse.
{
// Request data from mouse via issuing get single data packet command.
if(requestData(ps2Ctrl.supportsIntelliMouseExtensions ? 3 : 3, dataBuf, DEFAULT_MOUSE_TIMEOUT))
{
data.valid = true;
data.overrun = false;
data.status = dataBuf[0];
data.position.x = dataBuf[1];
data.position.y = dataBuf[2];
data.wheel = ps2Ctrl.supportsIntelliMouseExtensions ? dataBuf[3] : 0;
} else
{
data.valid = false;
data.overrun = false;
}
}
return data;
};
// Method to request the latest mouse movement, wheel and key data. The method blocks until data is available or the timeout is reached. A timeout of 0
// will only return when the data has been received.
bool PS2Mouse::requestData(uint8_t expectedBytes, uint8_t *respBuf, uint32_t timeout)
{
// Locals.
//
// Simply pass on the request for the mouse to send data and await reply.
return(sendCmd(MOUSE_CMD_REQUEST_DATA, expectedBytes, respBuf, timeout));
}
// Method to send a command to the Mouse and await it's reply. If an ACK isnt returned then a resend request is made otherwise wait until all bytes
// arrive or we timeout.
//
bool PS2Mouse::sendCmd(uint8_t cmd, uint8_t expectedBytes, uint8_t *respBuf, uint32_t timeout)
{
// Locals.
//
uint32_t currentTime = millis();
uint32_t endTime = millis() + timeout;
uint8_t *pBuf = respBuf;
bool result = false;
// Send command.
writeByte(cmd);
// Wait for the expected number of bytes to arrive.
while(((timeout == 0) || (currentTime < endTime)) && ps2Ctrl.rxPos <= expectedBytes)
{
// If an ACK isnt received, request a resend.
if(ps2Ctrl.rxPos >= 1 && ps2Ctrl.rxBuf[0] != MOUSE_RESP_ACK) { writeByte(MOUSE_CMD_RESEND); }
// Get latest time.
currentTime = millis();
}
// Store the response in callers buffer.
for(int idx=0; idx < expectedBytes; idx++)
{
(*pBuf) = ps2Ctrl.rxBuf[idx+1];
pBuf++;
}
// Set return code, true if a valid packet was received.
if(((timeout == 0) || (currentTime < endTime)) && ps2Ctrl.rxPos >= expectedBytes && ps2Ctrl.rxBuf[0] == MOUSE_RESP_ACK) result = true;
// Debug print.
//printf("%d:%d:%02x,%02x,%02x,%02x, %02x, %d, result=%d, %d, %d, %d\n", result, ps2Ctrl.rxPos, ps2Ctrl.rxBuf[0], ps2Ctrl.rxBuf[1], ps2Ctrl.rxBuf[2], ps2Ctrl.rxBuf[3],ps2Ctrl.rxBuf[4], ps2Ctrl.bitCount, result, timeout, currentTime, endTime);
// And complete with result!
return(result);
}

View File

@@ -1 +0,0 @@
../../sharpkey/main/SWITCH.cpp

216
main/SWITCH.cpp Normal file
View File

@@ -0,0 +1,216 @@
/////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Name: SWITCH.cpp
// Created: May 2022
// Version: v1.0
// Author(s): Philip Smart
// Description: Base class for encapsulating the SharpKey WiFi/Config switch.
// Credits:
// Copyright: (c) 2019-2022 Philip Smart <philip.smart@net2net.org>
//
// History: May 2022 - Initial write.
// v1.00 Jun 2022 - Updates to add additional callbacks for RESET and CLEARNVS
//
// Notes: See Makefile to enable/disable conditional components
//
/////////////////////////////////////////////////////////////////////////////////////////////////////////
// This source file is free software: you can redistribute it and#or modify
// it under the terms of the GNU General Public License as published
// by the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This source file is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
/////////////////////////////////////////////////////////////////////////////////////////////////////////
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <iostream>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/semphr.h"
#include "esp_log.h"
#include "esp_system.h"
#include "nvs_flash.h"
#include "nvs.h"
#include "driver/gpio.h"
#include "soc/timer_group_struct.h"
#include "soc/timer_group_reg.h"
#include "driver/timer.h"
#include "sdkconfig.h"
#include "SWITCH.h"
// Primary SWITCH thread, running on Core 0.
// This thread is responsible for scanning the config/WiFi key on the SharpKey and generating callbacks according to state.
//
IRAM_ATTR void SWITCH::swInterface( void * pvParameters )
{
// Locals.
//
uint32_t keyDebCtr = 0;
uint32_t WIFIEN_MASK = (1 << (CONFIG_IF_WIFI_EN_KEY - 32));
uint32_t resetTimer = 0;
#define WIFIIFTAG "swInterface"
// Map the instantiating object so we can access its methods and data.
SWITCH* pThis = (SWITCH*)pvParameters;
// Loop indefinitely.
while(true)
{
// Check the switch, has it gone to zero, ie. pressed?
//
if((REG_READ(GPIO_IN1_REG) & WIFIEN_MASK) == 0)
{
// First press detection turn LED off.
if(keyDebCtr == 0)
{
pThis->led->setLEDMode(LED::LED_MODE_OFF, LED::LED_DUTY_CYCLE_OFF, 0, 0L, 0L);
}
// Entering WiFi enable mode, blink LED
if(keyDebCtr == 10)
{
pThis->led->setLEDMode(LED::LED_MODE_BLINK, LED::LED_DUTY_CYCLE_50, 1, 50000L, 500L);
}
// Enter default AP mode.
if(keyDebCtr == 50)
{
pThis->led->setLEDMode(LED::LED_MODE_BLINK, LED::LED_DUTY_CYCLE_30, 1, 25000L, 250L);
}
// Enter BT pairing mode.
if(keyDebCtr == 100)
{
pThis->led->setLEDMode(LED::LED_MODE_BLINK, LED::LED_DUTY_CYCLE_10, 1, 10000L, 100L);
}
// Enter Clear NVS settings mode.
if(keyDebCtr == 150)
{
pThis->led->setLEDMode(LED::LED_MODE_BLINK, LED::LED_DUTY_CYCLE_80, 5, 10000L, 1000L);
}
// Increment counter so we know how long it has been held.
keyDebCtr++;
} else
if((REG_READ(GPIO_IN1_REG) & WIFIEN_MASK) != 0 && keyDebCtr > 1)
{
// On first 1/2 second press, if WiFi active, disable and reboot.
if(keyDebCtr > 1 && keyDebCtr < 10)
{
// If a cancel callback has been setup, invoke it.
//
if(pThis->swCtrl.cancelEventCallback != NULL)
pThis->swCtrl.cancelEventCallback();
// If the reset timer is running then a previous button press occurred. If it is less than 1 second then a RESET event
// is required.
if(resetTimer != 0 && (pThis->milliSeconds() - resetTimer) < 1000L)
{
// If a handler is installed call it. If the return value is true then a restart is possible. No handler then we just restart.
if(pThis->swCtrl.resetEventCallback != NULL)
{
if(pThis->swCtrl.resetEventCallback())
esp_restart();
} else
esp_restart();
} else
{
resetTimer = pThis->milliSeconds();
}
}
// If counter is in range 1 to 4 seconds then assume a WiFi on (so long as the client parameters have been configured).
else if(keyDebCtr > 10 && keyDebCtr < 40)
{
// If a wifi enable callback has been setup, invoke it.
//
if(pThis->swCtrl.wifiEnEventCallback != NULL)
pThis->swCtrl.wifiEnEventCallback();
}
// If the key is held for 5 or more seconds, then enter Wifi Config Default AP mode.
else if(keyDebCtr > 50 && keyDebCtr < 100)
{
// If a wifi default enable callback has been setup, invoke it.
//
if(pThis->swCtrl.wifiDefEventCallback != NULL)
pThis->swCtrl.wifiDefEventCallback();
}
// If the key is held for 10 seconds or more, invoke Bluetooth pairing mode.
else if(keyDebCtr >= 100 && keyDebCtr < 150)
{
// If a bluetooth start pairing callback has been setup, invoke it.
//
if(pThis->swCtrl.btPairingEventCallback != NULL)
pThis->swCtrl.btPairingEventCallback();
}
// If the key is held for 15 seconds or more, invoke the clear NVS settings (factory) mode.
else if(keyDebCtr >= 150)
{
// If a clear NVS handler has been installed, call it.
//
if(pThis->swCtrl.clearNVSEventCallback != NULL)
pThis->swCtrl.clearNVSEventCallback();
}
// LED off, no longer needed.
pThis->led->setLEDMode(LED::LED_MODE_OFF, LED::LED_DUTY_CYCLE_OFF, 0, 0L, 0L);
// Re-init switch variables for next activation.
keyDebCtr = 0;
}
// Reset the reset timer if not activated.
if(resetTimer != 0 && (pThis->milliSeconds() - resetTimer) > 2000L) { resetTimer = 0; }
// Let other tasks run. NB. This value affects the debounce counter, update as necessary.
vTaskDelay(100);
}
return;
}
// Initialisation routine. Setup variables and spawn a task to monitor the config switch.
//
void SWITCH::init(void)
{
// Initialise control variables.
#define SWINITTAG "SWINIT"
// Core 0 - Application
// SWITCH handler thread.
ESP_LOGW(SWINITTAG, "Starting SWITCH thread...");
::xTaskCreatePinnedToCore(&this->swInterface, "switch", 4096, this, 0, &this->swCtrl.TaskSWIF, 0);
vTaskDelay(1500);
}
// Basic constructor, init variables!
SWITCH::SWITCH(LED *hdlLED)
{
swCtrl.cancelEventCallback = NULL;
swCtrl.wifiEnEventCallback = NULL;
swCtrl.wifiDefEventCallback = NULL;
swCtrl.btPairingEventCallback = NULL;
// Store the class name for later use.
this->swCtrl.swClassName = getClassName(__PRETTY_FUNCTION__);
// Save the LED object so it can be used to warn the user.
this->led = hdlLED;
// Initialse the SWITCH object.
init();
}
// Basic consructor, do nothing!
SWITCH::SWITCH(void)
{
// Store the class name for later use.
this->swCtrl.swClassName = getClassName(__PRETTY_FUNCTION__);
}
// Basic destructor.
SWITCH::~SWITCH(void)
{
}

View File

@@ -1 +0,0 @@
../../sharpkey/main/SharpKey.cpp

1074
main/SharpKey.cpp Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1 +0,0 @@
../../sharpkey/main/WiFi.cpp

2872
main/WiFi.cpp Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1 +0,0 @@
../../sharpkey/main/X1.cpp

1124
main/X1.cpp Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1 +0,0 @@
../../sharpkey/main/X68K.cpp

1067
main/X68K.cpp Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1 +0,0 @@
../../sharpkey/main/component.mk

8
main/component.mk Normal file
View File

@@ -0,0 +1,8 @@
#
# Main component makefile.
#
# This Makefile can be left empty. By default, it will take the sources in the
# src/ directory, compile them and link them into lib(subdirectory_name).a
# in the build directory. This behaviour is entirely configurable,
# please read the ESP-IDF documents if you need to do this.
#

View File

@@ -1 +0,0 @@
../../../sharpkey/main/include/BT.h

222
main/include/BT.h Normal file
View File

@@ -0,0 +1,222 @@
/////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Name: BT.h
// Created: Jan 2022
// Version: v1.0
// Author(s): Philip Smart
// Description: Header file for the Bluetooth Class.
//
// Credits:
// Copyright: (c) 2022 Philip Smart <philip.smart@net2net.org>
//
// History: Mar 2022 - Initial write.
//
// Notes: See Makefile to enable/disable conditional components
//
/////////////////////////////////////////////////////////////////////////////////////////////////////////
// This source file is free software: you can redistribute it and#or modify
// it under the terms of the GNU General Public License as published
// by the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This source file is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
/////////////////////////////////////////////////////////////////////////////////////////////////////////
#ifndef BT_H_
#define BT_H_
#include <string>
#include <vector>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/semphr.h"
#include "esp_err.h"
#include "esp_log.h"
#include "esp_system.h"
#include "esp_event.h"
#include "esp_bt.h"
#include "esp_bt_defs.h"
#include "esp_bt_main.h"
#include "esp_hidh.h"
#include "esp_hid_common.h"
#include "esp_gap_bt_api.h"
#include "esp_gap_ble_api.h"
// Bluetooth interface class. Provides Mouse and Keyboard functionality via the Bluetooth wireless interface.
class BT {
#define SIZEOF_ARRAY(a) (sizeof(a) / sizeof(*a))
public:
typedef void t_pairingHandler(uint32_t code, uint8_t trigger);
// Structure to contain details of a single device forming a scanned device list.
//
typedef struct {
esp_bd_addr_t bda;
std::string name;
int8_t rssi;
esp_hid_usage_t usage;
esp_hid_transport_t transport; //BT, BLE or USB
union {
struct {
esp_bt_cod_t cod;
esp_bt_uuid_t uuid;
} bt;
struct {
esp_ble_addr_type_t addr_type;
uint16_t appearance;
} ble;
};
// Display format values.
std::string deviceAddr; // MAC address of the Bluetooth device.
std::string deviceType; // BT, BLE or USB
} t_scanListItem;
// Prototypes.
BT(void);
virtual ~BT(void);
void getDeviceList(std::vector<t_scanListItem> &scanList, int waitTime);
bool setup(t_pairingHandler *handler = nullptr);
inline uint8_t getBatteryLevel() { return btCtrl.batteryLevel; }
inline void setBatteryLevel(uint8_t level) { btCtrl.batteryLevel = level; }
private:
static constexpr char const *TAG = "BT";
#ifdef CONFIG_CLASSIC_BT_ENABLED
const char *gap_bt_prop_type_names[5] = { "", "BDNAME", "COD", "RSSI", "EIR" };
const char *bt_gap_evt_names[10] = { "DISC_RES", "DISC_STATE_CHANGED", "RMT_SRVCS", "RMT_SRVC_REC", "AUTH_CMPL", "PIN_REQ", "CFM_REQ", "KEY_NOTIF", "KEY_REQ", "READ_RSSI_DELTA" };
#endif
const char *ble_gap_evt_names[28] = { "ADV_DATA_SET_COMPLETE", "SCAN_RSP_DATA_SET_COMPLETE", "SCAN_PARAM_SET_COMPLETE", "SCAN_RESULT", "ADV_DATA_RAW_SET_COMPLETE",
"SCAN_RSP_DATA_RAW_SET_COMPLETE", "ADV_START_COMPLETE", "SCAN_START_COMPLETE", "AUTH_CMPL", "KEY",
"SEC_REQ", "PASSKEY_NOTIF", "PASSKEY_REQ", "OOB_REQ", "LOCAL_IR",
"LOCAL_ER", "NC_REQ", "ADV_STOP_COMPLETE", "SCAN_STOP_COMPLETE", "SET_STATIC_RAND_ADDR",
"UPDATE_CONN_PARAMS", "SET_PKT_LENGTH_COMPLETE", "SET_LOCAL_PRIVACY_COMPLETE", "REMOVE_BOND_DEV_COMPLETE", "CLEAR_BOND_DEV_COMPLETE",
"GET_BOND_DEV_COMPLETE", "READ_RSSI_COMPLETE", "UPDATE_WHITELIST_COMPLETE" };
const char *ble_addr_type_names[4] = { "PUBLIC", "RANDOM", "RPA_PUBLIC", "RPA_RANDOM" };
// Define possible HIDH host modes.
static const esp_bt_mode_t HIDH_IDLE_MODE = (esp_bt_mode_t) 0x00;
static const esp_bt_mode_t HIDH_BLE_MODE = (esp_bt_mode_t) 0x01;
static const esp_bt_mode_t HIDH_BT_MODE = (esp_bt_mode_t) 0x02;
static const esp_bt_mode_t HIDH_BTDM_MODE = (esp_bt_mode_t) 0x03;
// Structure to maintain control variables.
typedef struct {
#ifdef CONFIG_CLASSIC_BT_ENABLED
std::vector<t_scanListItem> btScanList;
#endif
std::vector<t_scanListItem> bleScanList;
t_pairingHandler *pairingHandler;
esp_hidh_dev_t *hidhDevHdl;
int8_t batteryLevel;
#ifdef CONFIG_CLASSIC_BT_ENABLED
xSemaphoreHandle bt_hidh_cb_semaphore;
#endif
xSemaphoreHandle ble_hidh_cb_semaphore;
BT *pThis;
} t_btCtrl;
// All control variables are stored in a struct for ease of reference.
t_btCtrl btCtrl;
// Prototypes.
static void processBTGapEvent(esp_bt_gap_cb_event_t event, esp_bt_gap_cb_param_t * param);
static void processBLEGapEvent(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t * param);
t_scanListItem* findValidScannedDevice(esp_bd_addr_t bda, std::vector<t_scanListItem> &scanList);
void processBLEDeviceScanResult(esp_ble_gap_cb_param_t * scan_rst);
void addBLEScanDevice(esp_bd_addr_t bda, esp_ble_addr_type_t addr_type, uint16_t appearance, uint8_t *name, uint8_t name_len, int rssi);
#ifdef CONFIG_CLASSIC_BT_ENABLED
void processBTDeviceScanResult(esp_bt_gap_cb_param_t * param);
void addBTScanDevice(esp_bd_addr_t bda, esp_bt_cod_t *cod, esp_bt_uuid_t *uuid, uint8_t *name, uint8_t name_len, int rssi);
#endif
esp_err_t scanForBLEDevices(uint32_t timeout);
esp_err_t scanForBTDevices(uint32_t timeout);
esp_err_t scanForAllDevices(uint32_t timeout, size_t *noDevices, std::vector<t_scanListItem> &scanList);
void printUUID(esp_bt_uuid_t * uuid);
const char *ble_addr_type_str(esp_ble_addr_type_t ble_addr_type)
{
if (ble_addr_type > BLE_ADDR_TYPE_RPA_RANDOM)
{
return "UNKNOWN";
}
return ble_addr_type_names[ble_addr_type];
}
const char *ble_gap_evt_str(uint8_t event)
{
if (event >= SIZEOF_ARRAY(ble_gap_evt_names))
{
return "UNKNOWN";
}
return ble_gap_evt_names[event];
}
#ifdef CONFIG_CLASSIC_BT_ENABLED
const char *bt_gap_evt_str(uint8_t event)
{
if (event >= SIZEOF_ARRAY(bt_gap_evt_names))
{
return "UNKNOWN";
}
return bt_gap_evt_names[event];
}
#endif
const char *ble_key_type_str(esp_ble_key_type_t key_type)
{
const char *key_str = nullptr;
switch (key_type)
{
case ESP_LE_KEY_NONE:
key_str = "ESP_LE_KEY_NONE";
break;
case ESP_LE_KEY_PENC:
key_str = "ESP_LE_KEY_PENC";
break;
case ESP_LE_KEY_PID:
key_str = "ESP_LE_KEY_PID";
break;
case ESP_LE_KEY_PCSRK:
key_str = "ESP_LE_KEY_PCSRK";
break;
case ESP_LE_KEY_PLK:
key_str = "ESP_LE_KEY_PLK";
break;
case ESP_LE_KEY_LLK:
key_str = "ESP_LE_KEY_LLK";
break;
case ESP_LE_KEY_LENC:
key_str = "ESP_LE_KEY_LENC";
break;
case ESP_LE_KEY_LID:
key_str = "ESP_LE_KEY_LID";
break;
case ESP_LE_KEY_LCSRK:
key_str = "ESP_LE_KEY_LCSRK";
break;
default:
key_str = "INVALID BLE KEY TYPE";
break;
}
return key_str;
}
};
#endif // BT_H_

View File

@@ -1 +0,0 @@
../../../sharpkey/main/include/BTHID.h

701
main/include/BTHID.h Normal file
View File

@@ -0,0 +1,701 @@
/////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Name: BTHID.h
// Created: Mar 2022
// Version: v1.0
// Author(s): Philip Smart
// Description: Header file for the Bluetooth Keyboard Class.
//
// Credits:
// Copyright: (c) 2022 Philip Smart <philip.smart@net2net.org>
//
// History: Mar 2022 - Initial write.
// Jun 2022 - Updated with latest findings. Now checks the bonded list and opens
// connections or scans for new devices if no connections exist.
//
// Notes: See Makefile to enable/disable conditional components
//
/////////////////////////////////////////////////////////////////////////////////////////////////////////
// This source file is free software: you can redistribute it and#or modify
// it under the terms of the GNU General Public License as published
// by the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This source file is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
/////////////////////////////////////////////////////////////////////////////////////////////////////////
#ifndef BT_KEYBOARD_H_
#define BT_KEYBOARD_H_
#include <string>
#include <vector>
#include <cstring>
#include <functional>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/semphr.h"
#include "esp_err.h"
#include "esp_log.h"
#include "esp_system.h"
#include "esp_event.h"
#include "esp_bt.h"
#include "esp_bt_defs.h"
#include "esp_bt_main.h"
#include "esp_hidh.h"
#include "esp_hid_common.h"
#include "esp_gap_bt_api.h"
#include "esp_gap_ble_api.h"
#include "PS2KeyAdvanced.h"
#include "PS2Mouse.h"
#include "BT.h"
// Keyboard is a sub-class of BT which provides methods to setup BT for use by a keyboard.
class BTHID : public BT {
// Macros.
//
#define NUMELEM(a) (sizeof(a)/sizeof(a[0]))
// Global constants
#define MAX_KEYBOARD_DATA_BYTES 8
#define MAX_CCONTROL_DATA_BYTES 3
#define MAX_MOUSE_DATA_BYTES 7
#define MAX_BT2PS2_MAP_ENTRIES 179
#define MAX_BTMEDIA2PS2_MAP_ENTRIES 8
// LED's
#define BT_LED_NUMLOCK 0x01
#define BT_LED_CAPSLOCK 0x02
#define BT_LED_SCROLLLOCK 0x04
// Control keys.
#define BT_NONE 0x0000
#define BT_CTRL_LEFT 0x0001
#define BT_SHIFT_LEFT 0x0002
#define BT_ALT_LEFT 0x0004
#define BT_GUI_LEFT 0x0008
#define BT_CTRL_RIGHT 0x0010
#define BT_SHIFT_RIGHT 0x0020
#define BT_ALT_RIGHT 0x0040
#define BT_GUI_RIGHT 0x0080
#define BT_CAPS_LOCK 0x0100
#define BT_NUM_LOCK 0x0200
#define BT_SCROLL_LOCK 0x0400
#define BT_DUPLICATE 0xFFFF // Duplicate BT flags onto PS/2 flags.
#define BT_PS2_FUNCTION 0x01
#define BT_PS2_GUI 0x02
#define BT_PS2_ALT_GR 0x04
#define BT_PS2_ALT 0x08
#define BT_PS2_CAPS 0x10
#define BT_PS2_CTRL 0x20
#define BT_PS2_SHIFT 0x40
#define BT_PS2_BREAK 0x80
#define BT_KEY_NONE 0x00 // No key pressed
#define BT_KEY_ERR_OVF 0x01 // Keyboard Error Roll Over
// 0x02 // Keyboard POST Fail
// 0x03 // Keyboard Error Undefined
#define BT_KEY_A 0x04 // Keyboard a and A
#define BT_KEY_B 0x05 // Keyboard b and B
#define BT_KEY_C 0x06 // Keyboard c and C
#define BT_KEY_D 0x07 // Keyboard d and D
#define BT_KEY_E 0x08 // Keyboard e and E
#define BT_KEY_F 0x09 // Keyboard f and F
#define BT_KEY_G 0x0a // Keyboard g and G
#define BT_KEY_H 0x0b // Keyboard h and H
#define BT_KEY_I 0x0c // Keyboard i and I
#define BT_KEY_J 0x0d // Keyboard j and J
#define BT_KEY_K 0x0e // Keyboard k and K
#define BT_KEY_L 0x0f // Keyboard l and L
#define BT_KEY_M 0x10 // Keyboard m and M
#define BT_KEY_N 0x11 // Keyboard n and N
#define BT_KEY_O 0x12 // Keyboard o and O
#define BT_KEY_P 0x13 // Keyboard p and P
#define BT_KEY_Q 0x14 // Keyboard q and Q
#define BT_KEY_R 0x15 // Keyboard r and R
#define BT_KEY_S 0x16 // Keyboard s and S
#define BT_KEY_T 0x17 // Keyboard t and T
#define BT_KEY_U 0x18 // Keyboard u and U
#define BT_KEY_V 0x19 // Keyboard v and V
#define BT_KEY_W 0x1a // Keyboard w and W
#define BT_KEY_X 0x1b // Keyboard x and X
#define BT_KEY_Y 0x1c // Keyboard y and Y
#define BT_KEY_Z 0x1d // Keyboard z and Z
#define BT_KEY_1 0x1e // Keyboard 1 and !
#define BT_KEY_2 0x1f // Keyboard 2 and @
#define BT_KEY_3 0x20 // Keyboard 3 and #
#define BT_KEY_4 0x21 // Keyboard 4 and $
#define BT_KEY_5 0x22 // Keyboard 5 and %
#define BT_KEY_6 0x23 // Keyboard 6 and ^
#define BT_KEY_7 0x24 // Keyboard 7 and &
#define BT_KEY_8 0x25 // Keyboard 8 and *
#define BT_KEY_9 0x26 // Keyboard 9 and (
#define BT_KEY_0 0x27 // Keyboard 0 and )
#define BT_KEY_ENTER 0x28 // Keyboard Return (ENTER)
#define BT_KEY_ESC 0x29 // Keyboard ESCAPE
#define BT_KEY_BACKSPACE 0x2a // Keyboard DELETE (Backspace)
#define BT_KEY_TAB 0x2b // Keyboard Tab
#define BT_KEY_SPACE 0x2c // Keyboard Spacebar
#define BT_KEY_MINUS 0x2d // Keyboard - and _
#define BT_KEY_EQUAL 0x2e // Keyboard = and +
#define BT_KEY_LEFTBRACE 0x2f // Keyboard [ and {
#define BT_KEY_RIGHTBRACE 0x30 // Keyboard ] and }
#define BT_KEY_BACKSLASH 0x31 // Keyboard \ and |
#define BT_KEY_HASHTILDE 0x32 // Keyboard Non-US # and ~
#define BT_KEY_SEMICOLON 0x33 // Keyboard ; and :
#define BT_KEY_APOSTROPHE 0x34 // Keyboard ' and "
#define BT_KEY_GRAVE 0x35 // Keyboard ` and ~
#define BT_KEY_COMMA 0x36 // Keyboard , and <
#define BT_KEY_DOT 0x37 // Keyboard . and >
#define BT_KEY_SLASH 0x38 // Keyboard / and ?
#define BT_KEY_CAPSLOCK 0x39 // Keyboard Caps Lock
#define BT_KEY_F1 0x3a // Keyboard F1
#define BT_KEY_F2 0x3b // Keyboard F2
#define BT_KEY_F3 0x3c // Keyboard F3
#define BT_KEY_F4 0x3d // Keyboard F4
#define BT_KEY_F5 0x3e // Keyboard F5
#define BT_KEY_F6 0x3f // Keyboard F6
#define BT_KEY_F7 0x40 // Keyboard F7
#define BT_KEY_F8 0x41 // Keyboard F8
#define BT_KEY_F9 0x42 // Keyboard F9
#define BT_KEY_F10 0x43 // Keyboard F10
#define BT_KEY_F11 0x44 // Keyboard F11
#define BT_KEY_F12 0x45 // Keyboard F12
#define BT_KEY_SYSRQ 0x46 // Keyboard Print Screen
#define BT_KEY_SCROLLLOCK 0x47 // Keyboard Scroll Lock
#define BT_KEY_PAUSE 0x48 // Keyboard Pause
#define BT_KEY_INSERT 0x49 // Keyboard Insert
#define BT_KEY_HOME 0x4a // Keyboard Home
#define BT_KEY_PAGEUP 0x4b // Keyboard Page Up
#define BT_KEY_DELETE 0x4c // Keyboard Delete Forward
#define BT_KEY_END 0x4d // Keyboard End
#define BT_KEY_PAGEDOWN 0x4e // Keyboard Page Down
#define BT_KEY_RIGHT 0x4f // Keyboard Right Arrow
#define BT_KEY_LEFT 0x50 // Keyboard Left Arrow
#define BT_KEY_DOWN 0x51 // Keyboard Down Arrow
#define BT_KEY_UP 0x52 // Keyboard Up Arrow
#define BT_KEY_NUMLOCK 0x53 // Keyboard Num Lock and Clear
#define BT_KEY_KPSLASH 0x54 // Keypad /
#define BT_KEY_KPASTERISK 0x55 // Keypad *
#define BT_KEY_KPMINUS 0x56 // Keypad -
#define BT_KEY_KPPLUS 0x57 // Keypad +
#define BT_KEY_KPENTER 0x58 // Keypad ENTER
#define BT_KEY_KP1 0x59 // Keypad 1 and End
#define BT_KEY_KP2 0x5a // Keypad 2 and Down Arrow
#define BT_KEY_KP3 0x5b // Keypad 3 and PageDn
#define BT_KEY_KP4 0x5c // Keypad 4 and Left Arrow
#define BT_KEY_KP5 0x5d // Keypad 5
#define BT_KEY_KP6 0x5e // Keypad 6 and Right Arrow
#define BT_KEY_KP7 0x5f // Keypad 7 and Home
#define BT_KEY_KP8 0x60 // Keypad 8 and Up Arrow
#define BT_KEY_KP9 0x61 // Keypad 9 and Page Up
#define BT_KEY_KP0 0x62 // Keypad 0 and Insert
#define BT_KEY_KPDOT 0x63 // Keypad . and Delete
#define BT_KEY_102ND 0x64 // Keyboard Non-US \ and |
#define BT_KEY_COMPOSE 0x65 // Keyboard Application
#define BT_KEY_POWER 0x66 // Keyboard Power
#define BT_KEY_KPEQUAL 0x67 // Keypad =
#define BT_KEY_F13 0x68 // Keyboard F13
#define BT_KEY_F14 0x69 // Keyboard F14
#define BT_KEY_F15 0x6a // Keyboard F15
#define BT_KEY_F16 0x6b // Keyboard F16
#define BT_KEY_F17 0x6c // Keyboard F17
#define BT_KEY_F18 0x6d // Keyboard F18
#define BT_KEY_F19 0x6e // Keyboard F19
#define BT_KEY_F20 0x6f // Keyboard F20
#define BT_KEY_F21 0x70 // Keyboard F21
#define BT_KEY_F22 0x71 // Keyboard F22
#define BT_KEY_F23 0x72 // Keyboard F23
#define BT_KEY_F24 0x73 // Keyboard F24
#define BT_KEY_OPEN 0x74 // Keyboard Execute
#define BT_KEY_HELP 0x75 // Keyboard Help
#define BT_KEY_PROPS 0x76 // Keyboard Menu
#define BT_KEY_FRONT 0x77 // Keyboard Select
#define BT_KEY_STOP 0x78 // Keyboard Stop
#define BT_KEY_AGAIN 0x79 // Keyboard Again
#define BT_KEY_UNDO 0x7a // Keyboard Undo
#define BT_KEY_CUT 0x7b // Keyboard Cut
#define BT_KEY_COPY 0x7c // Keyboard Copy
#define BT_KEY_PASTE 0x7d // Keyboard Paste
#define BT_KEY_FIND 0x7e // Keyboard Find
#define BT_KEY_MUTE 0x7f // Keyboard Mute
#define BT_KEY_VOLUMEUP 0x80 // Keyboard Volume Up
#define BT_KEY_VOLUMEDOWN 0x81 // Keyboard Volume Down
// 0x82 Keyboard Locking Caps Lock
// 0x83 Keyboard Locking Num Lock
// 0x84 Keyboard Locking Scroll Lock
#define BT_KEY_KPCOMMA 0x85 // Keypad Comma
// 0x86 Keypad Equal Sign
#define BT_KEY_RO 0x87 // Keyboard International1
#define BT_KEY_KATAKANAHIRAGANA 0x88 // Keyboard International2
#define BT_KEY_YEN 0x89 // Keyboard International3
#define BT_KEY_HENKAN 0x8a // Keyboard International4
#define BT_KEY_MUHENKAN 0x8b // Keyboard International5
#define BT_KEY_KPJPCOMMA 0x8c // Keyboard International6
// 0x8d Keyboard International7
// 0x8e Keyboard International8
// 0x8f Keyboard International9
#define BT_KEY_HANGEUL 0x90 // Keyboard LANG1
#define BT_KEY_HANJA 0x91 // Keyboard LANG2
#define BT_KEY_KATAKANA 0x92 // Keyboard LANG3
#define BT_KEY_HIRAGANA 0x93 // Keyboard LANG4
#define BT_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 BT_KEY_KPLEFTPAREN 0xb6 // Keypad (
#define BT_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 BT_KEY_LEFTCTRL 0xe0 // Keyboard Left Control
#define BT_KEY_LEFTSHIFT 0xe1 // Keyboard Left Shift
#define BT_KEY_LEFTALT 0xe2 // Keyboard Left Alt
#define BT_KEY_LEFTMETA 0xe3 // Keyboard Left GUI
#define BT_KEY_RIGHTCTRL 0xe4 // Keyboard Right Control
#define BT_KEY_RIGHTSHIFT 0xe5 // Keyboard Right Shift
#define BT_KEY_RIGHTALT 0xe6 // Keyboard Right Alt
#define BT_KEY_RIGHTMETA 0xe7 // Keyboard Right GUI
#define BT_KEY_MEDIA_PLAYPAUSE 0xe8
#define BT_KEY_MEDIA_STOPCD 0xe9
#define BT_KEY_MEDIA_PREVIOUSSONG 0xea
#define BT_KEY_MEDIA_NEXTSONG 0xeb
#define BT_KEY_MEDIA_EJECTCD 0xec
#define BT_KEY_MEDIA_VOLUMEUP 0xed
#define BT_KEY_MEDIA_VOLUMEDOWN 0xee
#define BT_KEY_MEDIA_MUTE 0xef
#define BT_KEY_MEDIA_WWW 0xf0
#define BT_KEY_MEDIA_BACK 0xf1
#define BT_KEY_MEDIA_FORWARD 0xf2
#define BT_KEY_MEDIA_STOP 0xf3
#define BT_KEY_MEDIA_FIND 0xf4
#define BT_KEY_MEDIA_SCROLLUP 0xf5
#define BT_KEY_MEDIA_SCROLLDOWN 0xf6
#define BT_KEY_MEDIA_EDIT 0xf7
#define BT_KEY_MEDIA_SLEEP 0xf8
#define BT_KEY_MEDIA_COFFEE 0xf9
#define BT_KEY_MEDIA_REFRESH 0xfa
#define BT_KEY_MEDIA_CALC 0xfb
// Media key definition. On the ESP module a seperate usage type, CCONTROL is created for media keys and it delivers a 24bit word, each bit signifying a key.
#define BT_MEDIA_SEARCH 0x00200000
#define BT_MEDIA_HOME 0x00080000
#define BT_MEDIA_BRIGHTNESS_UP 0x00004000
#define BT_MEDIA_BRIGHTNESS_DOWN 0x00008000
#define BT_MEDIA_MUTE 0x00000040
#define BT_MEDIA_VOL_DOWN 0x00000020
#define BT_MEDIA_VOL_UP 0x00000010
#define BT_MEDIA_TRACK_PREV 0x00000001
// PS2 Flag definitions.
#define PS2_FLG_NONE 0x00 // No keys active = 0
#define PS2_FLG_SHIFT PS2_SHIFT >> 8 // Shift Key active = 1
#define PS2_FLG_CTRL PS2_CTRL >> 8 // Ctrl Key active = 1
#define PS2_FLG_CAPS PS2_CAPS >> 8 // CAPS active = 1
#define PS2_FLG_ALT PS2_ALT >> 8 // ALT flag used as Right CTRL flag, active = 1
#define PS2_FLG_ALTGR PS2_ALT_GR >> 8 // ALTGR active = 1
#define PS2_FLG_GUI PS2_GUI >> 8 // GUI Key active = 1
#define PS2_FLG_FUNC PS2_FUNCTION >> 8 // Special Function Keys active = 1
#define PS2_FLG_BREAK PS2_BREAL >> 8 // BREAK Key active = 1
public:
struct KeyInfo {
uint8_t keys[MAX_KEYBOARD_DATA_BYTES];
uint8_t length;
bool cControl;
esp_hidh_dev_t *hdlDev;
};
// Prototypes.
BTHID(void);
virtual ~BTHID(void);
bool setup(t_pairingHandler *handler);
bool openDevice(esp_bd_addr_t bda, esp_hid_transport_t transport, esp_ble_addr_type_t addrType);
bool closeDevice(esp_bd_addr_t bda);
void checkBTDevices(void);
bool setResolution(enum PS2Mouse::PS2_RESOLUTION resolution);
bool setScaling(enum PS2Mouse::PS2_SCALING scaling);
bool setSampleRate(enum PS2Mouse::PS2_SAMPLING rate);
void processBTKeys(void);
uint16_t getKey(uint32_t timeout = 0);
// Method to register an object method for callback with context.
template<typename A, typename B>
void setMouseDataCallback(A func_ptr, B obj_ptr)
{
btHIDCtrl.ms.mouseDataCallback = bind(func_ptr, obj_ptr, 1, std::placeholders::_1);
}
// Template to aid in conversion of an enum to integer.
template <typename E> constexpr typename std::underlying_type<E>::type to_underlying(E e) noexcept
{
return static_cast<typename std::underlying_type<E>::type>(e);
}
private:
static constexpr char const * TAG = "BTHID";
// Structure to hold details of an active or post-active connection.
typedef struct {
esp_bd_addr_t bda;
esp_hid_transport_t transport;
esp_ble_addr_type_t addrType;
esp_hid_usage_t usage;
esp_hidh_dev_t *hidhDevHdl;
uint32_t nextCheckTime;
bool open;
} t_activeDev;
// Structure to encapsulate a single key map from Bluetooth to PS/2.
typedef struct {
uint8_t btKeyCode;
uint16_t btCtrl;
uint8_t ps2KeyCode;
uint16_t ps2Ctrl;
} t_keyMapEntry;
// Structure to encapsulate the entire static keyboard mapping table.
typedef struct {
t_keyMapEntry kme[MAX_BT2PS2_MAP_ENTRIES];
} t_keyMap;
// Structure to contain a media key map.
typedef struct {
uint32_t mediaKey; // 24bit Media key value.
uint8_t ps2Key; // Equivalent PS/2 key for media key.
uint16_t ps2Ctrl; // PS/2 translated control flags.
} t_mediaMapEntry;
// Structure to encapsulate Media key mappings.
typedef struct {
t_mediaMapEntry kme[MAX_BTMEDIA2PS2_MAP_ENTRIES];
} t_mediaKeyMap;
// Structure to maintain control variables.
typedef struct {
// Array of active devices which connect with the SharpKey.
std::vector<t_activeDev> devices;
// Keyboard handling.
struct {
// Queues for storing data in the 2 processing stages.
xQueueHandle rawKeyQueue;
xQueueHandle keyQueue;
uint8_t lastKeys[MAX_KEYBOARD_DATA_BYTES]; // Required to generate a PS/2 break event when a key is released.
uint32_t lastMediaKey; // Required to detect changes in the media control keys, ie. release.
uint16_t btFlags; // Bluetooth control flags.
uint16_t ps2Flags; // PS/2 translated control flags.
uint8_t statusLED; // Keyboard LED state.
t_keyMapEntry *kme; // Pointer to the mapping array.
t_mediaMapEntry *kmeMedia; // Pointer to the media key mapping array.
int kmeRows; // Number of entries in the BT to PS/2 mapping table.
int kmeMediaRows; // Number of entries in the BT to PS/2 media key mapping table.
} kbd;
// Mouse handling.
struct {
int resolution; // PS/2 compatible resolution (pixels per mm) setting.
int scaling; // PS/2 compatible scaling (1:1 or 2:1).
int sampleRate; // PS/2 compatible sample rate (10 .. 200).
int xDivisor; // Divisor on the X plane to scale down the 12bit BT resolution.
int yDivisor; // Divisor on the Y plane to scale down the 12bit BT resolution.
// Callback for streaming processed mouse data to HID handler.
std::function<void(PS2Mouse::MouseData)> mouseDataCallback;
} ms;
BTHID *pThis;
} t_btHIDCtrl;
// All control variables are stored in a struct for ease of reference.
t_btHIDCtrl btHIDCtrl;
// Prototypes.
static void hidh_callback(void * handler_args, esp_event_base_t base, int32_t id, void * event_data);
void pushKeyToFIFO(esp_hid_usage_t src, esp_hidh_dev_t *hdlDev, uint8_t *keys, uint8_t size);
void setStatusLED(esp_hidh_dev_t *dev, uint8_t led);
void clearStatusLED(esp_hidh_dev_t *dev, uint8_t led);
uint16_t mapBTMediaToPS2(uint32_t key);
uint16_t mapBTtoPS2(uint8_t key);
inline uint32_t milliSeconds(void)
{
return( (uint32_t) (clock() ) );
}
// Mapping for Media keys. ESP module seperates them but not properly, some media keys are sent as normal key scancodes others as control key bit maps.
// Hence two mapping tables, one for normal scancodes and one for media codes.
t_mediaKeyMap MediaKeyToPS2 = {
{
{ BT_MEDIA_SEARCH, PS2_KEY_WEB_SEARCH, PS2_FLG_NONE, },
{ BT_MEDIA_HOME, PS2_KEY_WEB_HOME, PS2_FLG_NONE, },
{ BT_MEDIA_BRIGHTNESS_UP, PS2_KEY_WEB_FORWARD, PS2_FLG_NONE, },
{ BT_MEDIA_BRIGHTNESS_DOWN, PS2_KEY_WEB_BACK, PS2_FLG_NONE, },
{ BT_MEDIA_MUTE, PS2_KEY_MUTE, PS2_FLG_NONE, },
{ BT_MEDIA_VOL_DOWN, PS2_KEY_VOL_DN, PS2_FLG_NONE, },
{ BT_MEDIA_VOL_UP, PS2_KEY_VOL_UP, PS2_FLG_NONE, },
{ BT_MEDIA_TRACK_PREV, PS2_KEY_PREV_TR, PS2_FLG_NONE, },
}};
// Mapping table between BT Keyboard Scan Codes and PS/2 Keyboard Scan Codes.
//
t_keyMap BTKeyToPS2 = {
{
// Bluetooth Key Bluetooth Control, PS/2 Key PS/2 Control,
{ BT_KEY_A, BT_NONE, PS2_KEY_A, PS2_FLG_NONE, },
{ BT_KEY_B, BT_NONE, PS2_KEY_B, PS2_FLG_NONE, },
{ BT_KEY_C, BT_NONE, PS2_KEY_C, PS2_FLG_NONE, },
{ BT_KEY_D, BT_NONE, PS2_KEY_D, PS2_FLG_NONE, },
{ BT_KEY_E, BT_NONE, PS2_KEY_E, PS2_FLG_NONE, },
{ BT_KEY_F, BT_NONE, PS2_KEY_F, PS2_FLG_NONE, },
{ BT_KEY_G, BT_NONE, PS2_KEY_G, PS2_FLG_NONE, },
{ BT_KEY_H, BT_NONE, PS2_KEY_H, PS2_FLG_NONE, },
{ BT_KEY_I, BT_NONE, PS2_KEY_I, PS2_FLG_NONE, },
{ BT_KEY_J, BT_NONE, PS2_KEY_J, PS2_FLG_NONE, },
{ BT_KEY_K, BT_NONE, PS2_KEY_K, PS2_FLG_NONE, },
{ BT_KEY_L, BT_NONE, PS2_KEY_L, PS2_FLG_NONE, },
{ BT_KEY_M, BT_NONE, PS2_KEY_M, PS2_FLG_NONE, },
{ BT_KEY_N, BT_NONE, PS2_KEY_N, PS2_FLG_NONE, },
{ BT_KEY_O, BT_NONE, PS2_KEY_O, PS2_FLG_NONE, },
{ BT_KEY_P, BT_NONE, PS2_KEY_P, PS2_FLG_NONE, },
{ BT_KEY_Q, BT_NONE, PS2_KEY_Q, PS2_FLG_NONE, },
{ BT_KEY_R, BT_NONE, PS2_KEY_R, PS2_FLG_NONE, },
{ BT_KEY_S, BT_NONE, PS2_KEY_S, PS2_FLG_NONE, },
{ BT_KEY_T, BT_NONE, PS2_KEY_T, PS2_FLG_NONE, },
{ BT_KEY_U, BT_NONE, PS2_KEY_U, PS2_FLG_NONE, },
{ BT_KEY_V, BT_NONE, PS2_KEY_V, PS2_FLG_NONE, },
{ BT_KEY_W, BT_NONE, PS2_KEY_W, PS2_FLG_NONE, },
{ BT_KEY_X, BT_NONE, PS2_KEY_X, PS2_FLG_NONE, },
{ BT_KEY_Y, BT_NONE, PS2_KEY_Y, PS2_FLG_NONE, },
{ BT_KEY_Z, BT_NONE, PS2_KEY_Z, PS2_FLG_NONE, },
{ BT_KEY_1, BT_NONE, PS2_KEY_1, PS2_FLG_NONE, },
{ BT_KEY_2, BT_NONE, PS2_KEY_2, PS2_FLG_NONE, },
{ BT_KEY_3, BT_NONE, PS2_KEY_3, PS2_FLG_NONE, },
{ BT_KEY_4, BT_NONE, PS2_KEY_4, PS2_FLG_NONE, },
{ BT_KEY_5, BT_NONE, PS2_KEY_5, PS2_FLG_NONE, },
{ BT_KEY_6, BT_NONE, PS2_KEY_6, PS2_FLG_NONE, },
{ BT_KEY_7, BT_NONE, PS2_KEY_7, PS2_FLG_NONE, },
{ BT_KEY_8, BT_NONE, PS2_KEY_8, PS2_FLG_NONE, },
{ BT_KEY_9, BT_NONE, PS2_KEY_9, PS2_FLG_NONE, },
{ BT_KEY_0, BT_NONE, PS2_KEY_0, PS2_FLG_NONE, },
{ BT_KEY_ENTER, BT_NONE, PS2_KEY_ENTER, PS2_FLG_NONE, },
{ BT_KEY_ESC, BT_NONE, PS2_KEY_ESC, PS2_FLG_NONE, },
{ BT_KEY_BACKSPACE, BT_NONE, PS2_KEY_BS, PS2_FLG_NONE, },
{ BT_KEY_TAB, BT_NONE, PS2_KEY_TAB, PS2_FLG_NONE, },
{ BT_KEY_SPACE, BT_NONE, PS2_KEY_SPACE, PS2_FLG_NONE, },
{ BT_KEY_MINUS, BT_NONE, PS2_KEY_MINUS, PS2_FLG_NONE, },
{ BT_KEY_EQUAL, BT_NONE, PS2_KEY_EQUAL, PS2_FLG_NONE, },
{ BT_KEY_LEFTBRACE, BT_NONE, PS2_KEY_OPEN_SQ, PS2_FLG_NONE, },
{ BT_KEY_RIGHTBRACE, BT_NONE, PS2_KEY_CLOSE_SQ, PS2_FLG_NONE, },
{ BT_KEY_BACKSLASH, BT_NONE, PS2_KEY_BACK, PS2_FLG_NONE, },
{ BT_KEY_HASHTILDE, BT_NONE, PS2_KEY_HASH, PS2_FLG_NONE, },
{ BT_KEY_SEMICOLON, BT_NONE, PS2_KEY_SEMI, PS2_FLG_NONE, },
{ BT_KEY_APOSTROPHE, BT_NONE, PS2_KEY_APOS, PS2_FLG_NONE, },
{ BT_KEY_GRAVE, BT_NONE, PS2_KEY_BTICK, PS2_FLG_NONE, },
{ BT_KEY_COMMA, BT_NONE, PS2_KEY_COMMA, PS2_FLG_NONE, },
{ BT_KEY_DOT, BT_NONE, PS2_KEY_DOT, PS2_FLG_NONE, },
{ BT_KEY_SLASH, BT_NONE, PS2_KEY_DIV, PS2_FLG_NONE, },
{ BT_KEY_CAPSLOCK, BT_NONE, PS2_KEY_CAPS, PS2_FLG_NONE, },
{ BT_KEY_F1, BT_NONE, PS2_KEY_F1, PS2_FLG_NONE, },
{ BT_KEY_F2, BT_NONE, PS2_KEY_F2, PS2_FLG_NONE, },
{ BT_KEY_F3, BT_NONE, PS2_KEY_F3, PS2_FLG_NONE, },
{ BT_KEY_F4, BT_NONE, PS2_KEY_F4, PS2_FLG_NONE, },
{ BT_KEY_F5, BT_NONE, PS2_KEY_F5, PS2_FLG_NONE, },
{ BT_KEY_F6, BT_NONE, PS2_KEY_F6, PS2_FLG_NONE, },
{ BT_KEY_F7, BT_NONE, PS2_KEY_F7, PS2_FLG_NONE, },
{ BT_KEY_F8, BT_NONE, PS2_KEY_F8, PS2_FLG_NONE, },
{ BT_KEY_F9, BT_NONE, PS2_KEY_F9, PS2_FLG_NONE, },
{ BT_KEY_F10, BT_NONE, PS2_KEY_F10, PS2_FLG_NONE, },
{ BT_KEY_F11, BT_NONE, PS2_KEY_F11, PS2_FLG_NONE, },
{ BT_KEY_F12, BT_NONE, PS2_KEY_F12, PS2_FLG_NONE, },
{ BT_KEY_SYSRQ, BT_NONE, PS2_KEY_PRTSCR, PS2_FLG_NONE, },
{ BT_KEY_SCROLLLOCK, BT_NONE, PS2_KEY_SCROLL, PS2_FLG_NONE, },
{ BT_KEY_PAUSE, BT_NONE, PS2_KEY_PAUSE, PS2_FLG_NONE, },
{ BT_KEY_INSERT, BT_NONE, PS2_KEY_INSERT, PS2_FLG_NONE, },
{ BT_KEY_HOME, BT_NONE, PS2_KEY_HOME, PS2_FLG_NONE, },
{ BT_KEY_PAGEUP, BT_NONE, PS2_KEY_PGUP, PS2_FLG_NONE, },
{ BT_KEY_DELETE, BT_NONE, PS2_KEY_DELETE, PS2_FLG_NONE, },
{ BT_KEY_END, BT_NONE, PS2_KEY_END, PS2_FLG_NONE, },
{ BT_KEY_PAGEDOWN, BT_NONE, PS2_KEY_PGDN, PS2_FLG_NONE, },
{ BT_KEY_RIGHT, BT_NONE, PS2_KEY_R_ARROW, PS2_FLG_NONE, },
{ BT_KEY_LEFT, BT_NONE, PS2_KEY_L_ARROW, PS2_FLG_NONE, },
{ BT_KEY_DOWN, BT_NONE, PS2_KEY_DN_ARROW, PS2_FLG_NONE, },
{ BT_KEY_UP, BT_NONE, PS2_KEY_UP_ARROW, PS2_FLG_NONE, },
{ BT_KEY_NUMLOCK, BT_NONE, PS2_KEY_NUM, PS2_FLG_NONE, },
{ BT_KEY_KPSLASH, BT_NONE, PS2_KEY_KP_DIV, PS2_FLG_NONE, },
{ BT_KEY_KPASTERISK, BT_NONE, PS2_KEY_KP_TIMES, PS2_FLG_NONE, },
{ BT_KEY_KPMINUS, BT_NONE, PS2_KEY_KP_MINUS, PS2_FLG_NONE, },
{ BT_KEY_KPPLUS, BT_NONE, PS2_KEY_KP_PLUS, PS2_FLG_NONE, },
{ BT_KEY_KPENTER, BT_NONE, PS2_KEY_KP_ENTER, PS2_FLG_NONE, },
{ BT_KEY_KP1, BT_NUM_LOCK, PS2_KEY_KP1, PS2_FLG_NONE, },
{ BT_KEY_KP2, BT_NUM_LOCK, PS2_KEY_KP2, PS2_FLG_NONE, },
{ BT_KEY_KP3, BT_NUM_LOCK, PS2_KEY_KP3, PS2_FLG_NONE, },
{ BT_KEY_KP4, BT_NUM_LOCK, PS2_KEY_KP4, PS2_FLG_NONE, },
{ BT_KEY_KP5, BT_NUM_LOCK, PS2_KEY_KP5, PS2_FLG_NONE, },
{ BT_KEY_KP6, BT_NUM_LOCK, PS2_KEY_KP6, PS2_FLG_NONE, },
{ BT_KEY_KP7, BT_NUM_LOCK, PS2_KEY_KP7, PS2_FLG_NONE, },
{ BT_KEY_KP8, BT_NUM_LOCK, PS2_KEY_KP8, PS2_FLG_NONE, },
{ BT_KEY_KP9, BT_NUM_LOCK, PS2_KEY_KP9, PS2_FLG_NONE, },
{ BT_KEY_KP0, BT_NUM_LOCK, PS2_KEY_KP0, PS2_FLG_NONE, },
{ BT_KEY_KPDOT, BT_NUM_LOCK, PS2_KEY_KP_DOT, PS2_FLG_NONE, },
{ BT_KEY_KP1, BT_NONE, PS2_KEY_END, PS2_FLG_NONE, },
{ BT_KEY_KP2, BT_NONE, PS2_KEY_DN_ARROW, PS2_FLG_NONE, },
{ BT_KEY_KP3, BT_NONE, PS2_KEY_PGDN, PS2_FLG_NONE, },
{ BT_KEY_KP4, BT_NONE, PS2_KEY_L_ARROW, PS2_FLG_NONE, },
{ BT_KEY_KP5, BT_NONE, 0x00, PS2_FLG_NONE, },
{ BT_KEY_KP6, BT_NONE, PS2_KEY_R_ARROW, PS2_FLG_NONE, },
{ BT_KEY_KP7, BT_NONE, PS2_KEY_HOME, PS2_FLG_NONE, },
{ BT_KEY_KP8, BT_NONE, PS2_KEY_UP_ARROW, PS2_FLG_NONE, },
{ BT_KEY_KP9, BT_NONE, PS2_KEY_PGUP, PS2_FLG_NONE, },
{ BT_KEY_KP0, BT_NONE, PS2_KEY_INSERT, PS2_FLG_NONE, },
{ BT_KEY_KPDOT, BT_NONE, PS2_KEY_DELETE, PS2_FLG_NONE, },
{ BT_KEY_102ND, BT_NONE, PS2_KEY_BACK, PS2_FLG_NONE, },
{ BT_KEY_COMPOSE, BT_NONE, PS2_KEY_MENU, PS2_FLG_NONE, },
{ BT_KEY_POWER, BT_NONE, PS2_KEY_POWER, PS2_FLG_NONE, },
{ BT_KEY_KPEQUAL, BT_NONE, PS2_KEY_KP_EQUAL, PS2_FLG_NONE, },
{ BT_KEY_F13, BT_NONE, PS2_KEY_F13, PS2_FLG_NONE, },
{ BT_KEY_F14, BT_NONE, PS2_KEY_F14, PS2_FLG_NONE, },
{ BT_KEY_F15, BT_NONE, PS2_KEY_F15, PS2_FLG_NONE, },
{ BT_KEY_F16, BT_NONE, PS2_KEY_F16, PS2_FLG_NONE, },
{ BT_KEY_F17, BT_NONE, PS2_KEY_F17, PS2_FLG_NONE, },
{ BT_KEY_F18, BT_NONE, PS2_KEY_F18, PS2_FLG_NONE, },
{ BT_KEY_F19, BT_NONE, PS2_KEY_F19, PS2_FLG_NONE, },
{ BT_KEY_F20, BT_NONE, PS2_KEY_F20, PS2_FLG_NONE, },
{ BT_KEY_F21, BT_NONE, PS2_KEY_F21, PS2_FLG_NONE, },
{ BT_KEY_F22, BT_NONE, PS2_KEY_F22, PS2_FLG_NONE, },
{ BT_KEY_F23, BT_NONE, PS2_KEY_F23, PS2_FLG_NONE, },
{ BT_KEY_F24, BT_NONE, PS2_KEY_F24, PS2_FLG_NONE, },
{ BT_KEY_OPEN, BT_NONE, 0x00, PS2_FLG_NONE, },
{ BT_KEY_HELP, BT_NONE, 0x00, PS2_FLG_NONE, },
{ BT_KEY_PROPS, BT_NONE, 0x00, PS2_FLG_NONE, },
{ BT_KEY_FRONT, BT_NONE, 0x00, PS2_FLG_NONE, },
{ BT_KEY_STOP, BT_NONE, PS2_KEY_STOP, PS2_FLG_NONE, },
{ BT_KEY_AGAIN, BT_NONE, 0x00, PS2_FLG_NONE, },
{ BT_KEY_UNDO, BT_NONE, 0x00, PS2_FLG_NONE, },
{ BT_KEY_CUT, BT_NONE, 0x00, PS2_FLG_NONE, },
{ BT_KEY_COPY, BT_NONE, 0x00, PS2_FLG_NONE, },
{ BT_KEY_PASTE, BT_NONE, 0x00, PS2_FLG_NONE, },
{ BT_KEY_FIND, BT_NONE, 0x00, PS2_FLG_NONE, },
{ BT_KEY_MUTE, BT_NONE, PS2_KEY_MUTE, PS2_FLG_NONE, },
{ BT_KEY_VOLUMEUP, BT_NONE, PS2_KEY_VOL_UP, PS2_FLG_NONE, },
{ BT_KEY_VOLUMEDOWN, BT_NONE, PS2_KEY_VOL_DN, PS2_FLG_NONE, },
{ BT_KEY_KPCOMMA, BT_NONE, PS2_KEY_KP_COMMA, PS2_FLG_NONE, },
{ BT_KEY_RO, BT_NONE, 0x00, PS2_FLG_NONE, },
{ BT_KEY_KATAKANAHIRAGANA, BT_NONE, 0x00, PS2_FLG_NONE, },
{ BT_KEY_YEN, BT_NONE, 0x00, PS2_FLG_NONE, },
{ BT_KEY_HENKAN, BT_NONE, 0x00, PS2_FLG_NONE, },
{ BT_KEY_MUHENKAN, BT_NONE, 0x00, PS2_FLG_NONE, },
{ BT_KEY_KPJPCOMMA, BT_NONE, 0x00, PS2_FLG_NONE, },
{ BT_KEY_HANGEUL, BT_NONE, 0x00, PS2_FLG_NONE, },
{ BT_KEY_HANJA, BT_NONE, 0x00, PS2_FLG_NONE, },
{ BT_KEY_KATAKANA, BT_NONE, 0x00, PS2_FLG_NONE, },
{ BT_KEY_HIRAGANA, BT_NONE, 0x00, PS2_FLG_NONE, },
{ BT_KEY_ZENKAKUHANKAKU, BT_NONE, 0x00, PS2_FLG_NONE, },
{ BT_KEY_KPLEFTPAREN, BT_NONE, 0x00, PS2_FLG_NONE, },
{ BT_KEY_KPRIGHTPAREN, BT_NONE, 0x00, PS2_FLG_NONE, },
// Control keys.
{ BT_KEY_LEFTCTRL, BT_NONE, PS2_KEY_L_CTRL, PS2_FLG_FUNC | PS2_FLG_CTRL, },
{ BT_KEY_LEFTSHIFT, BT_NONE, PS2_KEY_L_SHIFT, PS2_FLG_FUNC | PS2_FLG_SHIFT, },
{ BT_KEY_LEFTALT, BT_NONE, PS2_KEY_L_ALT, PS2_FLG_FUNC | PS2_FLG_ALT, },
{ BT_KEY_LEFTMETA, BT_NONE, PS2_KEY_L_GUI, PS2_FLG_FUNC | PS2_FLG_GUI, },
{ BT_KEY_RIGHTCTRL, BT_NONE, PS2_KEY_R_CTRL, PS2_FLG_FUNC | PS2_FLG_CTRL, },
{ BT_KEY_RIGHTSHIFT, BT_NONE, PS2_KEY_R_SHIFT, PS2_FLG_FUNC | PS2_FLG_SHIFT, },
{ BT_KEY_RIGHTALT, BT_NONE, PS2_KEY_R_ALT, PS2_FLG_FUNC | PS2_FLG_ALTGR, },
{ BT_KEY_RIGHTMETA, BT_NONE, PS2_KEY_R_GUI, PS2_FLG_FUNC | PS2_FLG_NONE, },
// Media keys
{ BT_KEY_MEDIA_PLAYPAUSE, BT_NONE, PS2_KEY_PLAY, PS2_FLG_NONE, },
{ BT_KEY_MEDIA_STOPCD, BT_NONE, PS2_KEY_STOP, PS2_FLG_NONE, },
{ BT_KEY_MEDIA_PREVIOUSSONG, BT_NONE, PS2_KEY_PREV_TR, PS2_FLG_NONE, },
{ BT_KEY_MEDIA_NEXTSONG, BT_NONE, PS2_KEY_NEXT_TR, PS2_FLG_NONE, },
{ BT_KEY_MEDIA_EJECTCD, BT_NONE, 0x00, PS2_FLG_NONE, },
{ BT_KEY_MEDIA_VOLUMEUP, BT_NONE, PS2_KEY_VOL_UP, PS2_FLG_NONE, },
{ BT_KEY_MEDIA_VOLUMEDOWN, BT_NONE, PS2_KEY_VOL_DN, PS2_FLG_NONE, },
{ BT_KEY_MEDIA_MUTE, BT_NONE, PS2_KEY_MUTE, PS2_FLG_NONE, },
{ BT_KEY_MEDIA_WWW, BT_NONE, PS2_KEY_WEB_SEARCH, PS2_FLG_NONE, },
{ BT_KEY_MEDIA_BACK, BT_NONE, PS2_KEY_WEB_BACK, PS2_FLG_NONE, },
{ BT_KEY_MEDIA_FORWARD, BT_NONE, PS2_KEY_WEB_FORWARD, PS2_FLG_NONE, },
{ BT_KEY_MEDIA_STOP, BT_NONE, PS2_KEY_WEB_STOP, PS2_FLG_NONE, },
{ BT_KEY_MEDIA_FIND, BT_NONE, PS2_KEY_WEB_SEARCH, PS2_FLG_NONE, },
{ BT_KEY_MEDIA_SCROLLUP, BT_NONE, 0x00, PS2_FLG_NONE, },
{ BT_KEY_MEDIA_SCROLLDOWN, BT_NONE, 0x00, PS2_FLG_NONE, },
{ BT_KEY_MEDIA_EDIT, BT_NONE, 0x00, PS2_FLG_NONE, },
{ BT_KEY_MEDIA_SLEEP, BT_NONE, 0x00, PS2_FLG_NONE, },
{ BT_KEY_MEDIA_COFFEE, BT_NONE, 0x00, PS2_FLG_NONE, },
{ BT_KEY_MEDIA_REFRESH, BT_NONE, 0x00, PS2_FLG_NONE, },
{ BT_KEY_MEDIA_CALC, BT_NONE, 0x00, PS2_FLG_NONE, },
}};
};
#endif // BT_KEYBOARD_H_

View File

@@ -1 +0,0 @@
../../../sharpkey/main/include/HID.h

385
main/include/HID.h Normal file
View File

@@ -0,0 +1,385 @@
/////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Name: HID.h
// Created: Mar 2022
// Version: v1.0
// Author(s): Philip Smart
// Description: A HID Class definition, used to instantiate differing input device classes and
// present a standard API.
// Credits:
// Copyright: (c) 2019-2022 Philip Smart <philip.smart@net2net.org>
//
// History: Mar 2022 - Initial write.
// v1.01 May 2022 - Initial release version.
// v1.02 Jun 2022 - Updates to support Bluetooth keyboard and mouse. The mouse can be
// a primary device or a secondary device for hosts which support
// keyboard and mouse over one physical port.
//
// Notes: See Makefile to enable/disable conditional components
//
/////////////////////////////////////////////////////////////////////////////////////////////////////////
// This source file is free software: you can redistribute it and#or modify
// it under the terms of the GNU General Public License as published
// by the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This source file is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
/////////////////////////////////////////////////////////////////////////////////////////////////////////
#ifndef HID_H
#define HID_H
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <iostream>
#include <vector>
#include <map>
#include <functional>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/semphr.h"
#include "esp_log.h"
#include "esp_system.h"
#include "nvs_flash.h"
#include "nvs.h"
#include "soc/timer_group_struct.h"
#include "soc/timer_group_reg.h"
#include "driver/timer.h"
#include "PS2KeyAdvanced.h"
#include "PS2Mouse.h"
#include "BTHID.h"
#include "LED.h"
#include "SWITCH.h"
// NB: Macros definitions put inside class for clarity, they are still global scope.
// Define a class which acts as the encapsulation object of many base classes which provide input device functionality.
class HID {
// Macros.
//
#define NUMELEM(a) (sizeof(a)/sizeof(a[0]))
// Constants.
#define HID_VERSION 1.02
#define HID_MOUSE_DATA_POLL_DELAY 10
#define MAX_MOUSE_INACTIVITY_TIME 500 * HID_MOUSE_DATA_POLL_DELAY
// Categories of configuration possible with the mouse. These are used primarily with the web based UI for rendering selection choices.
#define HID_MOUSE_HOST_SCALING_TYPE "host_scaling"
#define HID_MOUSE_SCALING_TYPE "mouse_scaling"
#define HID_MOUSE_RESOLUTION_TYPE "mouse_resolution"
#define HID_MOUSE_SAMPLING_TYPE "mouse_sampling"
#define HID_MOUSE_HOST_SCALING_1_1_NAME "1:1"
#define HID_MOUSE_HOST_SCALING_1_2_NAME "1:2"
#define HID_MOUSE_HOST_SCALING_1_3_NAME "1:3"
#define HID_MOUSE_HOST_SCALING_1_4_NAME "1:4"
#define HID_MOUSE_HOST_SCALING_1_5_NAME "1:5"
// Names for the configuration value settings.
#define HID_MOUSE_RESOLUTION_1_1_NAME "1 c/mm"
#define HID_MOUSE_RESOLUTION_1_2_NAME "2 c/mm"
#define HID_MOUSE_RESOLUTION_1_4_NAME "4 c/mm"
#define HID_MOUSE_RESOLUTION_1_8_NAME "8 c/mm"
#define HID_MOUSE_SCALING_1_1_NAME "1:1"
#define HID_MOUSE_SCALING_2_1_NAME "2:1"
#define HID_MOUSE_SAMPLE_RATE_10_NAME "10 S/s"
#define HID_MOUSE_SAMPLE_RATE_20_NAME "20 S/s"
#define HID_MOUSE_SAMPLE_RATE_40_NAME "40 S/s"
#define HID_MOUSE_SAMPLE_RATE_60_NAME "60 S/s"
#define HID_MOUSE_SAMPLE_RATE_80_NAME "80 S/s"
#define HID_MOUSE_SAMPLE_RATE_100_NAME "100 S/s"
#define HID_MOUSE_SAMPLE_RATE_200_NAME "200 S/s"
public:
// Types of devices the HID class can support.
enum HID_DEVICE_TYPES {
HID_DEVICE_TYPE_KEYBOARD = 0x00,
HID_DEVICE_TYPE_MOUSE = 0x01,
HID_DEVICE_TYPE_BLUETOOTH = 0x02,
};
// HID class can encapsulate many input device objects, only one at a time though. On startup the device is enumerated and then all
// functionality serves the device object.
enum HID_INPUT_DEVICE {
HID_DEVICE_PS2_KEYBOARD = 0x00,
HID_DEVICE_PS2_MOUSE = 0x01,
HID_DEVICE_BLUETOOTH = 0x02,
HID_DEVICE_BT_KEYBOARD = 0x03,
HID_DEVICE_BT_MOUSE = 0x04
};
// Scaling - The host receiving mouse data may have a different resolution to that of the mouse, so we use configurable host side scaling to compensate. The mouse data received
// is scaled according to the enum setting.
enum HID_MOUSE_HOST_SCALING {
HID_MOUSE_HOST_SCALING_1_1 = 0x00,
HID_MOUSE_HOST_SCALING_1_2 = 0x01,
HID_MOUSE_HOST_SCALING_1_3 = 0x02,
HID_MOUSE_HOST_SCALING_1_4 = 0x03,
HID_MOUSE_HOST_SCALING_1_5 = 0x04,
};
// Resolution - the mouse can digitize movement from 1mm to 1/8mm, the default being 1/4 (ie. 1mm = 4 counts). This allows configuration for a finer or rougher
// tracking digitisation.
enum HID_MOUSE_RESOLUTION {
HID_MOUSE_RESOLUTION_1_1 = PS2Mouse::PS2_MOUSE_RESOLUTION_1_1,
HID_MOUSE_RESOLUTION_1_2 = PS2Mouse::PS2_MOUSE_RESOLUTION_1_2,
HID_MOUSE_RESOLUTION_1_4 = PS2Mouse::PS2_MOUSE_RESOLUTION_1_4,
HID_MOUSE_RESOLUTION_1_8 = PS2Mouse::PS2_MOUSE_RESOLUTION_1_8,
};
// Scaling - the mouse can provide linear (1:1 no scaling) or non liner (2:1 scaling) adaptation of the digitised data. This allows configuration for amplification of movements.
enum HID_MOUSE_SCALING {
HID_MOUSE_SCALING_1_1 = PS2Mouse::PS2_MOUSE_SCALING_1_1,
HID_MOUSE_SCALING_2_1 = PS2Mouse::PS2_MOUSE_SCALING_2_1,
};
// Sampling rate - the mouse, in streaming mode, the mouse sends with movement updates. This allows for finer or rougher digitisation of movements. The default is 100 samples per
// second and the X68000 is fixed at 100 samples per second.
enum HID_MOUSE_SAMPLING {
HID_MOUSE_SAMPLE_RATE_10 = PS2Mouse::PS2_MOUSE_SAMPLE_RATE_10,
HID_MOUSE_SAMPLE_RATE_20 = PS2Mouse::PS2_MOUSE_SAMPLE_RATE_20,
HID_MOUSE_SAMPLE_RATE_40 = PS2Mouse::PS2_MOUSE_SAMPLE_RATE_40,
HID_MOUSE_SAMPLE_RATE_60 = PS2Mouse::PS2_MOUSE_SAMPLE_RATE_60,
HID_MOUSE_SAMPLE_RATE_80 = PS2Mouse::PS2_MOUSE_SAMPLE_RATE_80,
HID_MOUSE_SAMPLE_RATE_100 = PS2Mouse::PS2_MOUSE_SAMPLE_RATE_100,
HID_MOUSE_SAMPLE_RATE_200 = PS2Mouse::PS2_MOUSE_SAMPLE_RATE_200,
};
// Suspend flag. When active, the interface components enter an idle state after completing there latest cycle.
bool suspend = false;
bool suspended = true;
// Element to store mouse data in a queue. The data is actual mouse movements, any control data and private data for the actual mouse is stripped.
typedef struct {
int16_t xPos;
int16_t yPos;
uint8_t status;
uint8_t wheel;
} t_mouseMessageElement;
// Prototypes.
HID(enum HID_DEVICE_TYPES, NVS *hdlNVS, LED *hdlLED, SWITCH *hdlSWITCH);
HID(NVS *hdlNVS);
HID(void);
virtual ~HID(void);
bool isBluetooth(void);
void enableBluetooth(void);
void disableBluetooth(void);
bool isSuspended(bool waitForSuspend);
void suspendInterface(bool suspendIf);
bool persistConfig(void);
uint16_t read(void);
void setMouseResolution(enum HID_MOUSE_RESOLUTION resolution);
void setMouseHostScaling(enum HID_MOUSE_HOST_SCALING scaling);
void setMouseScaling(enum HID_MOUSE_SCALING scaling);
void setMouseSampleRate(enum HID_MOUSE_SAMPLING sampleRate);
void btStartPairing(void);
void btCancelPairing(void);
// Method to register an object method for callback with context.
template<typename A, typename B>
void setDataCallback(A func_ptr, B obj_ptr)
{
hidCtrl.dataCallback = bind(func_ptr, obj_ptr, std::placeholders::_1);
}
// Method to suspend input device activity, yielding to the OS until suspend is cleared.
inline virtual void yield(uint32_t delay)
{
// If suspended, go into a permanent loop until the suspend flag is reset.
if(this->suspend)
{
// Suspend the keyboard interface.
if(hidCtrl.deviceType == HID_DEVICE_TYPE_KEYBOARD) { printf("SUSPEND\n"); ps2Keyboard->suspend(true); }
this->suspended = true;
// Sleep while suspended.
while(this->suspend)
{
vTaskDelay(100);
}
// Release the keyboard interface.
if(hidCtrl.deviceType == HID_DEVICE_TYPE_KEYBOARD) ps2Keyboard->suspend(false);
this->suspended = false;
} else
// Otherwise just delay by the required amount for timing and to give other threads a time slice.
{
vTaskDelay(delay);
}
return;
}
// Method to see if the interface must enter suspend mode.
//
inline virtual bool suspendRequested(void)
{
return(this->suspend);
}
// Helper method to identify the sub class, this is used in non volatile key management.
// Warning: This method wont work if optimisation for size is enabled on the compiler.
const char *getClassName(const std::string& prettyFunction)
{
// First find the CLASS :: METHOD seperation.
size_t colons = prettyFunction.find("::");
// None, then this is not a class.
if (colons == std::string::npos)
return "::";
// Split out the class name.
size_t begin = prettyFunction.substr(0,colons).rfind(" ") + 1;
size_t end = colons - begin;
// Return the name.
return(prettyFunction.substr(begin,end).c_str());
}
// Template to aid in conversion of an enum to integer.
template <typename E> constexpr typename std::underlying_type<E>::type to_underlying(E e) noexcept
{
return static_cast<typename std::underlying_type<E>::type>(e);
}
// Method to return the class version number.
virtual float version(void)
{
return(HID_VERSION);
}
// Method to return the name of this class.
virtual std::string ifName(void)
{
return(className);
}
protected:
private:
// Prototypes.
void init(const char *className, enum HID_DEVICE_TYPES deviceTypes);
bool nvsPersistData(const char *key, void *pData, uint32_t size);
bool nvsRetrieveData(const char *key, void *pData, uint32_t size);
bool nvsCommitData(void);
void checkKeyboard( void );
bool checkPS2Keyboard( void );
bool checkPS2Mouse( void );
void checkMouse( void );
void processPS2Mouse( void );
void checkBTMouse( void );
void mouseReceiveData(uint8_t src, PS2Mouse::MouseData mouseData);
IRAM_ATTR static void hidControl( void * pvParameters );
static void btPairingHandler(uint32_t pid, uint8_t trigger);
inline uint32_t milliSeconds(void)
{
return( (uint32_t) (clock() ) );
}
enum HOST_CONFIG_MODES {
HOST_CONFIG_OFF = 0x00,
HOST_CONFIG_SCALING = 0x01,
HOST_CONFIG_RESOLUTION = 0x02,
};
// Structure to maintain configuration for the HID.
//
typedef struct {
struct {
// Mouse data Adjustment and filtering options.
//
enum HID_MOUSE_RESOLUTION resolution;
enum HID_MOUSE_SCALING scaling;
enum HID_MOUSE_SAMPLING sampleRate;
} mouse;
struct {
// Host data for adjustment and configuration.
enum HID_MOUSE_HOST_SCALING scaling;
} host;
struct {
// Configuration mode time period used to select configuration option. Once the middle key is held, the configuration option starts at 1, after this number of seconds
// the configuration option advances to the next configuration item, and so on...
uint16_t optionAdvanceDelay;
} params;
} t_hidConfig;
// Structure to maintain an active settings for HID devices.
typedef struct {
enum HID_INPUT_DEVICE hidDevice; // Active HID device, only one can be active.
enum HID_DEVICE_TYPES deviceType; // Type of device which is active.
bool ps2Active; // Flag to indicate PS/2 device is online and active.
uint32_t noEchoCount = 0L; // Echo back counter, used for testing if a keyboard is online.
TickType_t ps2CheckTimer = 0; // Check timer, used for timing periodic keyboard checks.
// Mouse control variables.
uint32_t noValidMouseMessage = 0;
int wheelCnt = 0;
uint32_t loopTimer = 0;
bool middleKeyPressed = false;
PS2Mouse::MouseData mouseData;
// Flag to indicate the mouse is active and online.
bool active;
// Flag to indicate the configuration data has been updated.
bool updated;
// Configuration mode selected when middle button pressed.
enum HOST_CONFIG_MODES configMode;
// Mutex to block access during maintenance tasks.
SemaphoreHandle_t mutexInternal;
// Callback for streaming input devices with data to be processed.
std::function<void(t_mouseMessageElement)> dataCallback;
} t_hidControl;
// Current configuration of the HID.
t_hidConfig hidConfig;
// Variables to control the HID.
t_hidControl hidCtrl;
// Handle to the persistent storage api.
nvs_handle_t nvsHandle;
// Name of this class, used for NVS access.
std::string className;
// NVS persistence object.
NVS *nvs;
// LED activity object handle.
LED *led;
// SWITCH object handle.
SWITCH *sw;
// Keyboard object for PS/2 data retrieval and management.
PS2KeyAdvanced *ps2Keyboard;
// Keyboard object for Bluetooth data retrieval and management.
BTHID *btHID;
// Mouse object for PS/2 data retrieval and management.
PS2Mouse *ps2Mouse;
// Thread handle for the HID control thread.
TaskHandle_t TaskHID = NULL;
};
#endif // HID_H

View File

@@ -1 +0,0 @@
../../../sharpkey/main/include/KeyInterface.h

203
main/include/KeyInterface.h Normal file
View File

@@ -0,0 +1,203 @@
/////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Name: KeyInterface.h
// Created: Mar 2022
// Version: v1.0
// Author(s): Philip Smart
// Description: Virtual class definition on which all host interfaces, instantiated as a singleton,
// are based.
// Credits:
// Copyright: (c) 2019-2022 Philip Smart <philip.smart@net2net.org>
//
// History: Mar 2022 - Initial write.
// v1.01 May 2022 - Initial release version.
//
// Notes: See Makefile to enable/disable conditional components
//
/////////////////////////////////////////////////////////////////////////////////////////////////////////
// This source file is free software: you can redistribute it and#or modify
// it under the terms of the GNU General Public License as published
// by the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This source file is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
/////////////////////////////////////////////////////////////////////////////////////////////////////////
#ifndef KEYINTERFACE_H
#define KEYINTERFACE_H
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <iostream>
#include <vector>
#include <map>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_log.h"
#include "esp_system.h"
#include "soc/timer_group_struct.h"
#include "soc/timer_group_reg.h"
#include "driver/timer.h"
#include "PS2KeyAdvanced.h"
#include "PS2Mouse.h"
#include "NVS.h"
#include "LED.h"
#include "HID.h"
// NB: Macros definitions put inside class for clarity, they are still global scope.
// Define a virtual class which acts as the base and specification of all super classes forming host
// interface objects.
class KeyInterface {
// Macros.
//
#define NUMELEM(a) (sizeof(a)/sizeof(a[0]))
// Constants.
#define KEYIF_VERSION 1.01
public:
// Suspend flag. When active, the interface components enter an idle state after completing there latest cycle.
bool suspend = false;
bool suspended = true;
// NVS object.
NVS *nvs;
// LED object.
LED *led;
// HID object, used for keyboard input.
HID *hid;
// Prototypes.
KeyInterface(void) {};
virtual ~KeyInterface(void) {};
KeyInterface(uint32_t ifMode, NVS *hdlNVS, LED *hdlLED, HID *hdlHID) { init(getClassName(__PRETTY_FUNCTION__), hdlNVS, hdlLED, hdlHID, ifMode); };
KeyInterface(NVS *hdlNVS, HID *hdlHID) { init(getClassName(__PRETTY_FUNCTION__), hdlNVS, hdlHID); };
void reconfigADC2Ports(bool setAsOutput);
void suspendInterface(bool suspendIf);
virtual bool isSuspended(bool waitForSuspend);
virtual bool isRunning(bool waitForRelease);
virtual void identify(void) { };
virtual void init(const char * subClassName, NVS *hdlNVS, LED *hdlLED, HID *hdlHID, uint32_t ifMode);
virtual void init(const char * subClassName, NVS *hdlNVS, HID *hdlHID);
// Persistence.
virtual bool persistConfig(void) { return(true); }
// Key mapping.
virtual IRAM_ATTR uint32_t mapKey(uint16_t scanCode) { return(0); };
virtual bool createKeyMapFile(std::fstream &outFile) { return(false); };
virtual bool storeDataToKeyMapFile(std::fstream &outFile, char *data, int size) { return(false); };
virtual bool storeDataToKeyMapFile(std::fstream & outFile, std::vector<uint32_t>& dataArray) { return(false); }
virtual bool closeAndCommitKeyMapFile(std::fstream &outFile, bool cleanupOnly) { return(false); };
virtual std::string getKeyMapFileName(void) { return("nokeymap.bin"); };
virtual void getKeyMapHeaders(std::vector<std::string>& headerList) { };
virtual void getKeyMapTypes(std::vector<std::string>& typeList) { };
virtual bool getKeyMapSelectList(std::vector<std::pair<std::string, int>>& selectList, std::string option) { return(true); }
virtual bool getKeyMapData(std::vector<uint32_t>& dataArray, int *row, bool start) { return(true); };
// Mouse config.
virtual void getMouseConfigTypes(std::vector<std::string>& typeList) { };
virtual bool getMouseSelectList(std::vector<std::pair<std::string, int>>& selectList, std::string option) { return(true); }
virtual bool setMouseConfigValue(std::string paramName, std::string paramValue) { return(true); }
// Method to suspend an active interface thread by holding in a tight loop, yielding to the OS. This method was chosen rather than the more conventional
// vTaskSuspend as it allows multiple threads, without giving a handle, to yield if required for a fixed period or indefinitely until the suspend mode is de-activated.
// The method is inline to avoid a call overhead as it is generally used in time sensitive interface timing.
inline virtual void yield(uint32_t delay)
{
// If suspended, go into a permanent loop until the suspend flag is reset.
if(this->suspend)
{
this->suspended = true;
while(this->suspend)
{
vTaskDelay(100);
}
this->suspended = false;
} else
// Otherwise just delay by the required amount for timing and to give other threads a time slice.
{
vTaskDelay(delay);
}
}
// Method to see if the interface must enter suspend mode.
//
inline virtual bool suspendRequested(void)
{
return(this->suspend);
}
// Helper method to identify the sub class, this is used in non volatile key management.
// Warning: This method wont work if optimisation for size is enabled on the compiler.
const char *getClassName(const std::string& prettyFunction)
{
// First find the CLASS :: METHOD seperation.
size_t colons = prettyFunction.find("::");
// None, then this is not a class.
if (colons == std::string::npos)
return "::";
// Split out the class name.
size_t begin = prettyFunction.substr(0,colons).rfind(" ") + 1;
size_t end = colons - begin;
// Return the name.
return(prettyFunction.substr(begin,end).c_str());
}
// Helper method to change a file extension.
void replaceExt(std::string& fileName, const std::string& newExt)
{
// Locals.
std::string::size_type extPos = fileName.rfind('.', fileName.length());
if(extPos != std::string::npos)
{
fileName.replace(extPos+1, newExt.length(), newExt);
}
return;
}
// Template to aid in conversion of an enum to integer.
template <typename E> constexpr typename std::underlying_type<E>::type to_underlying(E e) noexcept
{
return static_cast<typename std::underlying_type<E>::type>(e);
}
// Method to return the class version number.
virtual float version(void)
{
return(KEYIF_VERSION);
}
// Method to return the name of the inferface class.
virtual std::string ifName(void)
{
return(subClassName);
}
protected:
private:
// Prototypes.
virtual IRAM_ATTR void selectOption(uint8_t optionCode) {};
// Name of the sub-class for this instantiation.
std::string subClassName;
// Thread handle for the LED control thread.
TaskHandle_t TaskLEDIF = NULL;
};
#endif // KEYINTERFACE_H

View File

@@ -1 +0,0 @@
../../../sharpkey/main/include/LED.h

181
main/include/LED.h Normal file
View File

@@ -0,0 +1,181 @@
/////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Name: LED.h
// Created: Mar 2022
// Version: v1.0
// Author(s): Philip Smart
// Description: Class definition for the control of a single LED. The LED is used to indicate to a
// user a desired status. This class is normally instantiated as a singleton and
// manipulated by public methods.
// Credits:
// Copyright: (c) 2019-2022 Philip Smart <philip.smart@net2net.org>
//
// History: Mar 2022 - Initial write.
// v1.01 May 2022 - Initial release version.
//
// Notes: See Makefile to enable/disable conditional components
//
/////////////////////////////////////////////////////////////////////////////////////////////////////////
// This source file is free software: you can redistribute it and#or modify
// it under the terms of the GNU General Public License as published
// by the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This source file is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
/////////////////////////////////////////////////////////////////////////////////////////////////////////
#ifndef LED_H
#define LED_H
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <iostream>
#include <vector>
#include <map>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/semphr.h"
#include "esp_log.h"
#include "esp_system.h"
#include "soc/timer_group_struct.h"
#include "soc/timer_group_reg.h"
#include "driver/timer.h"
#include "PS2KeyAdvanced.h"
#include "PS2Mouse.h"
#include "NVS.h"
// NB: Macros definitions put inside class for clarity, they are still global scope.
// Define a class to encapsulate a LED and required control mechanisms,
class LED {
// Macros.
//
#define NUMELEM(a) (sizeof(a)/sizeof(a[0]))
// Constants.
#define LED_VERSION 1.01
public:
// Interface LED activity modes.
enum LED_MODE {
LED_MODE_OFF = 0x00,
LED_MODE_ON = 0x01,
LED_MODE_BLINK_ONESHOT = 0x02,
LED_MODE_BLINK = 0x03,
};
// Interface LED duty cycle.
enum LED_DUTY_CYCLE {
LED_DUTY_CYCLE_OFF = 0x00,
LED_DUTY_CYCLE_10 = 0x01,
LED_DUTY_CYCLE_20 = 0x02,
LED_DUTY_CYCLE_30 = 0x03,
LED_DUTY_CYCLE_40 = 0x04,
LED_DUTY_CYCLE_50 = 0x05,
LED_DUTY_CYCLE_60 = 0x06,
LED_DUTY_CYCLE_70 = 0x07,
LED_DUTY_CYCLE_80 = 0x08,
LED_DUTY_CYCLE_90 = 0x09,
};
// Prototypes.
LED(uint32_t hwPin);
LED(void);
virtual ~LED(void) {};
void identify(void) { };
// LED Control.
bool setLEDMode(enum LED_MODE mode, enum LED_DUTY_CYCLE dutyCycle, uint32_t maxBlinks, uint64_t usDutyPeriod, uint64_t msInterPeriod);
IRAM_ATTR static void ledInterface(void *pvParameters);
void ledInit(uint8_t ledPin);
// Helper method to identify the sub class, this is used in non volatile key management.
// Warning: This method wont work if optimisation for size is enabled on the compiler.
const char *getClassName(const std::string& prettyFunction)
{
// First find the CLASS :: METHOD seperation.
size_t colons = prettyFunction.find("::");
// None, then this is not a class.
if (colons == std::string::npos)
return "::";
// Split out the class name.
size_t begin = prettyFunction.substr(0,colons).rfind(" ") + 1;
size_t end = colons - begin;
// Return the name.
return(prettyFunction.substr(begin,end).c_str());
}
// Template to aid in conversion of an enum to integer.
template <typename E> constexpr typename std::underlying_type<E>::type to_underlying(E e) noexcept
{
return static_cast<typename std::underlying_type<E>::type>(e);
}
// Method to return the class version number.
virtual float version(void)
{
return(LED_VERSION);
}
// Method to return the name of the inferface class.
virtual std::string ifName(void)
{
return(className);
}
protected:
private:
// Prototypes.
// Structure to maintain configuration for the LED.
//
typedef struct {
bool valid; // The configuration is valid and should be processed.
bool updated; // This configuration is an update to override current configuration.
enum LED_MODE mode; // Mode of LED activity.
enum LED_DUTY_CYCLE dutyCycle; // Duty cycle of the BLINK LED period.
uint32_t maxBlinks; // Maximum number of blinks before switching to LED off mode.
uint64_t dutyPeriod; // Period, is micro-seconds of the full duty cycle.
uint64_t interPeriod; // Period, is milli-seconds between LED activity.
} t_ledConfig;
// Structure to maintain an active setting for the LED. The LED control thread uses these values to effect the required lighting of the LED.
typedef struct {
// Current, ie. working LED config acted upon by the LED thread.
t_ledConfig currentConfig;
// New config to replace current on next state.
t_ledConfig newConfig;
// Led GPIO pin.
uint8_t ledPin;
// Runtime parameters for state machine and control.
uint32_t blinkCnt; // count of blink on periods.
// Mutex to block access to limit one thread at a time.
SemaphoreHandle_t mutexInternal;
} t_ledControl;
// Variables to control the LED.
t_ledControl ledCtrl;
// Name of the class for this instantiation.
std::string className;
// Thread handle for the LED control thread.
TaskHandle_t TaskLEDIF = NULL;
};
#endif // LED_H

View File

@@ -1 +0,0 @@
../../../sharpkey/main/include/MZ2528.h

534
main/include/MZ2528.h Normal file
View File

@@ -0,0 +1,534 @@
/////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Name: MZ2528.h
// Created: Mar 2022
// Version: v1.0
// Author(s): Philip Smart
// Description: Header for the MZ-2500/MZ-2800 PS/2 logic.
// Credits:
// Copyright: (c) 2019-2022 Philip Smart <philip.smart@net2net.org>
//
// History: Mar 2022 - Initial write.
// v1.01 May 2022 - Initial release version.
// v1.02 Jun 2022 - Updates to reflect bluetooth.
//
// Notes: See Makefile to enable/disable conditional components
//
/////////////////////////////////////////////////////////////////////////////////////////////////////////
// This source file is free software: you can redistribute it and#or modify
// it under the terms of the GNU General Public License as published
// by the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This source file is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
/////////////////////////////////////////////////////////////////////////////////////////////////////////
#ifndef MZ2528_H
#define MZ2528_H
// Include the specification class.
#include "KeyInterface.h"
#include "NVS.h"
#include "LED.h"
#include "HID.h"
#include <vector>
#include <map>
// NB: Macros definitions put inside class for clarity, they are still global scope.
// Encapsulate the MZ-2500/MZ-2800 interface.
class MZ2528 : public KeyInterface {
// Macros.
//
#define NUMELEM(a) (sizeof(a)/sizeof(a[0]))
// Constants.
#define MZ2528IF_VERSION 1.02
#define MZ2528IF_KEYMAP_FILE "MZ2528_KeyMap.BIN"
#define PS2TBL_MZ_MAXROWS 165
#define PS2TBL_MZ_MAX_MKROW 3
#define PS2TBL_MZ_MAX_BRKROW 2
// PS2 Flag definitions.
#define PS2CTRL_NONE 0x00 // No keys active = 0
#define PS2CTRL_SHIFT 0x01 // Shfit Key active = 1
#define PS2CTRL_CTRL 0x02 // Ctrl Key active = 1
#define PS2CTRL_CAPS 0x04 // CAPS active = 1
#define PS2CTRL_ALT 0x08 // ALT active = 1
#define PS2CTRL_ALTGR 0x10 // ALTGR active = 1
#define PS2CTRL_GUI 0x20 // GUI Key active = 1
#define PS2CTRL_FUNC 0x40 // Special Function Keys active = 1
#define PS2CTRL_BREAK 0x80 // BREAK Key active = 1
#define PS2CTRL_EXACT 0x80 // EXACT Match active = 1
// The MZ-2500 machine can emulate 3 models, the MZ-80B, MZ-2000 and the MZ-2500. The MZ-2800 provides a new mode as well as the MZ-2500 mode and each has slight
// keyboard differences. This requires tagging of machine specific mappings. Normally a mapping would be MZ_ALL, ie. applied to all models, but if a machine specific
// mapping appears and it matches the current machine mode, this mapping is chosen.
#define MZ_ALL 0xFF
#define MZ_80B 0x01
#define MZ_2000 0x02
#define MZ_2500 0x04
#define MZ_2800 0x08
// Keyboard mapping table select list for target machine.
#define MZ2528_SEL_ALL "ALL"
#define MZ2528_SEL_MZ_80B "MZ80B"
#define MZ2528_SEL_MZ_2000 "MZ2000"
#define MZ2528_SEL_MZ_2500 "MZ2500"
#define MZ2528_SEL_MZ_2800 "MZ2800"
// The initial mapping is made inside the PS2KeyAdvanced class from Scan Code Set 2 to ASCII
// for a selected keyboard. Special functions are detected and combined inside this module
// before mapping with the table below to MZ Scan Matrix.
// ie. PS/2 Scan Code -> ASCII + Flags -> MZ Scan Matrix
// Keyboard mapping table column names.
#define PS2TBL_PS2KEYCODE_NAME "PS/2 KeyCode"
#define PS2TBL_PS2CTRL_NAME "PS/2 Control Key"
#define PS2TBL_KEYBOARDMODEL_NAME "For Keyboard"
#define PS2TBL_MACHINE_NAME "For Host Model"
#define PS2TBL_MZ_MK_ROW1_NAME "Make Row 1"
#define PS2TBL_MZ_MK_KEY1_NAME "Key 1"
#define PS2TBL_MZ_MK_ROW2_NAME "Row 2"
#define PS2TBL_MZ_MK_KEY2_NAME "Key 2"
#define PS2TBL_MZ_MK_ROW3_NAME "Row 3"
#define PS2TBL_MZ_MK_KEY3_NAME "Key 3"
#define PS2TBL_MZ_BRK_ROW1_NAME "Break Row 1"
#define PS2TBL_MZ_BRK_KEY1_NAME "Key 1"
#define PS2TBL_MZ_BRK_ROW2_NAME "Row 2"
#define PS2TBL_MZ_BRK_KEY2_NAME "Key 2"
// Keyboard mapping table column types.
#define PS2TBL_PS2KEYCODE_TYPE "hex"
#define PS2TBL_PS2CTRL_TYPE "custom_cbp_ps2ctrl"
#define PS2TBL_KEYBOARDMODEL_TYPE "custom_cbp_keybmodel"
#define PS2TBL_MACHINE_TYPE "custom_cbp_machine"
#define PS2TBL_MZ_MK_ROW1_TYPE "custom_rdp_mzrow"
#define PS2TBL_MZ_MK_KEY1_TYPE "hex"
#define PS2TBL_MZ_MK_ROW2_TYPE "custom_rdp_mzrow"
#define PS2TBL_MZ_MK_KEY2_TYPE "hex"
#define PS2TBL_MZ_MK_ROW3_TYPE "custom_rdp_mzrow"
#define PS2TBL_MZ_MK_KEY3_TYPE "hex"
#define PS2TBL_MZ_BRK_ROW1_TYPE "custom_rdp_mzrow"
#define PS2TBL_MZ_BRK_KEY1_TYPE "hex"
#define PS2TBL_MZ_BRK_ROW2_TYPE "custom_rdp_mzrow"
#define PS2TBL_MZ_BRK_KEY2_TYPE "hex"
// Keyboard mapping table select list for PS2CTRL.
#define PS2TBL_PS2CTRL_SEL_NONE "NONE"
#define PS2TBL_PS2CTRL_SEL_SHIFT "SHIFT"
#define PS2TBL_PS2CTRL_SEL_CTRL "CTRL"
#define PS2TBL_PS2CTRL_SEL_CAPS "CAPS"
#define PS2TBL_PS2CTRL_SEL_ALT "ALT"
#define PS2TBL_PS2CTRL_SEL_ALTGR "ALTGR"
#define PS2TBL_PS2CTRL_SEL_GUI "GUI"
#define PS2TBL_PS2CTRL_SEL_FUNC "FUNC"
#define PS2TBL_PS2CTRL_SEL_EXACT "EXACT"
// Keyboard mapping table select list for Model of keyboard.
#define KEYMAP_SEL_STANDARD "ALL"
#define KEYMAP_SEL_UK_WYSE_KB3926 "UK_WYSE_KB3926"
#define KEYMAP_SEL_JAPAN_OADG109 "JAPAN_OADG109"
#define KEYMAP_SEL_JAPAN_SANWA_SKBL1 "JAPAN_SANWA_SKBL1"
#define KEYMAP_SEL_NOT_ASSIGNED_4 "KEYBOARD_4"
#define KEYMAP_SEL_NOT_ASSIGNED_5 "KEYBOARD_5"
#define KEYMAP_SEL_NOT_ASSIGNED_6 "KEYBOARD_6"
#define KEYMAP_SEL_UK_PERIBOARD_810 "UK_PERIBOARD_810"
#define KEYMAP_SEL_UK_OMOTON_K8508 "UK_OMOTON_K8508"
// Keyboard models. The base on which this interface was created was a Wyse KB3926 PS/2 Keyboard and this is deemed STANDARD. Other models need to insert difference maps
// prior to the STANDARD entry along with the keyboard model so that it is processed first thus allowing differing keyboards with different maps.
#define KEYMAP_STANDARD 0xFF
#define KEYMAP_UK_WYSE_KB3926 0x01
#define KEYMAP_JAPAN_OADG109 0x02
#define KEYMAP_JAPAN_SANWA_SKBL1 0x04
#define KEYMAP_NOT_ASSIGNED_4 0x08
#define KEYMAP_NOT_ASSIGNED_5 0x10
#define KEYMAP_NOT_ASSIGNED_6 0x20
#define KEYMAP_UK_PERIBOARD_810 0x40
#define KEYMAP_UK_OMOTON_K8508 0x80
public:
// Prototypes.
MZ2528(uint32_t ifMode, NVS *hdlNVS, LED *hdlLED, HID *hdlHID, const char *fsPath);
MZ2528(NVS *hdlNVS, HID *hdlHID, const char *fsPath);
MZ2528(void);
~MZ2528(void);
bool createKeyMapFile(std::fstream &outFile);
bool storeDataToKeyMapFile(std::fstream &outFile, char *data, int size);
bool storeDataToKeyMapFile(std::fstream & outFile, std::vector<uint32_t>& dataArray);
bool closeAndCommitKeyMapFile(std::fstream &outFile, bool cleanupOnly);
std::string getKeyMapFileName(void) { return(MZ2528IF_KEYMAP_FILE); };
void getKeyMapHeaders(std::vector<std::string>& headerList);
void getKeyMapTypes(std::vector<std::string>& typeList);
bool getKeyMapSelectList(std::vector<std::pair<std::string, int>>& selectList, std::string option);
bool getKeyMapData(std::vector<uint32_t>& dataArray, int *row, bool start);
// Overloaded method to see if the interface must enter suspend mode, either triggered by an external event or internal.
//
inline bool suspendRequested(void)
{
return(this->suspend);
}
// // Method to overload the suspend mechanism and include the core release mechanism. Core release is needed in order to use ESP32 API's such as NVS.
// // The method is inline to avoid a call overhead as it is generally used in time sensitive interface timing.
// inline void yield(uint32_t delay)
// {
// // If suspended, go into a permanent loop until the suspend flag is reset.
// if(this->suspend)
// {
// this->suspended = true;
// while(this->suspend)
// {
// vTaskDelay(100);
// }
// this->suspended = false;
// } else
// // Otherwise just delay by the required amount for timing and to give other threads a time slice.
// {
// vTaskDelay(delay);
// }
// return;
// }
// Method to return the class version number.
float version(void)
{
return(MZ2528IF_VERSION);
}
protected:
private:
// Prototypes.
void updateMirrorMatrix(void);
uint32_t mapKey(uint16_t scanCode);
IRAM_ATTR static void mz25Interface(void *pvParameters );
IRAM_ATTR static void mz28Interface(void *pvParameters );
IRAM_ATTR static void hidInterface(void *pvParameters );
void selectOption(uint8_t optionCode);
bool loadKeyMap();
bool saveKeyMap(void);
void init(uint32_t ifMode, NVS *hdlNVS, LED *hdlLED, HID *hdlHID);
void init(NVS *hdlNVS, HID *hdlHID);
// Overload the base yield method to include suspension of the PS/2 Keyboard interface. This interface uses interrupts which are not mutex protected and clash with the
// WiFi API methods.
// inline void yield(uint32_t delay)
// {
// // If suspended, go into a permanent loop until the suspend flag is reset.
// if(this->suspend)
// {
// // Suspend the keyboard interface.
// Keyboard->suspend(true);
//
// // Use the base method logic.
// KeyInterface::yield(delay);
//
// // Release the keyboard interface.
// Keyboard->suspend(false);
// } else
// // Otherwise just delay by the required amount for timing and to give other threads a time slice.
// {
// KeyInterface::yield(delay);
// }
// return;
// }
// Structure to encapsulate a single key map from PS/2 to MZ-2500/MZ-2800.
typedef struct {
uint8_t ps2KeyCode;
uint8_t ps2Ctrl;
uint8_t keyboardModel;
uint8_t machine;
uint8_t mkRow[PS2TBL_MZ_MAX_MKROW];
uint8_t mkKey[PS2TBL_MZ_MAX_MKROW];
uint8_t brkRow[PS2TBL_MZ_MAX_BRKROW];
uint8_t brkKey[PS2TBL_MZ_MAX_BRKROW];
} t_keyMapEntry;
// Structure to encapsulate the entire static keyboard mapping table.
typedef struct {
t_keyMapEntry kme[PS2TBL_MZ_MAXROWS];
} t_keyMap;
// Structure to maintain the MZ2528 interface configuration data. This data is persisted through powercycles as needed.
typedef struct {
struct {
uint8_t activeKeyboardMap; // Model of keyboard a keymap entry is applicable to.
uint8_t activeMachineModel; // Machine model a keymap entry is applicable to.
} params;
} t_mzConfig;
// Configuration data.
t_mzConfig mzConfig;
// Structure to manage the translated key matrix. This is updated by the ps2Interface thread and read by the mzInterface thead.
typedef struct {
uint8_t strobeAll; // Strobe All flag, 16 possible rows have the same column AND'd together to create this 8bit map. It is used to see if any key has been pressed.
uint32_t strobeAllAsGPIO; // Strobe All signal but as a GPIO bit map to save time in the interface thread.
uint8_t keyMatrix[16]; // Key matrix as a 16x8 matrix.
uint32_t keyMatrixAsGPIO[16]; // Key matrix mapped as GPIO bits to save time in the interface thread.
bool mode2500;
bool optionSelect; // Flag to indicate a user requested keyboard configuration option is being selected.
std::string fsPath; // Path on the underlying filesystem where storage is mounted and accessible.
t_keyMapEntry *kme; // Pointer to an array in memory to contain PS2 to MZ-2500/MZ-2800 mapping values.
int kmeRows; // Number of rows in the kme table.
std::string keyMapFileName; // Name of file where extension or replacement key map entries are stored.
bool noKeyPressed; // Flag to indicate no key has been pressed.
bool persistConfig; // Flag to request saving of the config into NVS storage.
} t_mzControl;
// Thread handles - one per function, ie. HID interface and host target interface.
TaskHandle_t TaskHostIF = NULL;
TaskHandle_t TaskHIDIF = NULL;
// Control structure to control interaction and mapping of keys for the host.
t_mzControl mzControl;
// Spin lock mutex to hold a coresied to an uninterruptable method. This only works on dual core ESP32's.
portMUX_TYPE mzMutex;
// Flag to indicate host interface should yield the CPU.
volatile bool yieldHostInterface;
// // Keyboard object for PS/2 data retrieval and management.
// PS2KeyAdvanced *Keyboard;
// HID object, used for keyboard input.
// HID *hid;
// Lookup table to matrix row/column co-ordinates.
//
// Given that the MZ-2500 can emulate 3 machines and each machine has it's own mapping, differences are tagged by machine name, ie. ALL, MZ80B, MZ2000, MZ2500
//
// If a PS2 key is matched, then the Matrix is updated using MK_ROW to point into the array with MK_KEY being the column value, equivalent of strobe line and
// the required KEY bits to be set. Upto 3 matrix bits can be set (3 key presses on the MZ-2500 keyboard) per PS/2 key. Upto 2 matrix releases can be set per
// PS/2 key. A key release is used when a modifier may already have been pressed, ie. SHIFT and it needs to be released to set the required key into the matrix.
// A set bit = 1, reset bits = 0 but is inverted in the actual matrix (1 = inactive, 0 = active), this applies for releases two, if bit = 1 then that key will be released.
// The table is scanned for a match from top to bottom. The first match is used so order is important. Japanese characters are being added as I gleam more information.
///////////////////////////
// MZ-2500 Keyboard Map. //
///////////////////////////
//
// Row D7 D6 D5 D4 D3 D2 D1 D0
//----------------------------------------------------------------------------------
// 0 F8 F7 F6 F5 F4 F3 F2 F1
// 1 KP - KP + KP . KP , KP 9 KP 8 F1O F9
// 2 KP 7 KP 6 KP 5 KP 4 KP 3 KP 2 KP 1 KP 0
// 3 BREAK RIGHT LEFT DOWN UP RETURN SPACE TAB
// 4 G F E D C B A / ?
// 5 O N M L K J I H
// 6 W V U T S R Q P
// 7 , < . > _ YEN | ^ '¿ Z ¿ Y X ¿
// 8 7 ' 6 & 5 % 4 $ 3 # 2 " 1 ! 0
// 9 [ { @ ` - = ; + : * 9 ) 8 (
// 10 KP / KP * ESC BACKSPACE INST/DEL CLR/HOME COPY ] }
// 11 CTRL KANA SHIFT LOCK GRAPH
// 12 KJ2 KJ1
// 13 HELP ARGO
//
// Col 0 1 2 3 4 5 6 7 8 9 10 11 12 13
// --------------------------------------------------------------------------------------------------------------------------------------
// D0 F1 F9 KP 0 TAB / ? H P X 0 8 ( ] } GRAPH KJ1 ARGO
// D1 F2 F10 KP 1 SPACE A I Q Y 1 ! 9 ) COPY LOCK KJ2 HELP
// D2 F3 KP 8 KP 2 RETURN B J R Z 2 " : * CLR/HOME SHIFT
// D3 F4 KP 9 KP 3 UP C K S ^ '¿ 3 # ; + INST/DEL KANA
// D4 F5 KP , KP 4 DOWN D L T YEN | 4 $ - = BACKSPACE CTRL
// D5 F6 KP . KP 5 LEFT E M U _ 5 % @ ` ESC
// D6 F7 KP + KP 6 RIGHT F N V . > 6 & [ { KP *
// D7 F8 KP - KP 7 BREAK G O W , < 7 ' KP /
//
// This initial mapping is for the UK Wyse KB-3926 PS/2 keyboard and his equates to KEYMAP_STANDARD.
//
t_keyMap PS2toMZ = {
{
// < Keys to be applied on match > < Keys to be reset on match >
// PS2 Code PS2 Ctrl (Flags to Match) Keyboard Model Machine MK_ROW1 MK_ROW2 MK_ROW3 MK_KEY1 MK_KEY2 MK_KEY3 BRK_ROW1 BRK_ROW2 BRK_KEY1 BRK_KEY2
{ PS2_KEY_F1, PS2CTRL_FUNC, KEYMAP_STANDARD, MZ_ALL, 0x00, 0xFF, 0xFF, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }, // F1
{ PS2_KEY_F2, PS2CTRL_FUNC, KEYMAP_STANDARD, MZ_ALL, 0x00, 0xFF, 0xFF, 0x02, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }, // F2
{ PS2_KEY_F3, PS2CTRL_FUNC, KEYMAP_STANDARD, MZ_ALL, 0x00, 0xFF, 0xFF, 0x04, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }, // F3
{ PS2_KEY_F4, PS2CTRL_FUNC, KEYMAP_STANDARD, MZ_ALL, 0x00, 0xFF, 0xFF, 0x08, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }, // F4
{ PS2_KEY_F5, PS2CTRL_FUNC, KEYMAP_STANDARD, MZ_ALL, 0x00, 0xFF, 0xFF, 0x10, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }, // F5
{ PS2_KEY_F6, PS2CTRL_FUNC, KEYMAP_STANDARD, MZ_ALL, 0x00, 0xFF, 0xFF, 0x20, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }, // F6
{ PS2_KEY_F7, PS2CTRL_FUNC, KEYMAP_STANDARD, MZ_ALL, 0x00, 0xFF, 0xFF, 0x40, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }, // F7
{ PS2_KEY_F8, PS2CTRL_FUNC, KEYMAP_STANDARD, MZ_ALL, 0x00, 0xFF, 0xFF, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }, // F8
{ PS2_KEY_F9, PS2CTRL_FUNC, KEYMAP_STANDARD, MZ_ALL, 0x01, 0xFF, 0xFF, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }, // F9
{ PS2_KEY_F10, PS2CTRL_FUNC, KEYMAP_STANDARD, MZ_ALL, 0x01, 0xFF, 0xFF, 0x02, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }, // F10
{ PS2_KEY_F11, PS2CTRL_FUNC, KEYMAP_STANDARD, MZ_ALL, 0x0D, 0xFF, 0xFF, 0x02, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }, // HELP
{ PS2_KEY_F12, PS2CTRL_FUNC, KEYMAP_STANDARD, MZ_ALL, 0x0A, 0xFF, 0xFF, 0x02, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }, // COPY
{ PS2_KEY_TAB, PS2CTRL_NONE, KEYMAP_STANDARD, MZ_ALL, 0x03, 0xFF, 0xFF, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }, // TAB
{ PS2_KEY_0, PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ_ALL, 0x09, 0x0B, 0xFF, 0x02, 0x04, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }, // Close Right Bracket )
{ PS2_KEY_0, PS2CTRL_NONE, KEYMAP_STANDARD, MZ_ALL, 0x08, 0xFF, 0xFF, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }, // 0
{ PS2_KEY_1, PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ_ALL, 0x08, 0x0B, 0xFF, 0x02, 0x04, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }, // Exclamation
{ PS2_KEY_1, PS2CTRL_NONE, KEYMAP_STANDARD, MZ_ALL, 0x08, 0xFF, 0xFF, 0x02, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }, // 1
{ PS2_KEY_2, PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ_ALL, 0x08, 0x0B, 0xFF, 0x04, 0x04, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }, // Double quote.
{ PS2_KEY_2, PS2CTRL_NONE, KEYMAP_STANDARD, MZ_ALL, 0x08, 0xFF, 0xFF, 0x04, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }, // 2
{ PS2_KEY_3, PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ_ALL, 0x08, 0x0B, 0xFF, 0x08, 0x04, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }, // Pound Sign -> Hash
{ PS2_KEY_3, PS2CTRL_NONE, KEYMAP_STANDARD, MZ_ALL, 0x08, 0xFF, 0xFF, 0x08, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }, // 3
{ PS2_KEY_4, PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ_ALL, 0x08, 0x0B, 0xFF, 0x10, 0x04, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }, // Dollar
{ PS2_KEY_4, PS2CTRL_NONE, KEYMAP_STANDARD, MZ_ALL, 0x08, 0xFF, 0xFF, 0x10, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }, // 4
{ PS2_KEY_5, PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ_ALL, 0x08, 0x0B, 0xFF, 0x20, 0x04, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }, // Percent
{ PS2_KEY_5, PS2CTRL_NONE, KEYMAP_STANDARD, MZ_ALL, 0x08, 0xFF, 0xFF, 0x20, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }, // 5
{ PS2_KEY_6, PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ_ALL, 0x07, 0xFF, 0xFF, 0x08, 0xFF, 0xFF, 0x0B, 0xFF, 0x04, 0xFF, }, // Kappa
{ PS2_KEY_6, PS2CTRL_NONE, KEYMAP_STANDARD, MZ_ALL, 0x08, 0xFF, 0xFF, 0x40, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }, // 6
{ PS2_KEY_7, PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ_ALL, 0x08, 0x0B, 0xFF, 0x40, 0x04, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }, // Ampersand
{ PS2_KEY_7, PS2CTRL_NONE, KEYMAP_STANDARD, MZ_ALL, 0x08, 0xFF, 0xFF, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }, // 7
{ PS2_KEY_8, PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ_ALL, 0x09, 0x0B, 0xFF, 0x04, 0x04, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }, // Star
{ PS2_KEY_8, PS2CTRL_NONE, KEYMAP_STANDARD, MZ_ALL, 0x09, 0xFF, 0xFF, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }, // 8
{ PS2_KEY_9, PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ_ALL, 0x09, 0x0B, 0xFF, 0x01, 0x04, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }, // Open Left Bracket (
{ PS2_KEY_9, PS2CTRL_NONE, KEYMAP_STANDARD, MZ_ALL, 0x09, 0xFF, 0xFF, 0x02, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }, // 9
{ PS2_KEY_A, PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ_ALL, 0x04, 0xFF, 0xFF, 0x02, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }, // a
{ PS2_KEY_A, PS2CTRL_NONE, KEYMAP_STANDARD, MZ_ALL, 0x04, 0xFF, 0xFF, 0x02, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }, // A
{ PS2_KEY_B, PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ_ALL, 0x04, 0xFF, 0xFF, 0x04, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }, // b
{ PS2_KEY_B, PS2CTRL_NONE, KEYMAP_STANDARD, MZ_ALL, 0x04, 0xFF, 0xFF, 0x04, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }, // B
{ PS2_KEY_C, PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ_ALL, 0x04, 0xFF, 0xFF, 0x08, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }, // c
{ PS2_KEY_C, PS2CTRL_NONE, KEYMAP_STANDARD, MZ_ALL, 0x04, 0xFF, 0xFF, 0x08, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }, // C
{ PS2_KEY_D, PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ_ALL, 0x04, 0xFF, 0xFF, 0x10, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }, // d
{ PS2_KEY_D, PS2CTRL_NONE, KEYMAP_STANDARD, MZ_ALL, 0x04, 0xFF, 0xFF, 0x10, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }, // D
{ PS2_KEY_E, PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ_ALL, 0x04, 0xFF, 0xFF, 0x20, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }, // e
{ PS2_KEY_E, PS2CTRL_NONE, KEYMAP_STANDARD, MZ_ALL, 0x04, 0xFF, 0xFF, 0x20, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }, // E
{ PS2_KEY_F, PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ_ALL, 0x04, 0xFF, 0xFF, 0x40, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }, // f
{ PS2_KEY_F, PS2CTRL_NONE, KEYMAP_STANDARD, MZ_ALL, 0x04, 0xFF, 0xFF, 0x40, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }, // F
{ PS2_KEY_G, PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ_ALL, 0x04, 0xFF, 0xFF, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }, // g
{ PS2_KEY_G, PS2CTRL_NONE, KEYMAP_STANDARD, MZ_ALL, 0x04, 0xFF, 0xFF, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }, // G
{ PS2_KEY_H, PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ_ALL, 0x05, 0xFF, 0xFF, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }, // h
{ PS2_KEY_H, PS2CTRL_NONE, KEYMAP_STANDARD, MZ_ALL, 0x05, 0xFF, 0xFF, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }, // H
{ PS2_KEY_I, PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ_ALL, 0x05, 0xFF, 0xFF, 0x02, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }, // i
{ PS2_KEY_I, PS2CTRL_NONE, KEYMAP_STANDARD, MZ_ALL, 0x05, 0xFF, 0xFF, 0x02, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }, // I
{ PS2_KEY_J, PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ_ALL, 0x05, 0xFF, 0xFF, 0x04, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }, // j
{ PS2_KEY_J, PS2CTRL_NONE, KEYMAP_STANDARD, MZ_ALL, 0x05, 0xFF, 0xFF, 0x04, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }, // J
{ PS2_KEY_K, PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ_ALL, 0x05, 0xFF, 0xFF, 0x08, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }, // k
{ PS2_KEY_K, PS2CTRL_NONE, KEYMAP_STANDARD, MZ_ALL, 0x05, 0xFF, 0xFF, 0x08, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }, // K
{ PS2_KEY_L, PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ_ALL, 0x05, 0xFF, 0xFF, 0x10, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }, // l
{ PS2_KEY_L, PS2CTRL_NONE, KEYMAP_STANDARD, MZ_ALL, 0x05, 0xFF, 0xFF, 0x10, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }, // L
{ PS2_KEY_M, PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ_ALL, 0x05, 0xFF, 0xFF, 0x20, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }, // m
{ PS2_KEY_M, PS2CTRL_NONE, KEYMAP_STANDARD, MZ_ALL, 0x05, 0xFF, 0xFF, 0x20, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }, // M
{ PS2_KEY_N, PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ_ALL, 0x05, 0xFF, 0xFF, 0x40, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }, // n
{ PS2_KEY_N, PS2CTRL_NONE, KEYMAP_STANDARD, MZ_ALL, 0x05, 0xFF, 0xFF, 0x40, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }, // N
{ PS2_KEY_O, PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ_ALL, 0x05, 0xFF, 0xFF, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }, // o
{ PS2_KEY_O, PS2CTRL_NONE, KEYMAP_STANDARD, MZ_ALL, 0x05, 0xFF, 0xFF, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }, // O
{ PS2_KEY_P, PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ_ALL, 0x06, 0xFF, 0xFF, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }, // p
{ PS2_KEY_P, PS2CTRL_NONE, KEYMAP_STANDARD, MZ_ALL, 0x06, 0xFF, 0xFF, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }, // P
{ PS2_KEY_Q, PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ_ALL, 0x06, 0xFF, 0xFF, 0x02, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }, // q
{ PS2_KEY_Q, PS2CTRL_NONE, KEYMAP_STANDARD, MZ_ALL, 0x06, 0xFF, 0xFF, 0x02, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }, // Q
{ PS2_KEY_R, PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ_ALL, 0x06, 0xFF, 0xFF, 0x04, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }, // r
{ PS2_KEY_R, PS2CTRL_NONE, KEYMAP_STANDARD, MZ_ALL, 0x06, 0xFF, 0xFF, 0x04, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }, // R
{ PS2_KEY_S, PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ_ALL, 0x06, 0xFF, 0xFF, 0x08, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }, // s
{ PS2_KEY_S, PS2CTRL_NONE, KEYMAP_STANDARD, MZ_ALL, 0x06, 0xFF, 0xFF, 0x08, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }, // S
{ PS2_KEY_T, PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ_ALL, 0x06, 0xFF, 0xFF, 0x10, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }, // t
{ PS2_KEY_T, PS2CTRL_NONE, KEYMAP_STANDARD, MZ_ALL, 0x06, 0xFF, 0xFF, 0x10, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }, // T
{ PS2_KEY_U, PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ_ALL, 0x06, 0xFF, 0xFF, 0x20, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }, // u
{ PS2_KEY_U, PS2CTRL_NONE, KEYMAP_STANDARD, MZ_ALL, 0x06, 0xFF, 0xFF, 0x20, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }, // U
{ PS2_KEY_V, PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ_ALL, 0x06, 0xFF, 0xFF, 0x40, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }, // v
{ PS2_KEY_V, PS2CTRL_NONE, KEYMAP_STANDARD, MZ_ALL, 0x06, 0xFF, 0xFF, 0x40, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }, // V
{ PS2_KEY_W, PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ_ALL, 0x06, 0xFF, 0xFF, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }, // w
{ PS2_KEY_W, PS2CTRL_NONE, KEYMAP_STANDARD, MZ_ALL, 0x06, 0xFF, 0xFF, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }, // W
{ PS2_KEY_X, PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ_ALL, 0x07, 0xFF, 0xFF, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }, // x
{ PS2_KEY_X, PS2CTRL_NONE, KEYMAP_STANDARD, MZ_ALL, 0x07, 0xFF, 0xFF, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }, // X
{ PS2_KEY_Y, PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ_ALL, 0x07, 0xFF, 0xFF, 0x02, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }, // y
{ PS2_KEY_Y, PS2CTRL_NONE, KEYMAP_STANDARD, MZ_ALL, 0x07, 0xFF, 0xFF, 0x02, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }, // Y
{ PS2_KEY_Z, PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ_ALL, 0x07, 0xFF, 0xFF, 0x04, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }, // z
{ PS2_KEY_Z, PS2CTRL_NONE, KEYMAP_STANDARD, MZ_ALL, 0x07, 0xFF, 0xFF, 0x04, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }, // Z
// PS2 Code PS2 Ctrl (Flags to Match) Keyboard Model Machine MK_ROW1 MK_ROW2 MK_ROW3 MK_KEY1 MK_KEY2 MK_KEY3 BRK_ROW1 BRK_ROW2 BRK_KEY1 BRK_KEY2
{ PS2_KEY_SPACE, PS2CTRL_NONE, KEYMAP_STANDARD, MZ_ALL, 0x03, 0xFF, 0xFF, 0x02, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }, // Space
{ PS2_KEY_COMMA, PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ_ALL, 0x07, 0x0B, 0xFF, 0x80, 0x04, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }, // Less Than <
{ PS2_KEY_COMMA, PS2CTRL_NONE, KEYMAP_STANDARD, MZ_ALL, 0x07, 0xFF, 0xFF, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }, // Comma ,
{ PS2_KEY_SEMI, PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ_ALL, 0x09, 0xFF, 0xFF, 0x04, 0xFF, 0xFF, 0x0B, 0xFF, 0x04, 0xFF, }, // Colon :
{ PS2_KEY_SEMI, PS2CTRL_NONE, KEYMAP_STANDARD, MZ_ALL, 0x09, 0xFF, 0xFF, 0x08, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }, // Semi-Colon ;
{ PS2_KEY_DOT, PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ_ALL, 0x07, 0x0B, 0xFF, 0x40, 0x04, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }, // Greater Than >
{ PS2_KEY_DOT, PS2CTRL_NONE, KEYMAP_STANDARD, MZ_ALL, 0x07, 0xFF, 0xFF, 0x40, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }, // Full stop .
{ PS2_KEY_DIV, PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ_2000, 0x07, 0xFF, 0xFF, 0x20, 0xFF, 0xFF, 0x0B, 0xFF, 0x04, 0xFF, }, // Question ?
{ PS2_KEY_DIV, PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ_80B, 0x07, 0xFF, 0xFF, 0x20, 0xFF, 0xFF, 0x0B, 0xFF, 0x04, 0xFF, }, // Question ?
{ PS2_KEY_DIV, PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ_ALL, 0x04, 0x0B, 0xFF, 0x01, 0x04, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }, // Question ?
{ PS2_KEY_DIV, PS2CTRL_NONE, KEYMAP_STANDARD, MZ_ALL, 0x04, 0xFF, 0xFF, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }, // Divide /
{ PS2_KEY_MINUS, PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ_2000, 0x08, 0x0B, 0xFF, 0x01, 0x04, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }, // Upper bar
{ PS2_KEY_MINUS, PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ_80B, 0x08, 0x0B, 0xFF, 0x01, 0x04, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }, // Upper bar
{ PS2_KEY_MINUS, PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ_ALL, 0x07, 0xFF, 0xFF, 0x20, 0xFF, 0xFF, 0x0B, 0xFF, 0x04, 0xFF, }, // Underscore
{ PS2_KEY_MINUS, PS2CTRL_NONE, KEYMAP_STANDARD, MZ_ALL, 0x09, 0xFF, 0xFF, 0x10, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }, //
{ PS2_KEY_APOS, PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ_80B, 0x09, 0xFF, 0xFF, 0x20, 0xFF, 0xFF, 0x0B, 0xFF, 0x04, 0xFF, }, // At @
{ PS2_KEY_APOS, PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ_ALL, 0x09, 0xFF, 0xFF, 0x20, 0xFF, 0xFF, 0x0B, 0xFF, 0x04, 0xFF, }, // At @
{ PS2_KEY_APOS, PS2CTRL_NONE, KEYMAP_STANDARD, MZ_ALL, 0x08, 0x0B, 0xFF, 0x80, 0x04, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }, // Single quote '
{ PS2_KEY_OPEN_SQ, PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ_ALL, 0x09, 0x0B, 0xFF, 0x40, 0x04, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }, // Open Left Brace {
{ PS2_KEY_OPEN_SQ, PS2CTRL_NONE, KEYMAP_STANDARD, MZ_ALL, 0x09, 0xFF, 0xFF, 0x40, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }, // Open Left Square Bracket [
{ PS2_KEY_EQUAL, PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ_ALL, 0x09, 0x0B, 0xFF, 0x08, 0x04, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }, // Plus +
{ PS2_KEY_EQUAL, PS2CTRL_NONE, KEYMAP_STANDARD, MZ_ALL, 0x09, 0x0B, 0xFF, 0x10, 0x04, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }, // Equal =
{ PS2_KEY_CAPS, PS2CTRL_NONE, KEYMAP_STANDARD, MZ_ALL, 0x0B, 0xFF, 0xFF, 0x02, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }, // LOCK
{ PS2_KEY_ENTER, PS2CTRL_FUNC, KEYMAP_STANDARD, MZ_ALL, 0x03, 0xFF, 0xFF, 0x04, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }, // ENTER/RETURN
{ PS2_KEY_CLOSE_SQ, PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ_ALL, 0x0A, 0x0B, 0xFF, 0x01, 0x04, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }, // Close Right Brace }
{ PS2_KEY_CLOSE_SQ, PS2CTRL_NONE, KEYMAP_STANDARD, MZ_ALL, 0x0A, 0xFF, 0xFF, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }, // Close Right Square Bracket ]
{ PS2_KEY_BACK, PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ_ALL, 0x07, 0x0B, 0xFF, 0x10, 0x04, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }, //
{ PS2_KEY_BACK, PS2CTRL_NONE, KEYMAP_STANDARD, MZ_ALL, 0x07, 0xFF, 0xFF, 0x10, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }, // Back slash maps to Yen
{ PS2_KEY_BTICK, PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ_ALL, 0x07, 0x0B, 0xFF, 0x10, 0x04, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }, // Pipe
{ PS2_KEY_BTICK, PS2CTRL_NONE, KEYMAP_STANDARD, MZ_ALL, 0x09, 0x0B, 0xFF, 0x20, 0x04, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }, // Back tick `
{ PS2_KEY_HASH, PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ_2000, 0x07, 0x0B, 0xFF, 0x08, 0x04, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }, // Tilde
{ PS2_KEY_HASH, PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ_80B, 0x07, 0x0B, 0xFF, 0x08, 0x04, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }, // Tilde
{ PS2_KEY_HASH, PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ_ALL, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }, // Tilde has no mapping.
{ PS2_KEY_HASH, PS2CTRL_NONE, KEYMAP_STANDARD, MZ_ALL, 0x08, 0x0B, 0xFF, 0x08, 0x04, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }, // Hash
{ PS2_KEY_BS, PS2CTRL_FUNC, KEYMAP_STANDARD, MZ_ALL, 0x0A, 0xFF, 0xFF, 0x10, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }, // Backspace
{ PS2_KEY_ESC, PS2CTRL_FUNC, KEYMAP_STANDARD, MZ_ALL, 0x0A, 0xFF, 0xFF, 0x20, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }, // ESCape
{ PS2_KEY_SCROLL, PS2CTRL_FUNC, KEYMAP_STANDARD, MZ_ALL, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }, // Not assigned.
{ PS2_KEY_INSERT, PS2CTRL_FUNC, KEYMAP_STANDARD, MZ_ALL, 0x0A, 0x0B, 0xFF, 0x08, 0x04, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }, // INSERT
{ PS2_KEY_HOME, PS2CTRL_FUNC | PS2CTRL_SHIFT | PS2CTRL_EXACT, KEYMAP_STANDARD, MZ_ALL, 0x0A, 0x0B, 0xFF, 0x04, 0x04, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }, // CLR
{ PS2_KEY_HOME, PS2CTRL_FUNC, KEYMAP_STANDARD, MZ_ALL, 0x0A, 0xFF, 0xFF, 0x04, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }, // HOME
{ PS2_KEY_PGUP, PS2CTRL_FUNC, KEYMAP_STANDARD, MZ_ALL, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }, // Not assigned.
{ PS2_KEY_DELETE, PS2CTRL_FUNC, KEYMAP_STANDARD, MZ_ALL, 0x0A, 0xFF, 0xFF, 0x08, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }, // DELETE
{ PS2_KEY_END, PS2CTRL_FUNC, KEYMAP_STANDARD, MZ_ALL, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }, // Not assigned.
{ PS2_KEY_PGDN, PS2CTRL_FUNC, KEYMAP_STANDARD, MZ_80B|MZ_2000|MZ_2500, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }, // Not mapped
{ PS2_KEY_PGDN, PS2CTRL_FUNC, KEYMAP_STANDARD, MZ_2800, 0x0C, 0xFF, 0xFF, 0x10, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }, // Japanese Key - Previous
{ PS2_KEY_UP_ARROW, PS2CTRL_FUNC, KEYMAP_STANDARD, MZ_ALL, 0x03, 0xFF, 0xFF, 0x08, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }, // Up Arrow
{ PS2_KEY_L_ARROW, PS2CTRL_FUNC, KEYMAP_STANDARD, MZ_ALL, 0x03, 0xFF, 0xFF, 0x20, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }, // Left Arrow
{ PS2_KEY_DN_ARROW, PS2CTRL_FUNC, KEYMAP_STANDARD, MZ_ALL, 0x03, 0xFF, 0xFF, 0x10, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }, // Down Arrow
{ PS2_KEY_R_ARROW, PS2CTRL_FUNC, KEYMAP_STANDARD, MZ_ALL, 0x03, 0xFF, 0xFF, 0x40, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }, // Right Arrow
{ PS2_KEY_NUM, PS2CTRL_FUNC, KEYMAP_STANDARD, MZ_ALL, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }, // Not assigned.
// Keypad.
{ PS2_KEY_KP0, PS2CTRL_NONE, KEYMAP_STANDARD, MZ_ALL, 0x02, 0xFF, 0xFF, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }, // Keypad 0
{ PS2_KEY_KP1, PS2CTRL_NONE, KEYMAP_STANDARD, MZ_ALL, 0x02, 0xFF, 0xFF, 0x02, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }, // Keypad 1
{ PS2_KEY_KP2, PS2CTRL_NONE, KEYMAP_STANDARD, MZ_ALL, 0x02, 0xFF, 0xFF, 0x04, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }, // Keypad 2
{ PS2_KEY_KP3, PS2CTRL_NONE, KEYMAP_STANDARD, MZ_ALL, 0x02, 0xFF, 0xFF, 0x08, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }, // Keypad 3
{ PS2_KEY_KP4, PS2CTRL_NONE, KEYMAP_STANDARD, MZ_ALL, 0x02, 0xFF, 0xFF, 0x10, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }, // Keypad 4
{ PS2_KEY_KP5, PS2CTRL_NONE, KEYMAP_STANDARD, MZ_ALL, 0x02, 0xFF, 0xFF, 0x20, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }, // Keypad 5
{ PS2_KEY_KP6, PS2CTRL_NONE, KEYMAP_STANDARD, MZ_ALL, 0x02, 0xFF, 0xFF, 0x40, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }, // Keypad 6
{ PS2_KEY_KP7, PS2CTRL_NONE, KEYMAP_STANDARD, MZ_ALL, 0x02, 0xFF, 0xFF, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }, // Keypad 7
{ PS2_KEY_KP8, PS2CTRL_NONE, KEYMAP_STANDARD, MZ_ALL, 0x01, 0xFF, 0xFF, 0x04, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }, // Keypad 8
{ PS2_KEY_KP9, PS2CTRL_NONE, KEYMAP_STANDARD, MZ_ALL, 0x01, 0xFF, 0xFF, 0x08, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }, // Keypad 9
{ PS2_KEY_KP_COMMA, PS2CTRL_NONE, KEYMAP_STANDARD, MZ_ALL, 0x01, 0xFF, 0xFF, 0x10, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }, // Keypad Comma ,
{ PS2_KEY_KP_DOT, PS2CTRL_NONE, KEYMAP_STANDARD, MZ_ALL, 0x01, 0xFF, 0xFF, 0x20, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }, // Keypad Full stop .
{ PS2_KEY_KP_PLUS, PS2CTRL_NONE, KEYMAP_STANDARD, MZ_ALL, 0x01, 0xFF, 0xFF, 0x40, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }, // Keypad Plus +
{ PS2_KEY_KP_MINUS, PS2CTRL_NONE, KEYMAP_STANDARD, MZ_ALL, 0x01, 0xFF, 0xFF, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }, // Keypad Minus -
{ PS2_KEY_KP_TIMES, PS2CTRL_NONE, KEYMAP_STANDARD, MZ_ALL, 0x0A, 0xFF, 0xFF, 0x40, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }, // Keypad Times *
{ PS2_KEY_KP_DIV, PS2CTRL_NONE, KEYMAP_STANDARD, MZ_ALL, 0x0A, 0xFF, 0xFF, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }, // Keypad Divide /
{ PS2_KEY_KP_ENTER, PS2CTRL_NONE, KEYMAP_STANDARD, MZ_ALL, 0x03, 0xFF, 0xFF, 0x04, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }, // Keypad Ebter /
// PS2 Code PS2 Ctrl (Flags to Match) Keyboard Model Machine MK_ROW1 MK_ROW2 MK_ROW3 MK_KEY1 MK_KEY2 MK_KEY3 BRK_ROW1 BRK_ROW2 BRK_KEY1 BRK_KEY2
// Special keys.
{ PS2_KEY_PRTSCR, PS2CTRL_FUNC, KEYMAP_STANDARD, MZ_ALL, 0x0D, 0xFF, 0xFF, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }, // ARGO KEY
{ PS2_KEY_PAUSE, PS2CTRL_FUNC, KEYMAP_STANDARD, MZ_ALL, 0x03, 0xFF, 0xFF, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }, // BREAK KEY
{ PS2_KEY_L_GUI, PS2CTRL_FUNC | PS2CTRL_GUI, KEYMAP_STANDARD, MZ_ALL, 0x0B, 0xFF, 0xFF, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }, // GRAPH KEY
{ PS2_KEY_L_ALT, PS2CTRL_FUNC | PS2CTRL_ALT, KEYMAP_STANDARD, MZ_ALL, 0x0C, 0xFF, 0xFF, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }, // KJ1 Sentence
{ PS2_KEY_R_ALT, PS2CTRL_FUNC | PS2CTRL_ALTGR, KEYMAP_STANDARD, MZ_ALL, 0x0C, 0xFF, 0xFF, 0x02, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }, // KJ2 Transform
{ PS2_KEY_R_GUI, PS2CTRL_FUNC | PS2CTRL_GUI, KEYMAP_STANDARD, MZ_ALL, 0x0B, 0xFF, 0xFF, 0x08, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }, // KANA KEY
{ PS2_KEY_MENU, PS2CTRL_FUNC | PS2CTRL_GUI, KEYMAP_STANDARD, MZ_ALL, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }, // Not assigned.
// Modifiers are last, only being selected if an earlier match isnt made.
{ PS2_KEY_L_SHIFT, PS2CTRL_FUNC, KEYMAP_STANDARD, MZ_ALL, 0x0B, 0xFF, 0xFF, 0x04, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, },
{ PS2_KEY_R_SHIFT, PS2CTRL_FUNC, KEYMAP_STANDARD, MZ_ALL, 0x0B, 0xFF, 0xFF, 0x04, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, },
{ PS2_KEY_L_CTRL, PS2CTRL_FUNC, KEYMAP_STANDARD, MZ_ALL, 0x0B, 0xFF, 0xFF, 0x10, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, },
{ PS2_KEY_R_CTRL, PS2CTRL_FUNC, KEYMAP_STANDARD, MZ_80B|MZ_2000|MZ_2500, 0x0B, 0xFF, 0xFF, 0x10, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }, // Map to Control
{ PS2_KEY_R_CTRL, PS2CTRL_FUNC, KEYMAP_STANDARD, MZ_2800, 0x0C, 0xFF, 0xFF, 0x08, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }, // Japanese Key - Cancel
{ 0, PS2CTRL_NONE, KEYMAP_STANDARD, MZ_ALL, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, },
}};
};
#endif // MZ2528_H

View File

@@ -1 +0,0 @@
../../../sharpkey/main/include/MZ5665.h

574
main/include/MZ5665.h Normal file
View File

@@ -0,0 +1,574 @@
/////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Name: MZ5665.h
// Created: Apr 2022
// Version: v1.0
// Author(s): Philip Smart
// Description: Header for the Sharp MZ-6500 to HID (PS/2, Bluetooth) interface logic.
// Credits:
// Copyright: (c) 2019-2022 Philip Smart <philip.smart@net2net.org>
//
// History: Apr 2022 - Initial write.
// v1.01 Jun 2022 - Updates to reflect changes realised in other modules due to addition of
// bluetooth and suspend logic due to NVS issues using both cores.
//
// Notes: See Makefile to enable/disable conditional components
//
/////////////////////////////////////////////////////////////////////////////////////////////////////////
// This source file is free software: you can redistribute it and#or modify
// it under the terms of the GNU General Public License as published
// by the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This source file is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
/////////////////////////////////////////////////////////////////////////////////////////////////////////
#ifndef MZ5665_H
#define MZ5665_H
// Include the specification class.
#include "KeyInterface.h"
#include "NVS.h"
#include "LED.h"
#include "HID.h"
#include <vector>
#include <map>
// NB: Macros definitions put inside class for clarity, they are still global scope.
// Encapsulate the Sharp MZ-6500 interface.
class MZ5665 : public KeyInterface {
// Macros.
//
#define NUMELEM(a) (sizeof(a)/sizeof(a[0]))
// Constants.
#define MZ5665IF_VERSION 1.01
#define MZ5665IF_KEYMAP_FILE "MZ5665_KeyMap.BIN"
#define MAX_MZ5665_XMIT_KEY_BUF 16
#define PS2TBL_MZ5665_MAXROWS 349
// MZ-6500 Key control bit mask.
#define MZ5665_CTRL_GRAPH ((unsigned char) (1 << 4))
#define MZ5665_CTRL_CAPS ((unsigned char) (1 << 3))
#define MZ5665_CTRL_KANA ((unsigned char) (1 << 2))
#define MZ5665_CTRL_SHIFT ((unsigned char) (1 << 1))
#define MZ5665_CTRL_CTRL ((unsigned char) (1 << 0))
// Special key definition.
#define MZ5665_KEY_UP 0x1E // ↑
#define MZ5665_KEY_DOWN 0x1F // ↓
#define MZ5665_KEY_LEFT 0x1D // ←
#define MZ5665_KEY_RIGHT 0x1C // → →
#define MZ5665_KEY_INS 0x12 // INS
#define MZ5665_KEY_DEL 0x08 // DEL
#define MZ5665_KEY_CLR 0x0C // CLR
#define MZ5665_KEY_HOME 0x0B // HOME
// PS2 Flag definitions.
#define PS2CTRL_NONE 0x00 // No keys active = 0
#define PS2CTRL_SHIFT 0x01 // Shfit Key active = 1
#define PS2CTRL_CTRL 0x02 // Ctrl Key active = 1
#define PS2CTRL_CAPS 0x04 // CAPS active = 1
#define PS2CTRL_KANA 0x08 // KANA active = 1
#define PS2CTRL_GRAPH 0x10 // GRAPH active = 1
#define PS2CTRL_GUI 0x20 // GUI Key active = 1
#define PS2CTRL_FUNC 0x40 // Special Function Keys active = 1
#define PS2CTRL_BREAK 0x80 // BREAK Key active = 1
#define PS2CTRL_EXACT 0x80 // EXACT Match active = 1
// The initial mapping is made inside the PS2KeyAdvanced class from Scan Code Set 2 to ASCII
// for a selected keyboard. Special functions are detected and combined inside this module
// before mapping with the table below to extract the MZ-6500 key code and control data.
// ie. PS/2 Scan Code -> ASCII + Flags -> MZ-6500 Key Code + Ctrl Data
// Keyboard mapping table column names.
#define PS2TBL_PS2KEYCODE_NAME "PS/2 KeyCode"
#define PS2TBL_PS2CTRL_NAME "PS/2 Control Key"
#define PS2TBL_KEYBOARDMODEL_NAME "For Keyboard"
#define PS2TBL_MACHINE_NAME "For Host Model"
#define PS2TBL_MZ5665_KEYCODE_NAME "MZ5665 KeyCode"
#define PS2TBL_MZ5665__CTRL_NAME "MZ5665 Control Key"
// Keyboard mapping table column types.
#define PS2TBL_PS2KEYCODE_TYPE "hex"
#define PS2TBL_PS2CTRL_TYPE "custom_cbp_ps2ctrl"
#define PS2TBL_KEYBOARDMODEL_TYPE "custom_cbp_keybmodel"
#define PS2TBL_MACHINE_TYPE "custom_cbp_machine"
#define PS2TBL_MZ5665_KEYCODE_TYPE "hex"
#define PS2TBL_MZ5665_CTRL_TYPE "custom_cbn_x1ctrl"
// Keyboard mapping table select list for PS2CTRL.
#define PS2TBL_PS2CTRL_SEL_NONE "NONE"
#define PS2TBL_PS2CTRL_SEL_SHIFT "SHIFT"
#define PS2TBL_PS2CTRL_SEL_CTRL "CTRL"
#define PS2TBL_PS2CTRL_SEL_CAPS "CAPS"
#define PS2TBL_PS2CTRL_SEL_KANA "KANA"
#define PS2TBL_PS2CTRL_SEL_GRAPH "GRAPH"
#define PS2TBL_PS2CTRL_SEL_GUI "GUI"
#define PS2TBL_PS2CTRL_SEL_FUNC "FUNC"
#define PS2TBL_PS2CTRL_SEL_EXACT "EXACT"
// Keyboard mapping table select list for Model of keyboard.
#define KEYMAP_SEL_STANDARD "ALL"
#define KEYMAP_SEL_UK_WYSE_KB3926 "UK_WYSE_KB3926"
#define KEYMAP_SEL_JAPAN_OADG109 "JAPAN_OADG109"
#define KEYMAP_SEL_JAPAN_SANWA_SKBL1 "JAPAN_SANWA_SKBL1"
#define KEYMAP_SEL_NOT_ASSIGNED_4 "KEYBOARD_4"
#define KEYMAP_SEL_NOT_ASSIGNED_5 "KEYBOARD_5"
#define KEYMAP_SEL_NOT_ASSIGNED_6 "KEYBOARD_6"
#define KEYMAP_SEL_UK_PERIBOARD_810 "UK_PERIBOARD_810"
#define KEYMAP_SEL_UK_OMOTON_K8508 "UK_OMOTON_K8508"
// Keyboard mapping table select list for target machine.
#define MZ5665_SEL_ALL "ALL"
// Keyboard mapping table select list for MZ5665 Control codes.
#define MZ5665_CTRL_SEL_GRAPH "GRAPH"
#define MZ5665_CTRL_SEL_CAPS "CAPS"
#define MZ5665_CTRL_SEL_KANA "KANA"
#define MZ5665_CTRL_SEL_SHIFT "SHIFT"
#define MZ5665_CTRL_SEL_CTRL "CTRL"
// The Sharp MZ-6500 Series was released over a number of years and each iteration added changes/updates. In order to cater for differences, it is possible to assign a key mapping
// to a specific machine type(s) or all of the series by adding the flags below into the mapping table.
#define MZ5665_ALL 0xFF
// Keyboard models. The base on which this interface was created was a Wyse KB3926 PS/2 Keyboard and this is deemed STANDARD. Other models need to insert difference maps
// prior to the STANDARD entry along with the keyboard model so that it is processed first thus allowing differing keyboards with different maps.
#define KEYMAP_STANDARD 0xFF
#define KEYMAP_UK_WYSE_KB3926 0x01
#define KEYMAP_JAPAN_OADG109 0x02
#define KEYMAP_JAPAN_SANWA_SKBL1 0x04
#define KEYMAP_NOT_ASSIGNED_4 0x08
#define KEYMAP_NOT_ASSIGNED_5 0x10
#define KEYMAP_NOT_ASSIGNED_6 0x20
#define KEYMAP_UK_PERIBOARD_810 0x40
#define KEYMAP_UK_OMOTON_K8508 0x80
public:
// Prototypes.
MZ5665(void);
MZ5665(uint32_t ifMode, NVS *hdlNVS, LED *hdlLED, HID *hdlHID, const char *fsPath);
MZ5665(NVS *hdlNVS, HID *hdlHID, const char *fsPath);
~MZ5665(void);
bool createKeyMapFile(std::fstream &outFile);
bool storeDataToKeyMapFile(std::fstream &outFile, char *data, int size);
bool storeDataToKeyMapFile(std::fstream & outFile, std::vector<uint32_t>& dataArray);
bool closeAndCommitKeyMapFile(std::fstream &outFile, bool cleanupOnly);
std::string getKeyMapFileName(void) { return(MZ5665IF_KEYMAP_FILE); };
void getKeyMapHeaders(std::vector<std::string>& headerList);
void getKeyMapTypes(std::vector<std::string>& typeList);
bool getKeyMapSelectList(std::vector<std::pair<std::string, int>>& selectList, std::string option);
bool getKeyMapData(std::vector<uint32_t>& dataArray, int *row, bool start);
// Method to return the class version number.
float version(void)
{
return(MZ5665IF_VERSION);
}
protected:
private:
// Prototypes.
void pushKeyToQueue(uint32_t key);
IRAM_ATTR static void mzInterface( void * pvParameters );
IRAM_ATTR static void hidInterface( void * pvParameters );
void selectOption(uint8_t optionCode);
uint32_t mapKey(uint16_t scanCode);
bool loadKeyMap();
bool saveKeyMap(void);
void init(uint32_t ifMode, NVS *hdlNVS, LED *hdlLED, HID *hdlHID);
void init(NVS *hdlNVS, HID *hdlHID);
// // Overload the base yield method to include suspension of the PS/2 Keyboard interface. This interface uses interrupts which are not mutex protected and clash with the
// // WiFi API methods.
// inline void yield(uint32_t delay)
// {
// // If suspended, go into a permanent loop until the suspend flag is reset.
// if(this->suspend)
// {
// // Suspend the keyboard interface.
// Keyboard->suspend(true);
//
// // Use the base method logic.
// KeyInterface::yield(delay);
//
// // Release the keyboard interface.
// Keyboard->suspend(false);
// } else
// // Otherwise just delay by the required amount for timing and to give other threads a time slice.
// {
// KeyInterface::yield(delay);
// }
// return;
// }
// Structure to encapsulate a single key map from PS/2 to MZ-5600/MZ-6500.
typedef struct {
uint8_t ps2KeyCode;
uint8_t ps2Ctrl;
uint8_t keyboardModel;
uint8_t machine;
uint8_t mzKey;
uint8_t mzCtrl;
} t_keyMapEntry;
// Structure to encapsulate the entire static keyboard mapping table.
typedef struct {
t_keyMapEntry kme[PS2TBL_MZ5665_MAXROWS];
} t_keyMap;
// Structure to maintain the MZ-5600/MZ-6500 interface configuration data. This data is persisted through powercycles as needed.
typedef struct {
struct {
uint8_t activeKeyboardMap; // Model of keyboard a keymap entry is applicable to.
uint8_t activeMachineModel; // Machine model a keymap entry is applicable to.
} params;
} t_mzConfig;
// Configuration data.
t_mzConfig mzConfig;
// Structure to manage the control signals signifying the state of the MZ-6500 keyboard.
typedef struct {
bool optionSelect; // Flag to indicate a user requested keyboard configuration option is being selected.
uint8_t keyCtrl; // Keyboard state flag control.
std::string fsPath; // Path on the underlying filesystem where storage is mounted and accessible.
t_keyMapEntry *kme; // Pointer to an array in memory to contain PS2 to MZ-6500 mapping values.
int kmeRows; // Number of rows in the kme table.
std::string keyMapFileName; // Name of file where extension or replacement key map entries are stored.
} t_mzControl;
// Transmit buffer queue item.
typedef struct {
uint32_t keyCode; // 16bit, bits 8:0 represent the key, 9 if CTRL to be sent, 10 if ALT to be sent.
} t_xmitQueueMessage;
// Thread handles - one per function, ie. HID interface and host target interface.
TaskHandle_t TaskHostIF = NULL;
TaskHandle_t TaskHIDIF = NULL;
// Control structure to control interaction and mapping of keys for the host.
t_mzControl mzCtrl;
// Spin lock mutex to hold a coresied to an uninterruptable method. This only works on dual core ESP32's.
portMUX_TYPE mzMutex;
//
// This mapping is for the UK Wyse KB-3926 PS/2 keyboard
//
t_keyMap PS2toMZ5665 = {
{
// HELP
// COPY
////PS2 Code PS2 Ctrl (Flags to Match) Keyboard Model Machine MZ5665 Data MZ5665 Ctrl (Flags to Set).
//{ PS2_KEY_F1, PS2CTRL_FUNC | PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ5665_ALL, 'v', 0x00, }, // SHIFT+F1
//{ PS2_KEY_F2, PS2CTRL_FUNC | PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ5665_ALL, 'w', 0x00, }, // SHIFT+F2
//{ PS2_KEY_F3, PS2CTRL_FUNC | PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ5665_ALL, 'x', 0x00, }, // SHIFT+F3
//{ PS2_KEY_F4, PS2CTRL_FUNC | PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ5665_ALL, 'y', 0x00, }, // SHIFT+F4
//{ PS2_KEY_F5, PS2CTRL_FUNC | PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ5665_ALL, 'z', 0x00, }, // SHIFT+F5
//{ PS2_KEY_F1, PS2CTRL_FUNC, KEYMAP_STANDARD, MZ5665_ALL, 'q', 0x00, }, // F1
//{ PS2_KEY_F2, PS2CTRL_FUNC, KEYMAP_STANDARD, MZ5665_ALL, 'r', 0x00, }, // F2
//{ PS2_KEY_F3, PS2CTRL_FUNC, KEYMAP_STANDARD, MZ5665_ALL, 's', 0x00, }, // F3
//{ PS2_KEY_F4, PS2CTRL_FUNC, KEYMAP_STANDARD, MZ5665_ALL, 't', 0x00, }, // F4
//{ PS2_KEY_F5, PS2CTRL_FUNC, KEYMAP_STANDARD, MZ5665_ALL, 'u', 0x00, }, // F5
//{ PS2_KEY_F6, PS2CTRL_FUNC, KEYMAP_STANDARD, MZ5665_ALL, 0xEC, 0x00, }, // F6
//{ PS2_KEY_F7, PS2CTRL_FUNC, KEYMAP_STANDARD, MZ5665_ALL, 0xEB, 0x00, }, // F7
//{ PS2_KEY_F8, PS2CTRL_FUNC, KEYMAP_STANDARD, MZ5665_ALL, 0xE2, 0x00, }, // F8
//{ PS2_KEY_F9, PS2CTRL_FUNC, KEYMAP_STANDARD, MZ5665_ALL, 0xE1, 0x00, }, // F9
//{ PS2_KEY_F10, PS2CTRL_FUNC, KEYMAP_STANDARD, MZ5665_ALL, 0x00, 0x00, }, // XFER
//{ PS2_KEY_F11, PS2CTRL_FUNC, KEYMAP_STANDARD, MZ5665_ALL, 0xFE, 0x00, }, // HELP
//{ PS2_KEY_F12, PS2CTRL_FUNC, KEYMAP_STANDARD, MZ5665_ALL, 0x00, 0x00, }, // COPY
//{ PS2_KEY_TAB, PS2CTRL_NONE, KEYMAP_STANDARD, MZ5665_ALL, 0x09, 0x00, }, // TAB
// Numeric keys.
{ PS2_KEY_0, PS2CTRL_NONE, KEYMAP_STANDARD, MZ5665_ALL, '0', 0x00, }, // 0
{ PS2_KEY_1, PS2CTRL_NONE, KEYMAP_STANDARD, MZ5665_ALL, '1', 0x00, }, // 1
{ PS2_KEY_2, PS2CTRL_NONE, KEYMAP_STANDARD, MZ5665_ALL, '2', 0x00, }, // 2
{ PS2_KEY_3, PS2CTRL_NONE, KEYMAP_STANDARD, MZ5665_ALL, '3', 0x00, }, // 3
{ PS2_KEY_4, PS2CTRL_NONE, KEYMAP_STANDARD, MZ5665_ALL, '4', 0x00, }, // 4
{ PS2_KEY_5, PS2CTRL_NONE, KEYMAP_STANDARD, MZ5665_ALL, '5', 0x00, }, // 5
{ PS2_KEY_6, PS2CTRL_NONE, KEYMAP_STANDARD, MZ5665_ALL, '6', 0x00, }, // 6
{ PS2_KEY_7, PS2CTRL_NONE, KEYMAP_STANDARD, MZ5665_ALL, '7', 0x00, }, // 7
{ PS2_KEY_8, PS2CTRL_NONE, KEYMAP_STANDARD, MZ5665_ALL, '8', 0x00, }, // 8
{ PS2_KEY_9, PS2CTRL_NONE, KEYMAP_STANDARD, MZ5665_ALL, '9', 0x00, }, // 9
// Punctuation keys.
{ PS2_KEY_0, PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ5665_ALL, ')', 0x00, }, // Close Right Bracket )
{ PS2_KEY_1, PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ5665_ALL, '!', 0x00, }, // Exclamation
{ PS2_KEY_2, PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ5665_ALL, '"', 0x00, }, // Double quote.
{ PS2_KEY_3, PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ5665_ALL, 0x23, 0x00, }, // Pound Sign -> Hash
{ PS2_KEY_4, PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ5665_ALL, '$', 0x00, }, // Dollar
{ PS2_KEY_5, PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ5665_ALL, '%', 0x00, }, // Percent
{ PS2_KEY_6, PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ5665_ALL, '^', 0x00, }, // Kappa
{ PS2_KEY_7, PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ5665_ALL, '&', 0x00, }, // Ampersand
{ PS2_KEY_8, PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ5665_ALL, '*', 0x00, }, // Star
{ PS2_KEY_9, PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ5665_ALL, '(', 0x00, }, // Open Left Bracket (
// ALPHA keys, lower and uppercase.
//PS2 Code PS2 Ctrl (Flags to Match) Keyboard Model Machine MZ5665 Data MZ5665 Ctrl (Flags to Set).
{ PS2_KEY_A, PS2CTRL_SHIFT | PS2CTRL_CAPS, KEYMAP_STANDARD, MZ5665_ALL, 'a', 0x00, }, // a
{ PS2_KEY_A, PS2CTRL_CAPS, KEYMAP_STANDARD, MZ5665_ALL, 'A', 0x00, }, // A
{ PS2_KEY_B, PS2CTRL_SHIFT | PS2CTRL_CAPS, KEYMAP_STANDARD, MZ5665_ALL, 'b', 0x00, }, // b
{ PS2_KEY_B, PS2CTRL_CAPS, KEYMAP_STANDARD, MZ5665_ALL, 'B', 0x00, }, // B
{ PS2_KEY_C, PS2CTRL_SHIFT | PS2CTRL_CAPS, KEYMAP_STANDARD, MZ5665_ALL, 'c', 0x00, }, // c
{ PS2_KEY_C, PS2CTRL_CAPS, KEYMAP_STANDARD, MZ5665_ALL, 'C', 0x00, }, // C
{ PS2_KEY_D, PS2CTRL_SHIFT | PS2CTRL_CAPS, KEYMAP_STANDARD, MZ5665_ALL, 'd', 0x00, }, // d
{ PS2_KEY_D, PS2CTRL_CAPS, KEYMAP_STANDARD, MZ5665_ALL, 'D', 0x00, }, // D
{ PS2_KEY_E, PS2CTRL_SHIFT | PS2CTRL_CAPS, KEYMAP_STANDARD, MZ5665_ALL, 'e', 0x00, }, // e
{ PS2_KEY_E, PS2CTRL_CAPS, KEYMAP_STANDARD, MZ5665_ALL, 'E', 0x00, }, // E
{ PS2_KEY_F, PS2CTRL_SHIFT | PS2CTRL_CAPS, KEYMAP_STANDARD, MZ5665_ALL, 'f', 0x00, }, // f
{ PS2_KEY_F, PS2CTRL_CAPS, KEYMAP_STANDARD, MZ5665_ALL, 'F', 0x00, }, // F
{ PS2_KEY_G, PS2CTRL_SHIFT | PS2CTRL_CAPS, KEYMAP_STANDARD, MZ5665_ALL, 'g', 0x00, }, // g
{ PS2_KEY_G, PS2CTRL_CAPS, KEYMAP_STANDARD, MZ5665_ALL, 'G', 0x00, }, // G
{ PS2_KEY_H, PS2CTRL_SHIFT | PS2CTRL_CAPS, KEYMAP_STANDARD, MZ5665_ALL, 'h', 0x00, }, // h
{ PS2_KEY_H, PS2CTRL_CAPS, KEYMAP_STANDARD, MZ5665_ALL, 'H', 0x00, }, // H
{ PS2_KEY_I, PS2CTRL_SHIFT | PS2CTRL_CAPS, KEYMAP_STANDARD, MZ5665_ALL, 'i', 0x00, }, // i
{ PS2_KEY_I, PS2CTRL_CAPS, KEYMAP_STANDARD, MZ5665_ALL, 'I', 0x00, }, // I
{ PS2_KEY_J, PS2CTRL_SHIFT | PS2CTRL_CAPS, KEYMAP_STANDARD, MZ5665_ALL, 'j', 0x00, }, // j
{ PS2_KEY_J, PS2CTRL_CAPS, KEYMAP_STANDARD, MZ5665_ALL, 'J', 0x00, }, // J
{ PS2_KEY_K, PS2CTRL_SHIFT | PS2CTRL_CAPS, KEYMAP_STANDARD, MZ5665_ALL, 'k', 0x00, }, // k
{ PS2_KEY_K, PS2CTRL_CAPS, KEYMAP_STANDARD, MZ5665_ALL, 'K', 0x00, }, // K
{ PS2_KEY_L, PS2CTRL_SHIFT | PS2CTRL_CAPS, KEYMAP_STANDARD, MZ5665_ALL, 'l', 0x00, }, // l
{ PS2_KEY_L, PS2CTRL_CAPS, KEYMAP_STANDARD, MZ5665_ALL, 'L', 0x00, }, // L
{ PS2_KEY_M, PS2CTRL_SHIFT | PS2CTRL_CAPS, KEYMAP_STANDARD, MZ5665_ALL, 'm', 0x00, }, // m
{ PS2_KEY_M, PS2CTRL_CAPS, KEYMAP_STANDARD, MZ5665_ALL, 'M', 0x00, }, // M
{ PS2_KEY_N, PS2CTRL_SHIFT | PS2CTRL_CAPS, KEYMAP_STANDARD, MZ5665_ALL, 'n', 0x00, }, // n
{ PS2_KEY_N, PS2CTRL_CAPS, KEYMAP_STANDARD, MZ5665_ALL, 'N', 0x00, }, // N
{ PS2_KEY_O, PS2CTRL_SHIFT | PS2CTRL_CAPS, KEYMAP_STANDARD, MZ5665_ALL, 'o', 0x00, }, // o
{ PS2_KEY_O, PS2CTRL_CAPS, KEYMAP_STANDARD, MZ5665_ALL, 'O', 0x00, }, // O
{ PS2_KEY_P, PS2CTRL_SHIFT | PS2CTRL_CAPS, KEYMAP_STANDARD, MZ5665_ALL, 'p', 0x00, }, // p
{ PS2_KEY_P, PS2CTRL_CAPS, KEYMAP_STANDARD, MZ5665_ALL, 'P', 0x00, }, // P
{ PS2_KEY_Q, PS2CTRL_SHIFT | PS2CTRL_CAPS, KEYMAP_STANDARD, MZ5665_ALL, 'q', 0x00, }, // q
{ PS2_KEY_Q, PS2CTRL_CAPS, KEYMAP_STANDARD, MZ5665_ALL, 'Q', 0x00, }, // Q
{ PS2_KEY_R, PS2CTRL_SHIFT | PS2CTRL_CAPS, KEYMAP_STANDARD, MZ5665_ALL, 'r', 0x00, }, // r
{ PS2_KEY_R, PS2CTRL_CAPS, KEYMAP_STANDARD, MZ5665_ALL, 'R', 0x00, }, // R
{ PS2_KEY_S, PS2CTRL_SHIFT | PS2CTRL_CAPS, KEYMAP_STANDARD, MZ5665_ALL, 's', 0x00, }, // s
{ PS2_KEY_S, PS2CTRL_CAPS, KEYMAP_STANDARD, MZ5665_ALL, 'S', 0x00, }, // S
{ PS2_KEY_T, PS2CTRL_SHIFT | PS2CTRL_CAPS, KEYMAP_STANDARD, MZ5665_ALL, 't', 0x00, }, // t
{ PS2_KEY_T, PS2CTRL_CAPS, KEYMAP_STANDARD, MZ5665_ALL, 'T', 0x00, }, // T
{ PS2_KEY_U, PS2CTRL_SHIFT | PS2CTRL_CAPS, KEYMAP_STANDARD, MZ5665_ALL, 'u', 0x00, }, // u
{ PS2_KEY_U, PS2CTRL_CAPS, KEYMAP_STANDARD, MZ5665_ALL, 'U', 0x00, }, // U
{ PS2_KEY_V, PS2CTRL_SHIFT | PS2CTRL_CAPS, KEYMAP_STANDARD, MZ5665_ALL, 'v', 0x00, }, // v
{ PS2_KEY_V, PS2CTRL_CAPS, KEYMAP_STANDARD, MZ5665_ALL, 'V', 0x00, }, // V
{ PS2_KEY_W, PS2CTRL_SHIFT | PS2CTRL_CAPS, KEYMAP_STANDARD, MZ5665_ALL, 'w', 0x00, }, // w
{ PS2_KEY_W, PS2CTRL_CAPS, KEYMAP_STANDARD, MZ5665_ALL, 'W', 0x00, }, // W
{ PS2_KEY_X, PS2CTRL_SHIFT | PS2CTRL_CAPS, KEYMAP_STANDARD, MZ5665_ALL, 'x', 0x00, }, // x
{ PS2_KEY_X, PS2CTRL_CAPS, KEYMAP_STANDARD, MZ5665_ALL, 'X', 0x00, }, // X
{ PS2_KEY_Y, PS2CTRL_SHIFT | PS2CTRL_CAPS, KEYMAP_STANDARD, MZ5665_ALL, 'y', 0x00, }, // y
{ PS2_KEY_Y, PS2CTRL_CAPS, KEYMAP_STANDARD, MZ5665_ALL, 'Y', 0x00, }, // Y
{ PS2_KEY_Z, PS2CTRL_SHIFT | PS2CTRL_CAPS, KEYMAP_STANDARD, MZ5665_ALL, 'z', 0x00, }, // z
{ PS2_KEY_Z, PS2CTRL_CAPS, KEYMAP_STANDARD, MZ5665_ALL, 'Z', 0x00, }, // Z
//PS2 Code PS2 Ctrl (Flags to Match) Keyboard Model Machine MZ5665 Data MZ5665 Ctrl (Flags to Set).
{ PS2_KEY_SPACE, PS2CTRL_NONE, KEYMAP_STANDARD, MZ5665_ALL, ' ', 0x00, }, // Space
{ PS2_KEY_COMMA, PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ5665_ALL, '<', 0x00, }, // Less Than <
{ PS2_KEY_COMMA, PS2CTRL_NONE, KEYMAP_STANDARD, MZ5665_ALL, ',', 0x00, }, // Comma ,
{ PS2_KEY_SEMI, PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ5665_ALL, ':', 0x00, }, // Colon :
{ PS2_KEY_SEMI, PS2CTRL_NONE, KEYMAP_STANDARD, MZ5665_ALL, ';', 0x00, }, // Semi-Colon ;
{ PS2_KEY_DOT, PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ5665_ALL, '>', 0x00, }, // Greater Than >
{ PS2_KEY_DOT, PS2CTRL_NONE, KEYMAP_STANDARD, MZ5665_ALL, '.', 0x00, }, // Full stop .
{ PS2_KEY_DIV, PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ5665_ALL, '?', 0x00, }, // Question ?
{ PS2_KEY_DIV, PS2CTRL_NONE, KEYMAP_STANDARD, MZ5665_ALL, '/', 0x00, }, // Divide /
{ PS2_KEY_MINUS, PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ5665_ALL, '_', 0x00, }, // Underscore
{ PS2_KEY_MINUS, PS2CTRL_NONE, KEYMAP_STANDARD, MZ5665_ALL, '-', 0x00, },
{ PS2_KEY_APOS, PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ5665_ALL, '@', 0x00, }, // At @
{ PS2_KEY_APOS, PS2CTRL_NONE, KEYMAP_STANDARD, MZ5665_ALL, '\'', 0x00, }, // Single quote '
{ PS2_KEY_OPEN_SQ, PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ5665_ALL, '{', 0x00, }, // Open Left Brace {
{ PS2_KEY_OPEN_SQ, PS2CTRL_NONE, KEYMAP_STANDARD, MZ5665_ALL, '[', 0x00, }, // Open Left Square Bracket [
{ PS2_KEY_EQUAL, PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ5665_ALL, '+', 0x00, }, // Plus +
{ PS2_KEY_EQUAL, PS2CTRL_NONE, KEYMAP_STANDARD, MZ5665_ALL, '=', 0x00, }, // Equal =
{ PS2_KEY_CAPS, PS2CTRL_NONE, KEYMAP_STANDARD, MZ5665_ALL, ' ', 0x00, }, // LOCK
{ PS2_KEY_ENTER, PS2CTRL_NONE, KEYMAP_STANDARD, MZ5665_ALL, 0x0D, 0x00, }, // ENTER/RETURN
{ PS2_KEY_CLOSE_SQ, PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ5665_ALL, '}', 0x00, }, // Close Right Brace }
{ PS2_KEY_CLOSE_SQ, PS2CTRL_NONE, KEYMAP_STANDARD, MZ5665_ALL, ']', 0x00, }, // Close Right Square Bracket ]
{ PS2_KEY_BACK, PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ5665_ALL, '|', 0x00, }, //
{ PS2_KEY_BACK, PS2CTRL_NONE, KEYMAP_STANDARD, MZ5665_ALL, '\\', 0x00, }, // Back slash maps to Yen
{ PS2_KEY_BTICK, PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ5665_ALL, '`', 0x00, }, // Pipe
{ PS2_KEY_BTICK, PS2CTRL_NONE, KEYMAP_STANDARD, MZ5665_ALL, '|', 0x00, }, // Back tick `
{ PS2_KEY_HASH, PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ5665_ALL, '~', 0x00, }, // Tilde has no mapping.
{ PS2_KEY_HASH, PS2CTRL_NONE, KEYMAP_STANDARD, MZ5665_ALL, '#', 0x00, }, // Hash
{ PS2_KEY_BS, PS2CTRL_FUNC, KEYMAP_STANDARD, MZ5665_ALL, 0x08, 0x00, }, // Backspace
{ PS2_KEY_ESC, PS2CTRL_FUNC, KEYMAP_STANDARD, MZ5665_ALL, 0x1B, 0x00, }, // ESCape
{ PS2_KEY_SCROLL, PS2CTRL_FUNC, KEYMAP_STANDARD, MZ5665_ALL, ' ', 0x00, }, // Not assigned.
{ PS2_KEY_INSERT, PS2CTRL_FUNC, KEYMAP_STANDARD, MZ5665_ALL, MZ5665_KEY_INS, 0x00, }, // INSERT
{ PS2_KEY_HOME, PS2CTRL_FUNC | PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ5665_ALL, MZ5665_KEY_CLR, 0x00, }, // CLR
{ PS2_KEY_HOME, PS2CTRL_FUNC, KEYMAP_STANDARD, MZ5665_ALL, MZ5665_KEY_HOME, 0x00, }, // HOME
{ PS2_KEY_DELETE, PS2CTRL_FUNC, KEYMAP_STANDARD, MZ5665_ALL, MZ5665_KEY_DEL, 0x00, }, // DELETE
{ PS2_KEY_END, PS2CTRL_FUNC, KEYMAP_STANDARD, MZ5665_ALL, 0x11, 0x00, }, // END
{ PS2_KEY_PGUP, PS2CTRL_FUNC, KEYMAP_STANDARD, MZ5665_ALL, 0x0E, 0x00, }, // Roll Up.
{ PS2_KEY_PGDN, PS2CTRL_FUNC, KEYMAP_STANDARD, MZ5665_ALL, 0x0F, 0x00, }, // Roll Down
{ PS2_KEY_UP_ARROW, PS2CTRL_FUNC, KEYMAP_STANDARD, MZ5665_ALL, MZ5665_KEY_UP, 0x00, }, // Up Arrow
{ PS2_KEY_L_ARROW, PS2CTRL_FUNC, KEYMAP_STANDARD, MZ5665_ALL, MZ5665_KEY_LEFT, 0x00, }, // Left Arrow
{ PS2_KEY_DN_ARROW, PS2CTRL_FUNC, KEYMAP_STANDARD, MZ5665_ALL, MZ5665_KEY_DOWN, 0x00, }, // Down Arrow
{ PS2_KEY_R_ARROW, PS2CTRL_FUNC, KEYMAP_STANDARD, MZ5665_ALL, MZ5665_KEY_RIGHT, 0x00, }, // Right Arrow
{ PS2_KEY_NUM, PS2CTRL_FUNC, KEYMAP_STANDARD, MZ5665_ALL, 0x00, 0x00, }, // Not assigned.
// GRPH (Alt Gr)
//PS2 Code PS2 Ctrl (Flags to Match) Keyboard Model Machine MZ5665 Data MZ5665 Ctrl (Flags to Set).
{ PS2_KEY_0, PS2CTRL_GRAPH, KEYMAP_STANDARD, MZ5665_ALL, 0xFA, 0x00, }, // GRPH+0
{ PS2_KEY_1, PS2CTRL_GRAPH, KEYMAP_STANDARD, MZ5665_ALL, 0xF1, 0x00, }, // GRPH+1
{ PS2_KEY_2, PS2CTRL_GRAPH, KEYMAP_STANDARD, MZ5665_ALL, 0xF2, 0x00, }, // GRPH+2
{ PS2_KEY_3, PS2CTRL_GRAPH, KEYMAP_STANDARD, MZ5665_ALL, 0xF3, 0x00, }, // GRPH+3
{ PS2_KEY_4, PS2CTRL_GRAPH, KEYMAP_STANDARD, MZ5665_ALL, 0xF4, 0x00, }, // GRPH+4
{ PS2_KEY_5, PS2CTRL_GRAPH, KEYMAP_STANDARD, MZ5665_ALL, 0xF5, 0x00, }, // GRPH+5
{ PS2_KEY_6, PS2CTRL_GRAPH, KEYMAP_STANDARD, MZ5665_ALL, 0xF6, 0x00, }, // GRPH+6
{ PS2_KEY_7, PS2CTRL_GRAPH, KEYMAP_STANDARD, MZ5665_ALL, 0xF7, 0x00, }, // GRPH+7
{ PS2_KEY_8, PS2CTRL_GRAPH, KEYMAP_STANDARD, MZ5665_ALL, 0xF8, 0x00, }, // GRPH+8
{ PS2_KEY_9, PS2CTRL_GRAPH, KEYMAP_STANDARD, MZ5665_ALL, 0xF9, 0x00, }, // GRPH+9
{ PS2_KEY_A, PS2CTRL_GRAPH, KEYMAP_STANDARD, MZ5665_ALL, 0x7F, 0x00, }, // GRPH+A
{ PS2_KEY_B, PS2CTRL_GRAPH, KEYMAP_STANDARD, MZ5665_ALL, 0x84, 0x00, }, // GRPH+B
{ PS2_KEY_C, PS2CTRL_GRAPH, KEYMAP_STANDARD, MZ5665_ALL, 0x82, 0x00, }, // GRPH+C
{ PS2_KEY_D, PS2CTRL_GRAPH, KEYMAP_STANDARD, MZ5665_ALL, 0xEA, 0x00, }, // GRPH+D
{ PS2_KEY_E, PS2CTRL_GRAPH, KEYMAP_STANDARD, MZ5665_ALL, 0xE2, 0x00, }, // GRPH+E
{ PS2_KEY_F, PS2CTRL_GRAPH, KEYMAP_STANDARD, MZ5665_ALL, 0xEB, 0x00, }, // GRPH+F
{ PS2_KEY_G, PS2CTRL_GRAPH, KEYMAP_STANDARD, MZ5665_ALL, 0xEC, 0x00, }, // GRPH+G
{ PS2_KEY_H, PS2CTRL_GRAPH, KEYMAP_STANDARD, MZ5665_ALL, 0xED, 0x00, }, // GRPH+H
{ PS2_KEY_I, PS2CTRL_GRAPH, KEYMAP_STANDARD, MZ5665_ALL, 0xE7, 0x00, }, // GRPH+I
{ PS2_KEY_J, PS2CTRL_GRAPH, KEYMAP_STANDARD, MZ5665_ALL, 0xEE, 0x00, }, // GRPH+J
{ PS2_KEY_K, PS2CTRL_GRAPH, KEYMAP_STANDARD, MZ5665_ALL, 0xEF, 0x00, }, // GRPH+K
{ PS2_KEY_L, PS2CTRL_GRAPH, KEYMAP_STANDARD, MZ5665_ALL, 0x8E, 0x00, }, // GRPH+L
{ PS2_KEY_M, PS2CTRL_GRAPH, KEYMAP_STANDARD, MZ5665_ALL, 0x86, 0x00, }, // GRPH+M
{ PS2_KEY_N, PS2CTRL_GRAPH, KEYMAP_STANDARD, MZ5665_ALL, 0x85, 0x00, }, // GRPH+N
{ PS2_KEY_O, PS2CTRL_GRAPH, KEYMAP_STANDARD, MZ5665_ALL, 0xF0, 0x00, }, // GRPH+O
{ PS2_KEY_P, PS2CTRL_GRAPH, KEYMAP_STANDARD, MZ5665_ALL, 0x8D, 0x00, }, // GRPH+P
{ PS2_KEY_Q, PS2CTRL_GRAPH, KEYMAP_STANDARD, MZ5665_ALL, 0xE0, 0x00, }, // GRPH+Q
{ PS2_KEY_R, PS2CTRL_GRAPH, KEYMAP_STANDARD, MZ5665_ALL, 0xE3, 0x00, }, // GRPH+R
{ PS2_KEY_S, PS2CTRL_GRAPH, KEYMAP_STANDARD, MZ5665_ALL, 0xE9, 0x00, }, // GRPH+S
{ PS2_KEY_T, PS2CTRL_GRAPH, KEYMAP_STANDARD, MZ5665_ALL, 0xE4, 0x00, }, // GRPH+T
{ PS2_KEY_U, PS2CTRL_GRAPH, KEYMAP_STANDARD, MZ5665_ALL, 0xE6, 0x00, }, // GRPH+U
{ PS2_KEY_V, PS2CTRL_GRAPH, KEYMAP_STANDARD, MZ5665_ALL, 0x83, 0x00, }, // GRPH+V
{ PS2_KEY_W, PS2CTRL_GRAPH, KEYMAP_STANDARD, MZ5665_ALL, 0xE1, 0x00, }, // GRPH+W
{ PS2_KEY_X, PS2CTRL_GRAPH, KEYMAP_STANDARD, MZ5665_ALL, 0x81, 0x00, }, // GRPH+X
{ PS2_KEY_Y, PS2CTRL_GRAPH, KEYMAP_STANDARD, MZ5665_ALL, 0xE5, 0x00, }, // GRPH+Y
{ PS2_KEY_Z, PS2CTRL_GRAPH, KEYMAP_STANDARD, MZ5665_ALL, 0x80, 0x00, }, // GRPH+Z
{ PS2_KEY_COMMA, PS2CTRL_GRAPH, KEYMAP_STANDARD, MZ5665_ALL, 0x87, 0x00, }, // GRPH+,
{ PS2_KEY_SEMI, PS2CTRL_GRAPH, KEYMAP_STANDARD, MZ5665_ALL, 0x89, 0x00, }, // GRPH+;
{ PS2_KEY_DOT, PS2CTRL_GRAPH, KEYMAP_STANDARD, MZ5665_ALL, 0x88, 0x00, }, // GRPH+.
{ PS2_KEY_DIV, PS2CTRL_GRAPH, KEYMAP_STANDARD, MZ5665_ALL, 0xFE, 0x00, }, // GRPH+/
{ PS2_KEY_MINUS, PS2CTRL_GRAPH, KEYMAP_STANDARD, MZ5665_ALL, 0x8C, 0x00, }, // GRPH+-
{ PS2_KEY_APOS, PS2CTRL_GRAPH, KEYMAP_STANDARD, MZ5665_ALL, 0x8A, 0x00, }, // GRPH+'
{ PS2_KEY_OPEN_SQ, PS2CTRL_GRAPH, KEYMAP_STANDARD, MZ5665_ALL, 0xFC, 0x00, }, // GRPH+[
{ PS2_KEY_CLOSE_SQ, PS2CTRL_GRAPH, KEYMAP_STANDARD, MZ5665_ALL, 0xE8, 0x00, }, // GRPH+]
{ PS2_KEY_BACK, PS2CTRL_GRAPH, KEYMAP_STANDARD, MZ5665_ALL, 0x90, 0x00, }, // GRPH+Backslash
{ PS2_KEY_KP0, PS2CTRL_GRAPH, KEYMAP_STANDARD, MZ5665_ALL, 0x8F, 0x00, }, // GRPH+Keypad 0
{ PS2_KEY_KP1, PS2CTRL_GRAPH, KEYMAP_STANDARD, MZ5665_ALL, 0x99, 0x00, }, // GRPH+Keypad 1
{ PS2_KEY_KP2, PS2CTRL_GRAPH, KEYMAP_STANDARD, MZ5665_ALL, 0x92, 0x00, }, // GRPH+Keypad 2
{ PS2_KEY_KP3, PS2CTRL_GRAPH, KEYMAP_STANDARD, MZ5665_ALL, 0x98, 0x00, }, // GRPH+Keypad 3
{ PS2_KEY_KP4, PS2CTRL_GRAPH, KEYMAP_STANDARD, MZ5665_ALL, 0x95, 0x00, }, // GRPH+Keypad 4
{ PS2_KEY_KP5, PS2CTRL_GRAPH, KEYMAP_STANDARD, MZ5665_ALL, 0x96, 0x00, }, // GRPH+Keypad 5
{ PS2_KEY_KP6, PS2CTRL_GRAPH, KEYMAP_STANDARD, MZ5665_ALL, 0x94, 0x00, }, // GRPH+Keypad 6
{ PS2_KEY_KP7, PS2CTRL_GRAPH, KEYMAP_STANDARD, MZ5665_ALL, 0x9A, 0x00, }, // GRPH+Keypad 7
{ PS2_KEY_KP8, PS2CTRL_GRAPH, KEYMAP_STANDARD, MZ5665_ALL, 0x93, 0x00, }, // GRPH+Keypad 8
{ PS2_KEY_KP9, PS2CTRL_GRAPH, KEYMAP_STANDARD, MZ5665_ALL, 0x97, 0x00, }, // GRPH+Keypad 9
{ PS2_KEY_KP_DOT, PS2CTRL_GRAPH, KEYMAP_STANDARD, MZ5665_ALL, 0x91, 0x00, }, // GRPH+Keypad Full stop .
{ PS2_KEY_KP_PLUS, PS2CTRL_GRAPH, KEYMAP_STANDARD, MZ5665_ALL, 0x9D, 0x00, }, // GRPH+Keypad Plus +
{ PS2_KEY_KP_MINUS, PS2CTRL_GRAPH, KEYMAP_STANDARD, MZ5665_ALL, 0x9C, 0x00, }, // GRPH+Keypad Minus -
{ PS2_KEY_KP_TIMES, PS2CTRL_GRAPH, KEYMAP_STANDARD, MZ5665_ALL, 0x9B, 0x00, }, // GRPH+Keypad Times *
{ PS2_KEY_KP_DIV, PS2CTRL_GRAPH, KEYMAP_STANDARD, MZ5665_ALL, 0x9E, 0x00, }, // GRPH+Keypad Divide /
{ PS2_KEY_KP_ENTER, PS2CTRL_GRAPH, KEYMAP_STANDARD, MZ5665_ALL, 0x90, 0x00, }, // GRPH+Keypad Ebter /
// KANA (Alt)
//PS2 Code PS2 Ctrl (Flags to Match) Keyboard Model Machine MZ5665 Data MZ5665 Ctrl (Flags to Set).
{ PS2_KEY_0, PS2CTRL_KANA | PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ5665_ALL, 0xA6, 0x00, }, // KANA+SHIFT+0
{ PS2_KEY_0, PS2CTRL_KANA, KEYMAP_STANDARD, MZ5665_ALL, 0xDC, 0x00, }, // KANA+0
{ PS2_KEY_1, PS2CTRL_KANA, KEYMAP_STANDARD, MZ5665_ALL, 0xC7, 0x00, }, // KANA+1
{ PS2_KEY_2, PS2CTRL_KANA, KEYMAP_STANDARD, MZ5665_ALL, 0xCC, 0x00, }, // KANA+2
{ PS2_KEY_3, PS2CTRL_KANA | PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ5665_ALL, 0xA7, 0x00, }, // KANA+SHIFT+3
{ PS2_KEY_3, PS2CTRL_KANA, KEYMAP_STANDARD, MZ5665_ALL, 0xB1, 0x00, }, // KANA+3
{ PS2_KEY_4, PS2CTRL_KANA | PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ5665_ALL, 0xA9, 0x00, }, // KANA+SHIFT+4
{ PS2_KEY_4, PS2CTRL_KANA, KEYMAP_STANDARD, MZ5665_ALL, 0xB3, 0x00, }, // KANA+4
{ PS2_KEY_5, PS2CTRL_KANA | PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ5665_ALL, 0xAA, 0x00, }, // KANA+SHIFT+5
{ PS2_KEY_5, PS2CTRL_KANA, KEYMAP_STANDARD, MZ5665_ALL, 0xB4, 0x00, }, // KANA+5
{ PS2_KEY_6, PS2CTRL_KANA | PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ5665_ALL, 0xAB, 0x00, }, // KANA+SHIFT+6
{ PS2_KEY_6, PS2CTRL_KANA, KEYMAP_STANDARD, MZ5665_ALL, 0xB5, 0x00, }, // KANA+6
{ PS2_KEY_7, PS2CTRL_KANA | PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ5665_ALL, 0xAC, 0x00, }, // KANA+SHIFT+7
{ PS2_KEY_7, PS2CTRL_KANA, KEYMAP_STANDARD, MZ5665_ALL, 0xD4, 0x00, }, // KANA+7
{ PS2_KEY_8, PS2CTRL_KANA | PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ5665_ALL, 0xAD, 0x00, }, // KANA+SHIFT+8
{ PS2_KEY_8, PS2CTRL_KANA, KEYMAP_STANDARD, MZ5665_ALL, 0xD5, 0x00, }, // KANA+8
{ PS2_KEY_9, PS2CTRL_KANA | PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ5665_ALL, 0xAE, 0x00, }, // KANA+SHIFT+9
{ PS2_KEY_9, PS2CTRL_KANA, KEYMAP_STANDARD, MZ5665_ALL, 0xD6, 0x00, }, // KANA+9
{ PS2_KEY_A, PS2CTRL_KANA, KEYMAP_STANDARD, MZ5665_ALL, 0xC1, 0x00, }, // KANA+A
{ PS2_KEY_B, PS2CTRL_KANA, KEYMAP_STANDARD, MZ5665_ALL, 0xBA, 0x00, }, // KANA+B
{ PS2_KEY_C, PS2CTRL_KANA, KEYMAP_STANDARD, MZ5665_ALL, 0xBF, 0x00, }, // KANA+C
{ PS2_KEY_D, PS2CTRL_KANA, KEYMAP_STANDARD, MZ5665_ALL, 0xBC, 0x00, }, // KANA+D
{ PS2_KEY_E, PS2CTRL_KANA | PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ5665_ALL, 0xA8, 0x00, }, // KANA+SHIFT+E
{ PS2_KEY_E, PS2CTRL_KANA, KEYMAP_STANDARD, MZ5665_ALL, 0xB2, 0x00, }, // KANA+E
{ PS2_KEY_F, PS2CTRL_KANA, KEYMAP_STANDARD, MZ5665_ALL, 0xCA, 0x00, }, // KANA+F
{ PS2_KEY_G, PS2CTRL_KANA, KEYMAP_STANDARD, MZ5665_ALL, 0xB7, 0x00, }, // KANA+G
{ PS2_KEY_H, PS2CTRL_KANA, KEYMAP_STANDARD, MZ5665_ALL, 0xB8, 0x00, }, // KANA+H
{ PS2_KEY_I, PS2CTRL_KANA, KEYMAP_STANDARD, MZ5665_ALL, 0xC6, 0x00, }, // KANA+I
{ PS2_KEY_J, PS2CTRL_KANA, KEYMAP_STANDARD, MZ5665_ALL, 0xCF, 0x00, }, // KANA+J
{ PS2_KEY_K, PS2CTRL_KANA, KEYMAP_STANDARD, MZ5665_ALL, 0xC9, 0x00, }, // KANA+K
{ PS2_KEY_L, PS2CTRL_KANA, KEYMAP_STANDARD, MZ5665_ALL, 0xD8, 0x00, }, // KANA+L
{ PS2_KEY_M, PS2CTRL_KANA, KEYMAP_STANDARD, MZ5665_ALL, 0xD3, 0x00, }, // KANA+M
{ PS2_KEY_N, PS2CTRL_KANA, KEYMAP_STANDARD, MZ5665_ALL, 0xD0, 0x00, }, // KANA+N
{ PS2_KEY_O, PS2CTRL_KANA, KEYMAP_STANDARD, MZ5665_ALL, 0xD7, 0x00, }, // KANA+O
{ PS2_KEY_P, PS2CTRL_KANA, KEYMAP_STANDARD, MZ5665_ALL, 0xBE, 0x00, }, // KANA+P
{ PS2_KEY_Q, PS2CTRL_KANA, KEYMAP_STANDARD, MZ5665_ALL, 0xC0, 0x00, }, // KANA+Q
{ PS2_KEY_R, PS2CTRL_KANA, KEYMAP_STANDARD, MZ5665_ALL, 0xBD, 0x00, }, // KANA+R
{ PS2_KEY_S, PS2CTRL_KANA, KEYMAP_STANDARD, MZ5665_ALL, 0xC4, 0x00, }, // KANA+S
{ PS2_KEY_T, PS2CTRL_KANA, KEYMAP_STANDARD, MZ5665_ALL, 0xB6, 0x00, }, // KANA+T
{ PS2_KEY_U, PS2CTRL_KANA, KEYMAP_STANDARD, MZ5665_ALL, 0xC5, 0x00, }, // KANA+U
{ PS2_KEY_V, PS2CTRL_KANA, KEYMAP_STANDARD, MZ5665_ALL, 0xCB, 0x00, }, // KANA+V
{ PS2_KEY_W, PS2CTRL_KANA, KEYMAP_STANDARD, MZ5665_ALL, 0xC3, 0x00, }, // KANA+W
{ PS2_KEY_X, PS2CTRL_KANA, KEYMAP_STANDARD, MZ5665_ALL, 0xBB, 0x00, }, // KANA+X
{ PS2_KEY_Y, PS2CTRL_KANA, KEYMAP_STANDARD, MZ5665_ALL, 0xDD, 0x00, }, // KANA+Y
{ PS2_KEY_Z, PS2CTRL_KANA | PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ5665_ALL, 0xAF, 0x00, }, // KANA+SHIFT+Z
{ PS2_KEY_Z, PS2CTRL_KANA, KEYMAP_STANDARD, MZ5665_ALL, 0xC2, 0x00, }, // KANA+Z
{ PS2_KEY_COMMA, PS2CTRL_KANA | PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ5665_ALL, 0xA4, 0x00, }, // KANA+SHIFT+,
{ PS2_KEY_COMMA, PS2CTRL_KANA, KEYMAP_STANDARD, MZ5665_ALL, 0xC8, 0x00, }, // KANA+,
{ PS2_KEY_SEMI, PS2CTRL_KANA, KEYMAP_STANDARD, MZ5665_ALL, 0xDA, 0x00, }, // KANA+;
{ PS2_KEY_DOT, PS2CTRL_KANA | PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ5665_ALL, 0xA1, 0x00, }, // KANA+SHIFT+.
{ PS2_KEY_DOT, PS2CTRL_KANA, KEYMAP_STANDARD, MZ5665_ALL, 0xD9, 0x00, }, // KANA+.
{ PS2_KEY_DIV, PS2CTRL_KANA | PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ5665_ALL, 0xA5, 0x00, }, // KANA+SHIFT+/
{ PS2_KEY_DIV, PS2CTRL_KANA, KEYMAP_STANDARD, MZ5665_ALL, 0xD2, 0x00, }, // KANA+/
{ PS2_KEY_MINUS, PS2CTRL_KANA, KEYMAP_STANDARD, MZ5665_ALL, 0xCE, 0x00, }, // KANA+-
{ PS2_KEY_APOS, PS2CTRL_KANA, KEYMAP_STANDARD, MZ5665_ALL, 0xDE, 0x00, }, // KANA+'
{ PS2_KEY_OPEN_SQ, PS2CTRL_KANA | PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ5665_ALL, 0xA2, 0x00, }, // KANA+SHIFT+[
{ PS2_KEY_OPEN_SQ, PS2CTRL_KANA, KEYMAP_STANDARD, MZ5665_ALL, 0xDF, 0x00, }, // KANA+[
{ PS2_KEY_CLOSE_SQ, PS2CTRL_KANA | PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ5665_ALL, 0xA3, 0x00, }, // KANA+SHIFT+]
{ PS2_KEY_CLOSE_SQ, PS2CTRL_KANA, KEYMAP_STANDARD, MZ5665_ALL, 0xD1, 0x00, }, // KANA+]
{ PS2_KEY_BACK, PS2CTRL_KANA, KEYMAP_STANDARD, MZ5665_ALL, 0xDB, 0x00, }, // KANA+Backslash
{ PS2_KEY_BS, PS2CTRL_KANA | PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ5665_ALL, 0x12, 0x00, }, // KANA+SHIFT+Backspace
// Keypad.
{ PS2_KEY_KP0, PS2CTRL_NONE, KEYMAP_STANDARD, MZ5665_ALL, '0', 0x00, }, // Keypad 0
{ PS2_KEY_KP1, PS2CTRL_NONE, KEYMAP_STANDARD, MZ5665_ALL, '1', 0x00, }, // Keypad 1
{ PS2_KEY_KP2, PS2CTRL_NONE, KEYMAP_STANDARD, MZ5665_ALL, '2', 0x00, }, // Keypad 2
{ PS2_KEY_KP3, PS2CTRL_NONE, KEYMAP_STANDARD, MZ5665_ALL, '3', 0x00, }, // Keypad 3
{ PS2_KEY_KP4, PS2CTRL_NONE, KEYMAP_STANDARD, MZ5665_ALL, '4', 0x00, }, // Keypad 4
{ PS2_KEY_KP5, PS2CTRL_NONE, KEYMAP_STANDARD, MZ5665_ALL, '5', 0x00, }, // Keypad 5
{ PS2_KEY_KP6, PS2CTRL_NONE, KEYMAP_STANDARD, MZ5665_ALL, '6', 0x00, }, // Keypad 6
{ PS2_KEY_KP7, PS2CTRL_NONE, KEYMAP_STANDARD, MZ5665_ALL, '7', 0x00, }, // Keypad 7
{ PS2_KEY_KP8, PS2CTRL_NONE, KEYMAP_STANDARD, MZ5665_ALL, '8', 0x00, }, // Keypad 8
{ PS2_KEY_KP9, PS2CTRL_NONE, KEYMAP_STANDARD, MZ5665_ALL, '9', 0x00, }, // Keypad 9
{ PS2_KEY_KP_COMMA, PS2CTRL_NONE, KEYMAP_STANDARD, MZ5665_ALL, ',', 0x00, }, // Keypad Comma ,
{ PS2_KEY_KP_DOT, PS2CTRL_NONE, KEYMAP_STANDARD, MZ5665_ALL, '.', 0x00, }, // Keypad Full stop .
{ PS2_KEY_KP_PLUS, PS2CTRL_NONE, KEYMAP_STANDARD, MZ5665_ALL, '+', 0x00, }, // Keypad Plus +
{ PS2_KEY_KP_MINUS, PS2CTRL_NONE, KEYMAP_STANDARD, MZ5665_ALL, '-', 0x00, }, // Keypad Minus -
{ PS2_KEY_KP_TIMES, PS2CTRL_NONE, KEYMAP_STANDARD, MZ5665_ALL, '*', 0x00, }, // Keypad Times *
{ PS2_KEY_KP_DIV, PS2CTRL_NONE, KEYMAP_STANDARD, MZ5665_ALL, '/', 0x00, }, // Keypad Divide /
{ PS2_KEY_KP_ENTER, PS2CTRL_NONE, KEYMAP_STANDARD, MZ5665_ALL, 0x0D, 0x00, }, // Keypad Ebter /
//PS2 Code PS2 Ctrl (Flags to Match) Keyboard Model Machine MZ5665 Data MZ5665 Ctrl (Flags to Set).
// Special keys.
{ PS2_KEY_PRTSCR, PS2CTRL_FUNC, KEYMAP_STANDARD, MZ5665_ALL, 0x00, 0x00, }, // ARGO KEY
{ PS2_KEY_PAUSE, PS2CTRL_NONE, KEYMAP_STANDARD, MZ5665_ALL, 0x03, 0x00, }, // BREAK KEY
{ PS2_KEY_L_GUI, PS2CTRL_FUNC | PS2CTRL_GUI, KEYMAP_STANDARD, MZ5665_ALL, 0x00, 0x00, }, // GRAPH KEY
//{ PS2_KEY_L_ALT, PS2CTRL_FUNC | PS2CTRL_KANA, KEYMAP_STANDARD, MZ5665_ALL, 0x00, 0x00, }, // KJ1 Sentence
//{ PS2_KEY_R_ALT, PS2CTRL_FUNC | PS2CTRL_GRAPH, KEYMAP_STANDARD, MZ5665_ALL, 0x00, 0x00, }, // KJ2 Transform
{ PS2_KEY_R_GUI, PS2CTRL_FUNC | PS2CTRL_GUI, KEYMAP_STANDARD, MZ5665_ALL, 0x00, 0x00, }, // KANA KEY
{ PS2_KEY_MENU, PS2CTRL_FUNC | PS2CTRL_GUI, KEYMAP_STANDARD, MZ5665_ALL, 0x00, 0x00, }, // Not assigned.
// Modifiers are last, only being selected if an earlier match isnt made.
{ PS2_KEY_L_SHIFT, PS2CTRL_NONE, KEYMAP_STANDARD, MZ5665_ALL, 0x00, 0x00, },
{ PS2_KEY_R_SHIFT, PS2CTRL_NONE, KEYMAP_STANDARD, MZ5665_ALL, 0x00, 0x00, },
{ PS2_KEY_L_CTRL, PS2CTRL_NONE, KEYMAP_STANDARD, MZ5665_ALL, 0x00, 0x00, },
{ PS2_KEY_R_CTRL, PS2CTRL_NONE, KEYMAP_STANDARD, MZ5665_ALL, 0x00, 0x00, }, // Map to Control
{ 0, PS2CTRL_NONE, KEYMAP_STANDARD, MZ5665_ALL, 0x00, 0x00, },
}};
};
#endif // MZ5665_H

View File

@@ -1 +0,0 @@
../../../sharpkey/main/include/Mouse.h

151
main/include/Mouse.h Normal file
View File

@@ -0,0 +1,151 @@
/////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Name: Mouse.h
// Created: Mar 2022
// Version: v1.0
// Author(s): Philip Smart
// Description: Header for the PS/2 Mouse to Sharp Host interface logic.
// Credits:
// Copyright: (c) 2019-2022 Philip Smart <philip.smart@net2net.org>
//
// History: Mar 2022 - Initial write.
// v1.01 May 2022 - Initial release version.
// v1.02 Jun 2022 - Updates to reflect changes realised in other modules due to addition of
// bluetooth and suspend logic due to NVS issues using both cores.
// Updates to reflect moving functionality into the HID and to support
// Bluetooth as a primary mouse or secondary mouse.
//
// Notes: See Makefile to enable/disable conditional components
//
/////////////////////////////////////////////////////////////////////////////////////////////////////////
// This source file is free software: you can redistribute it and#or modify
// it under the terms of the GNU General Public License as published
// by the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This source file is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
/////////////////////////////////////////////////////////////////////////////////////////////////////////
#ifndef MOUSE_H
#define MOUSE_H
// Include the specification class.
#include "KeyInterface.h"
#include "NVS.h"
#include "HID.h"
// NB: Macros definitions put inside class for clarity, they are still global scope.
// Encapsulate the Mouse interface.
class Mouse : public KeyInterface {
// Macros.
//
#define NUMELEM(a) (sizeof(a)/sizeof(a[0]))
// Constants.
#define MOUSEIF_VERSION 1.02
#define MAX_MOUSE_XMIT_KEY_BUF 128
#define BITBANG_UART_BIT_TIME 208UL
public:
// Prototypes.
Mouse(void);
Mouse(uint32_t ifMode, NVS *hdlNVS, LED *hdlLED, HID *hdlHID);
Mouse(uint32_t ifMode, NVS *hdlNVS, LED *hdlLED, HID *hdlHID, bool secondaryIf);
Mouse(NVS *hdlNVShdlHID, HID *hdlHID);
~Mouse(void);
void getMouseConfigTypes(std::vector<std::string>& typeList);
bool getMouseSelectList(std::vector<std::pair<std::string, int>>& selectList, std::string option);
bool setMouseConfigValue(std::string paramName, std::string paramValue);
void mouseReceiveData(HID::t_mouseMessageElement mouseMessage);
bool persistConfig(void);
// Method to return the class version number.
float version(void)
{
return(MOUSEIF_VERSION);
}
protected:
private:
// Prototypes.
IRAM_ATTR static void hostInterface( void * pvParameters );
void init(uint32_t ifMode, NVS *hdlNVS, LED *hdlLED, HID *hdlHID);
void init(NVS *hdlNVS, HID *hdlHID);
// Structure to maintain mouse interface configuration data. This data is persisted through powercycles as needed.
typedef struct {
struct {
// PS/2 Mouse data Adjustment and filtering options.
//
enum HID::HID_MOUSE_RESOLUTION resolution;
enum HID::HID_MOUSE_SCALING scaling;
enum HID::HID_MOUSE_SAMPLING sampleRate;
} mouse;
struct {
// Host data for adjustment and configuration.
enum HID::HID_MOUSE_HOST_SCALING scaling;
} host;
struct {
} params;
} t_mouseConfig;
// Configuration data.
t_mouseConfig mouseConfig;
// Structure to manage the Mouse control variables signifying the state of the Mouse.
typedef struct {
} t_msControl;
// Mouse Control variables.
volatile t_msControl msCtrl;
// Structure to manage the Sharp host control variables which define control and data mapping of the host interface and data sent.
//
typedef struct {
#ifdef CONFIG_HOST_HW_UART
int uartNum;
int uartBufferSize;
int uartQueueSize;
#endif
bool secondaryIf; // Mouse runs in tandem with a keyboard interface.
// Data adjustment and processing options applied to the PS/2 data.
bool updated;
} t_hostControl;
// Host Control variables.
volatile t_hostControl hostControl;
// PS/2 to HOST serialiser buffer item.
typedef struct {
uint8_t xPos;
uint8_t yPos;
uint8_t status;
uint8_t wheel;
bool valid;
} t_xmitMessage;
// Create an object for storing the data to be sent to the Host. This data has already been converted and adjusted from the incoming PS/2 message.
t_xmitMessage xmitMsg;
// Thread handles - one per function, ie. ps/2 interface, host target interface, wifi interface.
TaskHandle_t TaskHostIF = NULL;
TaskHandle_t TaskHIDIF = NULL;
// Spin lock mutex to hold a coresied to an uninterruptable method. This only works on dual core ESP32's.
portMUX_TYPE x1Mutex;
};
#endif // MOUSE_H

View File

@@ -1 +0,0 @@
../../../sharpkey/main/include/NVS.h

162
main/include/NVS.h Normal file
View File

@@ -0,0 +1,162 @@
/////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Name: NVS.h
// Created: Mar 2022
// Version: v1.0
// Author(s): Philip Smart
// Description: Class definition to encapsulate the Espressif Non Volatile Storage into a thread safe
// object, The underlying API is supposed to be thread safe but experience has shown
// that two threads, each with there own handle can cause a lockup.
// Credits:
// Copyright: (c) 2019-2022 Philip Smart <philip.smart@net2net.org>
//
// History: Mar 2022 - Initial write.
// v1.01 May 2022 - Initial release version.
//
// Notes: See Makefile to enable/disable conditional components
//
/////////////////////////////////////////////////////////////////////////////////////////////////////////
// This source file is free software: you can redistribute it and#or modify
// it under the terms of the GNU General Public License as published
// by the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This source file is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
/////////////////////////////////////////////////////////////////////////////////////////////////////////
#ifndef NVS_H
#define NVS_H
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <iostream>
#include <vector>
#include <map>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/semphr.h"
#include "esp_log.h"
#include "esp_system.h"
#include "nvs_flash.h"
#include "nvs.h"
#include "soc/timer_group_struct.h"
#include "soc/timer_group_reg.h"
#include "driver/timer.h"
// NB: Macros definitions put inside class for clarity, they are still global scope.
// Define a virtual class which acts as the base and specification of all super classes forming host
// interface objects.
class NVS {
// Macros.
//
#define NUMELEM(a) (sizeof(a)/sizeof(a[0]))
// Constants.
#define NVS_VERSION 1.01
public:
// Prototypes.
NVS(void);
NVS(std::string keyName);
virtual ~NVS(void) {};
void eraseAll(void);
void init(void);
bool takeMutex(void);
void giveMutex(void);
// Persistence.
bool open(std::string keyName);
bool persistData(const char *key, void *pData, uint32_t size);
bool retrieveData(const char *key, void *pData, uint32_t size);
bool commitData(void);
// Helper method to identify the sub class, this is used in non volatile key management.
// Warning: This method wont work if optimisation for size is enabled on the compiler.
const char *getClassName(const std::string& prettyFunction)
{
// First find the CLASS :: METHOD seperation.
size_t colons = prettyFunction.find("::");
// None, then this is not a class.
if (colons == std::string::npos)
return "::";
// Split out the class name.
size_t begin = prettyFunction.substr(0,colons).rfind(" ") + 1;
size_t end = colons - begin;
// Return the name.
return(prettyFunction.substr(begin,end).c_str());
}
// Helper method to change a file extension.
void replaceExt(std::string& fileName, const std::string& newExt)
{
// Locals.
std::string::size_type extPos = fileName.rfind('.', fileName.length());
if(extPos != std::string::npos)
{
fileName.replace(extPos+1, newExt.length(), newExt);
}
return;
}
// Template to aid in conversion of an enum to integer.
template <typename E> constexpr typename std::underlying_type<E>::type to_underlying(E e) noexcept
{
return static_cast<typename std::underlying_type<E>::type>(e);
}
// Method to return the class version number.
virtual float version(void)
{
return(NVS_VERSION);
}
// Method to return the name of the class.
virtual std::string ifName(void)
{
return(nvsCtrl.nvsClassName);
}
// Method to return the name of the nvs key.
virtual std::string keyName(void)
{
return(nvsCtrl.nvsKeyName);
}
protected:
private:
// Structure to maintain an active setting for the LED. The LED control thread uses these values to effect the required lighting of the LED.
typedef struct {
// Handle to the persistent storage api.
nvs_handle_t nvsHandle;
// Name of the class for this instantiation.
std::string nvsClassName;
// Name of the key under which NVS was opened.
std::string nvsKeyName;
// Mutex to block access to limit one thread at a time.
SemaphoreHandle_t mutexInternal;
} t_nvsControl;
// Var to store all NVS control variables.
t_nvsControl nvsCtrl;
};
#endif // NVS_H

View File

@@ -1 +0,0 @@
../../../sharpkey/main/include/PC9801.h

529
main/include/PC9801.h Normal file
View File

@@ -0,0 +1,529 @@
/////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Name: PC9801.h
// Created: Apr 2022
// Version: v1.0
// Author(s): Philip Smart
// Description: Header for the NEC PC-9801 to HID (PS/2, Bluetooth) interface logic.
// Credits:
// Copyright: (c) 2019-2022 Philip Smart <philip.smart@net2net.org>
//
// History: Apr 2022 - Initial write.
// v1.01 Jun 2022 - Updates to reflect changes realised in other modules due to addition of
// bluetooth and suspend logic due to NVS issues using both cores.
//
//
// Notes: See Makefile to enable/disable conditional components
//
/////////////////////////////////////////////////////////////////////////////////////////////////////////
// This source file is free software: you can redistribute it and#or modify
// it under the terms of the GNU General Public License as published
// by the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This source file is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
/////////////////////////////////////////////////////////////////////////////////////////////////////////
#ifndef PC9801_H
#define PC9801_H
// Include the specification class.
#include "KeyInterface.h"
#include "NVS.h"
#include "LED.h"
#include "HID.h"
#include <vector>
#include <map>
// NB: Macros definitions put inside class for clarity, they are still global scope.
// Encapsulate the NEC PC-9801 interface.
class PC9801 : public KeyInterface {
// Macros.
//
#define NUMELEM(a) (sizeof(a)/sizeof(a[0]))
// Constants.
#define PC9801IF_VERSION 1.00
#define PC9801IF_KEYMAP_FILE "PC9801_KeyMap.BIN"
#define MAX_PC9801_XMIT_KEY_BUF 16
#define MAX_PC9801_RCV_KEY_BUF 16
// NEC PC-9801 Key control bit mask.
#define PC9801_CTRL_SHIFT ((unsigned char) (1 << 5))
#define PC9801_CTRL_RELEASESHIFT ((unsigned char) (1 << 4))
#define PC9801_CTRL_CTRL ((unsigned char) (1 << 3))
#define PC9801_CTRL_GRAPH ((unsigned char) (1 << 2))
#define PC9801_CTRL_CAPS ((unsigned char) (1 << 1))
#define PC9801_CTRL_KANA ((unsigned char) (1 << 0))
#define PC9801_CTRL_NONE 0x00
// Special key definition.
// #define PC9801_KEY_UP 0x1E // ↑
// #define PC9801_KEY_DOWN 0x1F // ↓
// #define PC9801_KEY_LEFT 0x1D // ←
// #define PC9801_KEY_RIGHT 0x1C // → →
// #define PC9801_KEY_INS 0x12 // INS
// #define PC9801_KEY_DEL 0x08 // DEL
// #define PC9801_KEY_CLR 0x0C // CLR
// #define PC9801_KEY_HOME 0x0B // HOME
// PS2 Flag definitions.
#define PS2CTRL_NONE 0x00 // No keys active = 0
#define PS2CTRL_SHIFT 0x01 // Shfit Key active = 1
#define PS2CTRL_CTRL 0x02 // Ctrl Key active = 1
#define PS2CTRL_CAPS 0x04 // CAPS active = 1
#define PS2CTRL_KANA 0x08 // KANA active = 1
#define PS2CTRL_GRAPH 0x10 // GRAPH active = 1
#define PS2CTRL_GUI 0x20 // GUI Key active = 1
#define PS2CTRL_FUNC 0x40 // Special Function Keys active = 1
#define PS2CTRL_BREAK 0x80 // BREAK Key active = 1
#define PS2CTRL_EXACT 0x80 // EXACT Match active = 1
// The initial mapping is made inside the PS2KeyAdvanced class from Scan Code Set 2 to ASCII
// for a selected keyboard. Special functions are detected and combined inside this module
// before mapping with the table below to extract the PC-9801 key code and control data.
// ie. PS/2 Scan Code -> ASCII + Flags -> PC-9801 Key Code + Ctrl Data
#define PS2TBL_PC9801_MAXCOLS 6
#define PS2TBL_PC9801_MAXROWS 131
// The initial mapping is made inside the PS2KeyAdvanced class from Scan Code Set 2 to ASCII
// for a selected keyboard. Special functions are detected and combined inside this module
// before mapping with the table below to extract the NEC PC-9801 key code and control data.
// ie. PS/2 Scan Code -> ASCII + Flags -> NEC PC-9801 Key Code + Ctrl Data
// Keyboard mapping table column names.
#define PS2TBL_PS2KEYCODE_NAME "PS/2 KeyCode"
#define PS2TBL_PS2CTRL_NAME "PS/2 Control Key"
#define PS2TBL_KEYBOARDMODEL_NAME "For Keyboard"
#define PS2TBL_MACHINE_NAME "For Host Model"
#define PS2TBL_PC9801_KEYCODE_NAME "PC9801 KeyCode"
#define PS2TBL_PC9801__CTRL_NAME "PC9801 Control Key"
// Keyboard mapping table column types.
#define PS2TBL_PS2KEYCODE_TYPE "hex"
#define PS2TBL_PS2CTRL_TYPE "custom_cbp_ps2ctrl"
#define PS2TBL_KEYBOARDMODEL_TYPE "custom_cbp_keybmodel"
#define PS2TBL_MACHINE_TYPE "custom_cbp_machine"
#define PS2TBL_PC9801_KEYCODE_TYPE "hex"
#define PS2TBL_PC9801_CTRL_TYPE "custom_cbn_x1ctrl"
// Keyboard mapping table select list for PS2CTRL.
#define PS2TBL_PS2CTRL_SEL_NONE "NONE"
#define PS2TBL_PS2CTRL_SEL_SHIFT "SHIFT"
#define PS2TBL_PS2CTRL_SEL_CTRL "CTRL"
#define PS2TBL_PS2CTRL_SEL_CAPS "CAPS"
#define PS2TBL_PS2CTRL_SEL_KANA "KANA"
#define PS2TBL_PS2CTRL_SEL_GRAPH "GRAPH"
#define PS2TBL_PS2CTRL_SEL_GUI "GUI"
#define PS2TBL_PS2CTRL_SEL_FUNC "FUNC"
#define PS2TBL_PS2CTRL_SEL_EXACT "EXACT"
// Keyboard mapping table select list for target machine.
#define PC9801_SEL_ALL "ALL"
#define PC9801_SEL_ORIG "ORIGINAL"
// Keyboard mapping table select list for Model of keyboard.
#define KEYMAP_SEL_STANDARD "ALL"
#define KEYMAP_SEL_UK_WYSE_KB3926 "UK_WYSE_KB3926"
#define KEYMAP_SEL_JAPAN_OADG109 "JAPAN_OADG109"
#define KEYMAP_SEL_JAPAN_SANWA_SKBL1 "JAPAN_SANWA_SKBL1"
#define KEYMAP_SEL_NOT_ASSIGNED_4 "KEYBOARD_4"
#define KEYMAP_SEL_NOT_ASSIGNED_5 "KEYBOARD_5"
#define KEYMAP_SEL_NOT_ASSIGNED_6 "KEYBOARD_6"
#define KEYMAP_SEL_UK_PERIBOARD_810 "UK_PERIBOARD_810"
#define KEYMAP_SEL_UK_OMOTON_K8508 "UK_OMOTON_K8508"
// Keyboard mapping table select list for PC9801 Control codes.
#define PC9801_CTRL_SEL_GRAPH "GRAPH"
#define PC9801_CTRL_SEL_CAPS "CAPS"
#define PC9801_CTRL_SEL_KANA "KANA"
#define PC9801_CTRL_SEL_SHIFT "SHIFT"
#define PC9801_CTRL_SEL_CTRL "CTRL"
// The NEC PC-9801 Series was released over a number of years and each iteration added changes/updates. In order to cater for differences, it is possible to assign a key mapping
// to a specific machine type(s) or all of the series by adding the flags below into the mapping table.
#define PC9801_ALL 0xFF
// Keyboard models. The base on which this interface was created was a Wyse KB3926 PS/2 Keyboard and this is deemed STANDARD. Other models need to insert difference maps
// prior to the STANDARD entry along with the keyboard model so that it is processed first thus allowing differing keyboards with different maps.
#define KEYMAP_STANDARD 0xFF
#define KEYMAP_UK_WYSE_KB3926 0x01
#define KEYMAP_JAPAN_OADG109 0x02
#define KEYMAP_JAPAN_SANWA_SKBL1 0x04
#define KEYMAP_NOT_ASSIGNED_4 0x08
#define KEYMAP_NOT_ASSIGNED_5 0x10
#define KEYMAP_NOT_ASSIGNED_6 0x20
#define KEYMAP_UK_PERIBOARD_810 0x40
#define KEYMAP_UK_OMOTON_K8508 0x80
// PC-9801 Scan codes - PS2 codes along with function keys (SHIFT, CTRL etc) are mapped to the X68000 scan codes below.
#define PC9801_KEY_ESC 0x00
#define PC9801_KEY_0 0x0A
#define PC9801_KEY_1 0x01
#define PC9801_KEY_2 0x02
#define PC9801_KEY_3 0x03
#define PC9801_KEY_4 0x04
#define PC9801_KEY_5 0x05
#define PC9801_KEY_6 0x06
#define PC9801_KEY_7 0x07
#define PC9801_KEY_8 0x08
#define PC9801_KEY_9 0x09
#define PC9801_KEY_A 0x1D
#define PC9801_KEY_B 0x2D
#define PC9801_KEY_C 0x2B
#define PC9801_KEY_D 0x1F
#define PC9801_KEY_E 0x12
#define PC9801_KEY_F 0x20
#define PC9801_KEY_G 0x21
#define PC9801_KEY_H 0x22
#define PC9801_KEY_I 0x17
#define PC9801_KEY_J 0x23
#define PC9801_KEY_K 0x24
#define PC9801_KEY_L 0x25
#define PC9801_KEY_M 0x2F
#define PC9801_KEY_N 0x2E
#define PC9801_KEY_O 0x18
#define PC9801_KEY_P 0x19
#define PC9801_KEY_Q 0x10
#define PC9801_KEY_R 0x13
#define PC9801_KEY_S 0x1E
#define PC9801_KEY_T 0x14
#define PC9801_KEY_U 0x16
#define PC9801_KEY_V 0x2C
#define PC9801_KEY_W 0x11
#define PC9801_KEY_X 0x2A
#define PC9801_KEY_Y 0x15
#define PC9801_KEY_Z 0x29
#define PC9801_KEY_AT 0x1A // Requires SHIFT
#define PC9801_KEY_MINUS 0x0B
#define PC9801_KEY_CIRCUMFLEX 0x0C
#define PC9801_KEY_YEN 0x0D
#define PC9801_KEY_BS 0x0E
#define PC9801_KEY_TAB 0x0F
#define PC9801_KEY_OPEN_SQ 0x1A
#define PC9801_KEY_CLOSE_SQ 0x1B
#define PC9801_KEY_RETURN 0x1C
#define PC9801_KEY_SEMI 0x26
#define PC9801_KEY_COLON 0x27
#define PC9801_KEY_COMMA 0x30
#define PC9801_KEY_DOT 0x31
#define PC9801_KEY_DIV 0x32
#define PC9801_KEY_UNDERLINE 0x0D // Requires SHIFT
#define PC9801_KEY_SPACE 0x34
#define PC9801_KEY_HOME 0x3E
#define PC9801_KEY_ROLLUP 0x36
#define PC9801_KEY_ROLLDN 0x37
#define PC9801_KEY_UNDO 0x3 // Not known3
#define PC9801_KEY_L_ARROW 0x3B
#define PC9801_KEY_UP_ARROW 0x3A
#define PC9801_KEY_R_ARROW 0x3C
#define PC9801_KEY_DN_ARROW 0x3D
#define PC9801_KEY_CLR 0x3F // Not known
#define PC9801_KEY_KP0 0x4E
#define PC9801_KEY_KP1 0x4A
#define PC9801_KEY_KP2 0x4B
#define PC9801_KEY_KP3 0x4C
#define PC9801_KEY_KP4 0x46
#define PC9801_KEY_KP5 0x47
#define PC9801_KEY_KP6 0x48
#define PC9801_KEY_KP7 0x42
#define PC9801_KEY_KP8 0x43
#define PC9801_KEY_KP9 0x44
#define PC9801_KEY_KP_DIV 0x41
#define PC9801_KEY_KP_TIMES 0x45
#define PC9801_KEY_KP_MINUS 0x4D
#define PC9801_KEY_KP_PLUS 0x49
#define PC9801_KEY_KP_EQUAL 0x4D
#define PC9801_KEY_KP_ENTER 0x1C
#define PC9801_KEY_KP_COMMA 0x4F
#define PC9801_KEY_KP_DOT 0x50
#define PC9801_KEY_SYMBOL 0x52 // Not known
#define PC9801_KEY_HELP 0x3F
#define PC9801_KEY_CAPS 0x71
#define PC9801_KEY_INS 0x38
#define PC9801_KEY_DEL 0x39
#define PC9801_KEY_BREAK 0x60 // Stop
#define PC9801_KEY_COPY 0x61
#define PC9801_KEY_SHIFT 0x70
#define PC9801_KEY_R_SHIFT 0x7D
#define PC9801_KEY_CTRL 0x74
#define PC9801_KEY_GRAPH 0x73
#define PC9801_KEY_XFER 0x35
#define PC9801_KEY_NFER 0x51
#define PC9801_KEY_KATAKANA 0x72
#define PC9801_KEY_ROMAJI 0x33
#define PC9801_KEY_F1 0x62
#define PC9801_KEY_F2 0x63
#define PC9801_KEY_F3 0x64
#define PC9801_KEY_F4 0x65
#define PC9801_KEY_F5 0x66
#define PC9801_KEY_F6 0x67
#define PC9801_KEY_F7 0x68
#define PC9801_KEY_F8 0x69
#define PC9801_KEY_F9 0x6A
#define PC9801_KEY_F10 0x6B
#define PC9801_KEY_F11 0x52
#define PC9801_KEY_F12 0x53
#define PC9801_KEY_F13 0x54
#define PC9801_KEY_F14 0x55
#define PC9801_KEY_F15 0x56
#define PC9801_KEY_NULL 0xFF
public:
// Prototypes.
PC9801(void);
PC9801(uint32_t ifMode, NVS *hdlNVS, LED *hdlLED, HID *hdlHID, const char *fsPath);
PC9801(NVS *hdlNVS, HID *hdlHID, const char *fsPath);
~PC9801(void);
bool createKeyMapFile(std::fstream &outFile);
bool storeDataToKeyMapFile(std::fstream &outFile, char *data, int size);
bool storeDataToKeyMapFile(std::fstream & outFile, std::vector<uint32_t>& dataArray);
bool closeAndCommitKeyMapFile(std::fstream &outFile, bool cleanupOnly);
std::string getKeyMapFileName(void) { return(PC9801IF_KEYMAP_FILE); };
void getKeyMapHeaders(std::vector<std::string>& headerList);
void getKeyMapTypes(std::vector<std::string>& typeList);
bool getKeyMapSelectList(std::vector<std::pair<std::string, int>>& selectList, std::string option);
bool getKeyMapData(std::vector<uint32_t>& dataArray, int *row, bool start);
// Method to return the class version number.
float version(void)
{
return(PC9801IF_VERSION);
}
protected:
private:
// Prototypes.
IRAM_ATTR void pushKeyToQueue(uint32_t key);
IRAM_ATTR void pushHostCmdToQueue(uint8_t cmd);
IRAM_ATTR static void pcInterface( void * pvParameters );
IRAM_ATTR static void hidInterface( void * pvParameters );
void selectOption(uint8_t optionCode);
uint32_t mapKey(uint16_t scanCode);
bool loadKeyMap();
bool saveKeyMap(void);
void init(uint32_t ifMode, NVS *hdlNVS, LED *hdlLED, HID *hdlHID);
void init(NVS *hdlNVS, HID *hdlHID);
// Structure to encapsulate a single key map from PS/2 to NEC PC-9801
typedef struct {
uint8_t ps2KeyCode;
uint8_t ps2Ctrl;
uint8_t keyboardModel;
uint8_t machine;
uint8_t pcKey;
uint8_t pcCtrl;
} t_keyMapEntry;
// Structure to encapsulate the entire static keyboard mapping table.
typedef struct {
t_keyMapEntry kme[PS2TBL_PC9801_MAXROWS];
} t_keyMap;
// Structure to maintain the NEC PC-9801 interface configuration data. This data is persisted through powercycles as needed.
typedef struct {
struct {
uint8_t activeKeyboardMap; // Model of keyboard a keymap entry is applicable to.
uint8_t activeMachineModel; // Machine model a keymap entry is applicable to.
bool useOnlyPersisted; // Flag to indicate wether the inbuilt keymap array should be combined with persisted values or the inbuilt array is ignored and only persisted values used.
} params;
} t_pcConfig;
// Configuration data.
t_pcConfig pcConfig;
// Structure to manage the control signals signifying the state of the NEC PC-9801 keyboard.
typedef struct {
uint8_t keyCtrl; // Keyboard state flag control.
bool optionSelect; // Flag to indicate a user requested keyboard configuration option is being selected.
int uartNum;
int uartBufferSize;
int uartQueueSize;
std::string fsPath; // Path on the underlying filesystem where storage is mounted and accessible.
t_keyMapEntry *kme; // Pointer to an array in memory to contain PS2 to NEC PC-9801 mapping values.
int kmeRows; // Number of rows in the kme table.
std::string keyMapFileName; // Name of file where extension or replacement key map entries are stored.
bool persistConfig; // Flag to request saving of the config into NVS storage.
} t_pcControl;
// Transmit buffer queue item.
typedef struct {
uint32_t keyCode; // Key data to be sent to PC-9801, 4 bytes to allow for extended sequences..
} t_xmitQueueMessage;
// Receive buffer queue item.
typedef struct {
uint8_t hostCmd; // Keyboard configuration command received from X68000.
} t_rcvQueueMessage;
// Thread handles - one per function, ie. HID interface and host target interface.
TaskHandle_t TaskHostIF = NULL;
TaskHandle_t TaskHIDIF = NULL;
// Control structure to control interaction and mapping of keys for the host.
t_pcControl pcCtrl;
// Spin lock mutex to hold a coresied to an uninterruptable method. This only works on dual core ESP32's.
portMUX_TYPE pcMutex;
//
// This mapping is for the UK Wyse KB-3926 PS/2 keyboard
//
t_keyMap PS2toPC9801 = {
{
//PS2 Code PS2 Ctrl (Flags to Match) Keyboard Model Machine PC-9801 Data PC-9801 Ctrl (Flags to Set).
// Function keys
// { PS2_KEY_F1, PS2CTRL_FUNC | PS2CTRL_CTRL, KEYMAP_STANDARD, PC9801_ALL, PC9801_KEY_HIRAGANA, PC9801_CTRL_NONE, }, // CTRL + F1 = Hiragana
// { PS2_KEY_F2, PS2CTRL_FUNC | PS2CTRL_CTRL, KEYMAP_STANDARD, PC9801_ALL, PC9801_KEY_FULLWIDTH, PC9801_CTRL_NONE, }, // CTRL + F2 = Full Width
// { PS2_KEY_F3, PS2CTRL_FUNC | PS2CTRL_CTRL, KEYMAP_STANDARD, PC9801_ALL, PC9801_KEY_KATAKANA, PC9801_CTRL_NONE, }, // CTRL + F3 = Katakana
// { PS2_KEY_F4, PS2CTRL_FUNC | PS2CTRL_CTRL, KEYMAP_STANDARD, PC9801_ALL, PC9801_KEY_ROMAJI, PC9801_CTRL_NONE, }, // CTRL + F4 = Romaji
// { PS2_KEY_F5, PS2CTRL_FUNC | PS2CTRL_CTRL, KEYMAP_STANDARD, PC9801_ALL, PC9801_KEY_TRANSPOSE, PC9801_CTRL_NONE, }, // CTRL + F5 = Tranpose
// { PS2_KEY_F6, PS2CTRL_FUNC | PS2CTRL_CTRL, KEYMAP_STANDARD, PC9801_ALL, PC9801_KEY_SYMBOL, PC9801_CTRL_NONE, }, // CTRL + F6 = Symbol
// { PS2_KEY_F7, PS2CTRL_FUNC | PS2CTRL_CTRL, KEYMAP_STANDARD, PC9801_ALL, PC9801_KEY_REGISTRATION, PC9801_CTRL_NONE, }, // CTRL + F7 = Registration - maybe a poor translation, needs better one!
// { PS2_KEY_F9, PS2CTRL_FUNC | PS2CTRL_CTRL, KEYMAP_STANDARD, PC9801_ALL, PC9801_KEY_COPY, PC9801_CTRL_NONE, }, // CTRL + F9 = Copy
// { PS2_KEY_F10, PS2CTRL_FUNC | PS2CTRL_CTRL, KEYMAP_STANDARD, PC9801_ALL, PC9801_KEY_HELP, PC9801_CTRL_NONE, }, // CTRL + F10 = Help
{ PS2_KEY_F1, PS2CTRL_FUNC, KEYMAP_STANDARD, PC9801_ALL, PC9801_KEY_F1, PC9801_CTRL_NONE, }, // F1
{ PS2_KEY_F2, PS2CTRL_FUNC, KEYMAP_STANDARD, PC9801_ALL, PC9801_KEY_F2, PC9801_CTRL_NONE, }, // F2
{ PS2_KEY_F3, PS2CTRL_FUNC, KEYMAP_STANDARD, PC9801_ALL, PC9801_KEY_F3, PC9801_CTRL_NONE, }, // F3
{ PS2_KEY_F4, PS2CTRL_FUNC, KEYMAP_STANDARD, PC9801_ALL, PC9801_KEY_F4, PC9801_CTRL_NONE, }, // F4
{ PS2_KEY_F5, PS2CTRL_FUNC, KEYMAP_STANDARD, PC9801_ALL, PC9801_KEY_F5, PC9801_CTRL_NONE, }, // F5
{ PS2_KEY_F6, PS2CTRL_FUNC, KEYMAP_STANDARD, PC9801_ALL, PC9801_KEY_F6, PC9801_CTRL_NONE, }, // F6
{ PS2_KEY_F7, PS2CTRL_FUNC, KEYMAP_STANDARD, PC9801_ALL, PC9801_KEY_F7, PC9801_CTRL_NONE, }, // F7
{ PS2_KEY_F8, PS2CTRL_FUNC, KEYMAP_STANDARD, PC9801_ALL, PC9801_KEY_F8, PC9801_CTRL_NONE, }, // F8
{ PS2_KEY_F9, PS2CTRL_FUNC, KEYMAP_STANDARD, PC9801_ALL, PC9801_KEY_F9, PC9801_CTRL_NONE, }, // F9
{ PS2_KEY_F10, PS2CTRL_FUNC, KEYMAP_STANDARD, PC9801_ALL, PC9801_KEY_F10, PC9801_CTRL_NONE, }, // F10
// { PS2_KEY_F11, PS2CTRL_FUNC, KEYMAP_STANDARD, PC9801_ALL, PC9801_KEY_OPT_1, PC9801_CTRL_NONE, }, // F11 - OPT.1
// { PS2_KEY_F12, PS2CTRL_FUNC, KEYMAP_STANDARD, PC9801_ALL, PC9801_KEY_OPT_2, PC9801_CTRL_NONE, }, // F12 - OPT.2
//PS2 Code PS2 Ctrl (Flags to Match) Machine PC-9801 Data PC-9801 Ctrl (Flags to Set).
// ALPHA keys, case is maaped in the PC-9801 via the SHIFT key event or CAPS key.
{ PS2_KEY_A, PS2CTRL_NONE, KEYMAP_STANDARD, PC9801_ALL, PC9801_KEY_A, PC9801_CTRL_NONE, }, // A
{ PS2_KEY_B, PS2CTRL_NONE, KEYMAP_STANDARD, PC9801_ALL, PC9801_KEY_B, PC9801_CTRL_NONE, }, // B
{ PS2_KEY_C, PS2CTRL_NONE, KEYMAP_STANDARD, PC9801_ALL, PC9801_KEY_C, PC9801_CTRL_NONE, }, // C
{ PS2_KEY_D, PS2CTRL_NONE, KEYMAP_STANDARD, PC9801_ALL, PC9801_KEY_D, PC9801_CTRL_NONE, }, // D
{ PS2_KEY_E, PS2CTRL_NONE, KEYMAP_STANDARD, PC9801_ALL, PC9801_KEY_E, PC9801_CTRL_NONE, }, // E
{ PS2_KEY_F, PS2CTRL_NONE, KEYMAP_STANDARD, PC9801_ALL, PC9801_KEY_F, PC9801_CTRL_NONE, }, // F
{ PS2_KEY_G, PS2CTRL_NONE, KEYMAP_STANDARD, PC9801_ALL, PC9801_KEY_G, PC9801_CTRL_NONE, }, // G
{ PS2_KEY_H, PS2CTRL_NONE, KEYMAP_STANDARD, PC9801_ALL, PC9801_KEY_H, PC9801_CTRL_NONE, }, // H
{ PS2_KEY_I, PS2CTRL_NONE, KEYMAP_STANDARD, PC9801_ALL, PC9801_KEY_I, PC9801_CTRL_NONE, }, // I
{ PS2_KEY_J, PS2CTRL_NONE, KEYMAP_STANDARD, PC9801_ALL, PC9801_KEY_J, PC9801_CTRL_NONE, }, // J
{ PS2_KEY_K, PS2CTRL_NONE, KEYMAP_STANDARD, PC9801_ALL, PC9801_KEY_K, PC9801_CTRL_NONE, }, // K
{ PS2_KEY_L, PS2CTRL_NONE, KEYMAP_STANDARD, PC9801_ALL, PC9801_KEY_L, PC9801_CTRL_NONE, }, // L
{ PS2_KEY_M, PS2CTRL_NONE, KEYMAP_STANDARD, PC9801_ALL, PC9801_KEY_M, PC9801_CTRL_NONE, }, // M
{ PS2_KEY_N, PS2CTRL_NONE, KEYMAP_STANDARD, PC9801_ALL, PC9801_KEY_N, PC9801_CTRL_NONE, }, // N
{ PS2_KEY_O, PS2CTRL_NONE, KEYMAP_STANDARD, PC9801_ALL, PC9801_KEY_O, PC9801_CTRL_NONE, }, // O
{ PS2_KEY_P, PS2CTRL_NONE, KEYMAP_STANDARD, PC9801_ALL, PC9801_KEY_P, PC9801_CTRL_NONE, }, // P
{ PS2_KEY_Q, PS2CTRL_NONE, KEYMAP_STANDARD, PC9801_ALL, PC9801_KEY_Q, PC9801_CTRL_NONE, }, // Q
{ PS2_KEY_R, PS2CTRL_NONE, KEYMAP_STANDARD, PC9801_ALL, PC9801_KEY_R, PC9801_CTRL_NONE, }, // R
{ PS2_KEY_S, PS2CTRL_NONE, KEYMAP_STANDARD, PC9801_ALL, PC9801_KEY_S, PC9801_CTRL_NONE, }, // S
{ PS2_KEY_T, PS2CTRL_NONE, KEYMAP_STANDARD, PC9801_ALL, PC9801_KEY_T, PC9801_CTRL_NONE, }, // T
{ PS2_KEY_U, PS2CTRL_NONE, KEYMAP_STANDARD, PC9801_ALL, PC9801_KEY_U, PC9801_CTRL_NONE, }, // U
{ PS2_KEY_V, PS2CTRL_NONE, KEYMAP_STANDARD, PC9801_ALL, PC9801_KEY_V, PC9801_CTRL_NONE, }, // V
{ PS2_KEY_W, PS2CTRL_NONE, KEYMAP_STANDARD, PC9801_ALL, PC9801_KEY_W, PC9801_CTRL_NONE, }, // W
{ PS2_KEY_X, PS2CTRL_NONE, KEYMAP_STANDARD, PC9801_ALL, PC9801_KEY_X, PC9801_CTRL_NONE, }, // X
{ PS2_KEY_Y, PS2CTRL_NONE, KEYMAP_STANDARD, PC9801_ALL, PC9801_KEY_Y, PC9801_CTRL_NONE, }, // Y
{ PS2_KEY_Z, PS2CTRL_NONE, KEYMAP_STANDARD, PC9801_ALL, PC9801_KEY_Z, PC9801_CTRL_NONE, }, // Z
// Numeric keys.
{ PS2_KEY_0, PS2CTRL_SHIFT, KEYMAP_STANDARD, PC9801_ALL, PC9801_KEY_9, PC9801_CTRL_NONE, }, // Close Bracket )
{ PS2_KEY_0, PS2CTRL_NONE, KEYMAP_STANDARD, PC9801_ALL, PC9801_KEY_0, PC9801_CTRL_NONE, }, // 0
{ PS2_KEY_1, PS2CTRL_NONE, KEYMAP_STANDARD, PC9801_ALL, PC9801_KEY_1, PC9801_CTRL_NONE, }, // 1
{ PS2_KEY_2, PS2CTRL_NONE, KEYMAP_STANDARD, PC9801_ALL, PC9801_KEY_2, PC9801_CTRL_NONE, }, // 2
{ PS2_KEY_3, PS2CTRL_NONE, KEYMAP_STANDARD, PC9801_ALL, PC9801_KEY_3, PC9801_CTRL_NONE, }, // 3
{ PS2_KEY_4, PS2CTRL_NONE, KEYMAP_STANDARD, PC9801_ALL, PC9801_KEY_4, PC9801_CTRL_NONE, }, // 4
{ PS2_KEY_5, PS2CTRL_NONE, KEYMAP_STANDARD, PC9801_ALL, PC9801_KEY_5, PC9801_CTRL_NONE, }, // 5
{ PS2_KEY_6, PS2CTRL_SHIFT, KEYMAP_STANDARD, PC9801_ALL, PC9801_KEY_CIRCUMFLEX, PC9801_CTRL_RELEASESHIFT, }, // Circumflex ^
{ PS2_KEY_6, PS2CTRL_NONE, KEYMAP_STANDARD, PC9801_ALL, PC9801_KEY_6, PC9801_CTRL_NONE, }, // 6
{ PS2_KEY_7, PS2CTRL_SHIFT, KEYMAP_STANDARD, PC9801_ALL, PC9801_KEY_6, PC9801_CTRL_NONE, }, // &
{ PS2_KEY_7, PS2CTRL_NONE, KEYMAP_STANDARD, PC9801_ALL, PC9801_KEY_7, PC9801_CTRL_NONE, }, // 7
{ PS2_KEY_8, PS2CTRL_SHIFT, KEYMAP_STANDARD, PC9801_ALL, PC9801_KEY_COLON, PC9801_CTRL_NONE, }, // Start *
{ PS2_KEY_8, PS2CTRL_NONE, KEYMAP_STANDARD, PC9801_ALL, PC9801_KEY_8, PC9801_CTRL_NONE, }, // 8
{ PS2_KEY_9, PS2CTRL_SHIFT, KEYMAP_STANDARD, PC9801_ALL, PC9801_KEY_8, PC9801_CTRL_NONE, }, // Open Bracket (
{ PS2_KEY_9, PS2CTRL_NONE, KEYMAP_STANDARD, PC9801_ALL, PC9801_KEY_9, PC9801_CTRL_NONE, }, // 9
//PS2 Code PS2 Ctrl (Flags to Match) Machine PC-9801 Data PC-9801 Ctrl (Flags to Set).
// Punctuation keys.
{ PS2_KEY_SPACE, PS2CTRL_NONE, KEYMAP_STANDARD, PC9801_ALL, PC9801_KEY_SPACE, PC9801_CTRL_NONE, }, // Space
{ PS2_KEY_MINUS, PS2CTRL_SHIFT, KEYMAP_STANDARD, PC9801_ALL, PC9801_KEY_CIRCUMFLEX, PC9801_CTRL_NONE, }, // Upper Bar
{ PS2_KEY_MINUS, PS2CTRL_NONE, KEYMAP_STANDARD, PC9801_ALL, PC9801_KEY_MINUS, PC9801_CTRL_NONE, }, // Minus -
{ PS2_KEY_EQUAL, PS2CTRL_SHIFT, KEYMAP_STANDARD, PC9801_ALL, PC9801_KEY_SEMI, PC9801_CTRL_SHIFT, }, // Plus +
{ PS2_KEY_EQUAL, PS2CTRL_NONE, KEYMAP_STANDARD, PC9801_ALL, PC9801_KEY_MINUS, PC9801_CTRL_SHIFT, }, // Equal =
{ PS2_KEY_DOT, PS2CTRL_SHIFT, KEYMAP_STANDARD, PC9801_ALL, PC9801_KEY_DOT, PC9801_CTRL_NONE, }, // Greater Than >
{ PS2_KEY_DOT, PS2CTRL_NONE, KEYMAP_STANDARD, PC9801_ALL, PC9801_KEY_DOT, PC9801_CTRL_NONE, }, // Dot
{ PS2_KEY_DIV, PS2CTRL_NONE, KEYMAP_STANDARD, PC9801_ALL, PC9801_KEY_DIV, PC9801_CTRL_NONE, }, // Divide /
{ PS2_KEY_SEMI, PS2CTRL_SHIFT, KEYMAP_STANDARD, PC9801_ALL, PC9801_KEY_COLON, PC9801_CTRL_RELEASESHIFT, }, // Colon :
{ PS2_KEY_SEMI, PS2CTRL_NONE, KEYMAP_STANDARD, PC9801_ALL, PC9801_KEY_SEMI, PC9801_CTRL_NONE, }, // Semi-Colon ;
{ PS2_KEY_OPEN_SQ, PS2CTRL_NONE, KEYMAP_STANDARD, PC9801_ALL, PC9801_KEY_OPEN_SQ, PC9801_CTRL_NONE, }, // [
{ PS2_KEY_CLOSE_SQ, PS2CTRL_NONE, KEYMAP_STANDARD, PC9801_ALL, PC9801_KEY_CLOSE_SQ, PC9801_CTRL_NONE, }, // ]
{ PS2_KEY_APOS, PS2CTRL_SHIFT, KEYMAP_STANDARD, PC9801_ALL, PC9801_KEY_AT, PC9801_CTRL_RELEASESHIFT, }, // @
{ PS2_KEY_APOS, PS2CTRL_NONE, KEYMAP_STANDARD, PC9801_ALL, PC9801_KEY_7, PC9801_CTRL_SHIFT, }, // '
{ PS2_KEY_BACK, PS2CTRL_SHIFT, KEYMAP_STANDARD, PC9801_ALL, PC9801_KEY_YEN, PC9801_CTRL_NONE, }, // Back slash maps to Yen
{ PS2_KEY_BACK, PS2CTRL_NONE, KEYMAP_STANDARD, PC9801_ALL, PC9801_KEY_YEN, PC9801_CTRL_NONE, }, // Back slash maps to Yen
{ PS2_KEY_HASH, PS2CTRL_NONE, KEYMAP_STANDARD, PC9801_ALL, PC9801_KEY_3, PC9801_CTRL_SHIFT, }, // Hash
{ PS2_KEY_COMMA, PS2CTRL_SHIFT, KEYMAP_STANDARD, PC9801_ALL, PC9801_KEY_COMMA, PC9801_CTRL_NONE, }, // Less Than <
{ PS2_KEY_COMMA, PS2CTRL_NONE, KEYMAP_STANDARD, PC9801_ALL, PC9801_KEY_COMMA, PC9801_CTRL_NONE, }, // Comma ,
{ PS2_KEY_BTICK, PS2CTRL_FUNC | PS2CTRL_SHIFT, KEYMAP_STANDARD, PC9801_ALL, PC9801_KEY_UNDERLINE, PC9801_CTRL_SHIFT, }, // Underline
{ PS2_KEY_BTICK, PS2CTRL_FUNC, KEYMAP_STANDARD, PC9801_ALL, PC9801_KEY_AT, PC9801_CTRL_SHIFT, }, // Back Tick `
// Control keys.
{ PS2_KEY_TAB, PS2CTRL_NONE, KEYMAP_STANDARD, PC9801_ALL, PC9801_KEY_TAB, PC9801_CTRL_NONE, }, // TAB
{ PS2_KEY_BS, PS2CTRL_FUNC, KEYMAP_STANDARD, PC9801_ALL, PC9801_KEY_BS, PC9801_CTRL_NONE, }, // Backspace
{ PS2_KEY_ESC, PS2CTRL_FUNC, KEYMAP_STANDARD, PC9801_ALL, PC9801_KEY_ESC, PC9801_CTRL_NONE, }, // ESCape
{ PS2_KEY_INSERT, PS2CTRL_FUNC, KEYMAP_STANDARD, PC9801_ALL, PC9801_KEY_INS, PC9801_CTRL_NONE, }, // INSERT
{ PS2_KEY_HOME, PS2CTRL_FUNC | PS2CTRL_SHIFT, KEYMAP_STANDARD, PC9801_ALL, PC9801_KEY_CLR, PC9801_CTRL_NONE, }, // CLR
{ PS2_KEY_HOME, PS2CTRL_FUNC, KEYMAP_STANDARD, PC9801_ALL, PC9801_KEY_HOME, PC9801_CTRL_NONE, }, // HOME
{ PS2_KEY_DELETE, PS2CTRL_FUNC, KEYMAP_STANDARD, PC9801_ALL, PC9801_KEY_DEL, PC9801_CTRL_NONE, }, // DELETE
{ PS2_KEY_UP_ARROW, PS2CTRL_FUNC, KEYMAP_STANDARD, PC9801_ALL, PC9801_KEY_UP_ARROW, PC9801_CTRL_NONE, }, // Up Arrow
{ PS2_KEY_L_ARROW, PS2CTRL_FUNC, KEYMAP_STANDARD, PC9801_ALL, PC9801_KEY_L_ARROW, PC9801_CTRL_NONE, }, // Left Arrow
{ PS2_KEY_DN_ARROW, PS2CTRL_FUNC, KEYMAP_STANDARD, PC9801_ALL, PC9801_KEY_DN_ARROW, PC9801_CTRL_NONE, }, // Down Arrow
{ PS2_KEY_R_ARROW, PS2CTRL_FUNC, KEYMAP_STANDARD, PC9801_ALL, PC9801_KEY_R_ARROW, PC9801_CTRL_NONE, }, // Right Arrow
{ PS2_KEY_PGUP, PS2CTRL_FUNC, KEYMAP_STANDARD, PC9801_ALL, PC9801_KEY_ROLLUP, PC9801_CTRL_NONE, }, // Roll Up.
{ PS2_KEY_PGDN, PS2CTRL_FUNC, KEYMAP_STANDARD, PC9801_ALL, PC9801_KEY_ROLLDN, PC9801_CTRL_NONE, }, // Roll Down
{ PS2_KEY_SCROLL, PS2CTRL_FUNC, KEYMAP_STANDARD, PC9801_ALL, ' ', PC9801_CTRL_NONE, }, // Not assigned.
{ PS2_KEY_ENTER, PS2CTRL_FUNC, KEYMAP_STANDARD, PC9801_ALL, PC9801_KEY_RETURN, PC9801_CTRL_NONE, }, // Not assigned.
{ PS2_KEY_CAPS, PS2CTRL_CAPS, KEYMAP_STANDARD, PC9801_ALL, PC9801_KEY_CAPS, PC9801_CTRL_NONE, }, // CAPS
{ PS2_KEY_END, PS2CTRL_FUNC, KEYMAP_STANDARD, PC9801_ALL, PC9801_KEY_UNDO, PC9801_CTRL_NONE, }, // UNDO
// Keypad.
{ PS2_KEY_KP0, PS2CTRL_NONE, KEYMAP_STANDARD, PC9801_ALL, PC9801_KEY_KP0, PC9801_CTRL_NONE, }, // Keypad 0
{ PS2_KEY_KP1, PS2CTRL_NONE, KEYMAP_STANDARD, PC9801_ALL, PC9801_KEY_KP1, PC9801_CTRL_NONE, }, // Keypad 1
{ PS2_KEY_KP2, PS2CTRL_NONE, KEYMAP_STANDARD, PC9801_ALL, PC9801_KEY_KP2, PC9801_CTRL_NONE, }, // Keypad 2
{ PS2_KEY_KP3, PS2CTRL_NONE, KEYMAP_STANDARD, PC9801_ALL, PC9801_KEY_KP3, PC9801_CTRL_NONE, }, // Keypad 3
{ PS2_KEY_KP4, PS2CTRL_NONE, KEYMAP_STANDARD, PC9801_ALL, PC9801_KEY_KP4, PC9801_CTRL_NONE, }, // Keypad 4
{ PS2_KEY_KP5, PS2CTRL_NONE, KEYMAP_STANDARD, PC9801_ALL, PC9801_KEY_KP5, PC9801_CTRL_NONE, }, // Keypad 5
{ PS2_KEY_KP6, PS2CTRL_NONE, KEYMAP_STANDARD, PC9801_ALL, PC9801_KEY_KP6, PC9801_CTRL_NONE, }, // Keypad 6
{ PS2_KEY_KP7, PS2CTRL_NONE, KEYMAP_STANDARD, PC9801_ALL, PC9801_KEY_KP7, PC9801_CTRL_NONE, }, // Keypad 7
{ PS2_KEY_KP8, PS2CTRL_NONE, KEYMAP_STANDARD, PC9801_ALL, PC9801_KEY_KP8, PC9801_CTRL_NONE, }, // Keypad 8
{ PS2_KEY_KP9, PS2CTRL_NONE, KEYMAP_STANDARD, PC9801_ALL, PC9801_KEY_KP9, PC9801_CTRL_NONE, }, // Keypad 9
{ PS2_KEY_KP_COMMA, PS2CTRL_NONE, KEYMAP_STANDARD, PC9801_ALL, PC9801_KEY_KP_COMMA, PC9801_CTRL_NONE, }, // Keypad Comma ,
{ PS2_KEY_KP_DOT, PS2CTRL_NONE, KEYMAP_STANDARD, PC9801_ALL, PC9801_KEY_KP_DOT, PC9801_CTRL_NONE, }, // Keypad Full stop .
{ PS2_KEY_KP_PLUS, PS2CTRL_NONE, KEYMAP_STANDARD, PC9801_ALL, PC9801_KEY_KP_PLUS, PC9801_CTRL_NONE, }, // Keypad Plus +
{ PS2_KEY_KP_MINUS, PS2CTRL_NONE, KEYMAP_STANDARD, PC9801_ALL, PC9801_KEY_KP_MINUS, PC9801_CTRL_NONE, }, // Keypad Minus -
{ PS2_KEY_KP_TIMES, PS2CTRL_NONE, KEYMAP_STANDARD, PC9801_ALL, PC9801_KEY_KP_TIMES, PC9801_CTRL_NONE, }, // Keypad Times *
{ PS2_KEY_KP_DIV, PS2CTRL_NONE, KEYMAP_STANDARD, PC9801_ALL, PC9801_KEY_KP_DIV, PC9801_CTRL_NONE, }, // Keypad Divide /
{ PS2_KEY_KP_EQUAL, PS2CTRL_NONE, KEYMAP_STANDARD, PC9801_ALL, PC9801_KEY_MINUS, PC9801_CTRL_SHIFT, }, // Keypad Equal =
{ PS2_KEY_KP_ENTER, PS2CTRL_NONE, KEYMAP_STANDARD, PC9801_ALL, PC9801_KEY_KP_ENTER, PC9801_CTRL_NONE, }, // Keypad Ebter /
{ PS2_KEY_KP_ENTER, PS2CTRL_NONE, KEYMAP_STANDARD, PC9801_ALL, PC9801_KEY_KP_EQUAL, PC9801_CTRL_NONE, }, // Keypad Ebter /
//PS2 Code PS2 Ctrl (Flags to Match) Machine PC-9801 Data PC-9801 Ctrl (Flags to Set).
// Special keys.
{ PS2_KEY_PRTSCR, PS2CTRL_FUNC, KEYMAP_STANDARD, PC9801_ALL, 0x00, PC9801_CTRL_NONE, }, //
{ PS2_KEY_PAUSE, PS2CTRL_FUNC | PS2CTRL_SHIFT, KEYMAP_STANDARD, PC9801_ALL, PC9801_KEY_BREAK, PC9801_CTRL_RELEASESHIFT, }, // BREAK KEY
// { PS2_KEY_L_GUI, PS2CTRL_FUNC, KEYMAP_STANDARD, PC9801_ALL, PC9801_KEY_XF1, PC9801_CTRL_NONE, }, // XF1
// { PS2_KEY_L_ALT, PS2CTRL_FUNC, KEYMAP_STANDARD, PC9801_ALL, PC9801_KEY_XF2, PC9801_CTRL_NONE, }, // XF2
// { PS2_KEY_R_ALT, PS2CTRL_FUNC, KEYMAP_STANDARD, PC9801_ALL, PC9801_KEY_XF3, PC9801_CTRL_NONE, }, // XF3
// { PS2_KEY_R_GUI, PS2CTRL_FUNC, KEYMAP_STANDARD, PC9801_ALL, PC9801_KEY_XF4, PC9801_CTRL_NONE, }, // XF4
// { PS2_KEY_MENU, PS2CTRL_FUNC, KEYMAP_STANDARD, PC9801_ALL, PC9801_KEY_XF5, PC9801_CTRL_NONE, }, // XF5
// Modifiers are last, only being selected if an earlier match isnt made.
{ PS2_KEY_L_SHIFT, PS2CTRL_FUNC, KEYMAP_STANDARD, PC9801_ALL, PC9801_KEY_SHIFT, PC9801_CTRL_NONE, }, //
{ PS2_KEY_R_SHIFT, PS2CTRL_FUNC, KEYMAP_STANDARD, PC9801_ALL, PC9801_KEY_SHIFT, PC9801_CTRL_NONE, }, //
{ PS2_KEY_L_CTRL, PS2CTRL_FUNC, KEYMAP_STANDARD, PC9801_ALL, PC9801_KEY_CTRL, PC9801_CTRL_NONE, }, // Map to Control
{ PS2_KEY_R_CTRL, PS2CTRL_FUNC, KEYMAP_STANDARD, PC9801_ALL, PC9801_KEY_CTRL, PC9801_CTRL_NONE, }, // Map to Control
{ 0, PS2CTRL_NONE, KEYMAP_STANDARD, PC9801_ALL, PC9801_KEY_NULL, PC9801_CTRL_NONE, }, //
}};
};
#endif // PC9801_H

View File

@@ -1 +0,0 @@
../../../sharpkey/main/include/PS2KeyAdvanced.h

View File

@@ -0,0 +1,451 @@
/* Version V1.0.9
PS2KeyAdvanced.h - PS2KeyAdvanced library
Copyright (c) 2007 Free Software Foundation. All right reserved.
Written by Paul Carpenter, PC Services <sales@pcserviceselectronics.co.uk>
Created September 2014
Updated January 2016 - Paul Carpenter - add tested on Due and tidy ups for V1.5 Library Management
January 2020 Fix typos, correct keyboard reset status improve library.properties
and additional platform handling and some documentation
March 2020 Add SAMD1 as recognised support as has been tested by user
Improve different architecture handling
November 2020 Add support for STM32 from user Hiabuto-de
Tested on STM32Duino-Framework and PlatformIO on STM32F103C8T6 and an IBM Model M
July 2021 Add workaround for ESP32 issue with Silicon (hardware) from user submissions
IMPORTANT WARNING
If using a DUE or similar board with 3V3 I/O you MUST put a level translator
like a Texas Instruments TXS0102 or FET circuit as the signals are
Bi-directional (signals transmitted from both ends on same wire).
Failure to do so may damage your Arduino Due or similar board.
Test History
September 2014 Uno and Mega 2560 September 2014 using Arduino V1.6.0
January 2016 Uno, Mega 2560 and Due using Arduino 1.6.7 and Due Board
Manager V1.6.6
ONLY use defines in this file others may disappear on updates.
This is for a LATIN style keyboard using Scan code set 2. See various
websites on what different scan code sets use. Scan Code Set 2 is the
default scan code set for PS2 keyboards on power up.
Will support most keyboards even ones with multimedia keys or even 24 function keys.
Fully featured PS2 keyboard library to provide
All function and movement keys supported even multi-lingual
Parity checking of data sent/received on receive request keyboard resend
Resends data when needed handles keyboard protocol for RESEND and ECHO
Functions for get and set of
Scancode set in use READ only
LED and LOCK control
ReadID
Reset keyboard
Send ECHO
Ignore Break codes for keys
Ignore typematic repeat of CTRL, SHIFT, ALT, Num, Scroll, Caps
Handles NUM, CAPS and SCROLL lock keys to LEDs
Handles NUM/SCROLL internally
Read function Returns an UNSIGNED INT containing
Make/Break status
Caps status
Shift, CTRL, ALT, ALT GR, GUI keys
Flag for function key not a displayable/printable character
8 bit key code
Code Ranges (bottom byte of unsigned int)
0 invalid/error
1-1F Functions (Caps, Shift, ALT, Enter, DEL... )
1A-1F Functions with ASCII control code
(DEL, BS, TAB, ESC, ENTER, SPACE)
20-61 Printable characters noting
0-9 = 0x30 to 0x39 as ASCII
A to Z = 0x41 to 0x5A as upper case ASCII type codes
8B Extra European key
61-A0 Function keys and other special keys (plus F2 and F1)
61-78 F1 to F24
79-8A Multimedia
8B NOT included
8C-8E ACPI power
91-A0 and F2 and F1 - Special multilingual
A8-FF Keyboard communications commands (note F2 and F1 are special
codes for special multi-lingual keyboards)
By using these ranges it is possible to perform detection of any key and do
easy translation to ASCII/UTF-8 avoiding keys that do not have a valid code.
Top Byte is 8 bits denoting as follows with defines for bit code
Define name bit description
PS2_BREAK 15 1 = Break key code
(MSB) 0 = Make Key code
PS2_SHIFT 14 1 = Shift key pressed as well (either side)
0 = NO shift key
PS2_CTRL 13 1 = Ctrl key pressed as well (either side)
0 = NO Ctrl key
PS2_CAPS 12 1 = Caps Lock ON
0 = Caps lock OFF
PS2_ALT 11 1 = Left Alt key pressed as well
0 = NO Left Alt key
PS2_ALT_GR 10 1 = Right Alt (Alt GR) key pressed as well
0 = NO Right Alt key
PS2_GUI 9 1 = GUI key pressed as well (either)
0 = NO GUI key
PS2_FUNCTION 8 1 = FUNCTION key non-printable character (plus space, tab, enter)
0 = standard character key
Error Codes
Most functions return 0 or 0xFFFF as error, other codes to note and
handle appropriately
0xAA keyboard has reset and passed power up tests
will happen if keyboard plugged in after code start
0xFC Keyboard General error or power up fail
It is responsibility of your programme to deal with converting special cases like
<CTRL>+<ENTER> sends a special code to something else. If you wish to do that make a
NEW library called SOMETHING different NOT a variant or revision of this one, as you
are changing base functionality
See PS2KeyCode.h for codes from the keyboard this library uses to decode.
(may disappear in updates do not rely on that file or definitions)
See this file for returned definitions of Keys
Note defines starting
PS2_KC_* are internal defines for codes from the keyboard
PS2_KEY_* are the codes this library returns
PS2_* remaining defines for use in higher levels
To get the key as ASCII/UTF-8 single byte character conversion requires use
of PS2KeyMap library AS WELL.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef PS2KeyAdvanced_h
#define PS2KeyAdvanced_h
// Platform specific areas
// Harvard architecture settings for PROGMEM
// Add separate for EACH architecture as easier to maintain
// AVR (includes Teensy 2.0)
#if defined( ARDUINO_ARCH_AVR )
#define PS2_SUPPORTED 1
#define PS2_REQUIRES_PROGMEM 1
#define PS2_CLEAR_PENDING_IRQ 1
#endif
// SAM (Due)
#if defined( ARDUINO_ARCH_SAM )
#define PS2_SUPPORTED 1
#define PS2_CLEAR_PENDING_IRQ 1
#endif
// SAMD1
#if defined( ARDUINO_ARCH_SAMD1 )
#define PS2_SUPPORTED 1
#define PS2_CLEAR_PENDING_IRQ 1
#endif
// STM32
#if defined( ARDUINO_ARCH_STM32 )
#define PS2_SUPPORTED 1
#define PS2_CLEAR_PENDING_IRQ 1
#endif
// ESP32
#if defined( ARDUINO_ARCH_ESP32 )
#define PS2_SUPPORTED 1
#define PS2_ONLY_CHANGE_IRQ 1
#endif
// Invalid architecture
#if !( defined( PS2_SUPPORTED ) )
#warning Library is NOT supported on this board Use at your OWN risk
#endif
/* Flags/bit masks for status bits in returned unsigned int value */
#define PS2_BREAK 0x8000
#define PS2_SHIFT 0x4000
#define PS2_CTRL 0x2000
#define PS2_CAPS 0x1000
#define PS2_ALT 0x800
#define PS2_ALT_GR 0x400
#define PS2_GUI 0x200
#define PS2_FUNCTION 0x100
/* General defines of communications codes */
/* Command or response */
#define PS2_KEY_RESEND 0xFE
#define PS2_KEY_ACK 0xFA
#define PS2_KEY_ECHO 0xEE
/* Responses */
#define PS2_KEY_BAT 0xAA
// Actually buffer overrun
#define PS2_KEY_OVERRUN 0xFF
// Below is general error code
#define PS2_KEY_ERROR 0xFC
/* Command parameters for functions */
/* LED codes OR together */
#define PS2_LOCK_SCROLL 0x01
#define PS2_LOCK_NUM 0x02
#define PS2_LOCK_CAPS 0x04
/* Only useful for very few keyboards */
#define PS2_LOCK_EXTRA 0x08
/* Returned keycode definitions */
/* Do NOT change these codings as you will break base
functionality use PS2KeyMap for that and internationalisation */
#define PS2_KEY_NUM 0x01
#define PS2_KEY_SCROLL 0x02
#define PS2_KEY_CAPS 0x03
#define PS2_KEY_PRTSCR 0x04
#define PS2_KEY_PAUSE 0x05
#define PS2_KEY_L_SHIFT 0x06
#define PS2_KEY_R_SHIFT 0x07
#define PS2_KEY_L_CTRL 0X08
#define PS2_KEY_R_CTRL 0X09
#define PS2_KEY_L_ALT 0x0A
#define PS2_KEY_R_ALT 0x0B
/* Sometimes called windows key */
#define PS2_KEY_L_GUI 0x0C
#define PS2_KEY_R_GUI 0x0D
#define PS2_KEY_MENU 0x0E
/* Break is CTRL + PAUSE generated inside keyboard */
#define PS2_KEY_BREAK 0x0F
/* Generated by some keyboards by ALT and PRTSCR */
#define PS2_KEY_SYSRQ 0x10
#define PS2_KEY_HOME 0x11
#define PS2_KEY_END 0x12
#define PS2_KEY_PGUP 0x13
#define PS2_KEY_PGDN 0x14
#define PS2_KEY_L_ARROW 0x15
#define PS2_KEY_R_ARROW 0x16
#define PS2_KEY_UP_ARROW 0x17
#define PS2_KEY_DN_ARROW 0x18
#define PS2_KEY_INSERT 0x19
#define PS2_KEY_DELETE 0x1A
#define PS2_KEY_ESC 0x1B
#define PS2_KEY_BS 0x1C
#define PS2_KEY_TAB 0x1D
#define PS2_KEY_ENTER 0x1E
#define PS2_KEY_SPACE 0x1F
#define PS2_KEY_KP0 0x20
#define PS2_KEY_KP1 0x21
#define PS2_KEY_KP2 0x22
#define PS2_KEY_KP3 0x23
#define PS2_KEY_KP4 0x24
#define PS2_KEY_KP5 0x25
#define PS2_KEY_KP6 0x26
#define PS2_KEY_KP7 0x27
#define PS2_KEY_KP8 0x28
#define PS2_KEY_KP9 0x29
#define PS2_KEY_KP_DOT 0x2A
#define PS2_KEY_KP_ENTER 0x2B
#define PS2_KEY_KP_PLUS 0x2C
#define PS2_KEY_KP_MINUS 0x2D
#define PS2_KEY_KP_TIMES 0x2E
#define PS2_KEY_KP_DIV 0x2F
#define PS2_KEY_0 0X30
#define PS2_KEY_1 0X31
#define PS2_KEY_2 0X32
#define PS2_KEY_3 0X33
#define PS2_KEY_4 0X34
#define PS2_KEY_5 0X35
#define PS2_KEY_6 0X36
#define PS2_KEY_7 0X37
#define PS2_KEY_8 0X38
#define PS2_KEY_9 0X39
#define PS2_KEY_APOS 0X3A
#define PS2_KEY_COMMA 0X3B
#define PS2_KEY_MINUS 0X3C
#define PS2_KEY_DOT 0X3D
#define PS2_KEY_DIV 0X3E
/* Some Numeric keyboards have an '=' on right keypad */
#define PS2_KEY_KP_EQUAL 0x3F
/* Single quote or back quote */
#define PS2_KEY_SINGLE 0X40
#define PS2_KEY_A 0X41
#define PS2_KEY_B 0X42
#define PS2_KEY_C 0X43
#define PS2_KEY_D 0X44
#define PS2_KEY_E 0X45
#define PS2_KEY_F 0X46
#define PS2_KEY_G 0X47
#define PS2_KEY_H 0X48
#define PS2_KEY_I 0X49
#define PS2_KEY_J 0X4A
#define PS2_KEY_K 0X4B
#define PS2_KEY_L 0X4C
#define PS2_KEY_M 0X4D
#define PS2_KEY_N 0X4E
#define PS2_KEY_O 0X4F
#define PS2_KEY_P 0X50
#define PS2_KEY_Q 0X51
#define PS2_KEY_R 0X52
#define PS2_KEY_S 0X53
#define PS2_KEY_T 0X54
#define PS2_KEY_U 0X55
#define PS2_KEY_V 0X56
#define PS2_KEY_W 0X57
#define PS2_KEY_X 0X58
#define PS2_KEY_Y 0X59
#define PS2_KEY_Z 0X5A
#define PS2_KEY_SEMI 0X5B
#define PS2_KEY_BACK 0X5C
#define PS2_KEY_OPEN_SQ 0X5D
#define PS2_KEY_CLOSE_SQ 0X5E
#define PS2_KEY_EQUAL 0X5F
/* Some Numeric keypads have a comma key */
#define PS2_KEY_KP_COMMA 0x60
#define PS2_KEY_F1 0X61
#define PS2_KEY_F2 0X62
#define PS2_KEY_F3 0X63
#define PS2_KEY_F4 0X64
#define PS2_KEY_F5 0X65
#define PS2_KEY_F6 0X66
#define PS2_KEY_F7 0X67
#define PS2_KEY_F8 0X68
#define PS2_KEY_F9 0X69
#define PS2_KEY_F10 0X6A
#define PS2_KEY_F11 0X6B
#define PS2_KEY_F12 0X6C
#define PS2_KEY_F13 0X6D
#define PS2_KEY_F14 0X6E
#define PS2_KEY_F15 0X6F
#define PS2_KEY_F16 0X70
#define PS2_KEY_F17 0X71
#define PS2_KEY_F18 0X72
#define PS2_KEY_F19 0X73
#define PS2_KEY_F20 0X74
#define PS2_KEY_F21 0X75
#define PS2_KEY_F22 0X76
#define PS2_KEY_F23 0X77
#define PS2_KEY_F24 0X78
#define PS2_KEY_NEXT_TR 0X79
#define PS2_KEY_PREV_TR 0X7A
#define PS2_KEY_STOP 0X7B
#define PS2_KEY_PLAY 0X7C
#define PS2_KEY_MUTE 0X7D
#define PS2_KEY_VOL_UP 0X7E
#define PS2_KEY_VOL_DN 0X7F
#define PS2_KEY_MEDIA 0X80
#define PS2_KEY_EMAIL 0X81
#define PS2_KEY_CALC 0X82
#define PS2_KEY_COMPUTER 0X83
#define PS2_KEY_WEB_SEARCH 0X84
#define PS2_KEY_WEB_HOME 0X85
#define PS2_KEY_WEB_BACK 0X86
#define PS2_KEY_WEB_FORWARD 0X87
#define PS2_KEY_WEB_STOP 0X88
#define PS2_KEY_WEB_REFRESH 0X89
#define PS2_KEY_WEB_FAVOR 0X8A
#define PS2_KEY_EUROPE2 0X8B
#define PS2_KEY_POWER 0X8C
#define PS2_KEY_SLEEP 0X8D
#define PS2_KEY_WAKE 0X90
#define PS2_KEY_INTL1 0X91
#define PS2_KEY_INTL2 0X92
#define PS2_KEY_INTL3 0X93
#define PS2_KEY_INTL4 0X94
#define PS2_KEY_INTL5 0X95
#define PS2_KEY_LANG1 0X96
#define PS2_KEY_LANG2 0X97
#define PS2_KEY_LANG3 0X98
#define PS2_KEY_LANG4 0X99
#define PS2_KEY_LANG5 0xA0
#define PS2_KEY_BTICK 0X9A
#define PS2_KEY_HASH 0X9B
/*
Purpose: Provides advanced access to PS2 keyboards
Public class definitions
See standard error codes for error code returns
*/
class PS2KeyAdvanced {
public:
/* This constructor does basically nothing. Please call the begin(int,int)
method before using any other method of this class. */
PS2KeyAdvanced( );
// Destructor - disable and detach interrupts and free up resources.
~PS2KeyAdvanced( );
/* Starts the keyboard "service" by registering the external interrupt.
setting the pin modes correctly and driving those needed to high.
Sets default LOCK status (LEDs) to passed in value or default of all off
The best place to call this method is in the setup routine. */
void begin( uint8_t, uint8_t );
// Additional key available check which doesnt affect the queue.
uint8_t keyAvailable(void);
/* Returns number of codes available or 0 for none */
uint8_t available( );
/* Returns the key last read from the keyboard.
If there is no key available, 0 is returned. */
uint16_t read( );
/* Returns the current status of Locks
Use Macro to mask out bits from
PS2_LOCK_NUM PS2_LOCK_CAPS PS2_LOCK_SCROLL */
uint8_t getLock( );
/* Sets the current status of Locks and LEDs
Use macro defines added together from
PS2_LOCK_NUM PS2_LOCK_CAPS PS2_LOCK_SCROLL */
void setLock( uint8_t );
/* Set library to not send break key codes
1 = no break codes
0 = send break codes */
void setNoBreak( uint8_t );
/* Set library to not repeat make codes for CTRL, ALT, GUI, SHIFT
1 = no repeat codes
0 = send repeat codes */
void setNoRepeat( uint8_t );
/* Resets keyboard when reset has completed
keyboard sends AA - Pass or FC for fail
Read from keyboard data buffer */
void resetKey( );
/* Get the current Scancode Set used in keyboard
returned data in keyboard buffer read as keys */
void getScanCodeSet( void );
/* Get the current Scancode Set used in keyboard
returned data in keyboard buffer read as keys */
void readID( void );
/* Send Echo command to keyboard
returned data in keyboard buffer read as keys */
void echo( void );
// Method to suspend PS2 activity, primarily by disabling the interrupts.
void suspend(bool suspend);
/* Send Typematic rate/delay command to keyboard
First Parameter rate is 0 - 0x1F (31)
0 = 30 CPS
0x1F = 2 CPS
default in keyboard is 0xB (10.9 CPS)
Second Parameter delay is 0 - 3 for 0.25s to 1s in 0.25 increments
default in keyboard is 1 = 0.5 second delay
Returned data in keyboard buffer read as keys */
int typematic( uint8_t , uint8_t );
};
#endif

View File

@@ -1 +0,0 @@
../../../sharpkey/main/include/PS2KeyCode.h

276
main/include/PS2KeyCode.h Normal file
View File

@@ -0,0 +1,276 @@
/* Version V1.0.8
PS2KeyCode.h - PS2KeyAdvanced library Internal actual PS2 key code sequences
Copyright (c) 2007 Free Software Foundation. All right reserved.
Written by Paul Carpenter, PC Services <sales@pcserviceselectronics.co.uk>
Created September 2014
Updated January 2016 - Paul Carpenter - add tested on Due and tidy ups for V1.5 Library Management
Updated December 2019 - Paul Carpenter - Fix typo in code for Multimedia STOP
PRIVATE to library
Test History
September 2014 Uno and Mega 2560 September 2014 using Arduino V1.6.0
January 2016 Uno, Mega 2560 and Due using Arduino 1.6.7 and Due Board
Manager V1.6.6
This is for a LATIN style keyboard. Will support most keyboards even ones
with multimedia keys or even 24 function keys.
Definitions used for key codes from a PS2 keyboard, do not use in your
code these are to be handled INTERNALLY by the library.
(may disappear in updates do not rely on this file or definitions)
See PS2KeyAdvanced.h for codes returned from library and flag settings
Defines are in three groups
Special codes definition of communications bytes
Single Byte codes returned as key codes
Two byte Codes preceded by E0 code returned as keycodes
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef PS2KeyCode_h
#define PS2KeyCode_h
/* Ignore code for key code translation */
#define PS2_KEY_IGNORE 0xBB
// buffer sizes keyboard RX and TX, then key reading buffer
// Minimum size 8 can be larger
#define _RX_BUFFER_SIZE 8
// Minimum size 6 can be larger
#define _TX_BUFFER_SIZE 6
// Output Buffer of unsigned int values. Minimum size 4 can be larger
#define _KEY_BUFF_SIZE 4
/* private defines for library files not global */
/* _ps2mode status flags */
#define _PS2_BUSY 0x80
#define _TX_MODE 0x40
#define _BREAK_KEY 0x20
#define _WAIT_RESPONSE 0x10
#define _E0_MODE 0x08
#define _E1_MODE 0x04
#define _LAST_VALID 0x02
/* _tx_ready flags */
#define _HANDSHAKE 0x80
#define _COMMAND 0x01
/* Key Repeat defines */
#define _NO_BREAKS 0x08
#define _NO_REPEATS 0x80
/* PS2_keystatus byte masks (from 16 bit int masks) */
#define _BREAK ( PS2_BREAK >> 8 )
#define _SHIFT ( PS2_SHIFT >> 8 )
#define _CTRL ( PS2_CTRL >> 8 )
#define _CAPS ( PS2_CAPS >> 8 )
#define _ALT ( PS2_ALT >> 8 )
#define _ALT_GR ( PS2_ALT_GR >> 8 )
#define _GUI ( PS2_GUI >> 8 )
#define _FUNCTION ( PS2_FUNCTION >> 8 )
/* General defines of comms codes */
/* Command or response */
#define PS2_KC_RESEND 0xFE
#define PS2_KC_ACK 0xFA
#define PS2_KC_ECHO 0xEE
/* Responses */
#define PS2_KC_BAT 0xAA
// Actually buffer overrun
#define PS2_KC_OVERRUN 0xFF
// Below is general error code
#define PS2_KC_ERROR 0xFC
#define PS2_KC_KEYBREAK 0xF0
#define PS2_KC_EXTEND1 0xE1
#define PS2_KC_EXTEND 0xE0
/* Commands */
#define PS2_KC_RESET 0xFF
#define PS2_KC_DEFAULTS 0xF6
#define PS2_KC_DISABLE 0xF5
#define PS2_KC_ENABLE 0xF4
#define PS2_KC_RATE 0xF3
#define PS2_KC_READID 0xF2
#define PS2_KC_SCANCODE 0xF0
#define PS2_KC_LOCK 0xED
/* Single Byte Key Codes */
#define PS2_KC_NUM 0x77
#define PS2_KC_SCROLL 0x7E
#define PS2_KC_CAPS 0x58
#define PS2_KC_L_SHIFT 0x12
#define PS2_KC_R_SHIFT 0x59
/* This is Left CTRL and ALT but Right version is in E0 with same code */
#define PS2_KC_CTRL 0X14
#define PS2_KC_ALT 0x11
/* Generated by some keyboards by ALT and PRTSCR */
#define PS2_KC_SYSRQ 0x84
#define PS2_KC_ESC 0x76
#define PS2_KC_BS 0x66
#define PS2_KC_TAB 0x0D
#define PS2_KC_ENTER 0x5A
#define PS2_KC_SPACE 0x29
#define PS2_KC_KP0 0x70
#define PS2_KC_KP1 0x69
#define PS2_KC_KP2 0x72
#define PS2_KC_KP3 0x7A
#define PS2_KC_KP4 0x6B
#define PS2_KC_KP5 0x73
#define PS2_KC_KP6 0x74
#define PS2_KC_KP7 0x6C
#define PS2_KC_KP8 0x75
#define PS2_KC_KP9 0x7D
#define PS2_KC_KP_DOT 0x71
#define PS2_KC_KP_PLUS 0x79
#define PS2_KC_KP_MINUS 0x7B
#define PS2_KC_KP_TIMES 0x7C
/* Some keyboards have an '=' on right keypad */
#define PS2_KC_KP_EQUAL 0x0F
#define PS2_KC_0 0X45
#define PS2_KC_1 0X16
#define PS2_KC_2 0X1E
#define PS2_KC_3 0X26
#define PS2_KC_4 0X25
#define PS2_KC_5 0X2E
#define PS2_KC_6 0X36
#define PS2_KC_7 0X3D
#define PS2_KC_8 0X3E
#define PS2_KC_9 0X46
#define PS2_KC_APOS 0X52
#define PS2_KC_COMMA 0X41
#define PS2_KC_MINUS 0X4E
#define PS2_KC_DOT 0X49
#define PS2_KC_DIV 0X4A
/* Single quote or back apostrophe */
#define PS2_KC_BTICK 0X0E
#define PS2_KC_A 0X1C
#define PS2_KC_B 0X32
#define PS2_KC_C 0X21
#define PS2_KC_D 0X23
#define PS2_KC_E 0X24
#define PS2_KC_F 0X2B
#define PS2_KC_G 0X34
#define PS2_KC_H 0X33
#define PS2_KC_I 0X43
#define PS2_KC_J 0X3B
#define PS2_KC_K 0X42
#define PS2_KC_L 0X4B
#define PS2_KC_M 0X3A
#define PS2_KC_N 0X31
#define PS2_KC_O 0X44
#define PS2_KC_P 0X4D
#define PS2_KC_Q 0X15
#define PS2_KC_R 0X2D
#define PS2_KC_S 0X1B
#define PS2_KC_T 0X2C
#define PS2_KC_U 0X3C
#define PS2_KC_V 0X2A
#define PS2_KC_W 0X1D
#define PS2_KC_X 0X22
#define PS2_KC_Y 0X35
#define PS2_KC_Z 0X1A
#define PS2_KC_SEMI 0X4C
#define PS2_KC_BACK 0X5D
// Extra key left of Z on 102 keyboards
#define PS2_KC_EUROPE2 0x61
#define PS2_KC_OPEN_SQ 0X54
#define PS2_KC_CLOSE_SQ 0X5B
#define PS2_KC_EQUAL 0X55
#define PS2_KC_F1 0X05
#define PS2_KC_F2 0X06
#define PS2_KC_F3 0X04
#define PS2_KC_F4 0X0C
#define PS2_KC_F5 0X03
#define PS2_KC_F6 0X0B
#define PS2_KC_F7 0X83
#define PS2_KC_F8 0X0A
#define PS2_KC_F9 0X01
#define PS2_KC_F10 0X09
#define PS2_KC_F11 0X78
#define PS2_KC_F12 0X07
#define PS2_KC_F13 0X08
#define PS2_KC_F14 0X10
#define PS2_KC_F15 0X18
#define PS2_KC_F16 0X20
#define PS2_KC_F17 0X28
#define PS2_KC_F18 0X30
#define PS2_KC_F19 0X38
#define PS2_KC_F20 0X40
#define PS2_KC_F21 0X48
#define PS2_KC_F22 0X50
#define PS2_KC_F23 0X57
#define PS2_KC_F24 0X5F
#define PS2_KC_KP_COMMA 0X6D
#define PS2_KC_INTL1 0X51
#define PS2_KC_INTL2 0X13
#define PS2_KC_INTL3 0X6A
#define PS2_KC_INTL4 0X64
#define PS2_KC_INTL5 0X67
#define PS2_KC_LANG1 0XF2
#define PS2_KC_LANG2 0XF1
#define PS2_KC_LANG3 0X63
#define PS2_KC_LANG4 0X62
#define PS2_KC_LANG5 0X5F
/* Extended key codes E0 table for two byte codes */
/* PS2_CTRL and PS2_ALT Need using in any table for the right keys */
/* first is special case for PRTSCR not always used so ignored by decoding */
#define PS2_KC_IGNORE 0x12
#define PS2_KC_PRTSCR 0x7C
/* Sometimes called windows key */
#define PS2_KC_L_GUI 0x1F
#define PS2_KC_R_GUI 0x27
#define PS2_KC_MENU 0x2F
/* Break is CTRL + PAUSE generated inside keyboard */
#define PS2_KC_BREAK 0x7E
#define PS2_KC_HOME 0x6C
#define PS2_KC_END 0x69
#define PS2_KC_PGUP 0x7D
#define PS2_KC_PGDN 0x7A
#define PS2_KC_L_ARROW 0x6B
#define PS2_KC_R_ARROW 0x74
#define PS2_KC_UP_ARROW 0x75
#define PS2_KC_DN_ARROW 0x72
#define PS2_KC_INSERT 0x70
#define PS2_KC_DELETE 0x71
#define PS2_KC_KP_ENTER 0x5A
#define PS2_KC_KP_DIV 0x4A
#define PS2_KC_NEXT_TR 0X4D
#define PS2_KC_PREV_TR 0X15
#define PS2_KC_STOP 0X3B
#define PS2_KC_PLAY 0X34
#define PS2_KC_MUTE 0X23
#define PS2_KC_VOL_UP 0X32
#define PS2_KC_VOL_DN 0X21
#define PS2_KC_MEDIA 0X50
#define PS2_KC_EMAIL 0X48
#define PS2_KC_CALC 0X2B
#define PS2_KC_COMPUTER 0X40
#define PS2_KC_WEB_SEARCH 0X10
#define PS2_KC_WEB_HOME 0X3A
#define PS2_KC_WEB_BACK 0X38
#define PS2_KC_WEB_FORWARD 0X30
#define PS2_KC_WEB_STOP 0X28
#define PS2_KC_WEB_REFRESH 0X20
#define PS2_KC_WEB_FAVOR 0X18
#define PS2_KC_POWER 0X37
#define PS2_KC_SLEEP 0X3F
#define PS2_KC_WAKE 0X5E
#endif

View File

@@ -1 +0,0 @@
../../../sharpkey/main/include/PS2KeyTable.h

393
main/include/PS2KeyTable.h Normal file
View File

@@ -0,0 +1,393 @@
/* Version V1.0.8
PS2KeyTable.h - PS2KeyAdvanced library keycode values to return values
Copyright (c) 2007 Free Software Foundation. All right reserved.
Written by Paul Carpenter, PC Services <sales@pcserviceselectronics.co.uk>
Created September 2014
V1.0.2 Updated January 2016 - Paul Carpenter - add tested on Due and tidy ups for V1.5 Library Management
PRIVATE to library
Test History
September 2014 Uno and Mega 2560 September 2014 using Arduino V1.6.0
January 2016 Uno, Mega 2560 and Due using Arduino 1.6.7 and Due Board
Manager V1.6.6
Internal to library private tables
(may disappear in updates do not rely on this file or definitions)
This is for a LATIN style keyboard. Will support most keyboards even ones
with multimedia keys or even 24 function keys.
Definitions used for key codes from a PS2 keyboard, do not use in your
code these are handled by the library.
See PS2KeyAdvanced.h for codes returned from library and flag settings
Two sets of tables
Single Byte codes returned as key codes
Two byte Codes preceded by E0 code returned as keycodes
Same tables used for make and break decode
Special cases are -
PRTSCR that ignores one of the sequences (E0,12) as this is not always sent
especially with modifier keys or some keyboards when typematic repeat comes on.
PAUSE as this is an 8 byte sequence only one starting E1 so main code gets E1
and waits for 7 more valid bytes to make the coding.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef PS2KeyTable_h
#define PS2KeyTable_h
/* Table contents are pairs of numbers
first code from keyboard
second is either PS2_KEY_IGNOPRE code or key code to return
Single byte Key table
In codes can only be 1 - 0x9F, plus 0xF2 and 0xF1
Out Codes in range 1 to 0x9F
*/
const uint8_t single_key[][ 2 ] = {
{ PS2_KC_NUM, PS2_KEY_NUM },
{ PS2_KC_SCROLL, PS2_KEY_SCROLL },
{ PS2_KC_CAPS, PS2_KEY_CAPS },
{ PS2_KC_L_SHIFT, PS2_KEY_L_SHIFT },
{ PS2_KC_R_SHIFT, PS2_KEY_R_SHIFT },
{ PS2_KC_CTRL, PS2_KEY_L_CTRL },
{ PS2_KC_ALT, PS2_KEY_L_ALT },
{ PS2_KC_SYSRQ, PS2_KEY_SYSRQ },
{ PS2_KC_ESC, PS2_KEY_ESC },
{ PS2_KC_BS, PS2_KEY_BS },
{ PS2_KC_TAB, PS2_KEY_TAB },
{ PS2_KC_ENTER, PS2_KEY_ENTER },
{ PS2_KC_SPACE, PS2_KEY_SPACE },
{ PS2_KC_KP0, PS2_KEY_KP0 },
{ PS2_KC_KP1, PS2_KEY_KP1 },
{ PS2_KC_KP2, PS2_KEY_KP2 },
{ PS2_KC_KP3, PS2_KEY_KP3 },
{ PS2_KC_KP4, PS2_KEY_KP4 },
{ PS2_KC_KP5, PS2_KEY_KP5 },
{ PS2_KC_KP6, PS2_KEY_KP6 },
{ PS2_KC_KP7, PS2_KEY_KP7 },
{ PS2_KC_KP8, PS2_KEY_KP8 },
{ PS2_KC_KP9, PS2_KEY_KP9 },
{ PS2_KC_KP_DOT, PS2_KEY_KP_DOT },
{ PS2_KC_KP_PLUS, PS2_KEY_KP_PLUS },
{ PS2_KC_KP_MINUS, PS2_KEY_KP_MINUS },
{ PS2_KC_KP_TIMES, PS2_KEY_KP_TIMES },
{ PS2_KC_KP_EQUAL, PS2_KEY_KP_EQUAL },
{ PS2_KC_0, PS2_KEY_0 },
{ PS2_KC_1, PS2_KEY_1 },
{ PS2_KC_2, PS2_KEY_2 },
{ PS2_KC_3, PS2_KEY_3 },
{ PS2_KC_4, PS2_KEY_4 },
{ PS2_KC_5, PS2_KEY_5 },
{ PS2_KC_6, PS2_KEY_6 },
{ PS2_KC_7, PS2_KEY_7 },
{ PS2_KC_8, PS2_KEY_8 },
{ PS2_KC_9, PS2_KEY_9 },
{ PS2_KC_APOS, PS2_KEY_APOS },
{ PS2_KC_COMMA, PS2_KEY_COMMA },
{ PS2_KC_MINUS, PS2_KEY_MINUS },
{ PS2_KC_DOT, PS2_KEY_DOT },
{ PS2_KC_DIV, PS2_KEY_DIV },
{ PS2_KC_BTICK, PS2_KEY_BTICK },
{ PS2_KC_A, PS2_KEY_A },
{ PS2_KC_B, PS2_KEY_B },
{ PS2_KC_C, PS2_KEY_C },
{ PS2_KC_D, PS2_KEY_D },
{ PS2_KC_E, PS2_KEY_E },
{ PS2_KC_F, PS2_KEY_F },
{ PS2_KC_G, PS2_KEY_G },
{ PS2_KC_H, PS2_KEY_H },
{ PS2_KC_I, PS2_KEY_I },
{ PS2_KC_J, PS2_KEY_J },
{ PS2_KC_K, PS2_KEY_K },
{ PS2_KC_L, PS2_KEY_L },
{ PS2_KC_M, PS2_KEY_M },
{ PS2_KC_N, PS2_KEY_N },
{ PS2_KC_O, PS2_KEY_O },
{ PS2_KC_P, PS2_KEY_P },
{ PS2_KC_Q, PS2_KEY_Q },
{ PS2_KC_R, PS2_KEY_R },
{ PS2_KC_S, PS2_KEY_S },
{ PS2_KC_T, PS2_KEY_T },
{ PS2_KC_U, PS2_KEY_U },
{ PS2_KC_V, PS2_KEY_V },
{ PS2_KC_W, PS2_KEY_W },
{ PS2_KC_X, PS2_KEY_X },
{ PS2_KC_Y, PS2_KEY_Y },
{ PS2_KC_Z, PS2_KEY_Z },
{ PS2_KC_SEMI, PS2_KEY_SEMI },
{ PS2_KC_BACK, PS2_KEY_HASH },
{ PS2_KC_OPEN_SQ, PS2_KEY_OPEN_SQ },
{ PS2_KC_CLOSE_SQ, PS2_KEY_CLOSE_SQ },
{ PS2_KC_EQUAL, PS2_KEY_EQUAL },
{ PS2_KC_EUROPE2, PS2_KEY_BACK },
{ PS2_KC_F1, PS2_KEY_F1 },
{ PS2_KC_F2, PS2_KEY_F2 },
{ PS2_KC_F3, PS2_KEY_F3 },
{ PS2_KC_F4, PS2_KEY_F4 },
{ PS2_KC_F5, PS2_KEY_F5 },
{ PS2_KC_F6, PS2_KEY_F6 },
{ PS2_KC_F7, PS2_KEY_F7 },
{ PS2_KC_F8, PS2_KEY_F8 },
{ PS2_KC_F9, PS2_KEY_F9 },
{ PS2_KC_F10, PS2_KEY_F10 },
{ PS2_KC_F11, PS2_KEY_F11 },
{ PS2_KC_F12, PS2_KEY_F12 },
{ PS2_KC_KP_COMMA, PS2_KEY_KP_COMMA },
{ PS2_KC_INTL1, PS2_KEY_INTL1 },
{ PS2_KC_INTL2, PS2_KEY_INTL2 },
{ PS2_KC_INTL3, PS2_KEY_INTL3 },
{ PS2_KC_INTL4, PS2_KEY_INTL4 },
{ PS2_KC_INTL5, PS2_KEY_INTL5 },
{ PS2_KC_LANG1, PS2_KEY_LANG1 },
{ PS2_KC_LANG2, PS2_KEY_LANG2 },
{ PS2_KC_LANG3, PS2_KEY_LANG3 },
{ PS2_KC_LANG4, PS2_KEY_LANG4 },
{ PS2_KC_LANG5, PS2_KEY_LANG5 }
};
/* Two byte Key table after an E0 byte received */
const uint8_t extended_key[][ 2 ] = {
{ PS2_KC_IGNORE, PS2_KEY_IGNORE },
{ PS2_KC_PRTSCR, PS2_KEY_PRTSCR },
{ PS2_KC_CTRL, PS2_KEY_R_CTRL },
{ PS2_KC_ALT, PS2_KEY_R_ALT },
{ PS2_KC_L_GUI, PS2_KEY_L_GUI },
{ PS2_KC_R_GUI, PS2_KEY_R_GUI },
{ PS2_KC_MENU, PS2_KEY_MENU },
{ PS2_KC_BREAK, PS2_KEY_BREAK },
{ PS2_KC_HOME, PS2_KEY_HOME },
{ PS2_KC_END, PS2_KEY_END },
{ PS2_KC_PGUP, PS2_KEY_PGUP },
{ PS2_KC_PGDN, PS2_KEY_PGDN },
{ PS2_KC_L_ARROW, PS2_KEY_L_ARROW },
{ PS2_KC_R_ARROW, PS2_KEY_R_ARROW },
{ PS2_KC_UP_ARROW, PS2_KEY_UP_ARROW },
{ PS2_KC_DN_ARROW, PS2_KEY_DN_ARROW },
{ PS2_KC_INSERT, PS2_KEY_INSERT },
{ PS2_KC_DELETE, PS2_KEY_DELETE },
{ PS2_KC_KP_ENTER, PS2_KEY_KP_ENTER },
{ PS2_KC_KP_DIV, PS2_KEY_KP_DIV },
{ PS2_KC_NEXT_TR, PS2_KEY_NEXT_TR },
{ PS2_KC_PREV_TR, PS2_KEY_PREV_TR },
{ PS2_KC_STOP, PS2_KEY_STOP },
{ PS2_KC_PLAY, PS2_KEY_PLAY },
{ PS2_KC_MUTE, PS2_KEY_MUTE },
{ PS2_KC_VOL_UP, PS2_KEY_VOL_UP },
{ PS2_KC_VOL_DN, PS2_KEY_VOL_DN },
{ PS2_KC_MEDIA, PS2_KEY_MEDIA },
{ PS2_KC_EMAIL, PS2_KEY_EMAIL },
{ PS2_KC_CALC, PS2_KEY_CALC },
{ PS2_KC_COMPUTER, PS2_KEY_COMPUTER },
{ PS2_KC_WEB_SEARCH, PS2_KEY_WEB_SEARCH },
{ PS2_KC_WEB_HOME, PS2_KEY_WEB_HOME },
{ PS2_KC_WEB_BACK, PS2_KEY_WEB_BACK },
{ PS2_KC_WEB_FORWARD, PS2_KEY_WEB_FORWARD },
{ PS2_KC_WEB_STOP, PS2_KEY_WEB_STOP },
{ PS2_KC_WEB_REFRESH, PS2_KEY_WEB_REFRESH },
{ PS2_KC_WEB_FAVOR, PS2_KEY_WEB_FAVOR },
{ PS2_KC_POWER, PS2_KEY_POWER },
{ PS2_KC_SLEEP, PS2_KEY_SLEEP },
{ PS2_KC_WAKE, PS2_KEY_WAKE }
};
/* Scroll lock numeric keypad re-mappings for NOT NUMLOCK */
/* in translated code order order is important */
const uint8_t scroll_remap[] = {
PS2_KEY_INSERT, // PS2_KEY_KP0
PS2_KEY_END, // PS2_KEY_KP1
PS2_KEY_DN_ARROW, // PS2_KEY_KP2
PS2_KEY_PGDN, // PS2_KEY_KP3
PS2_KEY_L_ARROW, // PS2_KEY_KP4
PS2_KEY_IGNORE, // PS2_KEY_KP5
PS2_KEY_R_ARROW, // PS2_KEY_KP6
PS2_KEY_HOME, // PS2_KEY_KP7
PS2_KEY_UP_ARROW, // PS2_KEY_KP8
PS2_KEY_PGUP, // PS2_KEY_KP9
PS2_KEY_DELETE // PS2_KEY_KP_DOT
};
//const uint8_t single_key[][ 2 ] = {
// { PS2_KC_NUM, PS2_KEY_NUM },
// { PS2_KC_SCROLL, PS2_KEY_SCROLL },
// { PS2_KC_CAPS, PS2_KEY_CAPS },
// { PS2_KC_L_SHIFT, PS2_KEY_L_SHIFT },
// { PS2_KC_R_SHIFT, PS2_KEY_R_SHIFT },
// { PS2_KC_CTRL, PS2_KEY_L_CTRL },
// { PS2_KC_ALT, PS2_KEY_L_ALT },
// { PS2_KC_SYSRQ, PS2_KEY_SYSRQ },
// { PS2_KC_ESC, PS2_KEY_ESC },
// { PS2_KC_BS, PS2_KEY_BS },
// { PS2_KC_TAB, PS2_KEY_TAB },
// { PS2_KC_ENTER, PS2_KEY_ENTER },
// { PS2_KC_SPACE, PS2_KEY_SPACE },
// { PS2_KC_KP0, PS2_KEY_KP0 },
// { PS2_KC_KP1, PS2_KEY_KP1 },
// { PS2_KC_KP2, PS2_KEY_KP2 },
// { PS2_KC_KP3, PS2_KEY_KP3 },
// { PS2_KC_KP4, PS2_KEY_KP4 },
// { PS2_KC_KP5, PS2_KEY_KP5 },
// { PS2_KC_KP6, PS2_KEY_KP6 },
// { PS2_KC_KP7, PS2_KEY_KP7 },
// { PS2_KC_KP8, PS2_KEY_KP8 },
// { PS2_KC_KP9, PS2_KEY_KP9 },
// { PS2_KC_KP_DOT, PS2_KEY_KP_DOT },
// { PS2_KC_KP_PLUS, PS2_KEY_KP_PLUS },
// { PS2_KC_KP_MINUS, PS2_KEY_KP_MINUS },
// { PS2_KC_KP_TIMES, PS2_KEY_KP_TIMES },
// { PS2_KC_KP_EQUAL, PS2_KEY_KP_EQUAL },
// { PS2_KC_0, PS2_KEY_0 },
// { PS2_KC_1, PS2_KEY_1 },
// { PS2_KC_2, PS2_KEY_2 },
// { PS2_KC_3, PS2_KEY_3 },
// { PS2_KC_4, PS2_KEY_4 },
// { PS2_KC_5, PS2_KEY_5 },
// { PS2_KC_6, PS2_KEY_6 },
// { PS2_KC_7, PS2_KEY_7 },
// { PS2_KC_8, PS2_KEY_8 },
// { PS2_KC_9, PS2_KEY_9 },
// { PS2_KC_APOS, PS2_KEY_APOS },
// { PS2_KC_COMMA, PS2_KEY_COMMA },
// { PS2_KC_MINUS, PS2_KEY_MINUS },
// { PS2_KC_DOT, PS2_KEY_DOT },
// { PS2_KC_DIV, PS2_KEY_DIV },
// { PS2_KC_BTICK, PS2_KEY_BTICK },
// { PS2_KC_A, PS2_KEY_A },
// { PS2_KC_B, PS2_KEY_B },
// { PS2_KC_C, PS2_KEY_C },
// { PS2_KC_D, PS2_KEY_D },
// { PS2_KC_E, PS2_KEY_E },
// { PS2_KC_F, PS2_KEY_F },
// { PS2_KC_G, PS2_KEY_G },
// { PS2_KC_H, PS2_KEY_H },
// { PS2_KC_I, PS2_KEY_I },
// { PS2_KC_J, PS2_KEY_J },
// { PS2_KC_K, PS2_KEY_K },
// { PS2_KC_L, PS2_KEY_L },
// { PS2_KC_M, PS2_KEY_M },
// { PS2_KC_N, PS2_KEY_N },
// { PS2_KC_O, PS2_KEY_O },
// { PS2_KC_P, PS2_KEY_P },
// { PS2_KC_Q, PS2_KEY_Q },
// { PS2_KC_R, PS2_KEY_R },
// { PS2_KC_S, PS2_KEY_S },
// { PS2_KC_T, PS2_KEY_T },
// { PS2_KC_U, PS2_KEY_U },
// { PS2_KC_V, PS2_KEY_V },
// { PS2_KC_W, PS2_KEY_W },
// { PS2_KC_X, PS2_KEY_X },
// { PS2_KC_Y, PS2_KEY_Y },
// { PS2_KC_Z, PS2_KEY_Z },
// { PS2_KC_SEMI, PS2_KEY_SEMI },
// { PS2_KC_BACK, PS2_KEY_BACK },
// { PS2_KC_OPEN_SQ, PS2_KEY_OPEN_SQ },
// { PS2_KC_CLOSE_SQ, PS2_KEY_CLOSE_SQ },
// { PS2_KC_EQUAL, PS2_KEY_EQUAL },
// { PS2_KC_EUROPE2, PS2_KEY_BACK },
// { PS2_KC_F1, PS2_KEY_F1 },
// { PS2_KC_F2, PS2_KEY_F2 },
// { PS2_KC_F3, PS2_KEY_F3 },
// { PS2_KC_F4, PS2_KEY_F4 },
// { PS2_KC_F5, PS2_KEY_F5 },
// { PS2_KC_F6, PS2_KEY_F6 },
// { PS2_KC_F7, PS2_KEY_F7 },
// { PS2_KC_F8, PS2_KEY_F8 },
// { PS2_KC_F9, PS2_KEY_F9 },
// { PS2_KC_F10, PS2_KEY_F10 },
// { PS2_KC_F11, PS2_KEY_F11 },
// { PS2_KC_F12, PS2_KEY_F12 },
// { PS2_KC_KP_COMMA, PS2_KEY_KP_COMMA },
// { PS2_KC_INTL1, PS2_KEY_INTL1 },
// { PS2_KC_INTL2, PS2_KEY_INTL2 },
// { PS2_KC_INTL3, PS2_KEY_INTL3 },
// { PS2_KC_INTL4, PS2_KEY_INTL4 },
// { PS2_KC_INTL5, PS2_KEY_INTL5 },
// { PS2_KC_LANG1, PS2_KEY_LANG1 },
// { PS2_KC_LANG2, PS2_KEY_LANG2 },
// { PS2_KC_LANG3, PS2_KEY_LANG3 },
// { PS2_KC_LANG4, PS2_KEY_LANG4 },
// { PS2_KC_LANG5, PS2_KEY_LANG5 }
// };
//
///* Two byte Key table after an E0 byte received */
//const uint8_t extended_key[][ 2 ] = {
// { PS2_KC_IGNORE, PS2_KEY_IGNORE },
// { PS2_KC_PRTSCR, PS2_KEY_PRTSCR },
// { PS2_KC_CTRL, PS2_KEY_R_CTRL },
// { PS2_KC_ALT, PS2_KEY_R_ALT },
// { PS2_KC_L_GUI, PS2_KEY_L_GUI },
// { PS2_KC_R_GUI, PS2_KEY_R_GUI },
// { PS2_KC_MENU, PS2_KEY_MENU },
// { PS2_KC_BREAK, PS2_KEY_BREAK },
// { PS2_KC_HOME, PS2_KEY_HOME },
// { PS2_KC_END, PS2_KEY_END },
// { PS2_KC_PGUP, PS2_KEY_PGUP },
// { PS2_KC_PGDN, PS2_KEY_PGDN },
// { PS2_KC_L_ARROW, PS2_KEY_L_ARROW },
// { PS2_KC_R_ARROW, PS2_KEY_R_ARROW },
// { PS2_KC_UP_ARROW, PS2_KEY_UP_ARROW },
// { PS2_KC_DN_ARROW, PS2_KEY_DN_ARROW },
// { PS2_KC_INSERT, PS2_KEY_INSERT },
// { PS2_KC_DELETE, PS2_KEY_DELETE },
// { PS2_KC_KP_ENTER, PS2_KEY_KP_ENTER },
// { PS2_KC_KP_DIV, PS2_KEY_KP_DIV },
// { PS2_KC_NEXT_TR, PS2_KEY_NEXT_TR },
// { PS2_KC_PREV_TR, PS2_KEY_PREV_TR },
// { PS2_KC_STOP, PS2_KEY_STOP },
// { PS2_KC_PLAY, PS2_KEY_PLAY },
// { PS2_KC_MUTE, PS2_KEY_MUTE },
// { PS2_KC_VOL_UP, PS2_KEY_VOL_UP },
// { PS2_KC_VOL_DN, PS2_KEY_VOL_DN },
// { PS2_KC_MEDIA, PS2_KEY_MEDIA },
// { PS2_KC_EMAIL, PS2_KEY_EMAIL },
// { PS2_KC_CALC, PS2_KEY_CALC },
// { PS2_KC_COMPUTER, PS2_KEY_COMPUTER },
// { PS2_KC_WEB_SEARCH, PS2_KEY_WEB_SEARCH },
// { PS2_KC_WEB_HOME, PS2_KEY_WEB_HOME },
// { PS2_KC_WEB_BACK, PS2_KEY_WEB_BACK },
// { PS2_KC_WEB_FORWARD, PS2_KEY_WEB_FORWARD },
// { PS2_KC_WEB_STOP, PS2_KEY_WEB_STOP },
// { PS2_KC_WEB_REFRESH, PS2_KEY_WEB_REFRESH },
// { PS2_KC_WEB_FAVOR, PS2_KEY_WEB_FAVOR },
// { PS2_KC_POWER, PS2_KEY_POWER },
// { PS2_KC_SLEEP, PS2_KEY_SLEEP },
// { PS2_KC_WAKE, PS2_KEY_WAKE }
// };
//
///* Scroll lock numeric keypad re-mappings for NOT NUMLOCK */
///* in translated code order order is important */
//const uint8_t scroll_remap[] = {
// PS2_KEY_INSERT, // PS2_KEY_KP0
// PS2_KEY_END, // PS2_KEY_KP1
// PS2_KEY_DN_ARROW, // PS2_KEY_KP2
// PS2_KEY_PGDN, // PS2_KEY_KP3
// PS2_KEY_L_ARROW, // PS2_KEY_KP4
// PS2_KEY_IGNORE, // PS2_KEY_KP5
// PS2_KEY_R_ARROW, // PS2_KEY_KP6
// PS2_KEY_HOME, // PS2_KEY_KP7
// PS2_KEY_UP_ARROW, // PS2_KEY_KP8
// PS2_KEY_PGUP, // PS2_KEY_KP9
// PS2_KEY_DELETE // PS2_KEY_KP_DOT
// };
//
#endif

View File

@@ -1 +0,0 @@
../../../sharpkey/main/include/PS2Mouse.h

187
main/include/PS2Mouse.h Normal file
View File

@@ -0,0 +1,187 @@
/////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Name: PS2Mouse.h
// Created: Jan 2022
// Version: v1.0
// Author(s): Philip Smart
// Description: Header file for the PS/2 Mouse Class.
//
// Credits:
// Copyright: (c) 2022 Philip Smart <philip.smart@net2net.org>
//
// History: Mar 2022 - Initial write.
//
// Notes: See Makefile to enable/disable conditional components
//
/////////////////////////////////////////////////////////////////////////////////////////////////////////
// This source file is free software: you can redistribute it and#or modify
// it under the terms of the GNU General Public License as published
// by the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This source file is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
/////////////////////////////////////////////////////////////////////////////////////////////////////////
#ifndef MOUSE_H_
#define MOUSE_H_
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <functional>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_log.h"
#include "Arduino.h"
#include "driver/gpio.h"
#include "soc/timer_group_struct.h"
#include "soc/timer_group_reg.h"
// PS/2 Mouse Class.
class PS2Mouse {
// mode status flags
#define _PS2_BUSY 0x04
#define _TX_MODE 0x02
#define _WAIT_RESPONSE 0x01
// Constants.
#define MAX_PS2_XMIT_KEY_BUF 16
#define MAX_PS2_RCV_KEY_BUF 16
#define INTELLI_MOUSE 3
#define SCALING_1_TO_1 0xE6
#define DEFAULT_MOUSE_TIMEOUT 100
public:
// Public structures used for containment of mouse movement and control data. These are used by the insantiating
// object to request and process mouse data.
// Postional data - X/Y co-ordinates of mouse movement.
typedef struct {
int x, y;
} Position;
// Mouse data, containing positional data, status, wheel data and validity.
typedef struct {
bool valid;
bool overrun;
int status;
Position position;
int wheel;
} MouseData;
// Enumeration of all processed mouse responses.
enum Responses {
MOUSE_RESP_ACK = 0xFA,
};
// Enumeration of all processed mouse commands.
enum Commands {
MOUSE_CMD_SET_SCALING_1_1 = 0xE6,
MOUSE_CMD_SET_SCALING_2_1 = 0xE7,
MOUSE_CMD_SET_RESOLUTION = 0xE8,
MOUSE_CMD_GET_STATUS = 0xE9,
MOUSE_CMD_SET_STREAM_MODE = 0xEA,
MOUSE_CMD_REQUEST_DATA = 0xEB,
MOUSE_CMD_SET_REMOTE_MODE = 0xF0,
MOUSE_CMD_GET_DEVICE_ID = 0xF2,
MOUSE_CMD_SET_SAMPLE_RATE = 0xF3,
MOUSE_CMD_ENABLE_STREAMING = 0xF4,
MOUSE_CMD_DISABLE_STREAMING = 0xF5,
MOUSE_CMD_RESEND = 0xFE,
MOUSE_CMD_RESET = 0xFF,
};
// Resolution - the PS/2 mouse can digitize movement from 1mm to 1/8mm, the default being 1/4 (ie. 1mm = 4 counts). This allows configuration for a finer or rougher
// tracking digitisation.
enum PS2_RESOLUTION {
PS2_MOUSE_RESOLUTION_1_1 = 0x00,
PS2_MOUSE_RESOLUTION_1_2 = 0x01,
PS2_MOUSE_RESOLUTION_1_4 = 0x02,
PS2_MOUSE_RESOLUTION_1_8 = 0x03,
};
// Scaling - the PS/2 mouse can provide linear (1:1 no scaling) or non liner (2:1 scaling) adaptation of the digitised data. This allows configuration for amplification of movements.
enum PS2_SCALING {
PS2_MOUSE_SCALING_1_1 = 0x00,
PS2_MOUSE_SCALING_2_1 = 0x01,
};
// Sampling rate - the PS/2 mouse, in streaming mode, the mouse sends with movement updates. This allows for finer or rougher digitisation of movements. The default is 100 samples per
// second and the X68000 is fixed at 100 samples per second. Adjusting the ps/2 sample rate will affect tracking granularity on the X68000.
enum PS2_SAMPLING {
PS2_MOUSE_SAMPLE_RATE_10 = 10,
PS2_MOUSE_SAMPLE_RATE_20 = 20,
PS2_MOUSE_SAMPLE_RATE_40 = 40,
PS2_MOUSE_SAMPLE_RATE_60 = 60,
PS2_MOUSE_SAMPLE_RATE_80 = 80,
PS2_MOUSE_SAMPLE_RATE_100 = 100,
PS2_MOUSE_SAMPLE_RATE_200 = 200,
};
// Public accessible prototypes.
PS2Mouse(int clockPin, int dataPin);
~PS2Mouse();
void writeByte(uint8_t);
bool setResolution(enum PS2_RESOLUTION resolution);
bool setStreamMode(void);
bool setRemoteMode(void);
bool setScaling(enum PS2_SCALING scaling);
char getDeviceId(void);
bool checkIntelliMouseExtensions(void);
bool setSampleRate(enum PS2_SAMPLING rate);
bool enableStreaming(void);
bool disableStreaming(void);
bool getStatus(uint8_t *respBuf);
bool reset(void);
MouseData readData(void);
void initialize(void);
// Method to register an object method for callback with context.
template<typename A, typename B>
void setMouseDataCallback(A func_ptr, B obj_ptr)
{
ps2Ctrl.mouseDataCallback = bind(func_ptr, obj_ptr, 0, std::placeholders::_1);
}
private:
// PS/2 Control structure - maintains all data and variables relevant to forming a connection with a PS/2 mouse, interaction and processing of its data.
struct {
int clkPin; // Hardware clock pin - bidirectional.
int dataPin; // Hardware data pin - bidirectional.
volatile uint8_t mode; // mode contains _PS2_BUSY bit 2 = busy until all expected bytes RX/TX
// _TX_MODE bit 1 = direction 1 = TX, 0 = RX (default)
// _WAIT_RESPONSE bit 0 = expecting data response
bool supportsIntelliMouseExtensions; // Intellimouse extensions supported.
bool streamingEnabled; // Streaming mode has been enabled.
volatile uint8_t bitCount; // Main state variable and bit count for interrupts
volatile uint8_t shiftReg; // Incoming/Outgoing data shift register.
volatile uint8_t parity; // Parity flag for data being sent/received.
uint16_t rxBuf[16]; // RX buffer - assembled bytes are stored in this buffer awaiting processing.
int rxPos; // Position in buffer to store next byte.
// Callback for streaming processed mouse data to HID handler.
std::function<void(PS2Mouse::MouseData)> mouseDataCallback;
} ps2Ctrl;
// Structure to store incoming streamed mouse data along with validity flags.
struct {
MouseData mouseData;
bool newData; // An update has occurred since the last query.
bool overrun; // A data overrun has occurred since the last query.
} streaming;
// Interrupt handler - needs to be declared static and assigned to internal RAM (within the ESP32) to function correctly.
IRAM_ATTR static void ps2interrupt( void );
// Prototypes.
bool requestData(uint8_t expectedBytes, uint8_t *respBuf, uint32_t timeout);
bool sendCmd(uint8_t cmd, uint8_t expectedBytes, uint8_t *respBuf, uint32_t timeout);
};
#endif // MOUSE_H_

View File

@@ -1 +0,0 @@
../../../sharpkey/main/include/SWITCH.h

232
main/include/SWITCH.h Normal file
View File

@@ -0,0 +1,232 @@
/////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Name: SWITCH.h
// Created: May 2022
// Version: v1.0
// Author(s): Philip Smart
// Description: Class definition to encapsulate the SharpKey WiFi/Config Switch.
//
// Credits:
// Copyright: (c) 2019-2022 Philip Smart <philip.smart@net2net.org>
//
// History: May 2022 - Initial write.
// v1.00 Jun 2022 - Updates to add additional callbacks for RESET and CLEARNVS
//
// Notes: See Makefile to enable/disable conditional components
//
/////////////////////////////////////////////////////////////////////////////////////////////////////////
// This source file is free software: you can redistribute it and#or modify
// it under the terms of the GNU General Public License as published
// by the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This source file is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
/////////////////////////////////////////////////////////////////////////////////////////////////////////
#ifndef SWITCH_H
#define SWITCH_H
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <iostream>
#include <functional>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/semphr.h"
#include "esp_log.h"
#include "esp_system.h"
#include "soc/timer_group_struct.h"
#include "soc/timer_group_reg.h"
#include "driver/timer.h"
#include "LED.h"
// NB: Macros definitions put inside class for clarity, they are still global scope.
// Switch class.
class SWITCH {
// Macros.
//
#define NUMELEM(a) (sizeof(a)/sizeof(a[0]))
// Constants.
#define SWITCH_VERSION 1.00
public:
// Prototypes.
SWITCH(LED *led);
SWITCH(void);
virtual ~SWITCH(void);
// Method to register an object method for callback with context.
template<typename A, typename B>
void setCancelEventCallback(A func_ptr, B obj_ptr)
{
swCtrl.cancelEventCallback = std::bind(func_ptr, obj_ptr);
}
template<typename A>
void setCancelEventCallback(A func_ptr)
{
swCtrl.cancelEventCallback = std::bind(func_ptr);
}
// Wifi enable (configured mode).
template<typename A, typename B>
void setWifiEnEventCallback(A func_ptr, B obj_ptr)
{
swCtrl.wifiEnEventCallback = std::bind(func_ptr, obj_ptr);
}
template<typename A>
void setWifiEnEventCallback(A func_ptr)
{
swCtrl.wifiEnEventCallback = std::bind(func_ptr);
}
// Wifi default mode enable.
template<typename A, typename B>
void setWifiDefEventCallback(A func_ptr, B obj_ptr)
{
swCtrl.wifiDefEventCallback = std::bind(func_ptr, obj_ptr);
}
template<typename A>
void setWifiDefEventCallback(A func_ptr)
{
swCtrl.wifiDefEventCallback = std::bind(func_ptr);
}
// Bluetooth start pairing event.
template<typename A, typename B>
void setBTPairingEventCallback(A func_ptr, B obj_ptr)
{
swCtrl.btPairingEventCallback = std::bind(func_ptr, obj_ptr);
}
template<typename A>
void setBTPairingEventCallback(A func_ptr)
{
swCtrl.btPairingEventCallback = std::bind(func_ptr);
}
// RESET event - callback is executed prior to issuing an esp_restart().
template<typename A, typename B>
void setResetEventCallback(A func_ptr, B obj_ptr)
{
swCtrl.resetEventCallback = std::bind(func_ptr, obj_ptr);
}
template<typename A>
void setResetEventCallback(A func_ptr)
{
swCtrl.resetEventCallback = std::bind(func_ptr);
}
// CLEARNVS event - callback when user requests all NVS settings are erased.
template<typename A, typename B>
void setClearNVSEventCallback(A func_ptr, B obj_ptr)
{
swCtrl.clearNVSEventCallback = std::bind(func_ptr, obj_ptr);
}
template<typename A>
void setClearNVSEventCallback(A func_ptr)
{
swCtrl.clearNVSEventCallback = std::bind(func_ptr);
}
// Helper method to identify the sub class, this is used in non volatile key management.
// Warning: This method wont work if optimisation for size is enabled on the compiler.
const char *getClassName(const std::string& prettyFunction)
{
// First find the CLASS :: METHOD seperation.
size_t colons = prettyFunction.find("::");
// None, then this is not a class.
if (colons == std::string::npos)
return "::";
// Split out the class name.
size_t begin = prettyFunction.substr(0,colons).rfind(" ") + 1;
size_t end = colons - begin;
// Return the name.
return(prettyFunction.substr(begin,end).c_str());
}
// Helper method to change a file extension.
void replaceExt(std::string& fileName, const std::string& newExt)
{
// Locals.
std::string::size_type extPos = fileName.rfind('.', fileName.length());
if(extPos != std::string::npos)
{
fileName.replace(extPos+1, newExt.length(), newExt);
}
return;
}
// Template to aid in conversion of an enum to integer.
template <typename E> constexpr typename std::underlying_type<E>::type to_underlying(E e) noexcept
{
return static_cast<typename std::underlying_type<E>::type>(e);
}
// Method to return the class version number.
virtual float version(void)
{
return(SWITCH_VERSION);
}
// Method to return the name of the class.
virtual std::string ifName(void)
{
return(swCtrl.swClassName);
}
protected:
private:
// Prototypes.
void init(void);
IRAM_ATTR static void swInterface( void * pvParameters );
inline uint32_t milliSeconds(void)
{
return( (uint32_t) clock() );
}
// Structure to maintain an active setting for the LED. The LED control thread uses these values to effect the required lighting of the LED.
typedef struct {
// Name of the class for this instantiation.
std::string swClassName;
// Thread handles - Switch interface.
TaskHandle_t TaskSWIF = NULL;
// Callback for Cancel Event.
std::function<void(void)> cancelEventCallback;
// Callback for WiFi Enable Event.
std::function<void(void)> wifiEnEventCallback;
// Callback for WiFi Default Event.
std::function<void(void)> wifiDefEventCallback;
// Callback for Bluetooth Pairing Event.
std::function<void(void)> btPairingEventCallback;
// Callback is executed prior to issuing an esp_restart().
std::function<bool(void)> resetEventCallback;
// Callback when user requests all NVS settings are erased.
std::function<void(void)> clearNVSEventCallback;
} t_swControl;
// Var to store all SWITCH control variables.
t_swControl swCtrl;
// LED activity object handle.
LED *led;
};
#endif // SWITCH_H

View File

@@ -1 +0,0 @@
../../../sharpkey/main/include/WiFi.h

400
main/include/WiFi.h Normal file
View File

@@ -0,0 +1,400 @@
/////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Name: WiFi.h
// Created: Mar 2022
// Version: v1.0
// Author(s): Philip Smart
// Description: Header for the WiFi AP/Client logic.
// Credits:
// Copyright: (c) 2019-2022 Philip Smart <philip.smart@net2net.org>
//
// History: Mar 2022 - Initial write.
// v1.01 May 2022 - Initial release version.
// v1.02 Jun 2022 - Seperated out the WiFi Enable switch and made the WiFi module active/
// via a reboot process. This is necessary now that Bluetooth is inbuilt
// as the ESP32 shares an antenna and both operating together electrically
// is difficult but also the IDF stack conflicts as well.
//
// Notes: See Makefile to enable/disable conditional components
//
/////////////////////////////////////////////////////////////////////////////////////////////////////////
// This source file is free software: you can redistribute it and#or modify
// it under the terms of the GNU General Public License as published
// by the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This source file is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
/////////////////////////////////////////////////////////////////////////////////////////////////////////
#ifndef WIFI_H
#define WIFI_H
#if defined(CONFIG_IF_WIFI_ENABLED)
#include "freertos/event_groups.h"
#include "esp_system.h"
#include "esp_wifi.h"
#include "esp_event.h"
#include "nvs_flash.h"
#include "lwip/err.h"
#include "lwip/sys.h"
#include <esp_http_server.h>
#include "esp_littlefs.h"
#include <iostream>
#include <sstream>
#include <vector>
#include <arpa/inet.h>
#include "NVS.h"
#include "LED.h"
#include "HID.h"
// Include the specification class.
#include "KeyInterface.h"
// Encapsulate the WiFi functionality.
class WiFi {
// Constants.
#define WIFI_VERSION 1.02
#define OBJECT_VERSION_LIST_MAX 18
#define FILEPACK_VERSION_FILE "version.txt"
#define WIFI_AP_DEFAULT_IP "192.168.4.1"
#define WIFI_AP_DEFAULT_GW "192.168.4.1"
#define WIFI_AP_DEFAULT_NETMASK "255.255.255.0"
// The event group allows multiple bits for each event, but we only care about two events:
// - we are connected to the AP with an IP
// - we failed to connect after the maximum amount of retries
#define WIFI_CONNECTED_BIT BIT0
#define WIFI_FAIL_BIT BIT1
// Tag for ESP WiFi logging.
#define WIFITAG "WiFi"
// Menu selection types.
enum WIFIMODES {
WIFI_OFF = 0x00, // WiFi is disabled.
WIFI_ON = 0x01, // WiFi is enabled.
WIFI_CONFIG_AP = 0x02, // WiFi is set to enable Access Point to configure WiFi settings.
WIFI_CONFIG_CLIENT = 0x03 // WiFi is set to enable Client mode using persisted settings.
};
// Default WiFi parameters.
#define MAX_WIFI_SSID_LEN 31
#define MAX_WIFI_PWD_LEN 63
#define MAX_WIFI_IP_LEN 15
#define MAX_WIFI_NETMASK_LEN 15
#define MAX_WIFI_GATEWAY_LEN 15
// Buffer size for sending file data in chunks to the browser.
#define MAX_CHUNK_SIZE 4096
// Max length a file path can have on the embedded storage device.
#define FILE_PATH_MAX (15 + CONFIG_LITTLEFS_OBJ_NAME_LEN)
public:
// Types for holding and maintaining a class/object to version number array.
typedef struct {
std::string object;
float version;
} t_versionItem;
typedef struct {
int elements;
t_versionItem *item[OBJECT_VERSION_LIST_MAX];
} t_versionList;
// Prototypes.
WiFi(KeyInterface *hdlKeyIf, KeyInterface *hdlMouseIf, bool defaultMode, NVS *nvs, LED *led, const char *fsPath, t_versionList *versionList);
WiFi(void);
~WiFi(void);
void run(void);
// Primary encapsulated interface object handle.
KeyInterface *keyIf;
// Secondary encapsulated interface object handle.
KeyInterface *mouseIf;
// Non Volatile Storage handle.
NVS *nvs;
// LED activity handle.
LED *led;
// Method to return the class version number.
float version(void)
{
return(WIFI_VERSION);
}
protected:
private:
// Type for key:value pairs.
typedef struct {
std::string name;
std::string value;
} t_kvPair;
// Structure to maintain wifi configuration data. This data is persisted through powercycles as needed.
typedef struct {
// Client access parameters, these, when valid, are used for binding to a known wifi access point.
struct {
bool valid;
char ssid[MAX_WIFI_SSID_LEN+1];
char pwd[MAX_WIFI_PWD_LEN+1];
bool useDHCP;
char ip[MAX_WIFI_IP_LEN+1];
char netmask[MAX_WIFI_NETMASK_LEN+1];
char gateway[MAX_WIFI_GATEWAY_LEN+1];
} clientParams;
// Structure to maintain Access Point parameters. These are configurable to allow possibility of changing them.
struct {
char ssid[MAX_WIFI_SSID_LEN+1];
char pwd[MAX_WIFI_PWD_LEN+1];
char ip[MAX_WIFI_IP_LEN+1];
char netmask[MAX_WIFI_NETMASK_LEN+1];
char gateway[MAX_WIFI_GATEWAY_LEN+1];
} apParams;
// General runtime control parameters.
struct {
// Configured mode of the Wifi: Access Point or Client.
enum WIFIMODES wifiMode;
} params;
} t_wifiConfig;
// Configuration data.
t_wifiConfig wifiConfig;
// Structure to manage the WiFi control variables, signifying the state of the Client or Access Point, runtime dependent, and
// necessary dedicated run variables (as opposed to locals).
typedef struct {
// Client mode variables, active when in client mode.
struct {
int clientRetryCnt;
bool connected;
char ssid[MAX_WIFI_SSID_LEN+1];
char pwd[MAX_WIFI_PWD_LEN+1];
char ip[MAX_WIFI_IP_LEN+1];
char netmask[MAX_WIFI_NETMASK_LEN+1];
char gateway[MAX_WIFI_GATEWAY_LEN+1];
} client;
// Access Point mode variabls, active when in AP mode.
struct {
char ssid[MAX_WIFI_SSID_LEN+1];
char pwd[MAX_WIFI_PWD_LEN+1];
char ip[MAX_WIFI_IP_LEN+1];
char netmask[MAX_WIFI_NETMASK_LEN+1];
char gateway[MAX_WIFI_GATEWAY_LEN+1];
} ap;
// HTTP session variables, parsed out of incoming connections. The sessions are synchronous so only maintain
// one copy.
struct {
std::string host;
std::string queryStr;
std::string fileName;
std::string filePath;
bool gzip;
bool deflate;
} session;
// Runtime variables, used for global control of the WiFi module.
//
struct {
// Default path on the underlying filesystem. This is where the NVS/SD partition is mounted and all files under this directory are accessible.
const char * fsPath;
// Version list of all objects used to build the SharpKey interface along with their version numbers.
t_versionList *versionList;
// Run mode of the Wifi: Off, On or Access Point.
enum WIFIMODES wifiMode;
// Handle to http server.
httpd_handle_t server;
// Class name, used for NVS keys.
std::string thisClass;
// Flag to raise a reboot button on the displayed page.
bool rebootButton;
// Flag to indicate a hard reboot needed.
bool reboot;
// Base path of file storag.
char basePath[FILE_PATH_MAX];
// String to hold any response error message.
std::string errorMsg;
} run;
} t_wifiControl;
// Control data.
t_wifiControl wifiCtrl;
// Prototypes.
bool setupWifiClient(void);
bool setupWifiAP(void);
bool stopWifi(void);
bool startWebserver(void);
void stopWebserver(void);
float getVersionNumber(std::string name);
esp_err_t expandAndSendFile(httpd_req_t *req, const char *basePath, std::string fileName);
esp_err_t expandVarsAndSend(httpd_req_t *req, std::string str);
esp_err_t sendKeyMapHeaders(httpd_req_t *req);
esp_err_t sendKeyMapTypes(httpd_req_t *req);
esp_err_t sendKeyMapCustomTypeFields(httpd_req_t *req);
esp_err_t sendKeyMapData(httpd_req_t *req);
esp_err_t sendKeyMapPopovers(httpd_req_t *req);
esp_err_t sendMouseRadioChoice(httpd_req_t *req, const char *option);
esp_err_t wifiDataPOSTHandler(httpd_req_t *req, std::vector<t_kvPair> pairs, std::string& resp);
esp_err_t mouseDataPOSTHandler(httpd_req_t *req, std::vector<t_kvPair> pairs, std::string& resp);
static esp_err_t defaultDataPOSTHandler(httpd_req_t *req);
static esp_err_t defaultDataGETHandler(httpd_req_t *req);
IRAM_ATTR static esp_err_t otaFirmwareUpdatePOSTHandler(httpd_req_t *req);
IRAM_ATTR static esp_err_t otaFilepackUpdatePOSTHandler(httpd_req_t *req);
static esp_err_t keymapUploadPOSTHandler(httpd_req_t *req);
static esp_err_t keymapTablePOSTHandler(httpd_req_t *req);
static esp_err_t defaultRebootHandler(httpd_req_t *req);
esp_err_t getPOSTData(httpd_req_t *req, std::vector<t_kvPair> *pairs);
bool isFileExt(std::string fileName, std::string extension);
esp_err_t setContentTypeFromFileType(httpd_req_t *req, std::string fileName);
esp_err_t getPathFromURI(std::string& destPath, std::string& destFile, const char *basePath, const char *uri);
esp_err_t getPathFromURI(std::string& destPath, const char *basePath, const char *uri);
static esp_err_t defaultFileHandler(httpd_req_t *req);
std::string esp32PartitionType(esp_partition_type_t type);
std::string esp32PartitionSubType(esp_partition_subtype_t subtype);
IRAM_ATTR static void pairBluetoothDevice(void *pvParameters);
IRAM_ATTR static void wifiAPHandler(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data);
IRAM_ATTR static void wifiClientHandler(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data);
// Method to split a string based on a delimiter and store in a vector.
std::vector<std::string> split(std::string s, std::string delimiter)
{
// Locals.
size_t pos_start = 0;
size_t pos_end;
size_t delim_len = delimiter.length();
std::string token;
std::vector<std::string> res;
// Loop through the string locating delimiters and split on each occurrence.
while((pos_end = s.find (delimiter, pos_start)) != std::string::npos)
{
token = s.substr (pos_start, pos_end - pos_start);
pos_start = pos_end + delim_len;
// Push each occurrence onto Vector.
res.push_back (token);
}
// Store last item in vector.
res.push_back (s.substr (pos_start));
return res;
}
// check if a given string is a numeric string or not
bool isNumber(const std::string &str)
{
// `std::find_first_not_of` searches the string for the first character
// that does not match any of the characters specified in its arguments
return !str.empty() &&
(str.find_first_not_of("[0123456789]") == std::string::npos);
}
// Function to split string `str` using a given delimiter
std::vector<std::string> split(const std::string &str, char delim)
{
auto i = 0;
std::vector<std::string> list;
auto pos = str.find(delim);
while (pos != std::string::npos)
{
list.push_back(str.substr(i, pos - i));
i = ++pos;
pos = str.find(delim, pos);
}
list.push_back(str.substr(i, str.length()));
return list;
}
// Function to validate an IP address
bool validateIP(std::string ip)
{
// split the string into tokens
std::vector<std::string> list = split(ip, '.');
// if the token size is not equal to four
if (list.size() != 4) {
return false;
}
// validate each token
for (std::string str: list)
{
// verify that the string is a number or not, and the numbers
// are in the valid range
if (!isNumber(str) || std::stoi(str) > 255 || std::stoi(str) < 0) {
return false;
}
}
return true;
}
// Method to split an IP4 address into its components, checking each for validity.
bool splitIP(std::string ip, int *a, int *b, int *c, int *d)
{
// Init.
*a = *b = *c = *d = 0;
// split the string into tokens
std::vector<std::string> list = split(ip, '.');
// if the token size is not equal to four
if (list.size() != 4) {
printf("Size:%d\n", list.size());
return false;
}
// Loop through vector and check each number for validity before assigning.
for(int idx=0; idx < 4; idx++)
{
// verify that the string is a number or not, and the numbers
// are in the valid range
if (!isNumber(list.at(idx)) || std::stoi(list.at(idx)) > 255 || std::stoi(list.at(idx)) < 0) {
printf("Item:%d, %s\n", idx, list.at(idx).c_str());
return false;
}
int frag = std::stoi(list.at(idx));
if(idx == 0) *a = frag;
if(idx == 1) *b = frag;
if(idx == 2) *c = frag;
if(idx == 3) *d = frag;
}
return true;
}
};
#endif
#endif // WIFI_H

View File

@@ -1 +0,0 @@
../../../sharpkey/main/include/X1.h

687
main/include/X1.h Normal file
View File

@@ -0,0 +1,687 @@
/////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Name: X1.h
// Created: Mar 2022
// Version: v1.0
// Author(s): Philip Smart
// Description: Header for the Sharp X1 to PS/2 interface logic.
// Credits:
// Copyright: (c) 2019-2022 Philip Smart <philip.smart@net2net.org>
//
// History: Mar 2022 - Initial write.
// v1.01 May 2022 - Initial release version.
// v1.02 Jun 2022 - Updates to reflect changes realised in other modules due to addition of
// bluetooth and suspend logic due to NVS issues using both cores.
// v1.03 Jun 2022 - Further updates adding in keymaps for UK BT and Japan OADG109.
//
// Notes: See Makefile to enable/disable conditional components
//
/////////////////////////////////////////////////////////////////////////////////////////////////////////
// This source file is free software: you can redistribute it and#or modify
// it under the terms of the GNU General Public License as published
// by the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This source file is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
/////////////////////////////////////////////////////////////////////////////////////////////////////////
#ifndef X1_H
#define X1_H
// Include the specification class.
#include "KeyInterface.h"
#include "NVS.h"
#include "LED.h"
#include "HID.h"
#include <vector>
#include <map>
// NB: Macros definitions put inside class for clarity, they are still global scope.
// Encapsulate the Sharp X1 interface.
class X1 : public KeyInterface {
// Macros.
//
#define NUMELEM(a) (sizeof(a)/sizeof(a[0]))
// Constants.
#define X1IF_VERSION 1.03
#define X1IF_KEYMAP_FILE "X1_KeyMap.BIN"
#define MAX_X1_XMIT_KEY_BUF 16
#define PS2TBL_X1_MAXROWS 349
// X1 Key control bit mask.
#define X1_CTRL_TENKEY ((unsigned char) (1 << 7))
#define X1_CTRL_PRESS ((unsigned char) (1 << 6))
#define X1_CTRL_REPEAT ((unsigned char) (1 << 5))
#define X1_CTRL_GRAPH ((unsigned char) (1 << 4))
#define X1_CTRL_CAPS ((unsigned char) (1 << 3))
#define X1_CTRL_KANA ((unsigned char) (1 << 2))
#define X1_CTRL_SHIFT ((unsigned char) (1 << 1))
#define X1_CTRL_CTRL ((unsigned char) (1 << 0))
// X1 Special Key definitions.
#define X1KEY_UP 0x1E // ↑
#define X1KEY_DOWN 0x1F // ↓
#define X1KEY_LEFT 0x1D // ←
#define X1KEY_RIGHT 0x1C // → →
#define X1KEY_INS 0x12 // INS
#define X1KEY_DEL 0x08 // DEL
#define X1KEY_CLR 0x0C // CLR
#define X1KEY_HOME 0x0B // HOME
// PS2 Flag definitions.
#define PS2CTRL_NONE 0x00 // No keys active = 0
#define PS2CTRL_SHIFT 0x01 // Shfit Key active = 1
#define PS2CTRL_CTRL 0x02 // Ctrl Key active = 1
#define PS2CTRL_CAPS 0x04 // CAPS active = 1
#define PS2CTRL_KANA 0x08 // KANA active = 1
#define PS2CTRL_GRAPH 0x10 // GRAPH active = 1
#define PS2CTRL_GUI 0x20 // GUI Key active = 1
#define PS2CTRL_FUNC 0x40 // Special Function Keys active = 1
#define PS2CTRL_BREAK 0x80 // BREAK Key active = 1
#define PS2CTRL_EXACT 0x80 // EXACT Match active = 1
// The initial mapping is made inside the PS2KeyAdvanced class from Scan Code Set 2 to ASCII
// for a selected keyboard. Special functions are detected and combined inside this module
// before mapping with the table below to extract the X1 key code and control data.
// ie. PS/2 Scan Code -> ASCII + Flags -> X1 Key Code + Ctrl Data
// Keyboard mapping table column names.
#define PS2TBL_PS2KEYCODE_NAME "PS/2 KeyCode"
#define PS2TBL_PS2CTRL_NAME "PS/2 Control Key"
#define PS2TBL_KEYBOARDMODEL_NAME "For Keyboard"
#define PS2TBL_MACHINE_NAME "For Host Model"
#define PS2TBL_X1MODE_NAME "X1 Mode"
#define PS2TBL_X1KEYCODE_NAME "X1 KeyCode 1"
#define PS2TBL_X1KEYCODE_BYTE2_NAME "X1 KeyCode 2"
#define PS2TBL_X1_CTRL_NAME "X1 Control Key"
// Keyboard mapping table column types.
#define PS2TBL_PS2KEYCODE_TYPE "hex"
#define PS2TBL_PS2CTRL_TYPE "custom_cbp_ps2ctrl"
#define PS2TBL_KEYBOARDMODEL_TYPE "custom_cbp_keybmodel"
#define PS2TBL_MACHINE_TYPE "custom_cbp_machine"
#define PS2TBL_X1MODE_TYPE "custom_cbp_x1mode"
#define PS2TBL_X1KEYCODE_TYPE "hex"
#define PS2TBL_X1KEYCODE_BYTE2_TYPE "hex"
#define PS2TBL_X1CTRL_TYPE "custom_cbn_x1ctrl"
// Keyboard mapping table select list for PS2CTRL.
#define PS2TBL_PS2CTRL_SEL_NONE "NONE"
#define PS2TBL_PS2CTRL_SEL_SHIFT "SHIFT"
#define PS2TBL_PS2CTRL_SEL_CTRL "CTRL"
#define PS2TBL_PS2CTRL_SEL_CAPS "CAPS"
#define PS2TBL_PS2CTRL_SEL_KANA "KANA"
#define PS2TBL_PS2CTRL_SEL_GRAPH "GRAPH"
#define PS2TBL_PS2CTRL_SEL_GUI "GUI"
#define PS2TBL_PS2CTRL_SEL_FUNC "FUNC"
#define PS2TBL_PS2CTRL_SEL_EXACT "EXACT"
// Keyboard mapping table select list for Model of keyboard.
#define KEYMAP_SEL_STANDARD "ALL"
#define KEYMAP_SEL_UK_WYSE_KB3926 "UK_WYSE_KB3926"
#define KEYMAP_SEL_JAPAN_OADG109 "JAPAN_OADG109"
#define KEYMAP_SEL_JAPAN_SANWA_SKBL1 "JAPAN_SANWA_SKBL1"
#define KEYMAP_SEL_NOT_ASSIGNED_4 "KEYBOARD_4"
#define KEYMAP_SEL_NOT_ASSIGNED_5 "KEYBOARD_5"
#define KEYMAP_SEL_NOT_ASSIGNED_6 "KEYBOARD_6"
#define KEYMAP_SEL_UK_PERIBOARD_810 "UK_PERIBOARD_810"
#define KEYMAP_SEL_UK_OMOTON_K8508 "UK_OMOTON_K8508"
// Keyboard mapping table select list for keyboard mode.
#define X1_SEL_MODE_A "Mode_A"
#define X1_SEL_MODE_B "Mode_B"
// Keyboard mapping table select list for target machine.
#define X1_SEL_ALL "ALL"
#define X1_SEL_ORIG "ORIGINAL"
#define X1_SEL_TURBO "TURBO"
#define X1_SEL_TURBOZ "TURBOZ"
// Keyboard mapping table select list for X1 Control codes.
#define X1_CTRL_SEL_TENKEY "TENKEY"
#define X1_CTRL_SEL_PRESS "PRESS"
#define X1_CTRL_SEL_REPEAT "REPEAT"
#define X1_CTRL_SEL_GRAPH "GRAPH"
#define X1_CTRL_SEL_CAPS "CAPS"
#define X1_CTRL_SEL_KANA "KANA"
#define X1_CTRL_SEL_SHIFT "SHIFT"
#define X1_CTRL_SEL_CTRL "CTRL"
// The Sharp X1 Series was released over a number of years and each iteration added changes/updates. In order to cater for differences, it is possible to assign a key mapping
// to a specific machine type(s) or all of the series by adding the flags below into the mapping table.
#define X1_ALL 0xFF
#define X1_ORIG 0x01
#define X1_TURBO 0x02
#define X1_TURBOZ 0x04
// The X1 Turbo onwards had a mode switch on the keyboard, Mode A was normal use, Mode B was for games, speeding up the key press by shortening the timing and setting common game keys pressed in a 24bit bit map.
// The mapping table caters for both, OR'ing data in Mode B so that multiple key presses are sent across as a bit map.
#define X1_MODE_A 0x01
#define X1_MODE_B 0x02
// Keyboard models. The base on which this interface was created was a Wyse KB3926 PS/2 Keyboard and this is deemed STANDARD. Other models need to insert difference maps
// prior to the STANDARD entry along with the keyboard model so that it is processed first thus allowing differing keyboards with different maps.
#define KEYMAP_STANDARD 0xFF
#define KEYMAP_UK_WYSE_KB3926 0x01
#define KEYMAP_JAPAN_OADG109 0x02
#define KEYMAP_JAPAN_SANWA_SKBL1 0x04
#define KEYMAP_NOT_ASSIGNED_4 0x08
#define KEYMAP_NOT_ASSIGNED_5 0x10
#define KEYMAP_NOT_ASSIGNED_6 0x20
#define KEYMAP_UK_PERIBOARD_810 0x40
#define KEYMAP_UK_OMOTON_K8508 0x80
public:
// Prototypes.
X1(void);
X1(uint32_t ifMode, NVS *hdlNVS, LED *hdlLED, HID *hdlHID, const char *fsPath);
X1(NVS *hdlNVS, HID *hdlHID, const char *fsPath);
~X1(void);
bool createKeyMapFile(std::fstream &outFile);
bool storeDataToKeyMapFile(std::fstream &outFile, char *data, int size);
bool storeDataToKeyMapFile(std::fstream & outFile, std::vector<uint32_t>& dataArray);
bool closeAndCommitKeyMapFile(std::fstream &outFile, bool cleanupOnly);
std::string getKeyMapFileName(void) { return(X1IF_KEYMAP_FILE); };
void getKeyMapHeaders(std::vector<std::string>& headerList);
void getKeyMapTypes(std::vector<std::string>& typeList);
bool getKeyMapSelectList(std::vector<std::pair<std::string, int>>& selectList, std::string option);
bool getKeyMapData(std::vector<uint32_t>& dataArray, int *row, bool start);
// Method to return the class version number.
float version(void)
{
return(X1IF_VERSION);
}
protected:
private:
// Prototypes.
void pushKeyToQueue(bool keybMode, uint32_t key);
IRAM_ATTR static void x1Interface( void * pvParameters );
IRAM_ATTR static void hidInterface( void * pvParameters );
void selectOption(uint8_t optionCode);
uint32_t mapKey(uint16_t scanCode);
bool loadKeyMap();
bool saveKeyMap(void);
void init(uint32_t ifMode, NVS *hdlNVS, LED *hdlLED, HID *hdlHID);
void init(NVS *hdlNVS, HID *hdlHID);
// // Overload the base yield method to include suspension of the PS/2 Keyboard interface. This interface uses interrupts which are not mutex protected and clash with the
// // WiFi API methods.
// inline void yield(uint32_t delay)
// {
// // If suspended, go into a permanent loop until the suspend flag is reset.
// if(this->suspend)
// {
// // Suspend the keyboard interface.
// Keyboard->suspend(true);
//
// // Use the base method logic.
// KeyInterface::yield(delay);
//
// // Release the keyboard interface.
// Keyboard->suspend(false);
// } else
// // Otherwise just delay by the required amount for timing and to give other threads a time slice.
// {
// KeyInterface::yield(delay);
// }
// return;
// }
// Structure to encapsulate a single key map from PS/2 to X1.
typedef struct {
uint8_t ps2KeyCode;
uint8_t ps2Ctrl;
uint8_t keyboardModel;
uint8_t machine;
uint8_t x1Mode;
uint8_t x1Key;
uint8_t x1Key2;
uint8_t x1Ctrl;
} t_keyMapEntry;
// Structure to encapsulate the entire static keyboard mapping table.
typedef struct {
t_keyMapEntry kme[PS2TBL_X1_MAXROWS];
} t_keyMap;
// Structure to maintain the X1 interface configuration data. This data is persisted through powercycles as needed.
typedef struct {
struct {
uint8_t activeKeyboardMap; // Model of keyboard a keymap entry is applicable to.
uint8_t activeMachineModel; // Machine model a keymap entry is applicable to.
} params;
} t_x1Config;
// Configuration data.
t_x1Config x1Config;
// Structure to manage the control signals signifying the state of the X1 keyboard.
typedef struct {
bool optionSelect; // Flag to indicate a user requested keyboard configuration option is being selected.
bool modeB; // Mode B (Game mode) flag. If set, Mode B active, clear, Mode A active (normal keyboard).
uint8_t keyCtrl; // Keyboard state flag control.
std::string fsPath; // Path on the underlying filesystem where storage is mounted and accessible.
t_keyMapEntry *kme; // Pointer to an array in memory to contain PS2 to X1 mapping values.
int kmeRows; // Number of rows in the kme table.
std::string keyMapFileName; // Name of file where extension or replacement key map entries are stored.
bool persistConfig; // Flag to request saving of the config into NVS storage.
} t_x1Control;
// Transmit buffer queue item.
typedef struct {
uint32_t keyCode; // 32bit because normal mode A is 16bit, game mode B is 24bit
bool modeB; // True if in game mode B.
} t_xmitQueueMessage;
// Thread handles - one per function, ie. HID interface and host target interface.
TaskHandle_t TaskHostIF = NULL;
TaskHandle_t TaskHIDIF = NULL;
// Control structure to control interaction and mapping of keys for the host.
t_x1Control x1Control;
// Spin lock mutex to hold a coresied to an uninterruptable method. This only works on dual core ESP32's.
portMUX_TYPE x1Mutex;
// Lookup table to match PS/2 codes to X1 Key and Control Data.
//
// Given that the X1 had many variants, with potential differences between them, the mapping table allows for ALL or variant specific entries, the first entry matching is selected.
//
//
// This mapping is for the UK Wyse KB-3926 PS/2 keyboard
//
t_keyMap PS2toX1 = {
{
// HELP
// COPY
// ModeB Byte1 ModeB Byte2 ModeB Byte3
//PS2 Code PS2 Ctrl (Flags to Match) Keyboard Model Machine X1 Keyb Mode X1 Data X1 Ctrl (Flags to Set).
{ PS2_KEY_F1, PS2CTRL_FUNC | PS2CTRL_SHIFT, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 'v', 0x00, 0xFF & ~(X1_CTRL_PRESS | X1_CTRL_TENKEY), }, // SHIFT+F1
{ PS2_KEY_F2, PS2CTRL_FUNC | PS2CTRL_SHIFT, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 'w', 0x00, 0xFF & ~(X1_CTRL_PRESS | X1_CTRL_TENKEY), }, // SHIFT+F2
{ PS2_KEY_F3, PS2CTRL_FUNC | PS2CTRL_SHIFT, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 'x', 0x00, 0xFF & ~(X1_CTRL_PRESS | X1_CTRL_TENKEY), }, // SHIFT+F3
{ PS2_KEY_F4, PS2CTRL_FUNC | PS2CTRL_SHIFT, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 'y', 0x00, 0xFF & ~(X1_CTRL_PRESS | X1_CTRL_TENKEY), }, // SHIFT+F4
{ PS2_KEY_F5, PS2CTRL_FUNC | PS2CTRL_SHIFT, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 'z', 0x00, 0xFF & ~(X1_CTRL_PRESS | X1_CTRL_TENKEY), }, // SHIFT+F5
{ PS2_KEY_F1, PS2CTRL_FUNC, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 'q', 0x00, 0xFF & ~(X1_CTRL_PRESS | X1_CTRL_TENKEY), }, // F1
{ PS2_KEY_F2, PS2CTRL_FUNC, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 'r', 0x00, 0xFF & ~(X1_CTRL_PRESS | X1_CTRL_TENKEY), }, // F2
{ PS2_KEY_F3, PS2CTRL_FUNC, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 's', 0x00, 0xFF & ~(X1_CTRL_PRESS | X1_CTRL_TENKEY), }, // F3
{ PS2_KEY_F4, PS2CTRL_FUNC, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 't', 0x00, 0xFF & ~(X1_CTRL_PRESS | X1_CTRL_TENKEY), }, // F4
{ PS2_KEY_F5, PS2CTRL_FUNC, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 'u', 0x00, 0xFF & ~(X1_CTRL_PRESS | X1_CTRL_TENKEY), }, // F5
{ PS2_KEY_F6, PS2CTRL_FUNC, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0xEC, 0x00, 0xFF & ~(X1_CTRL_PRESS | X1_CTRL_TENKEY), }, // F6
{ PS2_KEY_F7, PS2CTRL_FUNC, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0xEB, 0x00, 0xFF & ~(X1_CTRL_PRESS | X1_CTRL_TENKEY), }, // F7
{ PS2_KEY_F8, PS2CTRL_FUNC, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0xE2, 0x00, 0xFF & ~(X1_CTRL_PRESS | X1_CTRL_TENKEY), }, // F8
{ PS2_KEY_F9, PS2CTRL_FUNC, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0xE1, 0x00, 0xFF & ~(X1_CTRL_PRESS | X1_CTRL_TENKEY), }, // F9
{ PS2_KEY_F10, PS2CTRL_FUNC, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0x00, 0x00, 0xFF & ~(X1_CTRL_PRESS | X1_CTRL_TENKEY), }, // XFER
{ PS2_KEY_F11, PS2CTRL_FUNC, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0xFE, 0x00, 0xFF & ~(X1_CTRL_PRESS | X1_CTRL_TENKEY), }, // HELP
{ PS2_KEY_F12, PS2CTRL_FUNC, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0x00, 0x00, 0xFF & ~(X1_CTRL_PRESS | X1_CTRL_TENKEY), }, // COPY
{ PS2_KEY_TAB, PS2CTRL_NONE, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0x09, 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // TAB
// Control keys.
{ PS2_KEY_APOS, PS2CTRL_CTRL, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0x00, 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // CTRL-@
{ PS2_KEY_A, PS2CTRL_CTRL, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0x01, 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // CTRL-A
{ PS2_KEY_B, PS2CTRL_CTRL, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0x02, 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // CTRL-B
{ PS2_KEY_C, PS2CTRL_CTRL, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0x03, 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // CTRL-C
{ PS2_KEY_D, PS2CTRL_CTRL, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0x04, 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // CTRL-D
{ PS2_KEY_E, PS2CTRL_CTRL, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0x05, 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // CTRL-E
{ PS2_KEY_F, PS2CTRL_CTRL, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0x06, 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // CTRL-F
{ PS2_KEY_G, PS2CTRL_CTRL, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0x07, 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // CTRL-G
{ PS2_KEY_H, PS2CTRL_CTRL, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0x08, 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // CTRL-H
{ PS2_KEY_I, PS2CTRL_CTRL, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0x09, 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // CTRL-I
{ PS2_KEY_J, PS2CTRL_CTRL, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0x0A, 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // CTRL-J
{ PS2_KEY_K, PS2CTRL_CTRL, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0x0B, 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // CTRL-K
{ PS2_KEY_L, PS2CTRL_CTRL, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0x0C, 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // CTRL-L
{ PS2_KEY_M, PS2CTRL_CTRL, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0x0D, 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // CTRL-M
{ PS2_KEY_N, PS2CTRL_CTRL, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0x0E, 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // CTRL-N
{ PS2_KEY_O, PS2CTRL_CTRL, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0x0F, 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // CTRL-O
{ PS2_KEY_P, PS2CTRL_CTRL, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0x10, 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // CTRL-P
{ PS2_KEY_Q, PS2CTRL_CTRL, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0x11, 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // CTRL-Q
{ PS2_KEY_R, PS2CTRL_CTRL, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0x12, 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // CTRL-R
{ PS2_KEY_S, PS2CTRL_CTRL, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0x13, 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // CTRL-S
{ PS2_KEY_T, PS2CTRL_CTRL, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0x14, 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // CTRL-T
{ PS2_KEY_U, PS2CTRL_CTRL, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0x15, 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // CTRL-U
{ PS2_KEY_V, PS2CTRL_CTRL, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0x16, 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // CTRL-V
{ PS2_KEY_W, PS2CTRL_CTRL, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0x17, 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // CTRL-W
{ PS2_KEY_X, PS2CTRL_CTRL, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0x18, 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // CTRL-X
{ PS2_KEY_Y, PS2CTRL_CTRL, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0x19, 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // CTRL-Y
{ PS2_KEY_Z, PS2CTRL_CTRL, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0x1A, 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // CTRL-Z
{ PS2_KEY_OPEN_SQ, PS2CTRL_CTRL, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0x1B, 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // CTRL-[
{ PS2_KEY_BACK, PS2CTRL_CTRL, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0x1C, 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // CTRL-BACKSLASH
{ PS2_KEY_CLOSE_SQ, PS2CTRL_CTRL, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0x1D, 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // CTRL-]
{ PS2_KEY_6, PS2CTRL_CTRL, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0x1E, 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // CTRL-^
{ PS2_KEY_MINUS, PS2CTRL_CTRL, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0x1F, 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // CTRL-_
// Numeric keys.
{ PS2_KEY_0, PS2CTRL_NONE, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, '0', 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // 0
{ PS2_KEY_1, PS2CTRL_NONE, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, '1', 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // 1
{ PS2_KEY_2, PS2CTRL_NONE, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, '2', 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // 2
{ PS2_KEY_3, PS2CTRL_NONE, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, '3', 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // 3
{ PS2_KEY_4, PS2CTRL_NONE, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, '4', 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // 4
{ PS2_KEY_5, PS2CTRL_NONE, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, '5', 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // 5
{ PS2_KEY_6, PS2CTRL_NONE, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, '6', 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // 6
{ PS2_KEY_7, PS2CTRL_NONE, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, '7', 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // 7
{ PS2_KEY_8, PS2CTRL_NONE, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, '8', 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // 8
{ PS2_KEY_9, PS2CTRL_NONE, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, '9', 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // 9
// Punctuation keys.
{ PS2_KEY_0, PS2CTRL_SHIFT, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, ')', 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // Close Right Bracket )
{ PS2_KEY_1, PS2CTRL_SHIFT, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, '!', 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // Exclamation
{ PS2_KEY_2, PS2CTRL_SHIFT, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, '"', 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // Double quote.
{ PS2_KEY_3, PS2CTRL_SHIFT, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0x23, 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // Pound Sign -> Hash
{ PS2_KEY_4, PS2CTRL_SHIFT, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, '$', 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // Dollar
{ PS2_KEY_5, PS2CTRL_SHIFT, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, '%', 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // Percent
{ PS2_KEY_6, PS2CTRL_SHIFT, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, '^', 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // Kappa
{ PS2_KEY_7, PS2CTRL_SHIFT, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, '&', 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // Ampersand
{ PS2_KEY_8, PS2CTRL_SHIFT, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, '*', 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // Star
{ PS2_KEY_9, PS2CTRL_SHIFT, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, '(', 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // Open Left Bracket (
// ALPHA keys, lower and uppercase.
// ModeB Byte1 ModeB Byte2 ModeB Byte3
//PS2 Code PS2 Ctrl (Flags to Match) Machine X1 Keyb Mode X1 Data X1 Ctrl (Flags to Set).
{ PS2_KEY_A, PS2CTRL_SHIFT | PS2CTRL_CAPS, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 'a', 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // a
{ PS2_KEY_A, PS2CTRL_CAPS, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 'A', 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // A
{ PS2_KEY_B, PS2CTRL_SHIFT | PS2CTRL_CAPS, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 'b', 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // b
{ PS2_KEY_B, PS2CTRL_CAPS, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 'B', 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // B
{ PS2_KEY_C, PS2CTRL_SHIFT | PS2CTRL_CAPS, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 'c', 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // c
{ PS2_KEY_C, PS2CTRL_CAPS, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 'C', 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // C
{ PS2_KEY_D, PS2CTRL_SHIFT | PS2CTRL_CAPS, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 'd', 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // d
{ PS2_KEY_D, PS2CTRL_CAPS, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 'D', 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // D
{ PS2_KEY_E, PS2CTRL_SHIFT | PS2CTRL_CAPS, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 'e', 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // e
{ PS2_KEY_E, PS2CTRL_CAPS, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 'E', 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // E
{ PS2_KEY_F, PS2CTRL_SHIFT | PS2CTRL_CAPS, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 'f', 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // f
{ PS2_KEY_F, PS2CTRL_CAPS, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 'F', 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // F
{ PS2_KEY_G, PS2CTRL_SHIFT | PS2CTRL_CAPS, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 'g', 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // g
{ PS2_KEY_G, PS2CTRL_CAPS, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 'G', 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // G
{ PS2_KEY_H, PS2CTRL_SHIFT | PS2CTRL_CAPS, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 'h', 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // h
{ PS2_KEY_H, PS2CTRL_CAPS, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 'H', 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // H
{ PS2_KEY_I, PS2CTRL_SHIFT | PS2CTRL_CAPS, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 'i', 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // i
{ PS2_KEY_I, PS2CTRL_CAPS, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 'I', 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // I
{ PS2_KEY_J, PS2CTRL_SHIFT | PS2CTRL_CAPS, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 'j', 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // j
{ PS2_KEY_J, PS2CTRL_CAPS, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 'J', 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // J
{ PS2_KEY_K, PS2CTRL_SHIFT | PS2CTRL_CAPS, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 'k', 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // k
{ PS2_KEY_K, PS2CTRL_CAPS, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 'K', 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // K
{ PS2_KEY_L, PS2CTRL_SHIFT | PS2CTRL_CAPS, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 'l', 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // l
{ PS2_KEY_L, PS2CTRL_CAPS, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 'L', 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // L
{ PS2_KEY_M, PS2CTRL_SHIFT | PS2CTRL_CAPS, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 'm', 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // m
{ PS2_KEY_M, PS2CTRL_CAPS, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 'M', 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // M
{ PS2_KEY_N, PS2CTRL_SHIFT | PS2CTRL_CAPS, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 'n', 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // n
{ PS2_KEY_N, PS2CTRL_CAPS, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 'N', 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // N
{ PS2_KEY_O, PS2CTRL_SHIFT | PS2CTRL_CAPS, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 'o', 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // o
{ PS2_KEY_O, PS2CTRL_CAPS, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 'O', 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // O
{ PS2_KEY_P, PS2CTRL_SHIFT | PS2CTRL_CAPS, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 'p', 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // p
{ PS2_KEY_P, PS2CTRL_CAPS, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 'P', 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // P
{ PS2_KEY_Q, PS2CTRL_SHIFT | PS2CTRL_CAPS, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 'q', 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // q
{ PS2_KEY_Q, PS2CTRL_CAPS, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 'Q', 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // Q
{ PS2_KEY_R, PS2CTRL_SHIFT | PS2CTRL_CAPS, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 'r', 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // r
{ PS2_KEY_R, PS2CTRL_CAPS, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 'R', 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // R
{ PS2_KEY_S, PS2CTRL_SHIFT | PS2CTRL_CAPS, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 's', 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // s
{ PS2_KEY_S, PS2CTRL_CAPS, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 'S', 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // S
{ PS2_KEY_T, PS2CTRL_SHIFT | PS2CTRL_CAPS, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 't', 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // t
{ PS2_KEY_T, PS2CTRL_CAPS, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 'T', 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // T
{ PS2_KEY_U, PS2CTRL_SHIFT | PS2CTRL_CAPS, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 'u', 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // u
{ PS2_KEY_U, PS2CTRL_CAPS, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 'U', 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // U
{ PS2_KEY_V, PS2CTRL_SHIFT | PS2CTRL_CAPS, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 'v', 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // v
{ PS2_KEY_V, PS2CTRL_CAPS, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 'V', 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // V
{ PS2_KEY_W, PS2CTRL_SHIFT | PS2CTRL_CAPS, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 'w', 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // w
{ PS2_KEY_W, PS2CTRL_CAPS, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 'W', 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // W
{ PS2_KEY_X, PS2CTRL_SHIFT | PS2CTRL_CAPS, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 'x', 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // x
{ PS2_KEY_X, PS2CTRL_CAPS, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 'X', 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // X
{ PS2_KEY_Y, PS2CTRL_SHIFT | PS2CTRL_CAPS, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 'y', 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // y
{ PS2_KEY_Y, PS2CTRL_CAPS, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 'Y', 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // Y
{ PS2_KEY_Z, PS2CTRL_SHIFT | PS2CTRL_CAPS, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 'z', 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // z
{ PS2_KEY_Z, PS2CTRL_CAPS, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 'Z', 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // Z
// Mode B Mappings.
{ PS2_KEY_Q, PS2CTRL_NONE, KEYMAP_STANDARD, X1_ALL, X1_MODE_B, 0b10000000, 0b00000000, 0b00000000, }, // MODE B - Q
{ PS2_KEY_W, PS2CTRL_NONE, KEYMAP_STANDARD, X1_ALL, X1_MODE_B, 0b01000000, 0b00000000, 0b00000000, }, // MODE B - W
{ PS2_KEY_E, PS2CTRL_NONE, KEYMAP_STANDARD, X1_ALL, X1_MODE_B, 0b00100000, 0b00000000, 0b00000000, }, // MODE B - E
{ PS2_KEY_A, PS2CTRL_NONE, KEYMAP_STANDARD, X1_ALL, X1_MODE_B, 0b00010000, 0b00000000, 0b00000000, }, // MODE B - A
{ PS2_KEY_D, PS2CTRL_NONE, KEYMAP_STANDARD, X1_ALL, X1_MODE_B, 0b00001000, 0b00000000, 0b00000000, }, // MODE B - D
{ PS2_KEY_Z, PS2CTRL_NONE, KEYMAP_STANDARD, X1_ALL, X1_MODE_B, 0b00000100, 0b00000000, 0b00000000, }, // MODE B - Z
{ PS2_KEY_X, PS2CTRL_NONE, KEYMAP_STANDARD, X1_ALL, X1_MODE_B, 0b00000010, 0b00000000, 0b00000000, }, // MODE B - X
{ PS2_KEY_C, PS2CTRL_NONE, KEYMAP_STANDARD, X1_ALL, X1_MODE_B, 0b00000001, 0b00000000, 0b00000000, }, // MODE B - C
{ PS2_KEY_I, PS2CTRL_NONE, KEYMAP_STANDARD, X1_ALL, X1_MODE_B, 0b00000000, 0b00000000, 0b01000000, }, // MODE B - I - this is not 100%, the specs arent clear.
{ PS2_KEY_1, PS2CTRL_NONE, KEYMAP_STANDARD, X1_ALL, X1_MODE_B, 0b00000000, 0b00100000, 0b00000000, }, // MODE B - 1
{ PS2_KEY_2, PS2CTRL_NONE, KEYMAP_STANDARD, X1_ALL, X1_MODE_B, 0b00000000, 0b00001000, 0b00000000, }, // MODE B - 2
{ PS2_KEY_3, PS2CTRL_NONE, KEYMAP_STANDARD, X1_ALL, X1_MODE_B, 0b00000000, 0b00000001, 0b00000000, }, // MODE B - 3
{ PS2_KEY_4, PS2CTRL_NONE, KEYMAP_STANDARD, X1_ALL, X1_MODE_B, 0b00000000, 0b01000000, 0b00000000, }, // MODE B - 4
{ PS2_KEY_6, PS2CTRL_NONE, KEYMAP_STANDARD, X1_ALL, X1_MODE_B, 0b00000000, 0b00000010, 0b00000000, }, // MODE B - 6
{ PS2_KEY_7, PS2CTRL_NONE, KEYMAP_STANDARD, X1_ALL, X1_MODE_B, 0b00000000, 0b10000000, 0b00000000, }, // MODE B - 7
{ PS2_KEY_8, PS2CTRL_NONE, KEYMAP_STANDARD, X1_ALL, X1_MODE_B, 0b00000000, 0b00010000, 0b00000000, }, // MODE B - 8
{ PS2_KEY_9, PS2CTRL_NONE, KEYMAP_STANDARD, X1_ALL, X1_MODE_B, 0b00000000, 0b00000100, 0b00000000, }, // MODE B - 9
{ PS2_KEY_ESC, PS2CTRL_NONE, KEYMAP_STANDARD, X1_ALL, X1_MODE_B, 0b00000000, 0b00000000, 0b10000000, }, // MODE B - ESC
{ PS2_KEY_MINUS, PS2CTRL_NONE, KEYMAP_STANDARD, X1_ALL, X1_MODE_B, 0b00000000, 0b00000000, 0b00100000, }, // MODE B - MINUS
{ PS2_KEY_EQUAL, PS2CTRL_SHIFT, KEYMAP_STANDARD, X1_ALL, X1_MODE_B, 0b00000000, 0b00000000, 0b00010000, }, // MODE B - PLUS
{ PS2_KEY_8, PS2CTRL_SHIFT, KEYMAP_STANDARD, X1_ALL, X1_MODE_B, 0b00000000, 0b00000000, 0b00001000, }, // MODE B - TIMES
{ PS2_KEY_TAB, PS2CTRL_NONE, KEYMAP_STANDARD, X1_ALL, X1_MODE_B, 0b00000000, 0b00000000, 0b00000100, }, // MODE B - TAB
{ PS2_KEY_SPACE, PS2CTRL_NONE, KEYMAP_STANDARD, X1_ALL, X1_MODE_B, 0b00000000, 0b00000000, 0b00000010, }, // MODE B - SPACE
{ PS2_KEY_ENTER, PS2CTRL_NONE, KEYMAP_STANDARD, X1_ALL, X1_MODE_B, 0b00000000, 0b00000000, 0b00000001, }, // MODE B - RET
{ PS2_KEY_KP1, PS2CTRL_NONE, KEYMAP_STANDARD, X1_ALL, X1_MODE_B, 0b00000000, 0b00100000, 0b00000000, }, // MODE B - KeyPad 1
{ PS2_KEY_KP2, PS2CTRL_NONE, KEYMAP_STANDARD, X1_ALL, X1_MODE_B, 0b00000000, 0b00001000, 0b00000000, }, // MODE B - KeyPad 2
{ PS2_KEY_KP3, PS2CTRL_NONE, KEYMAP_STANDARD, X1_ALL, X1_MODE_B, 0b00000000, 0b00000001, 0b00000000, }, // MODE B - KeyPad 3
{ PS2_KEY_KP4, PS2CTRL_NONE, KEYMAP_STANDARD, X1_ALL, X1_MODE_B, 0b00000000, 0b01000000, 0b00000000, }, // MODE B - KeyPad 4
{ PS2_KEY_KP6, PS2CTRL_NONE, KEYMAP_STANDARD, X1_ALL, X1_MODE_B, 0b00000000, 0b00000010, 0b00000000, }, // MODE B - KeyPad 6
{ PS2_KEY_KP7, PS2CTRL_NONE, KEYMAP_STANDARD, X1_ALL, X1_MODE_B, 0b00000000, 0b10000000, 0b00000000, }, // MODE B - KeyPad 7
{ PS2_KEY_KP8, PS2CTRL_NONE, KEYMAP_STANDARD, X1_ALL, X1_MODE_B, 0b00000000, 0b00010000, 0b00000000, }, // MODE B - KeyPad 8
{ PS2_KEY_KP9, PS2CTRL_NONE, KEYMAP_STANDARD, X1_ALL, X1_MODE_B, 0b00000000, 0b00000100, 0b00000000, }, // MODE B - KeyPad 9
{ PS2_KEY_KP_MINUS, PS2CTRL_NONE, KEYMAP_STANDARD, X1_ALL, X1_MODE_B, 0b00000000, 0b00000000, 0b00100000, }, // MODE B - KeyPad MINUS
{ PS2_KEY_KP_PLUS, PS2CTRL_NONE, KEYMAP_STANDARD, X1_ALL, X1_MODE_B, 0b00000000, 0b00000000, 0b00010000, }, // MODE B - KeyPad PLUS
{ PS2_KEY_KP_TIMES, PS2CTRL_NONE, KEYMAP_STANDARD, X1_ALL, X1_MODE_B, 0b00000000, 0b00000000, 0b00001000, }, // MODE B - KeyPad TIMES
// ModeB Byte1 ModeB Byte2 ModeB Byte3
//PS2 Code PS2 Ctrl (Flags to Match) Machine X1 Keyb Mode X1 Data X1 Ctrl (Flags to Set).
{ PS2_KEY_SPACE, PS2CTRL_NONE, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, ' ', 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // Space
{ PS2_KEY_COMMA, PS2CTRL_SHIFT, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, '<', 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // Less Than <
{ PS2_KEY_COMMA, PS2CTRL_NONE, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, ',', 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // Comma ,
{ PS2_KEY_SEMI, PS2CTRL_SHIFT, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, ':', 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // Colon :
{ PS2_KEY_SEMI, PS2CTRL_NONE, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, ';', 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // Semi-Colon ;
{ PS2_KEY_DOT, PS2CTRL_SHIFT, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, '>', 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // Greater Than >
{ PS2_KEY_DOT, PS2CTRL_NONE, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, '.', 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // Full stop .
{ PS2_KEY_DIV, PS2CTRL_SHIFT, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, '?', 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // Question ?
{ PS2_KEY_DIV, PS2CTRL_NONE, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, '/', 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // Divide /
{ PS2_KEY_MINUS, PS2CTRL_SHIFT, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, '_', 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // Underscore
{ PS2_KEY_MINUS, PS2CTRL_NONE, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, '-', 0x00, 0xFF & ~(X1_CTRL_PRESS), },
{ PS2_KEY_APOS, PS2CTRL_SHIFT, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, '@', 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // At @
{ PS2_KEY_APOS, PS2CTRL_NONE, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, '\'', 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // Single quote '
{ PS2_KEY_OPEN_SQ, PS2CTRL_SHIFT, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, '{', 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // Open Left Brace {
{ PS2_KEY_OPEN_SQ, PS2CTRL_NONE, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, '[', 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // Open Left Square Bracket [
{ PS2_KEY_EQUAL, PS2CTRL_SHIFT, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, '+', 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // Plus +
{ PS2_KEY_EQUAL, PS2CTRL_NONE, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, '=', 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // Equal =
{ PS2_KEY_CAPS, PS2CTRL_NONE, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, ' ', 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // LOCK
{ PS2_KEY_ENTER, PS2CTRL_NONE, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0x0D, 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // ENTER/RETURN
{ PS2_KEY_CLOSE_SQ, PS2CTRL_SHIFT, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, '}', 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // Close Right Brace }
{ PS2_KEY_CLOSE_SQ, PS2CTRL_NONE, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, ']', 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // Close Right Square Bracket ]
{ PS2_KEY_BACK, PS2CTRL_SHIFT, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, '|', 0x00, 0xFF & ~(X1_CTRL_PRESS), }, //
{ PS2_KEY_BACK, PS2CTRL_NONE, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, '\\', 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // Back slash maps to Yen
{ PS2_KEY_BTICK, PS2CTRL_SHIFT, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, '`', 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // Pipe
{ PS2_KEY_BTICK, PS2CTRL_NONE, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, '|', 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // Back tick `
{ PS2_KEY_HASH, PS2CTRL_SHIFT, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, '~', 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // Tilde has no mapping.
{ PS2_KEY_HASH, PS2CTRL_NONE, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, '#', 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // Hash
{ PS2_KEY_BS, PS2CTRL_FUNC, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0x08, 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // Backspace
{ PS2_KEY_ESC, PS2CTRL_FUNC, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0x1B, 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // ESCape
{ PS2_KEY_SCROLL, PS2CTRL_FUNC, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, ' ', 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // Not assigned.
{ PS2_KEY_INSERT, PS2CTRL_FUNC, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, X1KEY_INS, 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // INSERT
{ PS2_KEY_HOME, PS2CTRL_FUNC | PS2CTRL_SHIFT, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, X1KEY_CLR, 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // CLR
{ PS2_KEY_HOME, PS2CTRL_FUNC, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, X1KEY_HOME, 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // HOME
{ PS2_KEY_DELETE, PS2CTRL_FUNC, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, X1KEY_DEL, 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // DELETE
{ PS2_KEY_END, PS2CTRL_FUNC, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0x11, 0x00, 0xFF & ~(X1_CTRL_PRESS | X1_CTRL_TENKEY), }, // END
{ PS2_KEY_PGUP, PS2CTRL_FUNC, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0x0E, 0x00, 0xFF & ~(X1_CTRL_PRESS | X1_CTRL_TENKEY), }, // Roll Up.
{ PS2_KEY_PGDN, PS2CTRL_FUNC, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0x0F, 0x00, 0xFF & ~(X1_CTRL_PRESS | X1_CTRL_TENKEY), }, // Roll Down
{ PS2_KEY_UP_ARROW, PS2CTRL_FUNC, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, X1KEY_UP, 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // Up Arrow
{ PS2_KEY_L_ARROW, PS2CTRL_FUNC, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, X1KEY_LEFT, 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // Left Arrow
{ PS2_KEY_DN_ARROW, PS2CTRL_FUNC, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, X1KEY_DOWN, 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // Down Arrow
{ PS2_KEY_R_ARROW, PS2CTRL_FUNC, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, X1KEY_RIGHT, 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // Right Arrow
{ PS2_KEY_NUM, PS2CTRL_FUNC, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0x00, 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // Not assigned.
// GRPH (Alt Gr)
// ModeB Byte1 ModeB Byte2 ModeB Byte3
//PS2 Code PS2 Ctrl (Flags to Match) Machine X1 Keyb Mode X1 Data X1 Ctrl (Flags to Set).
{ PS2_KEY_0, PS2CTRL_GRAPH, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0xFA, 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // GRPH+0
{ PS2_KEY_1, PS2CTRL_GRAPH, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0xF1, 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // GRPH+1
{ PS2_KEY_2, PS2CTRL_GRAPH, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0xF2, 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // GRPH+2
{ PS2_KEY_3, PS2CTRL_GRAPH, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0xF3, 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // GRPH+3
{ PS2_KEY_4, PS2CTRL_GRAPH, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0xF4, 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // GRPH+4
{ PS2_KEY_5, PS2CTRL_GRAPH, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0xF5, 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // GRPH+5
{ PS2_KEY_6, PS2CTRL_GRAPH, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0xF6, 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // GRPH+6
{ PS2_KEY_7, PS2CTRL_GRAPH, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0xF7, 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // GRPH+7
{ PS2_KEY_8, PS2CTRL_GRAPH, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0xF8, 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // GRPH+8
{ PS2_KEY_9, PS2CTRL_GRAPH, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0xF9, 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // GRPH+9
{ PS2_KEY_A, PS2CTRL_GRAPH, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0x7F, 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // GRPH+A
{ PS2_KEY_B, PS2CTRL_GRAPH, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0x84, 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // GRPH+B
{ PS2_KEY_C, PS2CTRL_GRAPH, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0x82, 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // GRPH+C
{ PS2_KEY_D, PS2CTRL_GRAPH, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0xEA, 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // GRPH+D
{ PS2_KEY_E, PS2CTRL_GRAPH, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0xE2, 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // GRPH+E
{ PS2_KEY_F, PS2CTRL_GRAPH, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0xEB, 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // GRPH+F
{ PS2_KEY_G, PS2CTRL_GRAPH, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0xEC, 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // GRPH+G
{ PS2_KEY_H, PS2CTRL_GRAPH, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0xED, 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // GRPH+H
{ PS2_KEY_I, PS2CTRL_GRAPH, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0xE7, 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // GRPH+I
{ PS2_KEY_J, PS2CTRL_GRAPH, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0xEE, 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // GRPH+J
{ PS2_KEY_K, PS2CTRL_GRAPH, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0xEF, 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // GRPH+K
{ PS2_KEY_L, PS2CTRL_GRAPH, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0x8E, 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // GRPH+L
{ PS2_KEY_M, PS2CTRL_GRAPH, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0x86, 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // GRPH+M
{ PS2_KEY_N, PS2CTRL_GRAPH, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0x85, 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // GRPH+N
{ PS2_KEY_O, PS2CTRL_GRAPH, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0xF0, 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // GRPH+O
{ PS2_KEY_P, PS2CTRL_GRAPH, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0x8D, 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // GRPH+P
{ PS2_KEY_Q, PS2CTRL_GRAPH, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0xE0, 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // GRPH+Q
{ PS2_KEY_R, PS2CTRL_GRAPH, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0xE3, 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // GRPH+R
{ PS2_KEY_S, PS2CTRL_GRAPH, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0xE9, 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // GRPH+S
{ PS2_KEY_T, PS2CTRL_GRAPH, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0xE4, 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // GRPH+T
{ PS2_KEY_U, PS2CTRL_GRAPH, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0xE6, 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // GRPH+U
{ PS2_KEY_V, PS2CTRL_GRAPH, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0x83, 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // GRPH+V
{ PS2_KEY_W, PS2CTRL_GRAPH, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0xE1, 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // GRPH+W
{ PS2_KEY_X, PS2CTRL_GRAPH, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0x81, 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // GRPH+X
{ PS2_KEY_Y, PS2CTRL_GRAPH, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0xE5, 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // GRPH+Y
{ PS2_KEY_Z, PS2CTRL_GRAPH, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0x80, 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // GRPH+Z
{ PS2_KEY_COMMA, PS2CTRL_GRAPH, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0x87, 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // GRPH+,
{ PS2_KEY_SEMI, PS2CTRL_GRAPH, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0x89, 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // GRPH+;
{ PS2_KEY_DOT, PS2CTRL_GRAPH, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0x88, 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // GRPH+.
{ PS2_KEY_DIV, PS2CTRL_GRAPH, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0xFE, 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // GRPH+/
{ PS2_KEY_MINUS, PS2CTRL_GRAPH, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0x8C, 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // GRPH+-
{ PS2_KEY_APOS, PS2CTRL_GRAPH, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0x8A, 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // GRPH+'
{ PS2_KEY_OPEN_SQ, PS2CTRL_GRAPH, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0xFC, 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // GRPH+[
{ PS2_KEY_CLOSE_SQ, PS2CTRL_GRAPH, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0xE8, 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // GRPH+]
{ PS2_KEY_BACK, PS2CTRL_GRAPH, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0x90, 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // GRPH+Backslash
{ PS2_KEY_KP0, PS2CTRL_GRAPH, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0x8F, 0x00, 0xFF & ~(X1_CTRL_TENKEY | X1_CTRL_PRESS), }, // GRPH+Keypad 0
{ PS2_KEY_KP1, PS2CTRL_GRAPH, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0x99, 0x00, 0xFF & ~(X1_CTRL_TENKEY | X1_CTRL_PRESS), }, // GRPH+Keypad 1
{ PS2_KEY_KP2, PS2CTRL_GRAPH, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0x92, 0x00, 0xFF & ~(X1_CTRL_TENKEY | X1_CTRL_PRESS), }, // GRPH+Keypad 2
{ PS2_KEY_KP3, PS2CTRL_GRAPH, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0x98, 0x00, 0xFF & ~(X1_CTRL_TENKEY | X1_CTRL_PRESS), }, // GRPH+Keypad 3
{ PS2_KEY_KP4, PS2CTRL_GRAPH, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0x95, 0x00, 0xFF & ~(X1_CTRL_TENKEY | X1_CTRL_PRESS), }, // GRPH+Keypad 4
{ PS2_KEY_KP5, PS2CTRL_GRAPH, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0x96, 0x00, 0xFF & ~(X1_CTRL_TENKEY | X1_CTRL_PRESS), }, // GRPH+Keypad 5
{ PS2_KEY_KP6, PS2CTRL_GRAPH, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0x94, 0x00, 0xFF & ~(X1_CTRL_TENKEY | X1_CTRL_PRESS), }, // GRPH+Keypad 6
{ PS2_KEY_KP7, PS2CTRL_GRAPH, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0x9A, 0x00, 0xFF & ~(X1_CTRL_TENKEY | X1_CTRL_PRESS), }, // GRPH+Keypad 7
{ PS2_KEY_KP8, PS2CTRL_GRAPH, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0x93, 0x00, 0xFF & ~(X1_CTRL_TENKEY | X1_CTRL_PRESS), }, // GRPH+Keypad 8
{ PS2_KEY_KP9, PS2CTRL_GRAPH, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0x97, 0x00, 0xFF & ~(X1_CTRL_TENKEY | X1_CTRL_PRESS), }, // GRPH+Keypad 9
{ PS2_KEY_KP_DOT, PS2CTRL_GRAPH, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0x91, 0x00, 0xFF & ~(X1_CTRL_TENKEY | X1_CTRL_PRESS), }, // GRPH+Keypad Full stop .
{ PS2_KEY_KP_PLUS, PS2CTRL_GRAPH, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0x9D, 0x00, 0xFF & ~(X1_CTRL_TENKEY | X1_CTRL_PRESS), }, // GRPH+Keypad Plus +
{ PS2_KEY_KP_MINUS, PS2CTRL_GRAPH, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0x9C, 0x00, 0xFF & ~(X1_CTRL_TENKEY | X1_CTRL_PRESS), }, // GRPH+Keypad Minus -
{ PS2_KEY_KP_TIMES, PS2CTRL_GRAPH, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0x9B, 0x00, 0xFF & ~(X1_CTRL_TENKEY | X1_CTRL_PRESS), }, // GRPH+Keypad Times *
{ PS2_KEY_KP_DIV, PS2CTRL_GRAPH, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0x9E, 0x00, 0xFF & ~(X1_CTRL_TENKEY | X1_CTRL_PRESS), }, // GRPH+Keypad Divide /
{ PS2_KEY_KP_ENTER, PS2CTRL_GRAPH, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0x90, 0x00, 0xFF & ~(X1_CTRL_TENKEY | X1_CTRL_PRESS), }, // GRPH+Keypad Enter /
// KANA (Alt)
// ModeB Byte1 ModeB Byte2 ModeB Byte3
//PS2 Code PS2 Ctrl (Flags to Match) Machine X1 Keyb Mode X1 Data X1 Ctrl (Flags to Set).
{ PS2_KEY_0, PS2CTRL_KANA | PS2CTRL_SHIFT, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0xA6, 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // KANA+SHIFT+0
{ PS2_KEY_0, PS2CTRL_KANA, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0xDC, 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // KANA+0
{ PS2_KEY_1, PS2CTRL_KANA, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0xC7, 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // KANA+1
{ PS2_KEY_2, PS2CTRL_KANA, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0xCC, 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // KANA+2
{ PS2_KEY_3, PS2CTRL_KANA | PS2CTRL_SHIFT, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0xA7, 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // KANA+SHIFT+3
{ PS2_KEY_3, PS2CTRL_KANA, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0xB1, 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // KANA+3
{ PS2_KEY_4, PS2CTRL_KANA | PS2CTRL_SHIFT, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0xA9, 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // KANA+SHIFT+4
{ PS2_KEY_4, PS2CTRL_KANA, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0xB3, 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // KANA+4
{ PS2_KEY_5, PS2CTRL_KANA | PS2CTRL_SHIFT, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0xAA, 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // KANA+SHIFT+5
{ PS2_KEY_5, PS2CTRL_KANA, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0xB4, 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // KANA+5
{ PS2_KEY_6, PS2CTRL_KANA | PS2CTRL_SHIFT, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0xAB, 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // KANA+SHIFT+6
{ PS2_KEY_6, PS2CTRL_KANA, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0xB5, 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // KANA+6
{ PS2_KEY_7, PS2CTRL_KANA | PS2CTRL_SHIFT, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0xAC, 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // KANA+SHIFT+7
{ PS2_KEY_7, PS2CTRL_KANA, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0xD4, 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // KANA+7
{ PS2_KEY_8, PS2CTRL_KANA | PS2CTRL_SHIFT, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0xAD, 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // KANA+SHIFT+8
{ PS2_KEY_8, PS2CTRL_KANA, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0xD5, 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // KANA+8
{ PS2_KEY_9, PS2CTRL_KANA | PS2CTRL_SHIFT, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0xAE, 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // KANA+SHIFT+9
{ PS2_KEY_9, PS2CTRL_KANA, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0xD6, 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // KANA+9
{ PS2_KEY_A, PS2CTRL_KANA, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0xC1, 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // KANA+A
{ PS2_KEY_B, PS2CTRL_KANA, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0xBA, 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // KANA+B
{ PS2_KEY_C, PS2CTRL_KANA, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0xBF, 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // KANA+C
{ PS2_KEY_D, PS2CTRL_KANA, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0xBC, 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // KANA+D
{ PS2_KEY_E, PS2CTRL_KANA | PS2CTRL_SHIFT, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0xA8, 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // KANA+SHIFT+E
{ PS2_KEY_E, PS2CTRL_KANA, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0xB2, 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // KANA+E
{ PS2_KEY_F, PS2CTRL_KANA, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0xCA, 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // KANA+F
{ PS2_KEY_G, PS2CTRL_KANA, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0xB7, 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // KANA+G
{ PS2_KEY_H, PS2CTRL_KANA, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0xB8, 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // KANA+H
{ PS2_KEY_I, PS2CTRL_KANA, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0xC6, 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // KANA+I
{ PS2_KEY_J, PS2CTRL_KANA, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0xCF, 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // KANA+J
{ PS2_KEY_K, PS2CTRL_KANA, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0xC9, 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // KANA+K
{ PS2_KEY_L, PS2CTRL_KANA, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0xD8, 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // KANA+L
{ PS2_KEY_M, PS2CTRL_KANA, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0xD3, 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // KANA+M
{ PS2_KEY_N, PS2CTRL_KANA, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0xD0, 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // KANA+N
{ PS2_KEY_O, PS2CTRL_KANA, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0xD7, 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // KANA+O
{ PS2_KEY_P, PS2CTRL_KANA, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0xBE, 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // KANA+P
{ PS2_KEY_Q, PS2CTRL_KANA, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0xC0, 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // KANA+Q
{ PS2_KEY_R, PS2CTRL_KANA, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0xBD, 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // KANA+R
{ PS2_KEY_S, PS2CTRL_KANA, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0xC4, 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // KANA+S
{ PS2_KEY_T, PS2CTRL_KANA, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0xB6, 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // KANA+T
{ PS2_KEY_U, PS2CTRL_KANA, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0xC5, 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // KANA+U
{ PS2_KEY_V, PS2CTRL_KANA, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0xCB, 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // KANA+V
{ PS2_KEY_W, PS2CTRL_KANA, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0xC3, 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // KANA+W
{ PS2_KEY_X, PS2CTRL_KANA, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0xBB, 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // KANA+X
{ PS2_KEY_Y, PS2CTRL_KANA, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0xDD, 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // KANA+Y
{ PS2_KEY_Z, PS2CTRL_KANA | PS2CTRL_SHIFT, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0xAF, 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // KANA+SHIFT+Z
{ PS2_KEY_Z, PS2CTRL_KANA, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0xC2, 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // KANA+Z
{ PS2_KEY_COMMA, PS2CTRL_KANA | PS2CTRL_SHIFT, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0xA4, 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // KANA+SHIFT+,
{ PS2_KEY_COMMA, PS2CTRL_KANA, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0xC8, 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // KANA+,
{ PS2_KEY_SEMI, PS2CTRL_KANA, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0xDA, 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // KANA+;
{ PS2_KEY_DOT, PS2CTRL_KANA | PS2CTRL_SHIFT, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0xA1, 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // KANA+SHIFT+.
{ PS2_KEY_DOT, PS2CTRL_KANA, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0xD9, 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // KANA+.
{ PS2_KEY_DIV, PS2CTRL_KANA | PS2CTRL_SHIFT, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0xA5, 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // KANA+SHIFT+/
{ PS2_KEY_DIV, PS2CTRL_KANA, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0xD2, 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // KANA+/
{ PS2_KEY_MINUS, PS2CTRL_KANA, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0xCE, 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // KANA+-
{ PS2_KEY_APOS, PS2CTRL_KANA, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0xDE, 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // KANA+'
{ PS2_KEY_OPEN_SQ, PS2CTRL_KANA | PS2CTRL_SHIFT, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0xA2, 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // KANA+SHIFT+[
{ PS2_KEY_OPEN_SQ, PS2CTRL_KANA, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0xDF, 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // KANA+[
{ PS2_KEY_CLOSE_SQ, PS2CTRL_KANA | PS2CTRL_SHIFT, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0xA3, 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // KANA+SHIFT+]
{ PS2_KEY_CLOSE_SQ, PS2CTRL_KANA, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0xD1, 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // KANA+]
{ PS2_KEY_BACK, PS2CTRL_KANA, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0xDB, 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // KANA+Backslash
{ PS2_KEY_BS, PS2CTRL_KANA | PS2CTRL_SHIFT, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0x12, 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // KANA+SHIFT+Backspace
// Keypad.
{ PS2_KEY_KP0, PS2CTRL_NONE, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, '0', 0x00, 0xFF & ~(X1_CTRL_TENKEY | X1_CTRL_PRESS), }, // Keypad 0
{ PS2_KEY_KP1, PS2CTRL_NONE, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, '1', 0x00, 0xFF & ~(X1_CTRL_TENKEY | X1_CTRL_PRESS), }, // Keypad 1
{ PS2_KEY_KP2, PS2CTRL_NONE, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, '2', 0x00, 0xFF & ~(X1_CTRL_TENKEY | X1_CTRL_PRESS), }, // Keypad 2
{ PS2_KEY_KP3, PS2CTRL_NONE, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, '3', 0x00, 0xFF & ~(X1_CTRL_TENKEY | X1_CTRL_PRESS), }, // Keypad 3
{ PS2_KEY_KP4, PS2CTRL_NONE, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, '4', 0x00, 0xFF & ~(X1_CTRL_TENKEY | X1_CTRL_PRESS), }, // Keypad 4
{ PS2_KEY_KP5, PS2CTRL_NONE, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, '5', 0x00, 0xFF & ~(X1_CTRL_TENKEY | X1_CTRL_PRESS), }, // Keypad 5
{ PS2_KEY_KP6, PS2CTRL_NONE, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, '6', 0x00, 0xFF & ~(X1_CTRL_TENKEY | X1_CTRL_PRESS), }, // Keypad 6
{ PS2_KEY_KP7, PS2CTRL_NONE, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, '7', 0x00, 0xFF & ~(X1_CTRL_TENKEY | X1_CTRL_PRESS), }, // Keypad 7
{ PS2_KEY_KP8, PS2CTRL_NONE, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, '8', 0x00, 0xFF & ~(X1_CTRL_TENKEY | X1_CTRL_PRESS), }, // Keypad 8
{ PS2_KEY_KP9, PS2CTRL_NONE, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, '9', 0x00, 0xFF & ~(X1_CTRL_TENKEY | X1_CTRL_PRESS), }, // Keypad 9
{ PS2_KEY_KP_COMMA, PS2CTRL_NONE, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, ',', 0x00, 0xFF & ~(X1_CTRL_TENKEY | X1_CTRL_PRESS), }, // Keypad Comma ,
{ PS2_KEY_KP_DOT, PS2CTRL_NONE, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, '.', 0x00, 0xFF & ~(X1_CTRL_TENKEY | X1_CTRL_PRESS), }, // Keypad Full stop .
{ PS2_KEY_KP_PLUS, PS2CTRL_NONE, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, '+', 0x00, 0xFF & ~(X1_CTRL_TENKEY | X1_CTRL_PRESS), }, // Keypad Plus +
{ PS2_KEY_KP_MINUS, PS2CTRL_NONE, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, '-', 0x00, 0xFF & ~(X1_CTRL_TENKEY | X1_CTRL_PRESS), }, // Keypad Minus -
{ PS2_KEY_KP_TIMES, PS2CTRL_NONE, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, '*', 0x00, 0xFF & ~(X1_CTRL_TENKEY | X1_CTRL_PRESS), }, // Keypad Times *
{ PS2_KEY_KP_DIV, PS2CTRL_NONE, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, '/', 0x00, 0xFF & ~(X1_CTRL_TENKEY | X1_CTRL_PRESS), }, // Keypad Divide /
{ PS2_KEY_KP_ENTER, PS2CTRL_NONE, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0x0D, 0x00, 0xFF & ~(X1_CTRL_TENKEY | X1_CTRL_PRESS), }, // Keypad Enter /
{ PS2_KEY_KP_EQUAL, PS2CTRL_NONE, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, '=', 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // Keypad Equal =
// ModeB Byte1 ModeB Byte2 ModeB Byte3
//PS2 Code PS2 Ctrl (Flags to Match) Machine X1 Keyb Mode X1 Data X1 Ctrl (Flags to Set).
// Special keys.
{ PS2_KEY_PRTSCR, PS2CTRL_FUNC, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0x00, 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // ARGO KEY
{ PS2_KEY_PAUSE, PS2CTRL_NONE, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0x03, 0x00, 0xFF & ~(X1_CTRL_PRESS | X1_CTRL_TENKEY), }, // BREAK KEY
{ PS2_KEY_L_GUI, PS2CTRL_FUNC | PS2CTRL_GUI, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0x00, 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // GRAPH KEY
//{ PS2_KEY_L_ALT, PS2CTRL_FUNC | PS2CTRL_KANA, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0x00, 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // KJ1 Sentence
//{ PS2_KEY_R_ALT, PS2CTRL_FUNC | PS2CTRL_GRAPH, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0x00, 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // KJ2 Transform
{ PS2_KEY_R_GUI, PS2CTRL_FUNC | PS2CTRL_GUI, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0x00, 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // KANA KEY
{ PS2_KEY_MENU, PS2CTRL_FUNC | PS2CTRL_GUI, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0x00, 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // Not assigned.
// Modifiers are last, only being selected if an earlier match isnt made.
{ PS2_KEY_L_SHIFT, PS2CTRL_NONE, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0x00, 0x00, 0xFF & ~(X1_CTRL_PRESS), },
{ PS2_KEY_R_SHIFT, PS2CTRL_NONE, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0x00, 0x00, 0xFF & ~(X1_CTRL_PRESS), },
{ PS2_KEY_L_CTRL, PS2CTRL_NONE, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0x00, 0x00, 0xFF & ~(X1_CTRL_PRESS), },
{ PS2_KEY_R_CTRL, PS2CTRL_NONE, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0x00, 0x00, 0xFF & ~(X1_CTRL_PRESS), }, // Map to Control
{ 0, PS2CTRL_NONE, KEYMAP_STANDARD, X1_ALL, X1_MODE_A, 0x00, 0x00, 0xFF & ~(X1_CTRL_PRESS), },
}};
};
#endif // X1_H

View File

@@ -1 +0,0 @@
../../../sharpkey/main/include/X68K.h

533
main/include/X68K.h Normal file
View File

@@ -0,0 +1,533 @@
/////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Name: X68K.h
// Created: Mar 2022
// Version: v1.0
// Author(s): Philip Smart
// Description: Header for the Sharp X68000 to PS/2 interface logic class.
// Credits:
// Copyright: (c) 2019-2022 Philip Smart <philip.smart@net2net.org>
//
// History: Mar 2022 - Initial write.
// v1.01 May 2022 - Initial release version.
// v1.02 Jun 2022 - Updates to reflect changes realised in other modules due to addition of
// bluetooth and suspend logic due to NVS issues using both cores.
// v1.03 Jun 2022 - Further updates adding in keymaps for UK BT and Japan OADG109.
//
// Notes: See Makefile to enable/disable conditional components
//
/////////////////////////////////////////////////////////////////////////////////////////////////////////
// This source file is free software: you can redistribute it and#or modify
// it under the terms of the GNU General Public License as published
// by the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This source file is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
/////////////////////////////////////////////////////////////////////////////////////////////////////////
#ifndef X68K_H
#define X68K_H
// Include the specification class.
#include "KeyInterface.h"
#include "NVS.h"
#include "LED.h"
#include "HID.h"
#include <vector>
#include <map>
// NB: Macros definitions put inside class for clarity, they are still global scope.
// Encapsulate the Sharp X68K interface.
class X68K : public KeyInterface {
// Macros.
//
#define NUMELEM(a) (sizeof(a)/sizeof(a[0]))
// Constants.
#define X68KIF_VERSION 1.03
#define X68KIF_KEYMAP_FILE "X68K_KeyMap.BIN"
#define MAX_X68K_XMIT_KEY_BUF 16
#define MAX_X68K_RCV_KEY_BUF 16
// PS2 Flag definitions.
#define PS2CTRL_NONE 0x00 // No keys active = 0
#define PS2CTRL_SHIFT 0x01 // Shfit Key active = 1
#define PS2CTRL_CTRL 0x02 // Ctrl Key active = 1
#define PS2CTRL_CAPS 0x04 // CAPS active = 1
#define PS2CTRL_R_CTRL 0x08 // ALT flag used as Right CTRL flag, active = 1
#define PS2CTRL_ALTGR 0x10 // ALTGR active = 1
#define PS2CTRL_GUI 0x20 // GUI Key active = 1
#define PS2CTRL_FUNC 0x40 // Special Function Keys active = 1
#define PS2CTRL_BREAK 0x80 // BREAK Key active = 1
#define PS2CTRL_EXACT 0x80 // EXACT Match active = 1
// The initial mapping is made inside the PS2KeyAdvanced class from Scan Code Set 2 to ASCII
// for a selected keyboard. Special functions are detected and combined inside this module
// before mapping with the table below to extract the X68K key code and control data.
// ie. PS/2 Scan Code -> ASCII + Flags -> X68K Key Code + Ctrl Data
#define PS2TBL_X68K_MAXCOLS 6
#define PS2TBL_X68K_MAXROWS 131
// Keyboard mapping table column names.
#define PS2TBL_PS2KEYCODE_NAME "PS/2 KeyCode"
#define PS2TBL_PS2CTRL_NAME "PS/2 Control Key"
#define PS2TBL_KEYBOARDMODEL_NAME "For Keyboard"
#define PS2TBL_MACHINE_NAME "For Host Model"
#define PS2TBL_X68KKEYCODE_NAME "X68K KeyCode"
#define PS2TBL_X68KCTRL_NAME "X68K Control Key"
// Keyboard mapping table column types.
#define PS2TBL_PS2KEYCODE_TYPE "hex"
#define PS2TBL_PS2CTRL_TYPE "custom_cbp_ps2ctrl"
#define PS2TBL_KEYBOARDMODEL_TYPE "custom_cbp_keybmodel"
#define PS2TBL_MACHINE_TYPE "custom_cbp_machine"
#define PS2TBL_X68KKEYCODE_TYPE "hex"
#define PS2TBL_X68KCTRL_TYPE "custom_cbp_x68kctrl"
// Keyboard mapping table select list for PS2CTRL.
#define PS2TBL_PS2CTRL_SEL_NONE "NONE"
#define PS2TBL_PS2CTRL_SEL_SHIFT "SHIFT"
#define PS2TBL_PS2CTRL_SEL_CTRL "CTRL"
#define PS2TBL_PS2CTRL_SEL_CAPS "CAPS"
#define PS2TBL_PS2CTRL_SEL_R_CTRL "RCTRL"
#define PS2TBL_PS2CTRL_SEL_ALTGR "ALTGR"
#define PS2TBL_PS2CTRL_SEL_GUI "GUI"
#define PS2TBL_PS2CTRL_SEL_FUNC "FUNC"
#define PS2TBL_PS2CTRL_SEL_EXACT "EXACT"
// Keyboard mapping table select list for target machine.
#define X68K_SEL_ALL "ALL"
#define X68K_SEL_ORIG "ORIGINAL"
#define X68K_SEL_ACE "ACE"
#define X68K_SEL_EXPERT "EXPERT"
#define X68K_SEL_PRO "PRO"
#define X68K_SEL_SUPER "SUPER"
#define X68K_SEL_XVI "XVI"
#define X68K_SEL_COMPACT "COMPACT"
#define X68K_SEL_X68030 "68030"
// Keyboard mapping table select list for Model of keyboard.
#define KEYMAP_SEL_STANDARD "ALL"
#define KEYMAP_SEL_UK_WYSE_KB3926 "UK_WYSE_KB3926"
#define KEYMAP_SEL_JAPAN_OADG109 "JAPAN_OADG109"
#define KEYMAP_SEL_JAPAN_SANWA_SKBL1 "JAPAN_SANWA_SKBL1"
#define KEYMAP_SEL_NOT_ASSIGNED_4 "KEYBOARD_4"
#define KEYMAP_SEL_NOT_ASSIGNED_5 "KEYBOARD_5"
#define KEYMAP_SEL_NOT_ASSIGNED_6 "KEYBOARD_6"
#define KEYMAP_SEL_UK_PERIBOARD_810 "UK_PERIBOARD_810"
#define KEYMAP_SEL_UK_OMOTON_K8508 "UK_OMOTON_K8508"
// Keyboard mapping table select list for X68K Control codes.
#define X68K_CTRL_SEL_NONE "NONE"
#define X68K_CTRL_SEL_SHIFT "SHIFT"
#define X68K_CTRL_SEL_RELEASESHIFT "RELEASESHIFT"
#define X68K_CTRL_SEL_R_CTRL "RCTRL"
// X68K Key control bit mask.
#define X68K_CTRL_SHIFT ((unsigned char) (1 << 7))
#define X68K_CTRL_RELEASESHIFT ((unsigned char) (1 << 6))
#define X68K_CTRL_R_CTRL ((unsigned char) (1 << 0))
#define X68K_CTRL_NONE 0x00
// The Sharp X68000 Series was released over a number of years with several iterations containing changes/updates. Generally Sharp kept the X68000 compatible through the range but just in case
// differences are found, it is possible to assign a key mapping to a specific machine type(s) or all of the series by adding the flags below into the mapping table.
#define X68K_ALL 0xFF
#define X68K_ORIG 0x01
#define X68K_ACE 0x02
#define X68K_EXPERT 0x04
#define X68K_PRO 0x08
#define X68K_SUPER 0x10
#define X68K_XVI 0x20
#define X68K_COMPACT 0x40
#define X68K_X68030 0x80
// Keyboard models. The base on which this interface was created was a Wyse KB3926 PS/2 Keyboard and this is deemed STANDARD. Other models need to insert difference maps
// prior to the STANDARD entry along with the keyboard model so that it is processed first thus allowing differing keyboards with different maps.
#define KEYMAP_STANDARD 0xFF
#define KEYMAP_UK_WYSE_KB3926 0x01
#define KEYMAP_JAPAN_OADG109 0x02
#define KEYMAP_JAPAN_SANWA_SKBL1 0x04
#define KEYMAP_NOT_ASSIGNED_4 0x08
#define KEYMAP_NOT_ASSIGNED_5 0x10
#define KEYMAP_NOT_ASSIGNED_6 0x20
#define KEYMAP_UK_PERIBOARD_810 0x40
#define KEYMAP_UK_OMOTON_K8508 0x80
// X68000 Scan codes - PS2 codes along with function keys (SHIFT, CTRL etc) are mapped to the X68000 scan codes below.
#define X68K_KEY_NULL 0x00
#define X68K_KEY_ESC 0x01
#define X68K_KEY_0 0x0B
#define X68K_KEY_1 0x02
#define X68K_KEY_2 0x03
#define X68K_KEY_3 0x04
#define X68K_KEY_4 0x05
#define X68K_KEY_5 0x06
#define X68K_KEY_6 0x07
#define X68K_KEY_7 0x08
#define X68K_KEY_8 0x09
#define X68K_KEY_9 0x0A
#define X68K_KEY_A 0x1E
#define X68K_KEY_B 0x2E
#define X68K_KEY_C 0x2C
#define X68K_KEY_D 0x20
#define X68K_KEY_E 0x13
#define X68K_KEY_F 0x21
#define X68K_KEY_G 0x22
#define X68K_KEY_H 0x23
#define X68K_KEY_I 0x18
#define X68K_KEY_J 0x24
#define X68K_KEY_K 0x25
#define X68K_KEY_L 0x26
#define X68K_KEY_M 0x30
#define X68K_KEY_N 0x2F
#define X68K_KEY_O 0x19
#define X68K_KEY_P 0x1A
#define X68K_KEY_Q 0x11
#define X68K_KEY_R 0x14
#define X68K_KEY_S 0x1F
#define X68K_KEY_T 0x15
#define X68K_KEY_U 0x17
#define X68K_KEY_V 0x2D
#define X68K_KEY_W 0x12
#define X68K_KEY_X 0x2B
#define X68K_KEY_Y 0x16
#define X68K_KEY_Z 0x2A
#define X68K_KEY_AT 0x1B
#define X68K_KEY_MINUS 0x0C
#define X68K_KEY_CIRCUMFLEX 0x0D
#define X68K_KEY_YEN 0x0E
#define X68K_KEY_BS 0x0F
#define X68K_KEY_TAB 0x10
#define X68K_KEY_OPEN_SQ 0x1C
#define X68K_KEY_CLOSE_SQ 0x29
#define X68K_KEY_RETURN 0x1D
#define X68K_KEY_SEMI 0x27
#define X68K_KEY_COLON 0x28
#define X68K_KEY_COMMA 0x31
#define X68K_KEY_DOT 0x32
#define X68K_KEY_DIV 0x33
#define X68K_KEY_UNDERLINE 0x34
#define X68K_KEY_SPACE 0x35
#define X68K_KEY_HOME 0x36
#define X68K_KEY_ROLLUP 0x38
#define X68K_KEY_ROLLDN 0x39
#define X68K_KEY_UNDO 0x3A
#define X68K_KEY_L_ARROW 0x3B
#define X68K_KEY_UP_ARROW 0x3C
#define X68K_KEY_R_ARROW 0x3D
#define X68K_KEY_DN_ARROW 0x3E
#define X68K_KEY_CLR 0x3F
#define X68K_KEY_KP0 0x4F
#define X68K_KEY_KP1 0x4B
#define X68K_KEY_KP2 0x4C
#define X68K_KEY_KP3 0x4D
#define X68K_KEY_KP4 0x47
#define X68K_KEY_KP5 0x48
#define X68K_KEY_KP6 0x49
#define X68K_KEY_KP7 0x43
#define X68K_KEY_KP8 0x44
#define X68K_KEY_KP9 0x45
#define X68K_KEY_KP_DIV 0x40
#define X68K_KEY_KP_TIMES 0x41
#define X68K_KEY_KP_MINUS 0x42
#define X68K_KEY_KP_PLUS 0x46
#define X68K_KEY_KP_EQUAL 0x4A
#define X68K_KEY_KP_ENTER 0x4E
#define X68K_KEY_KP_COMMA 0x50
#define X68K_KEY_KP_DOT 0x51
#define X68K_KEY_SYMBOL 0x52
#define X68K_KEY_HELP 0x54
#define X68K_KEY_CAPS 0x5D
#define X68K_KEY_INS 0x5E
#define X68K_KEY_DEL 0x37
#define X68K_KEY_BREAK 0x61
#define X68K_KEY_COPY 0x62
#define X68K_KEY_SHIFT 0x70
#define X68K_KEY_CTRL 0x71
#define X68K_KEY_XF1 0x55
#define X68K_KEY_XF2 0x56
#define X68K_KEY_XF3 0x57
#define X68K_KEY_XF4 0x58
#define X68K_KEY_XF5 0x59
#define X68K_KEY_REGISTRATION 0x53
#define X68K_KEY_KATAKANA 0x5A
#define X68K_KEY_ROMAJI 0x5B
#define X68K_KEY_TRANSPOSE 0x5C
#define X68K_KEY_HIRAGANA 0x5F
#define X68K_KEY_FULLWIDTH 0x60
#define X68K_KEY_F1 0x63
#define X68K_KEY_F2 0x64
#define X68K_KEY_F3 0x65
#define X68K_KEY_F4 0x66
#define X68K_KEY_F5 0x67
#define X68K_KEY_F6 0x68
#define X68K_KEY_F7 0x69
#define X68K_KEY_F8 0x6A
#define X68K_KEY_F9 0x6B
#define X68K_KEY_F10 0x6C
#define X68K_KEY_OPT_1 0x72
#define X68K_KEY_OPT_2 0x73
public:
// Prototypes.
X68K(void);
X68K(uint32_t ifMode, NVS *hdlNVS, LED *hdlLED, HID *hdlHID, const char *fsPath);
X68K(NVS *hdlNVS, HID *hdlHID, const char *fsPath);
~X68K(void);
bool createKeyMapFile(std::fstream &outFile);
bool storeDataToKeyMapFile(std::fstream &outFile, char *data, int size);
bool storeDataToKeyMapFile(std::fstream & outFile, std::vector<uint32_t>& dataArray);
bool closeAndCommitKeyMapFile(std::fstream &outFile, bool cleanupOnly);
std::string getKeyMapFileName(void) { return(X68KIF_KEYMAP_FILE); };
void getKeyMapHeaders(std::vector<std::string>& headerList);
void getKeyMapTypes(std::vector<std::string>& typeList);
bool getKeyMapSelectList(std::vector<std::pair<std::string, int>>& selectList, std::string option);
bool getKeyMapData(std::vector<uint32_t>& dataArray, int *row, bool start);
// Method to return the class version number.
float version(void)
{
return(X68KIF_VERSION);
}
protected:
private:
// Prototypes.
IRAM_ATTR void pushKeyToQueue(uint32_t key);
IRAM_ATTR void pushHostCmdToQueue(uint8_t cmd);
IRAM_ATTR static void x68kInterface( void * pvParameters );
IRAM_ATTR static void hidInterface( void * pvParameters );
void selectOption(uint8_t optionCode);
uint32_t mapKey(uint16_t scanCode);
bool loadKeyMap();
bool saveKeyMap(void);
void init(uint32_t ifMode, NVS *hdlNVS, LED *hdlLED, HID *hdlHID);
void init(NVS *hdlNVS, HID *hdlHID);
// Structure to encapsulate a single key map from PS/2 to X68K.
typedef struct {
uint8_t ps2KeyCode;
uint8_t ps2Ctrl;
uint8_t keyboardModel;
uint8_t machine;
uint8_t x68kKey;
uint8_t x68kCtrl;
} t_keyMapEntry;
// Structure to encapsulate the entire static keyboard mapping table.
typedef struct {
t_keyMapEntry kme[PS2TBL_X68K_MAXROWS];
} t_keyMap;
// Structure to maintain the X68000 interface configuration data. This data is persisted through powercycles as needed.
typedef struct {
struct {
uint8_t activeKeyboardMap; // Model of keyboard a keymap entry is applicable to.
uint8_t activeMachineModel; // Machine model a keymap entry is applicable to.
bool useOnlyPersisted; // Flag to indicate wether the inbuilt keymap array should be combined with persisted values or the inbuilt array is ignored and only persisted values used.
} params;
} t_x68kConfig;
// Configuration data.
t_x68kConfig x68kConfig;
// Structure to manage the control signals signifying the state of the X68K keyboard.
typedef struct {
uint8_t keyCtrl; // Keyboard state flag control.
bool optionSelect; // Flag to indicate a user requested keyboard configuration option is being selected.
int uartNum;
int uartBufferSize;
int uartQueueSize;
std::string fsPath; // Path on the underlying filesystem where storage is mounted and accessible.
t_keyMapEntry *kme; // Pointer to an array in memory to contain PS2 to X68K mapping values.
int kmeRows; // Number of rows in the kme table.
std::string keyMapFileName; // Name of file where extension or replacement key map entries are stored.
bool persistConfig; // Flag to request saving of the config into NVS storage.
} t_x68kControl;
// Transmit buffer queue item.
typedef struct {
uint32_t keyCode; // Key data to be sent to X68000.
} t_xmitQueueMessage;
// Receive buffer queue item.
typedef struct {
uint8_t hostCmd; // Keyboard configuration command received from X68000.
} t_rcvQueueMessage;
// Thread handles - one per function, ie. HID interface and host target interface.
TaskHandle_t TaskHostIF = NULL;
TaskHandle_t TaskHIDIF = NULL;
// Control structure to control interaction and mapping of keys for the host.
t_x68kControl x68kControl;
// Spin lock mutex to hold a coresied to an uninterruptable method. This only works on dual core ESP32's.
portMUX_TYPE x68kMutex;
// Lookup table to match PS/2 codes to X68K Key and Control Data.
//
// Given that the X68K had many variants, with potential differences between them, the mapping table allows for ALL or variant specific entries, the first entry matching is selected.
//
// This mapping is for the UK Wyse KB-3926 PS/2 keyboard which is deemed the KEYMAP_STANDARD and all other variants need to add additional mappings below, position sensitive, ie. add non-standard entries before standard entry.
//
//const unsigned char PS2toX68K[PS2TBL_X68K_MAXROWS][PS2TBL_X68K_MAXCOLS] =
//t_keyMapEntry PS2toX68K[PS2TBL_X68K_MAXROWS] =
t_keyMap PS2toX68K = {
{
//PS2 Code PS2 Ctrl (Flags to Match) Keyboard Model Machine X68K Data X68K Ctrl (Flags to Set).
// Function keys
{ PS2_KEY_F1, PS2CTRL_FUNC | PS2CTRL_CTRL | PS2CTRL_R_CTRL, KEYMAP_STANDARD, X68K_ALL, X68K_KEY_HIRAGANA, X68K_CTRL_NONE, }, // R_CTRL + F1 = Hiragana
{ PS2_KEY_F2, PS2CTRL_FUNC | PS2CTRL_CTRL | PS2CTRL_R_CTRL, KEYMAP_STANDARD, X68K_ALL, X68K_KEY_FULLWIDTH, X68K_CTRL_NONE, }, // R_CTRL + F2 = Full Width
{ PS2_KEY_F3, PS2CTRL_FUNC | PS2CTRL_CTRL | PS2CTRL_R_CTRL, KEYMAP_STANDARD, X68K_ALL, X68K_KEY_KATAKANA, X68K_CTRL_NONE, }, // R_CTRL + F3 = Katakana
{ PS2_KEY_F4, PS2CTRL_FUNC | PS2CTRL_CTRL | PS2CTRL_R_CTRL, KEYMAP_STANDARD, X68K_ALL, X68K_KEY_ROMAJI, X68K_CTRL_NONE, }, // R_CTRL + F4 = Romaji
{ PS2_KEY_F5, PS2CTRL_FUNC | PS2CTRL_CTRL | PS2CTRL_R_CTRL, KEYMAP_STANDARD, X68K_ALL, X68K_KEY_TRANSPOSE, X68K_CTRL_NONE, }, // R_CTRL + F5 = Tranpose
{ PS2_KEY_F6, PS2CTRL_FUNC | PS2CTRL_CTRL | PS2CTRL_R_CTRL, KEYMAP_STANDARD, X68K_ALL, X68K_KEY_SYMBOL, X68K_CTRL_NONE, }, // R_CTRL + F6 = Symbol
{ PS2_KEY_F7, PS2CTRL_FUNC | PS2CTRL_CTRL | PS2CTRL_R_CTRL, KEYMAP_STANDARD, X68K_ALL, X68K_KEY_REGISTRATION, X68K_CTRL_NONE, }, // R_CTRL + F7 = Registration - maybe a poor translation, needs better one!
{ PS2_KEY_F9, PS2CTRL_FUNC | PS2CTRL_CTRL | PS2CTRL_R_CTRL, KEYMAP_STANDARD, X68K_ALL, X68K_KEY_COPY, X68K_CTRL_NONE, }, // R_CTRL + F9 = Copy
{ PS2_KEY_F10, PS2CTRL_FUNC | PS2CTRL_CTRL | PS2CTRL_R_CTRL, KEYMAP_STANDARD, X68K_ALL, X68K_KEY_HELP, X68K_CTRL_NONE, }, // R_CTRL + F10 = Help
{ PS2_KEY_F1, PS2CTRL_FUNC, KEYMAP_STANDARD, X68K_ALL, X68K_KEY_F1, X68K_CTRL_NONE, }, // F1
{ PS2_KEY_F2, PS2CTRL_FUNC, KEYMAP_STANDARD, X68K_ALL, X68K_KEY_F2, X68K_CTRL_NONE, }, // F2
{ PS2_KEY_F3, PS2CTRL_FUNC, KEYMAP_STANDARD, X68K_ALL, X68K_KEY_F3, X68K_CTRL_NONE, }, // F3
{ PS2_KEY_F4, PS2CTRL_FUNC, KEYMAP_STANDARD, X68K_ALL, X68K_KEY_F4, X68K_CTRL_NONE, }, // F4
{ PS2_KEY_F5, PS2CTRL_FUNC, KEYMAP_STANDARD, X68K_ALL, X68K_KEY_F5, X68K_CTRL_NONE, }, // F5
{ PS2_KEY_F6, PS2CTRL_FUNC, KEYMAP_STANDARD, X68K_ALL, X68K_KEY_F6, X68K_CTRL_NONE, }, // F6
{ PS2_KEY_F7, PS2CTRL_FUNC, KEYMAP_STANDARD, X68K_ALL, X68K_KEY_F7, X68K_CTRL_NONE, }, // F7
{ PS2_KEY_F8, PS2CTRL_FUNC, KEYMAP_STANDARD, X68K_ALL, X68K_KEY_F8, X68K_CTRL_NONE, }, // F8
{ PS2_KEY_F9, PS2CTRL_FUNC, KEYMAP_STANDARD, X68K_ALL, X68K_KEY_F9, X68K_CTRL_NONE, }, // F9
{ PS2_KEY_F10, PS2CTRL_FUNC, KEYMAP_STANDARD, X68K_ALL, X68K_KEY_F10, X68K_CTRL_NONE, }, // F10
{ PS2_KEY_F11, PS2CTRL_FUNC, KEYMAP_STANDARD, X68K_ALL, X68K_KEY_OPT_1, X68K_CTRL_NONE, }, // F11 - OPT.1
{ PS2_KEY_F12, PS2CTRL_FUNC, KEYMAP_STANDARD, X68K_ALL, X68K_KEY_OPT_2, X68K_CTRL_NONE, }, // F12 - OPT.2
//PS2 Code PS2 Ctrl (Flags to Match) Machine X68K Data X68K Ctrl (Flags to Set).
// ALPHA keys, case is maaped in the X68000 via the SHIFT key event or CAPS key.
{ PS2_KEY_A, PS2CTRL_NONE, KEYMAP_STANDARD, X68K_ALL, X68K_KEY_A, X68K_CTRL_NONE, }, // A
{ PS2_KEY_B, PS2CTRL_NONE, KEYMAP_STANDARD, X68K_ALL, X68K_KEY_B, X68K_CTRL_NONE, }, // B
{ PS2_KEY_C, PS2CTRL_NONE, KEYMAP_STANDARD, X68K_ALL, X68K_KEY_C, X68K_CTRL_NONE, }, // C
{ PS2_KEY_D, PS2CTRL_NONE, KEYMAP_STANDARD, X68K_ALL, X68K_KEY_D, X68K_CTRL_NONE, }, // D
{ PS2_KEY_E, PS2CTRL_NONE, KEYMAP_STANDARD, X68K_ALL, X68K_KEY_E, X68K_CTRL_NONE, }, // E
{ PS2_KEY_F, PS2CTRL_NONE, KEYMAP_STANDARD, X68K_ALL, X68K_KEY_F, X68K_CTRL_NONE, }, // F
{ PS2_KEY_G, PS2CTRL_NONE, KEYMAP_STANDARD, X68K_ALL, X68K_KEY_G, X68K_CTRL_NONE, }, // G
{ PS2_KEY_H, PS2CTRL_NONE, KEYMAP_STANDARD, X68K_ALL, X68K_KEY_H, X68K_CTRL_NONE, }, // H
{ PS2_KEY_I, PS2CTRL_NONE, KEYMAP_STANDARD, X68K_ALL, X68K_KEY_I, X68K_CTRL_NONE, }, // I
{ PS2_KEY_J, PS2CTRL_NONE, KEYMAP_STANDARD, X68K_ALL, X68K_KEY_J, X68K_CTRL_NONE, }, // J
{ PS2_KEY_K, PS2CTRL_NONE, KEYMAP_STANDARD, X68K_ALL, X68K_KEY_K, X68K_CTRL_NONE, }, // K
{ PS2_KEY_L, PS2CTRL_NONE, KEYMAP_STANDARD, X68K_ALL, X68K_KEY_L, X68K_CTRL_NONE, }, // L
{ PS2_KEY_M, PS2CTRL_NONE, KEYMAP_STANDARD, X68K_ALL, X68K_KEY_M, X68K_CTRL_NONE, }, // M
{ PS2_KEY_N, PS2CTRL_NONE, KEYMAP_STANDARD, X68K_ALL, X68K_KEY_N, X68K_CTRL_NONE, }, // N
{ PS2_KEY_O, PS2CTRL_NONE, KEYMAP_STANDARD, X68K_ALL, X68K_KEY_O, X68K_CTRL_NONE, }, // O
{ PS2_KEY_P, PS2CTRL_NONE, KEYMAP_STANDARD, X68K_ALL, X68K_KEY_P, X68K_CTRL_NONE, }, // P
{ PS2_KEY_Q, PS2CTRL_NONE, KEYMAP_STANDARD, X68K_ALL, X68K_KEY_Q, X68K_CTRL_NONE, }, // Q
{ PS2_KEY_R, PS2CTRL_NONE, KEYMAP_STANDARD, X68K_ALL, X68K_KEY_R, X68K_CTRL_NONE, }, // R
{ PS2_KEY_S, PS2CTRL_NONE, KEYMAP_STANDARD, X68K_ALL, X68K_KEY_S, X68K_CTRL_NONE, }, // S
{ PS2_KEY_T, PS2CTRL_NONE, KEYMAP_STANDARD, X68K_ALL, X68K_KEY_T, X68K_CTRL_NONE, }, // T
{ PS2_KEY_U, PS2CTRL_NONE, KEYMAP_STANDARD, X68K_ALL, X68K_KEY_U, X68K_CTRL_NONE, }, // U
{ PS2_KEY_V, PS2CTRL_NONE, KEYMAP_STANDARD, X68K_ALL, X68K_KEY_V, X68K_CTRL_NONE, }, // V
{ PS2_KEY_W, PS2CTRL_NONE, KEYMAP_STANDARD, X68K_ALL, X68K_KEY_W, X68K_CTRL_NONE, }, // W
{ PS2_KEY_X, PS2CTRL_NONE, KEYMAP_STANDARD, X68K_ALL, X68K_KEY_X, X68K_CTRL_NONE, }, // X
{ PS2_KEY_Y, PS2CTRL_NONE, KEYMAP_STANDARD, X68K_ALL, X68K_KEY_Y, X68K_CTRL_NONE, }, // Y
{ PS2_KEY_Z, PS2CTRL_NONE, KEYMAP_STANDARD, X68K_ALL, X68K_KEY_Z, X68K_CTRL_NONE, }, // Z
// Numeric keys.
{ PS2_KEY_0, PS2CTRL_SHIFT, KEYMAP_STANDARD, X68K_ALL, X68K_KEY_9, X68K_CTRL_NONE, }, // Close Bracket )
{ PS2_KEY_0, PS2CTRL_NONE, KEYMAP_STANDARD, X68K_ALL, X68K_KEY_0, X68K_CTRL_NONE, }, // 0
{ PS2_KEY_1, PS2CTRL_NONE, KEYMAP_STANDARD, X68K_ALL, X68K_KEY_1, X68K_CTRL_NONE, }, // 1
{ PS2_KEY_2, PS2CTRL_NONE, KEYMAP_STANDARD, X68K_ALL, X68K_KEY_2, X68K_CTRL_NONE, }, // 2
{ PS2_KEY_3, PS2CTRL_NONE, KEYMAP_STANDARD, X68K_ALL, X68K_KEY_3, X68K_CTRL_NONE, }, // 3
{ PS2_KEY_4, PS2CTRL_NONE, KEYMAP_STANDARD, X68K_ALL, X68K_KEY_4, X68K_CTRL_NONE, }, // 4
{ PS2_KEY_5, PS2CTRL_NONE, KEYMAP_STANDARD, X68K_ALL, X68K_KEY_5, X68K_CTRL_NONE, }, // 5
{ PS2_KEY_6, PS2CTRL_SHIFT, KEYMAP_STANDARD, X68K_ALL, X68K_KEY_CIRCUMFLEX, X68K_CTRL_RELEASESHIFT, }, // Circumflex ^
{ PS2_KEY_6, PS2CTRL_NONE, KEYMAP_STANDARD, X68K_ALL, X68K_KEY_6, X68K_CTRL_NONE, }, // 6
{ PS2_KEY_7, PS2CTRL_SHIFT, KEYMAP_STANDARD, X68K_ALL, X68K_KEY_6, X68K_CTRL_NONE, }, // &
{ PS2_KEY_7, PS2CTRL_NONE, KEYMAP_STANDARD, X68K_ALL, X68K_KEY_7, X68K_CTRL_NONE, }, // 7
{ PS2_KEY_8, PS2CTRL_SHIFT, KEYMAP_STANDARD, X68K_ALL, X68K_KEY_COLON, X68K_CTRL_NONE, }, // Start *
{ PS2_KEY_8, PS2CTRL_NONE, KEYMAP_STANDARD, X68K_ALL, X68K_KEY_8, X68K_CTRL_NONE, }, // 8
{ PS2_KEY_9, PS2CTRL_SHIFT, KEYMAP_STANDARD, X68K_ALL, X68K_KEY_8, X68K_CTRL_NONE, }, // Open Bracket (
{ PS2_KEY_9, PS2CTRL_NONE, KEYMAP_STANDARD, X68K_ALL, X68K_KEY_9, X68K_CTRL_NONE, }, // 9
//PS2 Code PS2 Ctrl (Flags to Match) Machine X68K Data X68K Ctrl (Flags to Set).
// Punctuation keys.
{ PS2_KEY_SPACE, PS2CTRL_NONE, KEYMAP_STANDARD, X68K_ALL, X68K_KEY_SPACE, X68K_CTRL_NONE, }, // Space
{ PS2_KEY_MINUS, PS2CTRL_SHIFT, KEYMAP_STANDARD, X68K_ALL, X68K_KEY_CIRCUMFLEX, X68K_CTRL_NONE, }, // Upper Bar
{ PS2_KEY_MINUS, PS2CTRL_NONE, KEYMAP_STANDARD, X68K_ALL, X68K_KEY_MINUS, X68K_CTRL_NONE, }, // Minus -
{ PS2_KEY_EQUAL, PS2CTRL_SHIFT, KEYMAP_STANDARD, X68K_ALL, X68K_KEY_SEMI, X68K_CTRL_SHIFT, }, // Plus +
{ PS2_KEY_EQUAL, PS2CTRL_NONE, KEYMAP_STANDARD, X68K_ALL, X68K_KEY_MINUS, X68K_CTRL_SHIFT, }, // Equal =
{ PS2_KEY_DOT, PS2CTRL_SHIFT, KEYMAP_STANDARD, X68K_ALL, X68K_KEY_DOT, X68K_CTRL_NONE, }, // Greater Than >
{ PS2_KEY_DOT, PS2CTRL_NONE, KEYMAP_STANDARD, X68K_ALL, X68K_KEY_DOT, X68K_CTRL_NONE, }, // Dot
{ PS2_KEY_DIV, PS2CTRL_NONE, KEYMAP_STANDARD, X68K_ALL, X68K_KEY_DIV, X68K_CTRL_NONE, }, // Divide /
{ PS2_KEY_SEMI, PS2CTRL_SHIFT, KEYMAP_STANDARD, X68K_ALL, X68K_KEY_COLON, X68K_CTRL_RELEASESHIFT, }, // Colon :
{ PS2_KEY_SEMI, PS2CTRL_NONE, KEYMAP_STANDARD, X68K_ALL, X68K_KEY_SEMI, X68K_CTRL_NONE, }, // Semi-Colon ;
{ PS2_KEY_OPEN_SQ, PS2CTRL_NONE, KEYMAP_STANDARD, X68K_ALL, X68K_KEY_OPEN_SQ, X68K_CTRL_NONE, }, // [
{ PS2_KEY_CLOSE_SQ, PS2CTRL_NONE, KEYMAP_STANDARD, X68K_ALL, X68K_KEY_CLOSE_SQ, X68K_CTRL_NONE, }, // ]
{ PS2_KEY_APOS, PS2CTRL_SHIFT, KEYMAP_STANDARD, X68K_ALL, X68K_KEY_AT, X68K_CTRL_RELEASESHIFT, }, // @
{ PS2_KEY_APOS, PS2CTRL_NONE, KEYMAP_STANDARD, X68K_ALL, X68K_KEY_7, X68K_CTRL_SHIFT, }, // '
{ PS2_KEY_BACK, PS2CTRL_SHIFT, KEYMAP_STANDARD, X68K_ALL, X68K_KEY_YEN, X68K_CTRL_NONE, }, // Back slash maps to Yen
{ PS2_KEY_BACK, PS2CTRL_NONE, KEYMAP_STANDARD, X68K_ALL, X68K_KEY_YEN, X68K_CTRL_NONE, }, // Back slash maps to Yen
{ PS2_KEY_HASH, PS2CTRL_NONE, KEYMAP_STANDARD, X68K_ALL, X68K_KEY_3, X68K_CTRL_SHIFT, }, // Hash
{ PS2_KEY_COMMA, PS2CTRL_SHIFT, KEYMAP_STANDARD, X68K_ALL, X68K_KEY_COMMA, X68K_CTRL_NONE, }, // Less Than <
{ PS2_KEY_COMMA, PS2CTRL_NONE, KEYMAP_STANDARD, X68K_ALL, X68K_KEY_COMMA, X68K_CTRL_NONE, }, // Comma ,
{ PS2_KEY_BTICK, PS2CTRL_FUNC | PS2CTRL_SHIFT, KEYMAP_STANDARD, X68K_ALL, X68K_KEY_UNDERLINE, X68K_CTRL_SHIFT, }, // Underline
{ PS2_KEY_BTICK, PS2CTRL_FUNC, KEYMAP_STANDARD, X68K_ALL, X68K_KEY_AT, X68K_CTRL_SHIFT, }, // Back Tick `
// Control keys.
{ PS2_KEY_TAB, PS2CTRL_NONE, KEYMAP_STANDARD, X68K_ALL, X68K_KEY_TAB, X68K_CTRL_NONE, }, // TAB
{ PS2_KEY_BS, PS2CTRL_FUNC, KEYMAP_STANDARD, X68K_ALL, X68K_KEY_BS, X68K_CTRL_NONE, }, // Backspace
{ PS2_KEY_ESC, PS2CTRL_FUNC, KEYMAP_STANDARD, X68K_ALL, X68K_KEY_ESC, X68K_CTRL_NONE, }, // ESCape
{ PS2_KEY_INSERT, PS2CTRL_FUNC, KEYMAP_STANDARD, X68K_ALL, X68K_KEY_INS, X68K_CTRL_NONE, }, // INSERT
{ PS2_KEY_HOME, PS2CTRL_FUNC | PS2CTRL_SHIFT, KEYMAP_STANDARD, X68K_ALL, X68K_KEY_CLR, X68K_CTRL_NONE, }, // CLR
{ PS2_KEY_HOME, PS2CTRL_FUNC, KEYMAP_STANDARD, X68K_ALL, X68K_KEY_HOME, X68K_CTRL_NONE, }, // HOME
{ PS2_KEY_DELETE, PS2CTRL_FUNC, KEYMAP_STANDARD, X68K_ALL, X68K_KEY_DEL, X68K_CTRL_NONE, }, // DELETE
{ PS2_KEY_UP_ARROW, PS2CTRL_FUNC, KEYMAP_STANDARD, X68K_ALL, X68K_KEY_UP_ARROW, X68K_CTRL_NONE, }, // Up Arrow
{ PS2_KEY_L_ARROW, PS2CTRL_FUNC, KEYMAP_STANDARD, X68K_ALL, X68K_KEY_L_ARROW, X68K_CTRL_NONE, }, // Left Arrow
{ PS2_KEY_DN_ARROW, PS2CTRL_FUNC, KEYMAP_STANDARD, X68K_ALL, X68K_KEY_DN_ARROW, X68K_CTRL_NONE, }, // Down Arrow
{ PS2_KEY_R_ARROW, PS2CTRL_FUNC, KEYMAP_STANDARD, X68K_ALL, X68K_KEY_R_ARROW, X68K_CTRL_NONE, }, // Right Arrow
{ PS2_KEY_PGUP, PS2CTRL_FUNC, KEYMAP_STANDARD, X68K_ALL, X68K_KEY_ROLLUP, X68K_CTRL_NONE, }, // Roll Up.
{ PS2_KEY_PGDN, PS2CTRL_FUNC, KEYMAP_STANDARD, X68K_ALL, X68K_KEY_ROLLDN, X68K_CTRL_NONE, }, // Roll Down
{ PS2_KEY_SCROLL, PS2CTRL_FUNC, KEYMAP_STANDARD, X68K_ALL, ' ', X68K_CTRL_NONE, }, // Not assigned.
{ PS2_KEY_ENTER, PS2CTRL_FUNC, KEYMAP_STANDARD, X68K_ALL, X68K_KEY_RETURN, X68K_CTRL_NONE, }, // Not assigned.
{ PS2_KEY_CAPS, PS2CTRL_CAPS, KEYMAP_STANDARD, X68K_ALL, X68K_KEY_CAPS, X68K_CTRL_NONE, }, // CAPS
{ PS2_KEY_END, PS2CTRL_FUNC, KEYMAP_STANDARD, X68K_ALL, X68K_KEY_UNDO, X68K_CTRL_NONE, }, // UNDO
// Keypad.
{ PS2_KEY_KP0, PS2CTRL_NONE, KEYMAP_STANDARD, X68K_ALL, X68K_KEY_KP0, X68K_CTRL_NONE, }, // Keypad 0
{ PS2_KEY_KP1, PS2CTRL_NONE, KEYMAP_STANDARD, X68K_ALL, X68K_KEY_KP1, X68K_CTRL_NONE, }, // Keypad 1
{ PS2_KEY_KP2, PS2CTRL_NONE, KEYMAP_STANDARD, X68K_ALL, X68K_KEY_KP2, X68K_CTRL_NONE, }, // Keypad 2
{ PS2_KEY_KP3, PS2CTRL_NONE, KEYMAP_STANDARD, X68K_ALL, X68K_KEY_KP3, X68K_CTRL_NONE, }, // Keypad 3
{ PS2_KEY_KP4, PS2CTRL_NONE, KEYMAP_STANDARD, X68K_ALL, X68K_KEY_KP4, X68K_CTRL_NONE, }, // Keypad 4
{ PS2_KEY_KP5, PS2CTRL_NONE, KEYMAP_STANDARD, X68K_ALL, X68K_KEY_KP5, X68K_CTRL_NONE, }, // Keypad 5
{ PS2_KEY_KP6, PS2CTRL_NONE, KEYMAP_STANDARD, X68K_ALL, X68K_KEY_KP6, X68K_CTRL_NONE, }, // Keypad 6
{ PS2_KEY_KP7, PS2CTRL_NONE, KEYMAP_STANDARD, X68K_ALL, X68K_KEY_KP7, X68K_CTRL_NONE, }, // Keypad 7
{ PS2_KEY_KP8, PS2CTRL_NONE, KEYMAP_STANDARD, X68K_ALL, X68K_KEY_KP8, X68K_CTRL_NONE, }, // Keypad 8
{ PS2_KEY_KP9, PS2CTRL_NONE, KEYMAP_STANDARD, X68K_ALL, X68K_KEY_KP9, X68K_CTRL_NONE, }, // Keypad 9
{ PS2_KEY_KP_COMMA, PS2CTRL_NONE, KEYMAP_STANDARD, X68K_ALL, X68K_KEY_KP_COMMA, X68K_CTRL_NONE, }, // Keypad Comma ,
{ PS2_KEY_KP_DOT, PS2CTRL_NONE, KEYMAP_STANDARD, X68K_ALL, X68K_KEY_KP_DOT, X68K_CTRL_NONE, }, // Keypad Full stop .
{ PS2_KEY_KP_PLUS, PS2CTRL_NONE, KEYMAP_STANDARD, X68K_ALL, X68K_KEY_KP_PLUS, X68K_CTRL_NONE, }, // Keypad Plus +
{ PS2_KEY_KP_MINUS, PS2CTRL_NONE, KEYMAP_STANDARD, X68K_ALL, X68K_KEY_KP_MINUS, X68K_CTRL_NONE, }, // Keypad Minus -
{ PS2_KEY_KP_TIMES, PS2CTRL_NONE, KEYMAP_STANDARD, X68K_ALL, X68K_KEY_KP_TIMES, X68K_CTRL_NONE, }, // Keypad Times *
{ PS2_KEY_KP_DIV, PS2CTRL_NONE, KEYMAP_STANDARD, X68K_ALL, X68K_KEY_KP_DIV, X68K_CTRL_NONE, }, // Keypad Divide /
{ PS2_KEY_KP_EQUAL, PS2CTRL_NONE, KEYMAP_STANDARD, X68K_ALL, X68K_KEY_MINUS, X68K_CTRL_SHIFT, }, // Keypad Equal =
{ PS2_KEY_KP_ENTER, PS2CTRL_NONE, KEYMAP_STANDARD, X68K_ALL, X68K_KEY_KP_ENTER, X68K_CTRL_NONE, }, // Keypad Ebter /
{ PS2_KEY_KP_ENTER, PS2CTRL_NONE, KEYMAP_STANDARD, X68K_ALL, X68K_KEY_KP_EQUAL, X68K_CTRL_NONE, }, // Keypad Ebter /
//PS2 Code PS2 Ctrl (Flags to Match) Machine X68K Data X68K Ctrl (Flags to Set).
// Special keys.
{ PS2_KEY_PRTSCR, PS2CTRL_FUNC, KEYMAP_STANDARD, X68K_ALL, 0x00, X68K_CTRL_NONE, }, //
{ PS2_KEY_PAUSE, PS2CTRL_FUNC | PS2CTRL_SHIFT, KEYMAP_STANDARD, X68K_ALL, X68K_KEY_BREAK, X68K_CTRL_RELEASESHIFT, }, // BREAK KEY
{ PS2_KEY_L_GUI, PS2CTRL_FUNC, KEYMAP_STANDARD, X68K_ALL, X68K_KEY_XF1, X68K_CTRL_NONE, }, // XF1
{ PS2_KEY_L_ALT, PS2CTRL_FUNC, KEYMAP_STANDARD, X68K_ALL, X68K_KEY_XF2, X68K_CTRL_NONE, }, // XF2
{ PS2_KEY_R_ALT, PS2CTRL_FUNC, KEYMAP_STANDARD, X68K_ALL, X68K_KEY_XF3, X68K_CTRL_NONE, }, // XF3
{ PS2_KEY_R_GUI, PS2CTRL_FUNC, KEYMAP_STANDARD, X68K_ALL, X68K_KEY_XF4, X68K_CTRL_NONE, }, // XF4
{ PS2_KEY_MENU, PS2CTRL_FUNC, KEYMAP_STANDARD, X68K_ALL, X68K_KEY_XF5, X68K_CTRL_NONE, }, // XF5
// Modifiers are last, only being selected if an earlier match isnt made.
{ PS2_KEY_L_SHIFT, PS2CTRL_FUNC, KEYMAP_STANDARD, X68K_ALL, X68K_KEY_SHIFT, X68K_CTRL_NONE, }, //
{ PS2_KEY_R_SHIFT, PS2CTRL_FUNC, KEYMAP_STANDARD, X68K_ALL, X68K_KEY_SHIFT, X68K_CTRL_NONE, }, //
{ PS2_KEY_L_CTRL, PS2CTRL_FUNC, KEYMAP_STANDARD, X68K_ALL, X68K_KEY_CTRL, X68K_CTRL_NONE, }, // Map to Control
{ PS2_KEY_R_CTRL, PS2CTRL_FUNC, KEYMAP_STANDARD, X68K_ALL, X68K_KEY_CTRL, X68K_CTRL_NONE, }, // Map to Control
{ 0, PS2CTRL_NONE, KEYMAP_STANDARD, X68K_ALL, X68K_KEY_NULL, X68K_CTRL_NONE, }, //
}};
};
#endif // X68K_H

View File

@@ -1 +0,0 @@
../sharpkey/sdkconfig

1684
sdkconfig Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1 +1 @@
1.021
1.041

View File

@@ -1 +0,0 @@
../../../sharpkey/webserver/css/bootstrap.min.css.gz

Binary file not shown.

View File

@@ -1 +0,0 @@
../../../sharpkey/webserver/css

View File

@@ -1 +0,0 @@
../../../sharpkey/webserver/css/jquery.edittable.min.css

18
webserver/css/jquery.edittable.min.css vendored Normal file
View File

@@ -0,0 +1,18 @@
table.inputtable{width:100%;border:1px solid #ddd;border-collapse:collapse;border-spacing:0;-moz-box-shadow:0 1px 3px rgba(0,0,0,.075);-webkit-box-shadow:0 1px 3px rgba(0,0,0,.075);box-shadow:0 1px 3px rgba(0,0,0,.075);margin:15px 0}
table.inputtable a.icon-button{background-color:#ccc;display:inline-block;width:18px;height:18px;text-decoration:none;color:#fff;font-weight:800;line-height:16px;text-align:center;font-size:14px;-moz-border-radius:1px;-webkit-border-radius:1px;border-radius:1px;-moz-box-shadow:0 0 1px rgba(0,0,0,0.2);-webkit-box-shadow:0 0 1px rgba(0,0,0,0.2);box-shadow:0 0 1px rgba(0,0,0,0.2)}
table.inputtable a.icon-button.addcol,table.inputtable a.icon-button.addrow{background-color:#81b71a}
table.inputtable a.icon-button.delcol,table.inputtable a.icon-button.delrow{background-color:#db4a39}
table.inputtable a.icon-button.disabled{background-color:#eee}
table.inputtable td:last-child,table.inputtable th:last-child{width:54px;border:1px solid #eee;border-right:thick;}
table.inputtable td,table.inputtable th{border:1px solid #eee;text-align:center;height:40px;vertical-align:middle;font-size:14px}
table.inputtable th{background-color:#f1f1f1;border-top:none;border-bottom:2px solid #ddd;border-color:#ddd}
table.inputtable td input[type=text]{border:0;width:90%;height:100%;text-align:center;padding:0 5%}
table.inputtable tr td input:focus{background-color:#fafafa}
table.inputtable.wh tbody tr:nth-child(1),table.inputtable.wh tbody tr:nth-child(1) input{background-color:#fdfdfd;font-weight:800}
table.inputtable th:first-child,table.inputtable td:first-child{border-left:none}
table.inputtable tr:last-child td{border-bottom:none}
@media only screen and max-width 480px {
table.inputtable td,table.inputtable th{min-width:40px;height:80px}
table.inputtable a.icon-button{width:40px;height:40px;font-size:18px;min-width:40px;line-height:40px;margin:3px 0}
table.inputtable td input{height:80px}
}

View File

@@ -1 +0,0 @@
../../../sharpkey/webserver/css/sb-admin.css

159
webserver/css/sb-admin.css Normal file
View File

@@ -0,0 +1,159 @@
/*
Author: Start Bootstrap - http://startbootstrap.com
'SB Admin' HTML Template by Start Bootstrap
All Start Bootstrap themes are licensed under Apache 2.0.
For more info and more free Bootstrap 3 HTML themes, visit http://startbootstrap.com!
*/
/* ATTN: This is mobile first CSS - to update 786px and up screen width use the media query near the bottom of the document! */
/* Global Styles */
body {
margin-top: 50px;
}
#wrapper {
padding-left: 0;
}
#page-wrapper {
width: 100%;
padding: 5px 15px;
}
/* Nav Messages */
.messages-dropdown .dropdown-menu .message-preview .avatar,
.messages-dropdown .dropdown-menu .message-preview .name,
.messages-dropdown .dropdown-menu .message-preview .message,
.messages-dropdown .dropdown-menu .message-preview .time {
display: block;
}
.messages-dropdown .dropdown-menu .message-preview .avatar {
float: left;
margin-right: 15px;
}
.messages-dropdown .dropdown-menu .message-preview .name {
font-weight: bold;
}
.messages-dropdown .dropdown-menu .message-preview .message {
font-size: 12px;
}
.messages-dropdown .dropdown-menu .message-preview .time {
font-size: 12px;
}
/* Nav Announcements */
.announcement-heading {
font-size: 50px;
margin: 0;
}
.announcement-text {
margin: 0;
}
/* Table Headers */
table.tablesorter thead {
cursor: pointer;
}
table.tablesorter thead tr th:hover {
background-color: #f5f5f5;
}
/* Flot Chart Containers */
.flot-chart {
display: block;
height: 400px;
}
.flot-chart-content {
width: 100%;
height: 100%;
}
/* Edit Below to Customize Widths > 768px */
@media (min-width:768px) {
/* Wrappers */
#wrapper {
padding-left: 225px;
}
#page-wrapper {
padding: 15px 25px;
}
/* Side Nav */
.side-nav {
margin-left: -225px;
left: 225px;
width: 225px;
position: fixed;
top: 50px;
height: 100%;
border-radius: 0;
border: none;
background-color: #222222;
overflow-y: auto;
}
/* Bootstrap Default Overrides - Customized Dropdowns for the Side Nav */
.side-nav>li.dropdown>ul.dropdown-menu {
position: relative;
min-width: 225px;
margin: 0;
padding: 0;
border: none;
border-radius: 0;
background-color: transparent;
box-shadow: none;
-webkit-box-shadow: none;
}
.side-nav>li.dropdown>ul.dropdown-menu>li>a {
color: #999999;
padding: 15px 15px 15px 25px;
}
.side-nav>li.dropdown>ul.dropdown-menu>li>a:hover,
.side-nav>li.dropdown>ul.dropdown-menu>li>a.active,
.side-nav>li.dropdown>ul.dropdown-menu>li>a:focus {
color: #fff;
background-color: #080808;
}
.side-nav>li>a {
width: 225px;
}
.navbar-inverse .navbar-nav>li>a:hover,
.navbar-inverse .navbar-nav>li>a:focus {
background-color: #080808;
}
/* Nav Messages */
.messages-dropdown .dropdown-menu {
min-width: 300px;
}
.messages-dropdown .dropdown-menu li a {
white-space: normal;
}
}

View File

@@ -1 +0,0 @@
../../../sharpkey/webserver/css/sharpkey.css

266
webserver/css/sharpkey.css Normal file
View File

@@ -0,0 +1,266 @@
.wm-button {
width: 95px;
height: 25px;
background: blue;
border: none;
vertical-align: top;
margin-left: 25px;
cursor: pointer;
color: white;
transition: 2s;
border-radius: 12px;
}
.wm-button:disabled {
background: #999;
color: #555;
cursor: not-allowed;
}
.wm-button:hover {
background-color: #81ecec;
border: 2px solid #00cec9;
}
input[type="file"] {
display: none;
}
.firmware-file-upload {
width: 95px;
height: 25px;
background: blue;
border: none;
vertical-align: middle;
text-align: center;
line-height: 25px;
margin-left: 35px;
margin-bottom: 0px;
cursor: pointer;
color: white;
transition: 2s;
border-radius: 12px;
}
.firmware-file-upload:hover {
background-color: #81ecec;
border: 2px solid #00cec9;
}
.keymap-file-upload {
width: 95px;
height: 25px;
background: blue;
border: none;
vertical-align: middle;
text-align: center;
line-height: 25px;
margin-left: 35px;
margin-bottom: 0px;
cursor: pointer;
color: white;
transition: 2s;
border-radius: 12px;
}
.keymap-file-upload:hover {
background-color: #81ecec;
border: 2px solid #00cec9;
}
input[type=file]::file-selector-button {
border: 2px solid #6c5ce7;
padding: .2em .4em;
border-radius: .2em;
background-color: #a29bfe;
transition: 1s;
}
input[type=file]::file-selector-button:hover {
background-color: #81ecec;
border: 2px solid #00cec9;
}
.sk-modules-table {
border: none;
border-collapse: collapse;
}
.sk-modules-table caption {
padding-bottom: 0.5em;
}
.sk-modules-table th, .sk-modules-table td {
border: none;
padding: 0.2rem 2rem;
}
.sk-modules-table td {
white-space: nowrap;
}
.sk-modules-table th {
font-weight: normal;
}
.sk-modules-table td {
border-style: none;
vertical-align: top;
}
.sk-modules-table th {
padding: 0.2em;
vertical-align: middle;
text-align: center;
}
.sk-modules-table tbody td:first-child::after {
content: leader(". ");
}
.sk-client-wifi-config-table {
border: none;
border-collapse: collapse;
width: 1px !important;
table-layout: auto !important;
}
.sk-client-wifi-config-table caption {
padding-bottom: 0.5em;
}
.sk-client-wifi-config-table th, .sk-client-wifi-config-table td {
border: none;
padding: 0.2rem 2rem;
padding-left: 0;
padding-right: 4rem;
}
.sk-client-wifi-config-table td {
white-space: nowrap;
overflow: hidden;
border-style: none;
vertical-align: top;
width: auto !important;
}
.sk-client-wifi-config-table th {
font-weight: normal;
padding: 0.2em;
vertical-align: middle;
text-align: center;
width: auto !important;
}
#client-wifi-config-area {
overflow-x: scroll;
width: fit-content;
}
#firmware-revision-area {
overflow-x: scroll;
width: fit-content;
}
#esp32-partitions-area {
overflow-x: scroll;
width: fit-content;
}
.sk-partitions-table {
border: none;
border-collapse: collapse;
}
.sk-partitions-table caption {
padding-bottom: 0.5em;
}
.sk-partitions-table th, .sk-partitions-table td {
border: none;
padding: 0.2rem 2rem;
}
.sk-partitions-table td {
white-space: nowrap;
border-style: none;
vertical-align: top;
}
.sk-partitions-table th {
font-weight: normal;
padding: 0.2em;
vertical-align: middle;
text-align: center;
}
.sk-partitions-table tbody td:first-child::after {
content: leader(". ");
}
.sk-partitions-table tbody td:nth-child(4) {
text-align: right;
}
.sk-partitions-table tbody td:nth-child(5) {
text-align: right;
}
.sk-partitions-table tbody td:nth-child(6) {
text-align: center;
}
.sk-partitions-table tbody td:nth-child(8) {
text-align: center;
}
.table-condensed .progress {
margin-bottom: 0 !important;
width: 400px;
display: none;
}
.table-borderless > tbody > tr > td,
.table-borderless > thead > tr > td,
.table-borderless {
border-bottom: 0;
border-top: 0;
padding: 4px;
padding-top: 2px;
padding-bottom: 0;
white-space: nowrap;
}
.table-responsive {
border-bottom: 0;
border-top: 0;
border-left: 0;
border-right: 0;
padding: 4px;
padding-top: 2px;
padding-bottom: 0;
white-space: nowrap;
table-layout: auto;
}
.table {
margin-bottom: 10px;
}
.justify {
text-align: justify;
text-justify: inter-word;
}
.keymap {
max-height: 36.2em;
overflow: auto;
}
.hr_no_margin {
margin-top: 0.2em;
margin-bottom: 0.2em;
}
fieldset {
overflow: hidden;
}
.radio-mouse {
padding-right: 1em;
}
.radio-mouse label {
float: left;
clear: none;
display: block;
padding: 0px 1em 0px 8px;
}
input[type=radio] .radio-mouse,
input.radio .radio-mouse {
float: left;
clear: none;
margin: 2px 0 0 2px;
}

View File

@@ -1 +0,0 @@
../../../sharpkey/webserver/css/style.css

253
webserver/css/style.css Normal file
View File

@@ -0,0 +1,253 @@
/*
body {
margin: 0;
}
*/
/*
h1 {
text-align: center;
font-family: Tahoma, Arial, sans-serif;
color: #06D85F;
margin: 10px;
}
*/
.box {
width: 40%;
margin: 0 auto;
background: rgba(255,255,255,0.2);
padding: 35px;
border: 2px solid #fff;
border-radius: 20px/50px;
background-clip: padding-box;
text-align: center;
}
.overlay {
position: fixed;
top: 0;
bottom: 0;
left: 0;
right: 0;
background: rgba(0, 0, 0, 0.7);
//transition: opacity 500ms;
visibility: hidden;
opacity: 0;
}
.overlay:target {
visibility: visible;
opacity: 1;
}
.popup {
margin: 70px auto;
padding: 20px;
background: #fff;
border-radius: 5px;
width: 30%;
position: relative;
transition: all 5s ease-in-out;
}
.popup h2 {
margin-top: 0;
color: #333;
font-family: Tahoma, Arial, sans-serif;
}
.popup .close {
position: absolute;
top: 20px;
right: 30px;
transition: all 200ms;
font-size: 30px;
font-weight: bold;
text-decoration: none;
color: #333;
}
.popup .close:hover {
color: #06D85F;
}
.popup .content {
max-height: 30%;
overflow: auto;
}
@media screen and (max-width: 700px){
.box{
width: 90%;
}
.popup{
width: 90%;
}
}
/*
html {
font-family: Arial, Helvetica, sans-serif;
display: inline-block;
text-align: center;
}
h1 {
font-size: 1.8rem;
color: white;
}
p {
font-size: 1.1rem;
}
*/
.topnav {
overflow: hidden;
background-color: #0A1128;
}
.content {
padding: 5%;
}
.card-grid {
max-width: 800px;
margin: 0 auto;
display: grid;
grid-gap: 2rem;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
}
.card {
background-color: lightyellow;
box-shadow: 2px 2px 12px 1px rgba(140,140,140,.5);
}
.card-title {
font-size: 1.1rem;
font-weight: bold;
color: #034078
}
/*
input[type=submit] {
border: none;
color: #FEFCFB;
background-color: #034078;
padding: 15px 15px;
text-align: center;
text-decoration: none;
display: inline-block;
font-size: 18px;
width: 30%;
margin-right: 10px;
border-radius: 4px;
transition-duration: 0.4s;
}
input[type=submit]:hover {
background-color: #1282A2;
}
input[type=text], input[type=number], select {
width: 40%;
padding: 8px 10px;
margin: 12px;
display: inline-block;
border: 1px solid #ccc;
border-radius: 4px;
box-sizing: border-box;
}
input[type=url], input[type=number], select {
width: 50%;
padding: 12px 20px;
margin: 18px;
display: inline-block;
border: 1px solid #ccc;
border-radius: 4px;
box-sizing: border-box;
}
label {
font-size: 1rem;
}
*/
.value{
font-size: 1rem;
color: #1282A2;
}
.state {
font-size: 1rem;
color: #1282A2;
}
.button {
font-size: 2em;
padding: 3px;
color: #dbd75e;
border: 1px solid #000;
border-radius: 5px;
text-decoration: none;
cursor: pointer;
transition: all 1s ease-out;
background: #1b06d8;
}
.button:hover {
background: #06D85F;
}
/*
button {
//border: none;
// color: #FEFCFB;
// padding: 15px 32px;
// text-align: center;
// font-size: 30px;
// width: 100px;
// border-radius: 4px;
transition-duration: 0.4s;
}
.button-on {
// background-color: #034078;
}
.button-on:hover {
// background-color: #1282A2;
}
.button-off {
// background-color: #858585;
}
.button-off:hover {
// background-color: #252524;
}
*/
#sk-modules-table {
border: solid thin;
border-collapse: collapse;
}
#sk-modules-table caption {
padding-bottom: 0.5em;
}
#sk-modules-table th,
#sk-modules-table td {
border: solid thin;
padding: 0.5rem 2rem;
}
#sk-modules-table td {
white-space: nowrap;
}
#sk-modules-table th {
font-weight: normal;
}
#sk-modules-table td {
border-style: none solid;
vertical-align: top;
}
#sk-modules-table th {
padding: 0.2em;
vertical-align: middle;
text-align: center;
}
#sk-modules-table tbody td:first-child::after {
content: leader(". ");
}

View File

@@ -1 +0,0 @@
../../../sharpkey/webserver/css/styles.css

1
webserver/css/styles.css Normal file
View File

@@ -0,0 +1 @@
body { padding-bottom: 70px; }

View File

@@ -1 +0,0 @@
../../sharpkey/webserver/favicon.ico

Before

Width:  |  Height:  |  Size: 36 B

After

Width:  |  Height:  |  Size: 4.2 KiB

BIN
webserver/favicon.ico Normal file

Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 B

After

Width:  |  Height:  |  Size: 4.2 KiB

View File

@@ -1 +0,0 @@
../../../../sharpkey/webserver/font-awesome/css

View File

@@ -1 +0,0 @@
../../../../sharpkey/webserver/font-awesome/css/font-awesome.css

File diff suppressed because it is too large Load Diff

View File

@@ -1 +0,0 @@
../../../../sharpkey/webserver/font-awesome/css/font-awesome.min.css

File diff suppressed because one or more lines are too long

View File

@@ -1 +0,0 @@
../../../../sharpkey/webserver/font-awesome/css/font-awesome.min.css.orig

Some files were not shown because too many files have changed in this diff Show More