10 Commits

Author SHA1 Message Date
eaw
1fbd3a0fea Update README from eaw.app website content 2026-03-14 10:07:01 +00:00
Philip Smart
8a90b8fec8 Added NoriQs enhancements for the MZ65xx machines 2025-09-01 19:30:06 +01:00
Philip Smart
930b61aad1 Updates to PC-9801/X68000 detection algorithm 2023-05-24 09:06:31 +01:00
Philip Smart
95b4ce47fb Update to host detection logic 2023-05-10 09:49:24 +01:00
Philip Smart
0341bb35b6 Updated README 2022-12-12 20:41:20 +00:00
Philip Smart
22d036b858 Updated license file 2022-09-04 19:59:06 +01:00
Philip Smart
4f1d9b93e2 Update to README 2022-09-04 15:00:23 +01:00
Philip Smart
a0fc4ca3b7 Schematic updates and docs 2022-09-04 14:55:26 +01:00
Philip Smart
96a69cc86d Added source code, MZ6500 module still not complete 2022-09-04 14:51:38 +01:00
Philip Smart
8bba3b0e92 Bug found in PS2 Mouse detection logic 2022-06-27 23:35:08 +01:00
82 changed files with 31522 additions and 91 deletions

102
README.md
View File

@@ -1,7 +1,101 @@
## <font style="color: yellow;" size="6">SharpKey Multi-HID Inteface</font> # SharpKey
Please see the <a href="https://eaw.app/sharpkey">engineers@work</a> website for the latest documentation. **Website:** [engineers@work](https://eaw.app) | **Repository:** [git.eaw.app/eaw/SharpKey](https://git.eaw.app/eaw/SharpKey)
Click here to view the latest PDF version of the <a href="https://docs.google.com/viewer?url=https://eaw.app/Downloads/SharpKey_Multi-HID_Interface_User_Manual_v1_04.pdf">User Manual</a> or <a href="https://docs.google.com/viewer?url=https://eaw.app/Downloads/SharpKey_Multi-HID_Interface_Technical_Guide_v1_04.pdf">Technical Guide</a> ---
The firmware is undergoing rapid advances and will initially only be included as releases. <img src='../images/SharpKey_Overview.png' height='70%' width='70%' style="margin-left: auto; margin-right: auto; display: block;"/>
## <font style="color: yellow;" size="6">Summary</font>
<div style="text-align: justify">
The SharpKey is an IoT Multi-HID (Human Interface Device) to Multi-Host Interface with on-board web configuration and Over The Air update facilities. It enables more modern keyboard and mice
devices to be used with vintage computers where these devices are no longer obtainable or working.
<div style="padding-top: 0.8em;"></div>
The device is plug and play, it automatically detects connected input and host device types, self-configures and is ready for instant on useability. Bluetooth devices require the SharpKey and HID device to be set to pairing
mode for first time use and once paired operate exactly as wired equivalents.
<div style="padding-top: 0.8em;"></div>
At its heart, the SharpKey uses a dual-core WiFi/BT enabled SoC from Espressif with C++ based Object Oriented firmware. The on-board IoT web interface, operating in Station or Access Point mode, is based on venerable Javascript/JQuery/Bootstrap technologies
and supports most modern web browsers.
</div>
The SharpKey currently supports:
<div style="padding-left: 5%">
<font size="4">
<style>
table {
border-collapse: collapse;
}
tr td {
padding-top: 0em;
}
tr:nth-child(4) td {
padding-top: 0;
}
</style>
<table>
<tr><th><u>Input Devices</u></th><th>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</th><th colspan="1"></th><th><u>Host Computers</u></th></tr>
<tr><td>PS/2 Keyboards</td><td></td><td colspan="1"></td><td>Sharp X1</td><td>Sharp MZ-5600<sup>1.</sup></td></tr>
<tr><td>PS/2 Mice</td><td></td><td colspan="1"></td><td>Sharp X68000</td><td>Sharp MZ-6500<sup>1.</sup></td></tr>
<tr><td>PS/2 KVM Switch</td><td></td><td colspan="1"></td><td>Sharp MZ-2500</td><td>NEC PC-9801<sup>2.</sup></td></tr>
<tr><td>Bluetooth HID</td><td></td><td colspan="1"></td><td>Sharp MZ-2800</td></tr>
</table>
</font>
</div>
## <font style="color: yellow;" size="6">Overview</font>
Following on from the successful [mz25key interface](/mz25key/), the SharpKey advances the design in terms of hardware and software to provide an all in one expandable solution to interfacing keyboards and mice
to venerable Sharp and NEC computers.
<div style="text-align: justify">
The mz25key supports adding a PS/2 keyboard to a Sharp MZ-2500 or MZ-2800 computer whereas the SharpKey is more versatile in connecting both keyboards and mice, via PS/2 or Bluetooth, to a host console.
<div style="padding-top: 0.8em;"></div>
PS/2 mode supports one device at a time, device type being determined by the connected host port type using host specific cables. A mouse cable connected to the mouse port of an X68000 will require a PS/2 mouse connected to the SharpKey
and a keyboard cable connected to the keyboard port of an X68000 will require a PS/2 keyboard connected to the SharpKey.
<div style="padding-top: 0.8em;"></div>
In PS/2 mode, it is possible to connect multiple host consoles, each with its own SharpKey device, to one Keyboard, Mouse and Monitor via a PS/2 KVM Switch such as the Apex EL-80DT.
<div style="padding-top: 0.8em;"></div>
Bluetooth mode supports simultaneous use of keyboard and mouse where the host supports it and the correct host specific cable is used. ie. an X68000 uses a single cable to transmit both keyboard and mouse data allowing simultaneous use of keyboard and mouse via Bluetooth, whereas
an MZ-2500 is restricted to keyboard or mouse per SharpKey (ie. to connect both a keyboard and mouse to an MZ-2500 requires 2 SharpKey devices).
<div style="padding-top: 0.8em;"></div>
This site aims to provide all the information, both technical and user guides for the SharpKey, please click on required link in the left panel. The schematics, layout and firmware are available on <a href="https://git.eaw.app/eaw">Gitea</a>. Please follow or star a project
if you download and make use of it, either for creating your own SharpKey or basing another project on its design. Please note, the GNU license has a restriction that no commercial use can be made without prior written permission.
<div style="padding-top: 0.8em;"></div>
For more in depth detail, please click on a sidebar link to view the <a href="/sharpkey-usermanual">User Manual</a> or <a href="/sharpkey-technicalguide">Technical Guide</a>.
</div>
<div style="padding-top: 0.8em;"></div>
<p style="line-height: 1em; margin: 0;"><font size="2"><sup>1, 2.</sup>Waiting on testing, not yet released.</font></p>
--------------------------------------------------------------------------------------------------------
## <font style="color: yellow;" size="6">Credits</font>
<div style="text-align: justify">
Espressif IDF development environment and use of the ESP-32S reference material was used in the design of this Multi-HID interface.
</div>
--------------------------------------------------------------------------------------------------------
## <font style="color: yellow;" size="6">Licenses</font>
<div style="text-align: justify">
This design, hardware and software, is licensed under the GNU Public Licence v3.
<br><br>
No commercial use to be made of this design or any hardware/firmware component without express permission from the author. This condition overrides
any rights afforded by the GNU GPL 3 license.
</div>
--------------------------------------------------------------------------------------------------------
### <font style="color: yellow;" size="6">The Gnu Public License v3</font>
<div style="text-align: justify">
The source and binary files in this project marked as GPL v3 are 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.
<br><br>
The source files are 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.
<br><br>
You should have received a copy of the GNU General Public License along with this program. If not, see http://www.gnu.org/licenses/.
</div>

BIN
docs/KeyboardImage.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 835 KiB

BIN
docs/PS2 Keyboard.pdf Normal file

Binary file not shown.

BIN
docs/PS2_Mouse.pdf Normal file

Binary file not shown.

View File

@@ -62,7 +62,7 @@
35, 35,
36 36
], ],
"visible_layers": "ffdffdf_ffffffff", "visible_layers": "ffdffff_ffffffff",
"zone_display_mode": 0 "zone_display_mode": 0
}, },
"meta": { "meta": {

View File

@@ -8,7 +8,7 @@
(date "2022-03-09") (date "2022-03-09")
(rev "1.3") (rev "1.3")
(comment 1 "dedicated to the Host I/F, the second core to PS/2 capture, vector build and map.") (comment 1 "dedicated to the Host I/F, the second core to PS/2 capture, vector build and map.")
(comment 2 "toolchain. The requirements require control down to 100ns so one cpu core is always") (comment 2 "toolchain. The requirements require control down to 100ns so on cpu core is always")
(comment 3 "This design uses the common ESP32 SoC for its performance, low power and development ") (comment 3 "This design uses the common ESP32 SoC for its performance, low power and development ")
(comment 4 "PS/2 to Sharp MZ-2500/MZ-2800/X1/X68K Keyboard Interface.") (comment 4 "PS/2 to Sharp MZ-2500/MZ-2800/X1/X68K Keyboard Interface.")
) )
@@ -2744,12 +2744,8 @@
(effects (font (size 1.27 1.27)) (justify left bottom)) (effects (font (size 1.27 1.27)) (justify left bottom))
(uuid 5b701cbb-e617-42ef-ac32-12540c6d0846) (uuid 5b701cbb-e617-42ef-ac32-12540c6d0846)
) )
(text "NB: MPX must be strapped low or N/C." (at 19.05 177.8 0) (text " Mouse Signal Key\n\n2 - \n3 MSCTRL - Mouse Control Clock\n4 MSDATA - Mouse Data\n5 - \n6 - \n7 - \n8 - "
(effects (font (size 0.7874 0.7874)) (justify left bottom)) (at 19.05 172.72 0)
(uuid 5b743307-5117-4608-9c75-dffa68ddf8d9)
)
(text " Mouse Signal Key\n\n2 - N/C (pulled high internally)\n3 MSCTRL - Mouse Control Clock\n4 MSDATA - Mouse Data\n5 - Strap low\n6 - Strap low\n7 - Strap high\n8 - Strap low"
(at 13.97 167.64 0)
(effects (font (size 0.7874 0.7874)) (justify left bottom)) (effects (font (size 0.7874 0.7874)) (justify left bottom))
(uuid 72f91424-2afc-46bf-8d2d-785c6190adb8) (uuid 72f91424-2afc-46bf-8d2d-785c6190adb8)
) )
@@ -2770,23 +2766,23 @@
(effects (font (size 1.27 1.27)) (justify left bottom)) (effects (font (size 1.27 1.27)) (justify left bottom))
(uuid 97b72635-d769-41b5-be10-7466ea4805c9) (uuid 97b72635-d769-41b5-be10-7466ea4805c9)
) )
(text "DSCK / DSDA - I2C Interface to an OLED Display.\nRXD/TXD. - UART Receive and Transmit.\nDTR/RTS - UART control lines used for programming \n and reset of the ESP32.\n\nNB: MPX must be strapped low or N/C to program." (text "DSCK / DSDA - I2C Interface to an OLED Display.\nRXD/TXD. - UART Receive and Transmit.\nDTR/RTS - UART control lines used for programming \n and reset of the ESP32."
(at 247.65 80.01 0) (at 247.65 76.2 0)
(effects (font (size 0.7874 0.7874)) (justify left bottom)) (effects (font (size 0.7874 0.7874)) (justify left bottom))
(uuid b7a0bad2-b4a4-4aa2-929c-06f03cb704d9) (uuid b7a0bad2-b4a4-4aa2-929c-06f03cb704d9)
) )
(text " X68000 Keyboard Signal Key\n\n2 - N/C (pulled high internally)\n3 TXD - Transmit Data\n4 RXD - Receive Data\n5 READY - Keyboard Ready\n6 REMOTE - Remote\n7 - Strap low\n8 - Strap low\n" (text " X68000 Keyboard Signal Key\n\n2 - \n3 TXD - Transmit Data\n4 RXD - Receive Data\n5 READY - Keyboard Ready\n6 REMOTE - Remote\n7 - \n8 - "
(at 13.97 154.94 0) (at 19.05 158.75 0)
(effects (font (size 0.7874 0.7874)) (justify left bottom)) (effects (font (size 0.7874 0.7874)) (justify left bottom))
(uuid c2b0f666-5d14-4ae3-9993-f745a4ee42c1) (uuid c2b0f666-5d14-4ae3-9993-f745a4ee42c1)
) )
(text " X1 Signal Key\n\n2 - Strap low\n3 DATA - X1 Key Data\n4 - Strap low\n5 - Strap low\n6 - Strap low\n7 - Strap low\n8 - Strap low" (text " X1 Signal Key\n\n2 -\n3 DATA - X1 Key Data\n4 -\n5 - \n6 - \n7 - \n8 - "
(at 13.97 142.24 0) (at 19.05 144.78 0)
(effects (font (size 0.7874 0.7874)) (justify left bottom)) (effects (font (size 0.7874 0.7874)) (justify left bottom))
(uuid e869aad9-306b-4c57-9e33-d3fc2ad9b7c3) (uuid e869aad9-306b-4c57-9e33-d3fc2ad9b7c3)
) )
(text " MZ-2500/2800 Signal Key\n\n2 ~{RTSN} - H:Row Sent, L:Key Data Returned\n3 KD0 -\n4 KD1 -\n5 KD2 -\n6 KD3 - Bi-directional Bus\n7 KD4 - H:Key Data, L:Strobe All Data\n8 MPX - H:Upper Nibble, L:Lower Nibble" (text " MZ-2500/2800 Signal Key\n\n2 KD0 -\n3 KD1 -\n4 KD2 -\n5 KD3 - Bi-directional Bus\n6 KD4 - H:Key Data, L:Strobe All Data\n7 MPX - H:Upper Nibble, L:Lower Nibble\n8 ~{RTSN} - H:Row Sent, L:Key Data Returned"
(at 13.97 129.54 0) (at 19.05 130.81 0)
(effects (font (size 0.7874 0.7874)) (justify left bottom)) (effects (font (size 0.7874 0.7874)) (justify left bottom))
(uuid ebba3f64-f6e2-4115-9437-89e1a925877e) (uuid ebba3f64-f6e2-4115-9437-89e1a925877e)
) )
@@ -4085,7 +4081,7 @@
(property "Reference" "R21" (id 0) (at 143.51 88.9 0) (property "Reference" "R21" (id 0) (at 143.51 88.9 0)
(effects (font (size 0.7874 0.7874)) (justify left)) (effects (font (size 0.7874 0.7874)) (justify left))
) )
(property "Value" "DNP" (id 1) (at 143.51 90.17 0) (property "Value" "10K" (id 1) (at 143.51 90.17 0)
(effects (font (size 0.7874 0.7874)) (justify left)) (effects (font (size 0.7874 0.7874)) (justify left))
) )
(property "Footprint" "Resistor_SMD:R_0805_2012Metric" (id 2) (at 143.51 86.36 0) (property "Footprint" "Resistor_SMD:R_0805_2012Metric" (id 2) (at 143.51 86.36 0)
@@ -4260,7 +4256,7 @@
(reference "R20") (unit 1) (value "10K") (footprint "Resistor_SMD:R_0805_2012Metric") (reference "R20") (unit 1) (value "10K") (footprint "Resistor_SMD:R_0805_2012Metric")
) )
(path "/fabcffe5-3ed2-40e2-896a-ed011b2d8803" (path "/fabcffe5-3ed2-40e2-896a-ed011b2d8803"
(reference "R21") (unit 1) (value "DNP") (footprint "Resistor_SMD:R_0805_2012Metric") (reference "R21") (unit 1) (value "10K") (footprint "Resistor_SMD:R_0805_2012Metric")
) )
(path "/00000000-0000-0000-0000-000062009785" (path "/00000000-0000-0000-0000-000062009785"
(reference "SW1") (unit 1) (value "WiFi EN") (footprint "Button_Switch_SMD:SW_SPST_B3S-1000") (reference "SW1") (unit 1) (value "WiFi EN") (footprint "Button_Switch_SMD:SW_SPST_B3S-1000")

674
license.txt Normal file
View File

@@ -0,0 +1,674 @@
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The GNU General Public License is a free, copyleft license for
software and other kinds of works.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users. We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors. You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
To protect your rights, we need to prevent others from denying you
these rights or asking you to surrender the rights. Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received. You must make sure that they, too, receive
or can get the source code. And you must show them these terms so they
know their rights.
Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer you this License
giving you legal permission to copy, distribute and/or modify it.
For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software. For both users' and
authors' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.
Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so. This is fundamentally incompatible with the aim of
protecting users' freedom to change the software. The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable. Therefore, we
have designed this version of the GPL to prohibit the practice for those
products. If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.
Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary. To prevent this, the GPL assures that
patents cannot be used to render the program non-free.
The precise terms and conditions for copying, distribution and
modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based
on the Program.
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
The Corresponding Source for a work in source code form is that
same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
"keep intact all notices".
c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:
a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
13. Use with the GNU Affero General Public License.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU Affero General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the special requirements of the GNU Affero General Public License,
section 13, concerning interaction through a network will apply to the
combination as such.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the
Program specifies that a certain numbered version of the GNU General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU General Public License, you may choose any version ever published
by the Free Software Foundation.
If the Program specifies that a proxy can decide which future
versions of the GNU General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
Also add information on how to contact you by electronic and paper mail.
If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode:
<program> Copyright (C) <year> <name of author>
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, your program's commands
might be different; for a GUI interface, you would use an "about box".
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU GPL, see
<https://www.gnu.org/licenses/>.
The GNU General Public License does not permit incorporating your program
into proprietary programs. If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License. But first, please read
<https://www.gnu.org/licenses/why-not-lgpl.html>.

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

1181
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

1117
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

1112
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

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

@@ -0,0 +1,605 @@
/////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// 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.
// v1.02 Feb 2024 - Updated to actually work by NoriQ.
//
// 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.02
#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 0x1C // ↑
#define MZ5665_KEY_DOWN 0x1D // ↓
#define MZ5665_KEY_LEFT 0x1F // ←
#define MZ5665_KEY_RIGHT 0x1E // →
#define MZ5665_KEY_INS 0x0B // INS
#define MZ5665_KEY_DEL 0x7F // DEL
#define MZ5665_KEY_CLR 0x18 // CLR
#define MZ5665_KEY_HOME 0x8F // HOME
#define MZ5665_KEY_ARGO 0x14 // ARGO
#define MZ5665_KEY_KANA 0x17 // KANA
#define MZ5665_KEY_GRAPH 0x16 // GRAPH
#define MZ5665_KEY_BREAK 0x06 // Break
// 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);
bool waitSignal(uint32_t mask, bool val, uint64_t timeout);
// // 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 mzExt;
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 Ext MZ5665 Ctrl (Flags to Set).
//{ PS2_KEY_F1, PS2CTRL_FUNC | PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ5665_ALL, 'v', 0x00, 0x00, }, // SHIFT+F1
//{ PS2_KEY_F2, PS2CTRL_FUNC | PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ5665_ALL, 'w', 0x00, 0x00, }, // SHIFT+F2
//{ PS2_KEY_F3, PS2CTRL_FUNC | PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ5665_ALL, 'x', 0x00, 0x00, }, // SHIFT+F3
//{ PS2_KEY_F4, PS2CTRL_FUNC | PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ5665_ALL, 'y', 0x00, 0x00, }, // SHIFT+F4
//{ PS2_KEY_F5, PS2CTRL_FUNC | PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ5665_ALL, 'z', 0x00, 0x00, }, // SHIFT+F5
//{ PS2_KEY_F1, PS2CTRL_FUNC, KEYMAP_STANDARD, MZ5665_ALL, 'q', 0x00, 0x00, }, // F1
//{ PS2_KEY_F2, PS2CTRL_FUNC, KEYMAP_STANDARD, MZ5665_ALL, 'r', 0x00, 0x00, }, // F2
//{ PS2_KEY_F3, PS2CTRL_FUNC, KEYMAP_STANDARD, MZ5665_ALL, 's', 0x00, 0x00, }, // F3
//{ PS2_KEY_F4, PS2CTRL_FUNC, KEYMAP_STANDARD, MZ5665_ALL, 't', 0x00, 0x00, }, // F4
//{ PS2_KEY_F5, PS2CTRL_FUNC, KEYMAP_STANDARD, MZ5665_ALL, 'u', 0x00, 0x00, }, // F5
//{ PS2_KEY_F6, PS2CTRL_FUNC, KEYMAP_STANDARD, MZ5665_ALL, 0xEC, 0x00, 0x00, }, // F6
//{ PS2_KEY_F7, PS2CTRL_FUNC, KEYMAP_STANDARD, MZ5665_ALL, 0xEB, 0x00, 0x00, }, // F7
//{ PS2_KEY_F8, PS2CTRL_FUNC, KEYMAP_STANDARD, MZ5665_ALL, 0xE2, 0x00, 0x00, }, // F8
//{ PS2_KEY_F9, PS2CTRL_FUNC, KEYMAP_STANDARD, MZ5665_ALL, 0xE1, 0x00, 0x00, }, // F9
//{ PS2_KEY_F10, PS2CTRL_FUNC, KEYMAP_STANDARD, MZ5665_ALL, 0x00, 0x00, 0x00, }, // XFER
//{ PS2_KEY_F11, PS2CTRL_FUNC, KEYMAP_STANDARD, MZ5665_ALL, 0xFE, 0x00, 0x00, }, // HELP
//{ PS2_KEY_F12, PS2CTRL_FUNC, KEYMAP_STANDARD, MZ5665_ALL, 0x00, 0x00, 0x00, }, // COPY
//{ PS2_KEY_TAB, PS2CTRL_NONE, KEYMAP_STANDARD, MZ5665_ALL, 0x09, 0x00, 0x00, }, // TAB
// Numeric keys.
{ PS2_KEY_0, PS2CTRL_NONE, KEYMAP_STANDARD, MZ5665_ALL, '0', 0x00, 0x00, }, // 0
{ PS2_KEY_1, PS2CTRL_NONE, KEYMAP_STANDARD, MZ5665_ALL, '1', 0x00, 0x00, }, // 1
{ PS2_KEY_2, PS2CTRL_NONE, KEYMAP_STANDARD, MZ5665_ALL, '2', 0x00, 0x00, }, // 2
{ PS2_KEY_3, PS2CTRL_NONE, KEYMAP_STANDARD, MZ5665_ALL, '3', 0x00, 0x00, }, // 3
{ PS2_KEY_4, PS2CTRL_NONE, KEYMAP_STANDARD, MZ5665_ALL, '4', 0x00, 0x00, }, // 4
{ PS2_KEY_5, PS2CTRL_NONE, KEYMAP_STANDARD, MZ5665_ALL, '5', 0x00, 0x00, }, // 5
{ PS2_KEY_6, PS2CTRL_NONE, KEYMAP_STANDARD, MZ5665_ALL, '6', 0x00, 0x00, }, // 6
{ PS2_KEY_7, PS2CTRL_NONE, KEYMAP_STANDARD, MZ5665_ALL, '7', 0x00, 0x00, }, // 7
{ PS2_KEY_8, PS2CTRL_NONE, KEYMAP_STANDARD, MZ5665_ALL, '8', 0x00, 0x00, }, // 8
{ PS2_KEY_9, PS2CTRL_NONE, KEYMAP_STANDARD, MZ5665_ALL, '9', 0x00, 0x00, }, // 9
// Punctuation keys.
{ PS2_KEY_0, PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ5665_ALL, ')', 0x00, 0x00, }, // Close Right Bracket )
{ PS2_KEY_1, PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ5665_ALL, '!', 0x00, 0x00, }, // Exclamation
{ PS2_KEY_2, PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ5665_ALL, '"', 0x00, 0x00, }, // Double quote.
{ PS2_KEY_3, PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ5665_ALL, 0x23, 0x00, 0x00, }, // Pound Sign -> Hash
{ PS2_KEY_4, PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ5665_ALL, '$', 0x00, 0x00, }, // Dollar
{ PS2_KEY_5, PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ5665_ALL, '%', 0x00, 0x00, }, // Percent
{ PS2_KEY_6, PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ5665_ALL, '^', 0x00, 0x00, }, // Kappa
{ PS2_KEY_7, PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ5665_ALL, '&', 0x00, 0x00, }, // Ampersand
{ PS2_KEY_8, PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ5665_ALL, '*', 0x00, 0x00, }, // Star
{ PS2_KEY_9, PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ5665_ALL, '(', 0x00, 0x00, }, // Open Left Bracket (
// ALPHA keys, lower and uppercase.
//PS2 Code PS2 Ctrl (Flags to Match) Keyboard Model Machine MZ5665 Data MZ5665 Ext MZ5665 Ctrl (Flags to Set).
{ PS2_KEY_A, PS2CTRL_SHIFT | PS2CTRL_CAPS, KEYMAP_STANDARD, MZ5665_ALL, 'a', 0x00, 0x00, }, // a
{ PS2_KEY_A, PS2CTRL_CAPS, KEYMAP_STANDARD, MZ5665_ALL, 'A', 0x00, 0x00, }, // A
{ PS2_KEY_B, PS2CTRL_SHIFT | PS2CTRL_CAPS, KEYMAP_STANDARD, MZ5665_ALL, 'b', 0x00, 0x00, }, // b
{ PS2_KEY_B, PS2CTRL_CAPS, KEYMAP_STANDARD, MZ5665_ALL, 'B', 0x00, 0x00, }, // B
{ PS2_KEY_C, PS2CTRL_SHIFT | PS2CTRL_CAPS, KEYMAP_STANDARD, MZ5665_ALL, 'c', 0x00, 0x00, }, // c
{ PS2_KEY_C, PS2CTRL_CAPS, KEYMAP_STANDARD, MZ5665_ALL, 'C', 0x00, 0x00, }, // C
{ PS2_KEY_D, PS2CTRL_SHIFT | PS2CTRL_CAPS, KEYMAP_STANDARD, MZ5665_ALL, 'd', 0x00, 0x00, }, // d
{ PS2_KEY_D, PS2CTRL_CAPS, KEYMAP_STANDARD, MZ5665_ALL, 'D', 0x00, 0x00, }, // D
{ PS2_KEY_E, PS2CTRL_SHIFT | PS2CTRL_CAPS, KEYMAP_STANDARD, MZ5665_ALL, 'e', 0x00, 0x00, }, // e
{ PS2_KEY_E, PS2CTRL_CAPS, KEYMAP_STANDARD, MZ5665_ALL, 'E', 0x00, 0x00, }, // E
{ PS2_KEY_F, PS2CTRL_SHIFT | PS2CTRL_CAPS, KEYMAP_STANDARD, MZ5665_ALL, 'f', 0x00, 0x00, }, // f
{ PS2_KEY_F, PS2CTRL_CAPS, KEYMAP_STANDARD, MZ5665_ALL, 'F', 0x00, 0x00, }, // F
{ PS2_KEY_G, PS2CTRL_SHIFT | PS2CTRL_CAPS, KEYMAP_STANDARD, MZ5665_ALL, 'g', 0x00, 0x00, }, // g
{ PS2_KEY_G, PS2CTRL_CAPS, KEYMAP_STANDARD, MZ5665_ALL, 'G', 0x00, 0x00, }, // G
{ PS2_KEY_H, PS2CTRL_SHIFT | PS2CTRL_CAPS, KEYMAP_STANDARD, MZ5665_ALL, 'h', 0x00, 0x00, }, // h
{ PS2_KEY_H, PS2CTRL_CAPS, KEYMAP_STANDARD, MZ5665_ALL, 'H', 0x00, 0x00, }, // H
{ PS2_KEY_I, PS2CTRL_SHIFT | PS2CTRL_CAPS, KEYMAP_STANDARD, MZ5665_ALL, 'i', 0x00, 0x00, }, // i
{ PS2_KEY_I, PS2CTRL_CAPS, KEYMAP_STANDARD, MZ5665_ALL, 'I', 0x00, 0x00, }, // I
{ PS2_KEY_J, PS2CTRL_SHIFT | PS2CTRL_CAPS, KEYMAP_STANDARD, MZ5665_ALL, 'j', 0x00, 0x00, }, // j
{ PS2_KEY_J, PS2CTRL_CAPS, KEYMAP_STANDARD, MZ5665_ALL, 'J', 0x00, 0x00, }, // J
{ PS2_KEY_K, PS2CTRL_SHIFT | PS2CTRL_CAPS, KEYMAP_STANDARD, MZ5665_ALL, 'k', 0x00, 0x00, }, // k
{ PS2_KEY_K, PS2CTRL_CAPS, KEYMAP_STANDARD, MZ5665_ALL, 'K', 0x00, 0x00, }, // K
{ PS2_KEY_L, PS2CTRL_SHIFT | PS2CTRL_CAPS, KEYMAP_STANDARD, MZ5665_ALL, 'l', 0x00, 0x00, }, // l
{ PS2_KEY_L, PS2CTRL_CAPS, KEYMAP_STANDARD, MZ5665_ALL, 'L', 0x00, 0x00, }, // L
{ PS2_KEY_M, PS2CTRL_SHIFT | PS2CTRL_CAPS, KEYMAP_STANDARD, MZ5665_ALL, 'm', 0x00, 0x00, }, // m
{ PS2_KEY_M, PS2CTRL_CAPS, KEYMAP_STANDARD, MZ5665_ALL, 'M', 0x00, 0x00, }, // M
{ PS2_KEY_N, PS2CTRL_SHIFT | PS2CTRL_CAPS, KEYMAP_STANDARD, MZ5665_ALL, 'n', 0x00, 0x00, }, // n
{ PS2_KEY_N, PS2CTRL_CAPS, KEYMAP_STANDARD, MZ5665_ALL, 'N', 0x00, 0x00, }, // N
{ PS2_KEY_O, PS2CTRL_SHIFT | PS2CTRL_CAPS, KEYMAP_STANDARD, MZ5665_ALL, 'o', 0x00, 0x00, }, // o
{ PS2_KEY_O, PS2CTRL_CAPS, KEYMAP_STANDARD, MZ5665_ALL, 'O', 0x00, 0x00, }, // O
{ PS2_KEY_P, PS2CTRL_SHIFT | PS2CTRL_CAPS, KEYMAP_STANDARD, MZ5665_ALL, 'p', 0x00, 0x00, }, // p
{ PS2_KEY_P, PS2CTRL_CAPS, KEYMAP_STANDARD, MZ5665_ALL, 'P', 0x00, 0x00, }, // P
{ PS2_KEY_Q, PS2CTRL_SHIFT | PS2CTRL_CAPS, KEYMAP_STANDARD, MZ5665_ALL, 'q', 0x00, 0x00, }, // q
{ PS2_KEY_Q, PS2CTRL_CAPS, KEYMAP_STANDARD, MZ5665_ALL, 'Q', 0x00, 0x00, }, // Q
{ PS2_KEY_R, PS2CTRL_SHIFT | PS2CTRL_CAPS, KEYMAP_STANDARD, MZ5665_ALL, 'r', 0x00, 0x00, }, // r
{ PS2_KEY_R, PS2CTRL_CAPS, KEYMAP_STANDARD, MZ5665_ALL, 'R', 0x00, 0x00, }, // R
{ PS2_KEY_S, PS2CTRL_SHIFT | PS2CTRL_CAPS, KEYMAP_STANDARD, MZ5665_ALL, 's', 0x00, 0x00, }, // s
{ PS2_KEY_S, PS2CTRL_CAPS, KEYMAP_STANDARD, MZ5665_ALL, 'S', 0x00, 0x00, }, // S
{ PS2_KEY_T, PS2CTRL_SHIFT | PS2CTRL_CAPS, KEYMAP_STANDARD, MZ5665_ALL, 't', 0x00, 0x00, }, // t
{ PS2_KEY_T, PS2CTRL_CAPS, KEYMAP_STANDARD, MZ5665_ALL, 'T', 0x00, 0x00, }, // T
{ PS2_KEY_U, PS2CTRL_SHIFT | PS2CTRL_CAPS, KEYMAP_STANDARD, MZ5665_ALL, 'u', 0x00, 0x00, }, // u
{ PS2_KEY_U, PS2CTRL_CAPS, KEYMAP_STANDARD, MZ5665_ALL, 'U', 0x00, 0x00, }, // U
{ PS2_KEY_V, PS2CTRL_SHIFT | PS2CTRL_CAPS, KEYMAP_STANDARD, MZ5665_ALL, 'v', 0x00, 0x00, }, // v
{ PS2_KEY_V, PS2CTRL_CAPS, KEYMAP_STANDARD, MZ5665_ALL, 'V', 0x00, 0x00, }, // V
{ PS2_KEY_W, PS2CTRL_SHIFT | PS2CTRL_CAPS, KEYMAP_STANDARD, MZ5665_ALL, 'w', 0x00, 0x00, }, // w
{ PS2_KEY_W, PS2CTRL_CAPS, KEYMAP_STANDARD, MZ5665_ALL, 'W', 0x00, 0x00, }, // W
{ PS2_KEY_X, PS2CTRL_SHIFT | PS2CTRL_CAPS, KEYMAP_STANDARD, MZ5665_ALL, 'x', 0x00, 0x00, }, // x
{ PS2_KEY_X, PS2CTRL_CAPS, KEYMAP_STANDARD, MZ5665_ALL, 'X', 0x00, 0x00, }, // X
{ PS2_KEY_Y, PS2CTRL_SHIFT | PS2CTRL_CAPS, KEYMAP_STANDARD, MZ5665_ALL, 'y', 0x00, 0x00, }, // y
{ PS2_KEY_Y, PS2CTRL_CAPS, KEYMAP_STANDARD, MZ5665_ALL, 'Y', 0x00, 0x00, }, // Y
{ PS2_KEY_Z, PS2CTRL_SHIFT | PS2CTRL_CAPS, KEYMAP_STANDARD, MZ5665_ALL, 'z', 0x00, 0x00, }, // z
{ PS2_KEY_Z, PS2CTRL_CAPS, KEYMAP_STANDARD, MZ5665_ALL, 'Z', 0x00, 0x00, }, // Z
//PS2 Code PS2 Ctrl (Flags to Match) Keyboard Model Machine MZ5665 Data MZ5665 Ext MZ5665 Ctrl (Flags to Set).
{ PS2_KEY_SPACE, PS2CTRL_NONE, KEYMAP_STANDARD, MZ5665_ALL, ' ', 0x00, 0x00, }, // Space
{ PS2_KEY_COMMA, PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ5665_ALL, '<', 0x00, 0x00, }, // Less Than <
{ PS2_KEY_COMMA, PS2CTRL_NONE, KEYMAP_STANDARD, MZ5665_ALL, ',', 0x00, 0x00, }, // Comma ,
{ PS2_KEY_SEMI, PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ5665_ALL, ':', 0x00, 0x00, }, // Colon :
{ PS2_KEY_SEMI, PS2CTRL_NONE, KEYMAP_STANDARD, MZ5665_ALL, ';', 0x00, 0x00, }, // Semi-Colon ;
{ PS2_KEY_DOT, PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ5665_ALL, '>', 0x00, 0x00, }, // Greater Than >
{ PS2_KEY_DOT, PS2CTRL_NONE, KEYMAP_STANDARD, MZ5665_ALL, '.', 0x00, 0x00, }, // Full stop .
{ PS2_KEY_DIV, PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ5665_ALL, '?', 0x00, 0x00, }, // Question ?
{ PS2_KEY_DIV, PS2CTRL_NONE, KEYMAP_STANDARD, MZ5665_ALL, '/', 0x00, 0x00, }, // Divide /
{ PS2_KEY_MINUS, PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ5665_ALL, '_', 0x00, 0x00, }, // Underscore
{ PS2_KEY_MINUS, PS2CTRL_NONE, KEYMAP_STANDARD, MZ5665_ALL, '-', 0x00, 0x00, },
{ PS2_KEY_APOS, PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ5665_ALL, '@', 0x00, 0x00, }, // At @
{ PS2_KEY_APOS, PS2CTRL_NONE, KEYMAP_STANDARD, MZ5665_ALL, '\'', 0x00, 0x00, }, // Single quote 'x00
{ PS2_KEY_OPEN_SQ, PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ5665_ALL, '{', 0x00, 0x00, }, // Open Left Brace {
{ PS2_KEY_OPEN_SQ, PS2CTRL_NONE, KEYMAP_STANDARD, MZ5665_ALL, '[', 0x00, 0x00, }, // Open Left Square Bracket [
{ PS2_KEY_EQUAL, PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ5665_ALL, '+', 0x00, 0x00, }, // Plus +
{ PS2_KEY_EQUAL, PS2CTRL_NONE, KEYMAP_STANDARD, MZ5665_ALL, '=', 0x00, 0x00, }, // Equal =
{ PS2_KEY_CAPS, PS2CTRL_NONE, KEYMAP_STANDARD, MZ5665_ALL, ' ', 0x00, 0x00, }, // LOCK
{ PS2_KEY_ENTER, PS2CTRL_NONE, KEYMAP_STANDARD, MZ5665_ALL, 0x0D, 0x00, 0x00, }, // ENTER/RETURN
{ PS2_KEY_CLOSE_SQ, PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ5665_ALL, '}', 0x00, 0x00, }, // Close Right Brace }
{ PS2_KEY_CLOSE_SQ, PS2CTRL_NONE, KEYMAP_STANDARD, MZ5665_ALL, ']', 0x00, 0x00, }, // Close Right Square Bracket ]
{ PS2_KEY_BACK, PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ5665_ALL, '|', 0x00, 0x00, }, //
{ PS2_KEY_BACK, PS2CTRL_NONE, KEYMAP_STANDARD, MZ5665_ALL, '\\', 0x00, 0x00, }, // Back slash maps to Yen
{ PS2_KEY_BTICK, PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ5665_ALL, '`', 0x00, 0x00, }, // Pipe
{ PS2_KEY_BTICK, PS2CTRL_NONE, KEYMAP_STANDARD, MZ5665_ALL, '|', 0x00, 0x00, }, // Back tick `
{ PS2_KEY_HASH, PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ5665_ALL, '~', 0x00, 0x00, }, // Tilde has no mapping.
{ PS2_KEY_HASH, PS2CTRL_NONE, KEYMAP_STANDARD, MZ5665_ALL, '#', 0x00, 0x00, }, // Hash
{ PS2_KEY_BS, PS2CTRL_FUNC, KEYMAP_STANDARD, MZ5665_ALL, 0x08, 0x00, 0x00, }, // Backspace
{ PS2_KEY_ESC, PS2CTRL_FUNC, KEYMAP_STANDARD, MZ5665_ALL, 0x1B, 0x00, 0x00, }, // ESCape
{ PS2_KEY_SCROLL, PS2CTRL_FUNC, KEYMAP_STANDARD, MZ5665_ALL, ' ', 0x00, 0x00, }, // Not assigned.
{ PS2_KEY_INSERT, PS2CTRL_FUNC, KEYMAP_STANDARD, MZ5665_ALL, MZ5665_KEY_INS,0x00, 0x00, }, // INSERT
{ PS2_KEY_HOME, PS2CTRL_FUNC | PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ5665_ALL, MZ5665_KEY_CLR,0x00, 0x00, }, // CLR
{ PS2_KEY_HOME, PS2CTRL_FUNC, KEYMAP_STANDARD, MZ5665_ALL, MZ5665_KEY_HOME,0x00, 0x00, }, // HOME
{ PS2_KEY_DELETE, PS2CTRL_FUNC, KEYMAP_STANDARD, MZ5665_ALL, MZ5665_KEY_DEL,0x00, 0x00, }, // DELETE
{ PS2_KEY_END, PS2CTRL_FUNC, KEYMAP_STANDARD, MZ5665_ALL, 0x18, 0x00, 0x00, }, // END
{ PS2_KEY_PGUP, PS2CTRL_FUNC, KEYMAP_STANDARD, MZ5665_ALL, 0x80, 0x00, 0x00, }, // Roll Up.
{ PS2_KEY_PGDN, PS2CTRL_FUNC, KEYMAP_STANDARD, MZ5665_ALL, 0x90, 0x00, 0x00, }, // Roll Down
{ PS2_KEY_UP_ARROW, PS2CTRL_FUNC, KEYMAP_STANDARD, MZ5665_ALL, MZ5665_KEY_UP, 0x00, 0x00, }, // Up Arrow
{ PS2_KEY_L_ARROW, PS2CTRL_FUNC, KEYMAP_STANDARD, MZ5665_ALL, MZ5665_KEY_LEFT,0x00, 0x00, }, // Left Arrow
{ PS2_KEY_DN_ARROW, PS2CTRL_FUNC, KEYMAP_STANDARD, MZ5665_ALL, MZ5665_KEY_DOWN,0x00, 0x00, }, // Down Arrow
{ PS2_KEY_R_ARROW, PS2CTRL_FUNC, KEYMAP_STANDARD, MZ5665_ALL, MZ5665_KEY_RIGHT,0x00, 0x00, }, // Right Arrow
{ PS2_KEY_NUM, PS2CTRL_FUNC, KEYMAP_STANDARD, MZ5665_ALL, 0x00, 0x00, 0x00, }, // Not assigned.
// GRPH (Alt Gr)
//PS2 Code PS2 Ctrl (Flags to Match) Keyboard Model Machine MZ5665 Data MZ5665 Ext MZ5665 Ctrl (Flags to Set).
//{ PS2_KEY_0, PS2CTRL_GRAPH, KEYMAP_STANDARD, MZ5665_ALL, 0xFA, 0x00, 0x00, }, // GRPH+0
//{ PS2_KEY_1, PS2CTRL_GRAPH, KEYMAP_STANDARD, MZ5665_ALL, 0xF1, 0x00, 0x00, }, // GRPH+1
//{ PS2_KEY_2, PS2CTRL_GRAPH, KEYMAP_STANDARD, MZ5665_ALL, 0xF2, 0x00, 0x00, }, // GRPH+2
//{ PS2_KEY_3, PS2CTRL_GRAPH, KEYMAP_STANDARD, MZ5665_ALL, 0xF3, 0x00, 0x00, }, // GRPH+3
//{ PS2_KEY_4, PS2CTRL_GRAPH, KEYMAP_STANDARD, MZ5665_ALL, 0xF4, 0x00, 0x00, }, // GRPH+4
//{ PS2_KEY_5, PS2CTRL_GRAPH, KEYMAP_STANDARD, MZ5665_ALL, 0xF5, 0x00, 0x00, }, // GRPH+5
//{ PS2_KEY_6, PS2CTRL_GRAPH, KEYMAP_STANDARD, MZ5665_ALL, 0xF6, 0x00, 0x00, }, // GRPH+6
//{ PS2_KEY_7, PS2CTRL_GRAPH, KEYMAP_STANDARD, MZ5665_ALL, 0xF7, 0x00, 0x00, }, // GRPH+7
//{ PS2_KEY_8, PS2CTRL_GRAPH, KEYMAP_STANDARD, MZ5665_ALL, 0xF8, 0x00, 0x00, }, // GRPH+8
//{ PS2_KEY_9, PS2CTRL_GRAPH, KEYMAP_STANDARD, MZ5665_ALL, 0xF9, 0x00, 0x00, }, // GRPH+9
{ PS2_KEY_A, PS2CTRL_GRAPH, KEYMAP_STANDARD, MZ5665_ALL, 0x81, 0x01, 0x00, }, // GRPH+A
{ PS2_KEY_B, PS2CTRL_GRAPH, KEYMAP_STANDARD, MZ5665_ALL, 0x82, 0x01, 0x00, }, // GRPH+B
{ PS2_KEY_C, PS2CTRL_GRAPH, KEYMAP_STANDARD, MZ5665_ALL, 0x83, 0x01, 0x00, }, // GRPH+C
{ PS2_KEY_D, PS2CTRL_GRAPH, KEYMAP_STANDARD, MZ5665_ALL, 0x84, 0x01, 0x00, }, // GRPH+D
{ PS2_KEY_E, PS2CTRL_GRAPH, KEYMAP_STANDARD, MZ5665_ALL, 0x85, 0x01, 0x00, }, // GRPH+E
{ PS2_KEY_F, PS2CTRL_GRAPH, KEYMAP_STANDARD, MZ5665_ALL, 0x86, 0x01, 0x00, }, // GRPH+F
{ PS2_KEY_G, PS2CTRL_GRAPH, KEYMAP_STANDARD, MZ5665_ALL, 0x87, 0x01, 0x00, }, // GRPH+G
{ PS2_KEY_H, PS2CTRL_GRAPH, KEYMAP_STANDARD, MZ5665_ALL, 0x88, 0x01, 0x00, }, // GRPH+H
{ PS2_KEY_I, PS2CTRL_GRAPH, KEYMAP_STANDARD, MZ5665_ALL, 0x89, 0x01, 0x00, }, // GRPH+I
{ PS2_KEY_J, PS2CTRL_GRAPH, KEYMAP_STANDARD, MZ5665_ALL, 0x8A, 0x01, 0x00, }, // GRPH+J
{ PS2_KEY_K, PS2CTRL_GRAPH, KEYMAP_STANDARD, MZ5665_ALL, 0x8B, 0x01, 0x00, }, // GRPH+K
{ PS2_KEY_L, PS2CTRL_GRAPH, KEYMAP_STANDARD, MZ5665_ALL, 0x8C, 0x01, 0x00, }, // GRPH+L
{ PS2_KEY_M, PS2CTRL_GRAPH, KEYMAP_STANDARD, MZ5665_ALL, 0x8D, 0x01, 0x00, }, // GRPH+M
{ PS2_KEY_N, PS2CTRL_GRAPH, KEYMAP_STANDARD, MZ5665_ALL, 0x8E, 0x01, 0x00, }, // GRPH+N
{ PS2_KEY_O, PS2CTRL_GRAPH, KEYMAP_STANDARD, MZ5665_ALL, 0x8F, 0x01, 0x00, }, // GRPH+O
{ PS2_KEY_P, PS2CTRL_GRAPH, KEYMAP_STANDARD, MZ5665_ALL, 0x90, 0x01, 0x00, }, // GRPH+P
{ PS2_KEY_Q, PS2CTRL_GRAPH, KEYMAP_STANDARD, MZ5665_ALL, 0x91, 0x01, 0x00, }, // GRPH+Q
{ PS2_KEY_R, PS2CTRL_GRAPH, KEYMAP_STANDARD, MZ5665_ALL, 0x92, 0x01, 0x00, }, // GRPH+R
{ PS2_KEY_S, PS2CTRL_GRAPH, KEYMAP_STANDARD, MZ5665_ALL, 0x93, 0x01, 0x00, }, // GRPH+S
{ PS2_KEY_T, PS2CTRL_GRAPH, KEYMAP_STANDARD, MZ5665_ALL, 0x94, 0x01, 0x00, }, // GRPH+T
{ PS2_KEY_U, PS2CTRL_GRAPH, KEYMAP_STANDARD, MZ5665_ALL, 0x95, 0x01, 0x00, }, // GRPH+U
{ PS2_KEY_V, PS2CTRL_GRAPH, KEYMAP_STANDARD, MZ5665_ALL, 0x96, 0x01, 0x00, }, // GRPH+V
{ PS2_KEY_W, PS2CTRL_GRAPH, KEYMAP_STANDARD, MZ5665_ALL, 0x97, 0x01, 0x00, }, // GRPH+W
{ PS2_KEY_X, PS2CTRL_GRAPH, KEYMAP_STANDARD, MZ5665_ALL, 0x98, 0x01, 0x00, }, // GRPH+X
{ PS2_KEY_Y, PS2CTRL_GRAPH, KEYMAP_STANDARD, MZ5665_ALL, 0x99, 0x01, 0x00, }, // GRPH+Y
{ PS2_KEY_Z, PS2CTRL_GRAPH, KEYMAP_STANDARD, MZ5665_ALL, 0x9A, 0x01, 0x00, }, // GRPH+Z
{ PS2_KEY_DIV, PS2CTRL_GRAPH, KEYMAP_STANDARD, MZ5665_ALL, 0x9F, 0x01, 0x00, }, // GRPH+/
{ PS2_KEY_APOS, PS2CTRL_GRAPH, KEYMAP_STANDARD, MZ5665_ALL, 0x9D, 0x01, 0x00, }, // GRPH+'
{ PS2_KEY_OPEN_SQ, PS2CTRL_GRAPH, KEYMAP_STANDARD, MZ5665_ALL, 0x80, 0x01, 0x00, }, // GRPH+[
{ PS2_KEY_CLOSE_SQ, PS2CTRL_GRAPH, KEYMAP_STANDARD, MZ5665_ALL, 0x9B, 0x01, 0x00, }, // GRPH+]
{ PS2_KEY_EQUAL, PS2CTRL_GRAPH, KEYMAP_STANDARD, MZ5665_ALL, 0x9E, 0x01, 0x00, }, // GRPH+=
{ PS2_KEY_MINUS, PS2CTRL_GRAPH, KEYMAP_STANDARD, MZ5665_ALL, 0x9C, 0x01, 0x00, }, // GRPH+-
//{ PS2_KEY_COMMA, PS2CTRL_GRAPH, KEYMAP_STANDARD, MZ5665_ALL, 0x87, 0x00, 0x00, }, // GRPH+,
//{ PS2_KEY_SEMI, PS2CTRL_GRAPH, KEYMAP_STANDARD, MZ5665_ALL, 0x89, 0x00, 0x00, }, // GRPH+;
//{ PS2_KEY_DOT, PS2CTRL_GRAPH, KEYMAP_STANDARD, MZ5665_ALL, 0x88, 0x00, 0x00, }, // GRPH+.
//{ PS2_KEY_BACK, PS2CTRL_GRAPH, KEYMAP_STANDARD, MZ5665_ALL, 0x90, 0x00, 0x00, }, // GRPH+Backslash
//{ PS2_KEY_0, PS2CTRL_GRAPH | PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ5665_ALL, 0xFA, 0x00, 0x00, }, // GRPH+SHIFT+0
//{ PS2_KEY_1, PS2CTRL_GRAPH | PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ5665_ALL, 0xF1, 0x00, 0x00, }, // GRPH+SHIFT+1
//{ PS2_KEY_2, PS2CTRL_GRAPH | PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ5665_ALL, 0xF2, 0x00, 0x00, }, // GRPH+SHIFT+2
//{ PS2_KEY_3, PS2CTRL_GRAPH | PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ5665_ALL, 0xF3, 0x00, 0x00, }, // GRPH+SHIFT+3
//{ PS2_KEY_4, PS2CTRL_GRAPH | PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ5665_ALL, 0xF4, 0x00, 0x00, }, // GRPH+SHIFT+4
//{ PS2_KEY_5, PS2CTRL_GRAPH | PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ5665_ALL, 0xF5, 0x00, 0x00, }, // GRPH+SHIFT+5
//{ PS2_KEY_6, PS2CTRL_GRAPH | PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ5665_ALL, 0xF6, 0x00, 0x00, }, // GRPH+SHIFT+6
//{ PS2_KEY_7, PS2CTRL_GRAPH | PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ5665_ALL, 0xF7, 0x00, 0x00, }, // GRPH+SHIFT+7
//{ PS2_KEY_8, PS2CTRL_GRAPH | PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ5665_ALL, 0xF8, 0x00, 0x00, }, // GRPH+SHIFT+8
//{ PS2_KEY_9, PS2CTRL_GRAPH | PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ5665_ALL, 0xF9, 0x00, 0x00, }, // GRPH+SHIFT+9
{ PS2_KEY_A, PS2CTRL_GRAPH | PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ5665_ALL, 0xE1, 0x01, 0x00, }, // GRPH+SHIFT+A
{ PS2_KEY_B, PS2CTRL_GRAPH | PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ5665_ALL, 0xE2, 0x01, 0x00, }, // GRPH+SHIFT+B
{ PS2_KEY_C, PS2CTRL_GRAPH | PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ5665_ALL, 0xE3, 0x01, 0x00, }, // GRPH+SHIFT+C
{ PS2_KEY_D, PS2CTRL_GRAPH | PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ5665_ALL, 0xE4, 0x01, 0x00, }, // GRPH+SHIFT+D
{ PS2_KEY_E, PS2CTRL_GRAPH | PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ5665_ALL, 0xE5, 0x01, 0x00, }, // GRPH+SHIFT+E
{ PS2_KEY_F, PS2CTRL_GRAPH | PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ5665_ALL, 0xE6, 0x01, 0x00, }, // GRPH+SHIFT+F
{ PS2_KEY_G, PS2CTRL_GRAPH | PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ5665_ALL, 0xE7, 0x01, 0x00, }, // GRPH+SHIFT+G
{ PS2_KEY_H, PS2CTRL_GRAPH | PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ5665_ALL, 0xE8, 0x01, 0x00, }, // GRPH+SHIFT+H
{ PS2_KEY_I, PS2CTRL_GRAPH | PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ5665_ALL, 0xE9, 0x01, 0x00, }, // GRPH+SHIFT+I
{ PS2_KEY_J, PS2CTRL_GRAPH | PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ5665_ALL, 0xEA, 0x01, 0x00, }, // GRPH+SHIFT+J
{ PS2_KEY_K, PS2CTRL_GRAPH | PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ5665_ALL, 0xEB, 0x01, 0x00, }, // GRPH+SHIFT+K
{ PS2_KEY_L, PS2CTRL_GRAPH | PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ5665_ALL, 0xEC, 0x01, 0x00, }, // GRPH+SHIFT+L
{ PS2_KEY_M, PS2CTRL_GRAPH | PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ5665_ALL, 0xED, 0x01, 0x00, }, // GRPH+SHIFT+M
{ PS2_KEY_N, PS2CTRL_GRAPH | PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ5665_ALL, 0xEE, 0x01, 0x00, }, // GRPH+SHIFT+N
{ PS2_KEY_O, PS2CTRL_GRAPH | PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ5665_ALL, 0xEF, 0x01, 0x00, }, // GRPH+SHIFT+O
{ PS2_KEY_P, PS2CTRL_GRAPH | PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ5665_ALL, 0xF0, 0x01, 0x00, }, // GRPH+SHIFT+P
{ PS2_KEY_Q, PS2CTRL_GRAPH | PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ5665_ALL, 0xF1, 0x01, 0x00, }, // GRPH+SHIFT+Q
{ PS2_KEY_R, PS2CTRL_GRAPH | PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ5665_ALL, 0xF2, 0x01, 0x00, }, // GRPH+SHIFT+R
{ PS2_KEY_S, PS2CTRL_GRAPH | PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ5665_ALL, 0xF3, 0x01, 0x00, }, // GRPH+SHIFT+S
{ PS2_KEY_T, PS2CTRL_GRAPH | PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ5665_ALL, 0xF4, 0x01, 0x00, }, // GRPH+SHIFT+T
{ PS2_KEY_U, PS2CTRL_GRAPH | PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ5665_ALL, 0xF5, 0x01, 0x00, }, // GRPH+SHIFT+U
{ PS2_KEY_V, PS2CTRL_GRAPH | PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ5665_ALL, 0xF6, 0x01, 0x00, }, // GRPH+SHIFT+V
{ PS2_KEY_W, PS2CTRL_GRAPH | PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ5665_ALL, 0xF7, 0x01, 0x00, }, // GRPH+SHIFT+W
{ PS2_KEY_X, PS2CTRL_GRAPH | PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ5665_ALL, 0xF8, 0x01, 0x00, }, // GRPH+SHIFT+X
{ PS2_KEY_Y, PS2CTRL_GRAPH | PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ5665_ALL, 0xF9, 0x01, 0x00, }, // GRPH+SHIFT+Y
{ PS2_KEY_Z, PS2CTRL_GRAPH | PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ5665_ALL, 0xFA, 0x01, 0x00, }, // GRPH+SHIFT+Z
// KANA (Alt)
//PS2 Code PS2 Ctrl (Flags to Match) Keyboard Model Machine MZ5665 Data MZ5665 Ext MZ5665 Ctrl (Flags to Set).
{ PS2_KEY_0, PS2CTRL_KANA | PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ5665_ALL, 0xA6, 0x00, 0x00, }, // KANA+SHIFT+0
{ PS2_KEY_0, PS2CTRL_KANA, KEYMAP_STANDARD, MZ5665_ALL, 0xDC, 0x00, 0x00, }, // KANA+0
{ PS2_KEY_1, PS2CTRL_KANA, KEYMAP_STANDARD, MZ5665_ALL, 0xC7, 0x00, 0x00, }, // KANA+1
{ PS2_KEY_2, PS2CTRL_KANA, KEYMAP_STANDARD, MZ5665_ALL, 0xCC, 0x00, 0x00, }, // KANA+2
{ PS2_KEY_3, PS2CTRL_KANA | PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ5665_ALL, 0xA7, 0x00, 0x00, }, // KANA+SHIFT+3
{ PS2_KEY_3, PS2CTRL_KANA, KEYMAP_STANDARD, MZ5665_ALL, 0xB1, 0x00, 0x00, }, // KANA+3
{ PS2_KEY_4, PS2CTRL_KANA | PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ5665_ALL, 0xA9, 0x00, 0x00, }, // KANA+SHIFT+4
{ PS2_KEY_4, PS2CTRL_KANA, KEYMAP_STANDARD, MZ5665_ALL, 0xB3, 0x00, 0x00, }, // KANA+4
{ PS2_KEY_5, PS2CTRL_KANA | PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ5665_ALL, 0xAA, 0x00, 0x00, }, // KANA+SHIFT+5
{ PS2_KEY_5, PS2CTRL_KANA, KEYMAP_STANDARD, MZ5665_ALL, 0xB4, 0x00, 0x00, }, // KANA+5
{ PS2_KEY_6, PS2CTRL_KANA | PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ5665_ALL, 0xAB, 0x00, 0x00, }, // KANA+SHIFT+6
{ PS2_KEY_6, PS2CTRL_KANA, KEYMAP_STANDARD, MZ5665_ALL, 0xB5, 0x00, 0x00, }, // KANA+6
{ PS2_KEY_7, PS2CTRL_KANA | PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ5665_ALL, 0xAC, 0x00, 0x00, }, // KANA+SHIFT+7
{ PS2_KEY_7, PS2CTRL_KANA, KEYMAP_STANDARD, MZ5665_ALL, 0xD4, 0x00, 0x00, }, // KANA+7
{ PS2_KEY_8, PS2CTRL_KANA | PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ5665_ALL, 0xAD, 0x00, 0x00, }, // KANA+SHIFT+8
{ PS2_KEY_8, PS2CTRL_KANA, KEYMAP_STANDARD, MZ5665_ALL, 0xD5, 0x00, 0x00, }, // KANA+8
{ PS2_KEY_9, PS2CTRL_KANA | PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ5665_ALL, 0xAE, 0x00, 0x00, }, // KANA+SHIFT+9
{ PS2_KEY_9, PS2CTRL_KANA, KEYMAP_STANDARD, MZ5665_ALL, 0xD6, 0x00, 0x00, }, // KANA+9
{ PS2_KEY_A, PS2CTRL_KANA, KEYMAP_STANDARD, MZ5665_ALL, 0xC1, 0x00, 0x00, }, // KANA+A
{ PS2_KEY_B, PS2CTRL_KANA, KEYMAP_STANDARD, MZ5665_ALL, 0xBA, 0x00, 0x00, }, // KANA+B
{ PS2_KEY_C, PS2CTRL_KANA, KEYMAP_STANDARD, MZ5665_ALL, 0xBF, 0x00, 0x00, }, // KANA+C
{ PS2_KEY_D, PS2CTRL_KANA, KEYMAP_STANDARD, MZ5665_ALL, 0xBC, 0x00, 0x00, }, // KANA+D
{ PS2_KEY_E, PS2CTRL_KANA | PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ5665_ALL, 0xA8, 0x00, 0x00, }, // KANA+SHIFT+E
{ PS2_KEY_E, PS2CTRL_KANA, KEYMAP_STANDARD, MZ5665_ALL, 0xB2, 0x00, 0x00, }, // KANA+E
{ PS2_KEY_F, PS2CTRL_KANA, KEYMAP_STANDARD, MZ5665_ALL, 0xCA, 0x00, 0x00, }, // KANA+F
{ PS2_KEY_G, PS2CTRL_KANA, KEYMAP_STANDARD, MZ5665_ALL, 0xB7, 0x00, 0x00, }, // KANA+G
{ PS2_KEY_H, PS2CTRL_KANA, KEYMAP_STANDARD, MZ5665_ALL, 0xB8, 0x00, 0x00, }, // KANA+H
{ PS2_KEY_I, PS2CTRL_KANA, KEYMAP_STANDARD, MZ5665_ALL, 0xC6, 0x00, 0x00, }, // KANA+I
{ PS2_KEY_J, PS2CTRL_KANA, KEYMAP_STANDARD, MZ5665_ALL, 0xCF, 0x00, 0x00, }, // KANA+J
{ PS2_KEY_K, PS2CTRL_KANA, KEYMAP_STANDARD, MZ5665_ALL, 0xC9, 0x00, 0x00, }, // KANA+K
{ PS2_KEY_L, PS2CTRL_KANA, KEYMAP_STANDARD, MZ5665_ALL, 0xD8, 0x00, 0x00, }, // KANA+L
{ PS2_KEY_M, PS2CTRL_KANA, KEYMAP_STANDARD, MZ5665_ALL, 0xD3, 0x00, 0x00, }, // KANA+M
{ PS2_KEY_N, PS2CTRL_KANA, KEYMAP_STANDARD, MZ5665_ALL, 0xD0, 0x00, 0x00, }, // KANA+N
{ PS2_KEY_O, PS2CTRL_KANA, KEYMAP_STANDARD, MZ5665_ALL, 0xD7, 0x00, 0x00, }, // KANA+O
{ PS2_KEY_P, PS2CTRL_KANA, KEYMAP_STANDARD, MZ5665_ALL, 0xBE, 0x00, 0x00, }, // KANA+P
{ PS2_KEY_Q, PS2CTRL_KANA, KEYMAP_STANDARD, MZ5665_ALL, 0xC0, 0x00, 0x00, }, // KANA+Q
{ PS2_KEY_R, PS2CTRL_KANA, KEYMAP_STANDARD, MZ5665_ALL, 0xBD, 0x00, 0x00, }, // KANA+R
{ PS2_KEY_S, PS2CTRL_KANA, KEYMAP_STANDARD, MZ5665_ALL, 0xC4, 0x00, 0x00, }, // KANA+S
{ PS2_KEY_T, PS2CTRL_KANA, KEYMAP_STANDARD, MZ5665_ALL, 0xB6, 0x00, 0x00, }, // KANA+T
{ PS2_KEY_U, PS2CTRL_KANA, KEYMAP_STANDARD, MZ5665_ALL, 0xC5, 0x00, 0x00, }, // KANA+U
{ PS2_KEY_V, PS2CTRL_KANA, KEYMAP_STANDARD, MZ5665_ALL, 0xCB, 0x00, 0x00, }, // KANA+V
{ PS2_KEY_W, PS2CTRL_KANA, KEYMAP_STANDARD, MZ5665_ALL, 0xC3, 0x00, 0x00, }, // KANA+W
{ PS2_KEY_X, PS2CTRL_KANA, KEYMAP_STANDARD, MZ5665_ALL, 0xBB, 0x00, 0x00, }, // KANA+X
{ PS2_KEY_Y, PS2CTRL_KANA, KEYMAP_STANDARD, MZ5665_ALL, 0xDD, 0x00, 0x00, }, // KANA+Y
{ PS2_KEY_Z, PS2CTRL_KANA | PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ5665_ALL, 0xAF, 0x00, 0x00, }, // KANA+SHIFT+Z
{ PS2_KEY_Z, PS2CTRL_KANA, KEYMAP_STANDARD, MZ5665_ALL, 0xC2, 0x00, 0x00, }, // KANA+Z
{ PS2_KEY_COMMA, PS2CTRL_KANA | PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ5665_ALL, 0xA4, 0x00, 0x00, }, // KANA+SHIFT+,
{ PS2_KEY_COMMA, PS2CTRL_KANA, KEYMAP_STANDARD, MZ5665_ALL, 0xC8, 0x00, 0x00, }, // KANA+,
{ PS2_KEY_SEMI, PS2CTRL_KANA, KEYMAP_STANDARD, MZ5665_ALL, 0xDA, 0x00, 0x00, }, // KANA+;
{ PS2_KEY_DOT, PS2CTRL_KANA | PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ5665_ALL, 0xA1, 0x00, 0x00, }, // KANA+SHIFT+.
{ PS2_KEY_DOT, PS2CTRL_KANA, KEYMAP_STANDARD, MZ5665_ALL, 0xD9, 0x00, 0x00, }, // KANA+.
{ PS2_KEY_DIV, PS2CTRL_KANA | PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ5665_ALL, 0xA5, 0x00, 0x00, }, // KANA+SHIFT+/
{ PS2_KEY_DIV, PS2CTRL_KANA, KEYMAP_STANDARD, MZ5665_ALL, 0xD2, 0x00, 0x00, }, // KANA+/
{ PS2_KEY_MINUS, PS2CTRL_KANA, KEYMAP_STANDARD, MZ5665_ALL, 0xCE, 0x00, 0x00, }, // KANA+-
{ PS2_KEY_APOS, PS2CTRL_KANA, KEYMAP_STANDARD, MZ5665_ALL, 0xDE, 0x00, 0x00, }, // KANA+'
{ PS2_KEY_OPEN_SQ, PS2CTRL_KANA | PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ5665_ALL, 0xA2, 0x00, 0x00, }, // KANA+SHIFT+[
{ PS2_KEY_OPEN_SQ, PS2CTRL_KANA, KEYMAP_STANDARD, MZ5665_ALL, 0xDF, 0x00, 0x00, }, // KANA+[
{ PS2_KEY_CLOSE_SQ, PS2CTRL_KANA | PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ5665_ALL, 0xA3, 0x00, 0x00, }, // KANA+SHIFT+]
{ PS2_KEY_CLOSE_SQ, PS2CTRL_KANA, KEYMAP_STANDARD, MZ5665_ALL, 0xD1, 0x00, 0x00, }, // KANA+]
{ PS2_KEY_BACK, PS2CTRL_KANA, KEYMAP_STANDARD, MZ5665_ALL, 0xDB, 0x00, 0x00, }, // KANA+Backslash
{ PS2_KEY_BS, PS2CTRL_KANA | PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ5665_ALL, 0x12, 0x00, 0x00, }, // KANA+SHIFT+Backspace
// Keypad.
{ PS2_KEY_KP0, PS2CTRL_NONE, KEYMAP_STANDARD, MZ5665_ALL, '0', 0x00, 0x00, }, // Keypad 0
{ PS2_KEY_KP1, PS2CTRL_NONE, KEYMAP_STANDARD, MZ5665_ALL, '1', 0x00, 0x00, }, // Keypad 1
{ PS2_KEY_KP2, PS2CTRL_NONE, KEYMAP_STANDARD, MZ5665_ALL, '2', 0x00, 0x00, }, // Keypad 2
{ PS2_KEY_KP3, PS2CTRL_NONE, KEYMAP_STANDARD, MZ5665_ALL, '3', 0x00, 0x00, }, // Keypad 3
{ PS2_KEY_KP4, PS2CTRL_NONE, KEYMAP_STANDARD, MZ5665_ALL, '4', 0x00, 0x00, }, // Keypad 4
{ PS2_KEY_KP5, PS2CTRL_NONE, KEYMAP_STANDARD, MZ5665_ALL, '5', 0x00, 0x00, }, // Keypad 5
{ PS2_KEY_KP6, PS2CTRL_NONE, KEYMAP_STANDARD, MZ5665_ALL, '6', 0x00, 0x00, }, // Keypad 6
{ PS2_KEY_KP7, PS2CTRL_NONE, KEYMAP_STANDARD, MZ5665_ALL, '7', 0x00, 0x00, }, // Keypad 7
{ PS2_KEY_KP8, PS2CTRL_NONE, KEYMAP_STANDARD, MZ5665_ALL, '8', 0x00, 0x00, }, // Keypad 8
{ PS2_KEY_KP9, PS2CTRL_NONE, KEYMAP_STANDARD, MZ5665_ALL, '9', 0x00, 0x00, }, // Keypad 9
{ PS2_KEY_KP_COMMA, PS2CTRL_NONE, KEYMAP_STANDARD, MZ5665_ALL, ',', 0x00, 0x00, }, // Keypad Comma ,
{ PS2_KEY_KP_DOT, PS2CTRL_NONE, KEYMAP_STANDARD, MZ5665_ALL, '.', 0x00, 0x00, }, // Keypad Full stop .
{ PS2_KEY_KP_PLUS, PS2CTRL_NONE, KEYMAP_STANDARD, MZ5665_ALL, '+', 0x00, 0x00, }, // Keypad Plus +
{ PS2_KEY_KP_MINUS, PS2CTRL_NONE, KEYMAP_STANDARD, MZ5665_ALL, '-', 0x00, 0x00, }, // Keypad Minus -
{ PS2_KEY_KP_TIMES, PS2CTRL_NONE, KEYMAP_STANDARD, MZ5665_ALL, '*', 0x00, 0x00, }, // Keypad Times *
{ PS2_KEY_KP_DIV, PS2CTRL_NONE, KEYMAP_STANDARD, MZ5665_ALL, '/', 0x00, 0x00, }, // Keypad Divide /
{ PS2_KEY_KP_ENTER, PS2CTRL_NONE, KEYMAP_STANDARD, MZ5665_ALL, 0x0D, 0x00, 0x00, }, // Keypad Enter /
//PS2 Code PS2 Ctrl (Flags to Match) Keyboard Model Machine MZ5665 Data MZ5665 Ext MZ5665 Ctrl (Flags to Set).
// Special keys.
{ PS2_KEY_PRTSCR, PS2CTRL_FUNC, KEYMAP_STANDARD, MZ5665_ALL, 0x00, 0x00, 0x00, }, // ARGO KEY
{ PS2_KEY_PAUSE, PS2CTRL_NONE, KEYMAP_STANDARD, MZ5665_ALL, 0x06, 0x00, 0x00, }, // BREAK KEY
{ PS2_KEY_PAUSE, PS2CTRL_SHIFT, KEYMAP_STANDARD, MZ5665_ALL, 0x07, 0x00, 0x00, }, // SHIFT BREAK KEY
{ PS2_KEY_L_GUI, PS2CTRL_FUNC | PS2CTRL_GUI, KEYMAP_STANDARD, MZ5665_ALL, 0x00, 0x00, 0x00, }, //
//{ PS2_KEY_L_ALT, PS2CTRL_FUNC | PS2CTRL_KANA, KEYMAP_STANDARD, MZ5665_ALL, 0x00, 0x00, 0x00, }, // KJ1 Sentence
//{ PS2_KEY_R_ALT, PS2CTRL_FUNC | PS2CTRL_GRAPH, KEYMAP_STANDARD, MZ5665_ALL, 0x00, 0x00, 0x00, }, // KJ2 Transform
{ PS2_KEY_R_GUI, PS2CTRL_FUNC | PS2CTRL_GUI, KEYMAP_STANDARD, MZ5665_ALL, 0x00, 0x00, 0x00, }, //
{ PS2_KEY_MENU, PS2CTRL_FUNC | PS2CTRL_GUI, KEYMAP_STANDARD, MZ5665_ALL, 0x00, 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, 0x00, },
{ PS2_KEY_R_SHIFT, PS2CTRL_NONE, KEYMAP_STANDARD, MZ5665_ALL, 0x00, 0x00, 0x00, },
{ PS2_KEY_L_CTRL, PS2CTRL_NONE, KEYMAP_STANDARD, MZ5665_ALL, 0x00, 0x00, 0x00, },
{ PS2_KEY_R_CTRL, PS2CTRL_NONE, KEYMAP_STANDARD, MZ5665_ALL, 0x00, 0x00, 0x00, }, // Map to Control
{ 0, PS2CTRL_NONE, KEYMAP_STANDARD, MZ5665_ALL, 0x00, 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

Binary file not shown.

View File

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

1674
sdkconfig Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1 +1 @@
1.021 1.05

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; }

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