27#include "freertos/FreeRTOS.h"
33#pragma GCC optimize ("O2")
39#define PS2_CMD_SETLEDS 0xED
40#define PS2_CMD_ECHO 0xEE
41#define PS2_CMD_GETSET_CURRENT_SCANCODE_SET 0xF0
42#define PS2_CMD_SET_REMOTE_MODE 0xF0
43#define PS2_CMD_IDENTIFY 0xF2
44#define PS2_CMD_SET_TYPEMATIC_RATE_AND_DELAY 0xF3
45#define PS2_CMD_SET_SAMPLE_RATE 0xF3
46#define PS2_CMD_ENABLE_SCANNING 0xF4
47#define PS2_CMD_DISABLE_SCANNING 0xF5
48#define PS2_CMD_SET_DEFAULT_PARAMS 0xF6
49#define PS2_CMD_RESEND_LAST_BYTE 0xFE
50#define PS2_CMD_RESET 0xFF
51#define PS2_CMD_SET_STREAM_MODE 0xEA
52#define PS2_CMD_STATUS_REQUEST 0xE9
53#define PS2_CMD_SET_RESOLUTION 0xE8
54#define PS2_CMD_SET_SCALING 0xE6
56#define PS2_REPLY_ERROR1 0x00
57#define PS2_REPLY_ERROR2 0xFF
58#define PS2_REPLY_SELFTEST_OK 0xAA
59#define PS2_REPLY_ECHO 0xEE
60#define PS2_REPLY_ACK 0xFA
61#define PS2_REPLY_SELFTEST_FAILED1 0xFC
62#define PS2_REPLY_SELFTEST_FAILED2 0xFD
63#define PS2_REPLY_RESEND 0xFE
65#define PS2_DEFAULT_CMD_TIMEOUT 500
66#define PS2_DEFAULT_CMD_SUBTIMEOUT (PS2_DEFAULT_CMD_TIMEOUT / 2)
68#define PS2_QUICK_CMD_TIMEOUT 50
69#define PS2_QUICK_CMD_SUBTIMEOUT (PS2_QUICK_CMD_TIMEOUT / 2)
74 m_cmdTimeOut = PS2_DEFAULT_CMD_TIMEOUT;
75 m_cmdSubTimeOut = PS2_DEFAULT_CMD_SUBTIMEOUT;
79PS2Device::~PS2Device()
84void PS2Device::quickCheckHardware()
86 m_cmdTimeOut = PS2_QUICK_CMD_TIMEOUT;
87 m_cmdSubTimeOut = PS2_QUICK_CMD_SUBTIMEOUT;
103void PS2Device::begin(
int PS2Port)
109int PS2Device::dataAvailable()
115bool PS2Device::parityError()
117 return PS2Controller::parityError(m_PS2Port);
121bool PS2Device::syncError()
123 return PS2Controller::syncError(m_PS2Port);
127bool PS2Device::CLKTimeOutError()
129 return PS2Controller::CLKTimeOutError(m_PS2Port);
145int PS2Device::getData(
int timeOutMS)
147 constexpr int INTER_GETDATA_TIMEOUT_MS = 100;
148 constexpr int INTER_GETDATA_PAUSE_MS = 10;
150 int interTimeOut = timeOutMS > -1 ? imin(timeOutMS, INTER_GETDATA_TIMEOUT_MS) : INTER_GETDATA_TIMEOUT_MS;
158 if (ret > -1 || parityError() || syncError() || CLKTimeOutError() || timeout.expired(timeOutMS))
161 vTaskDelay(INTER_GETDATA_PAUSE_MS / portTICK_PERIOD_MS);
169 constexpr int INTER_WAITREPLY_TIMEOUT_MS = 10;
171 PS2DeviceLock deviceLock(
this);
174 PS2PortAutoDisableRX autoDisableRX(!m_PS2Port);
181 }
while (!timeout.expired(m_cmdTimeOut));
192void PS2Device::requestToResendLastByte()
198bool PS2Device::send_cmdLEDs(
bool numLock,
bool capsLock,
bool scrollLock)
200 PS2DeviceLock deviceLock(
this);
201 return sendCommand(PS2_CMD_SETLEDS, PS2_REPLY_ACK) &&
sendCommand((scrollLock << 0) | (numLock << 1) | (capsLock << 2), PS2_REPLY_ACK);
205bool PS2Device::send_cmdEcho()
211bool PS2Device::send_cmdGetScancodeSet(uint8_t * result)
213 PS2DeviceLock deviceLock(
this);
214 if (!
sendCommand(PS2_CMD_GETSET_CURRENT_SCANCODE_SET, PS2_REPLY_ACK))
218 *result = getData(m_cmdTimeOut);
219 return (*result >= 1 || *result <= 3);
223bool PS2Device::send_cmdSetScancodeSet(uint8_t scancodeSet)
225 PS2DeviceLock deviceLock(
this);
226 if (!
sendCommand(PS2_CMD_GETSET_CURRENT_SCANCODE_SET, PS2_REPLY_ACK))
235 PS2DeviceLock deviceLock(
this);
237 if (!send_cmdDisableScanning())
241 int b1 = getData(m_cmdTimeOut);
242 int b2 = getData(m_cmdTimeOut);
243 m_deviceID = (uint8_t)b1 | ((uint8_t)b2 << 8);
244 if (b1 == -1 && b2 == -1)
246 else if (b1 == 0x00 && b2 == -1)
248 else if (b1 == 0x03 && b2 == -1)
250 else if (b1 == 0x04 && b2 == -1)
252 else if ((b1 == 0xAB && b2 == 0x41) || (b1 == 0xAB && b2 == 0xC1))
254 else if (b1 == 0xAB && b2 == 0x83)
256 return send_cmdEnableScanning();
260bool PS2Device::send_cmdDisableScanning()
262 return sendCommand(PS2_CMD_DISABLE_SCANNING, PS2_REPLY_ACK);
266bool PS2Device::send_cmdEnableScanning()
268 return sendCommand(PS2_CMD_ENABLE_SCANNING, PS2_REPLY_ACK);
272const int16_t REPEATRATES[32] = { 33, 37, 41, 45, 50, 54, 58, 62, 66, 75, 83, 91,
273 100, 108, 125, 125, 133, 149, 166, 181, 200, 217, 232, 250,
274 270, 303, 333, 370, 400, 434, 476, 500};
279bool PS2Device::send_cmdTypematicRateAndDelay(
int repeatRateMS,
int repeatDelayMS)
281 PS2DeviceLock deviceLock(
this);
282 if (!
sendCommand(PS2_CMD_SET_TYPEMATIC_RATE_AND_DELAY, PS2_REPLY_ACK))
284 uint8_t byteToSend = 0b01011;
285 for (
int i = 0; i < 32; ++i)
286 if (REPEATRATES[i] >= repeatRateMS) {
290 byteToSend |= (repeatDelayMS / 250 - 1) << 5;
296bool PS2Device::send_cmdSetSampleRate(
int sampleRate)
298 PS2DeviceLock deviceLock(
this);
299 if (!
sendCommand(PS2_CMD_SET_SAMPLE_RATE, PS2_REPLY_ACK))
310bool PS2Device::send_cmdSetResolution(
int resolution)
312 PS2DeviceLock deviceLock(
this);
313 if (!
sendCommand(PS2_CMD_SET_RESOLUTION, PS2_REPLY_ACK))
322bool PS2Device::send_cmdSetScaling(
int scaling)
324 PS2DeviceLock deviceLock(
this);
325 if (!
sendCommand(PS2_CMD_SET_SCALING, PS2_REPLY_ACK))
331bool PS2Device::send_cmdSetDefaultParams()
333 return sendCommand(PS2_CMD_SET_DEFAULT_PARAMS, PS2_REPLY_ACK);
337bool PS2Device::send_cmdReset()
339 PS2DeviceLock deviceLock(
this);
342 return getData(500) == PS2_REPLY_SELFTEST_OK;
static void sendData(uint8_t data, int PS2Port)
Sends a command to the device.
static bool lock(int PS2Port, int timeOutMS)
Gets exclusive access to the specified PS/2 port.
static void disableRX(int PS2Port)
Disables inputs from PS/2 port driving the CLK line Low.
static void unlock(int PS2Port)
Releases port from exclusive access.
static int getData(int PS2Port, int timeOutMS)
Gets a scancode from the queue.
static bool dataAvailable(int PS2Port)
Determines if one byte has been received from the specified port.
static void enableRX(int PS2Port)
Enables inputs from PS/2 port releasing CLK line.
bool sendCommand(uint8_t cmd, uint8_t expectedReply)
Sends a raw command to the PS/2 device and wait for reply.
void unlock()
Releases device from exclusive access.
bool lock(int timeOutMS)
Gets exclusive access to the device.
void suspendPort()
Suspends PS/2 port driving the CLK line Low.
void resumePort()
Resumes PS/2 port releasing CLK line.
This file contains some utility classes and functions.
PS2DeviceType
Represents the type of device attached to PS/2 port.
@ MF2KeyboardWithTranslation
This file contains fabgl::PS2Device definition.