27#include "freertos/FreeRTOS.h"
34#pragma GCC optimize ("O2")
41bool Mouse::s_quickCheckHardware =
false;
45 : m_mouseAvailable(false),
47 m_mouseUpdateTask(nullptr),
48 m_receivedPacket(nullptr),
49 m_absoluteUpdate(false),
51 m_movementAcceleration(180),
52 m_wheelAcceleration(60000),
53 m_absoluteQueue(nullptr),
54 m_updateDisplayController(nullptr),
62 PS2DeviceLock lock(
this);
63 terminateAbsolutePositioner();
64 if (m_mouseUpdateTask)
65 vTaskDelete(m_mouseUpdateTask);
67 vQueueDelete(m_receivedPacket);
71void Mouse::begin(
int PS2Port)
73 if (s_quickCheckHardware)
74 PS2Device::quickCheckHardware();
75 PS2Device::begin(PS2Port);
77 m_receivedPacket = xQueueCreate(1,
sizeof(
MousePacket));
78 xTaskCreate(&mouseUpdateTask,
"", 1600,
this, 5, &m_mouseUpdateTask);
83void Mouse::begin(gpio_num_t clkGPIO, gpio_num_t dataGPIO)
85 PS2Controller::begin(clkGPIO, dataGPIO);
86 PS2Controller::setMouse(
this);
93 if (s_quickCheckHardware) {
94 m_mouseAvailable = send_cmdReset();
97 for (
int i = 0; i < 3; ++i) {
98 m_mouseAvailable = send_cmdReset();
101 vTaskDelay(500 / portTICK_PERIOD_MS);
104 vTaskDelay(200 / portTICK_PERIOD_MS);
108 if (m_mouseAvailable) {
110 if (send_cmdSetSampleRate(200) && send_cmdSetSampleRate(100) && send_cmdSetSampleRate(80) && identify() == PS2DeviceType::MouseWithScrollWheel) {
118 return m_mouseAvailable;
122int Mouse::getPacketSize()
128bool Mouse::packetAvailable()
130 return uxQueueMessagesWaiting(m_receivedPacket) > 0;
134bool Mouse::getNextPacket(
MousePacket * packet,
int timeOutMS,
bool requestResendOnTimeOut)
136 return xQueueReceive(m_receivedPacket, packet, msToTicks(timeOutMS));
140bool Mouse::deltaAvailable()
142 return packetAvailable();
165 if ((mousePacket->data[0] & 8) == 0)
168 m_prevStatus = m_status;
171 m_status.buttons.left = (mousePacket->data[0] & 0x01 ? 1 : 0);
172 m_status.buttons.middle = (mousePacket->data[0] & 0x04 ? 1 : 0);
173 m_status.buttons.right = (mousePacket->data[0] & 0x02 ? 1 : 0);
175 delta->
deltaX = (int16_t)(mousePacket->data[0] & 0x10 ? 0xFF00 | mousePacket->data[1] : mousePacket->data[1]);
176 delta->
deltaY = (int16_t)(mousePacket->data[0] & 0x20 ? 0xFF00 | mousePacket->data[2] : mousePacket->data[2]);
177 delta->
deltaZ = (int8_t)(getPacketSize() > 3 ? mousePacket->data[3] : 0);
178 delta->
overflowX = (mousePacket->data[0] & 0x40 ? 1 : 0);
179 delta->
overflowY = (mousePacket->data[0] & 0x80 ? 1 : 0);
180 delta->
buttons = m_status.buttons;
187bool Mouse::getNextDelta(
MouseDelta * delta,
int timeOutMS,
bool requestResendOnTimeOut)
190 return getNextPacket(&mousePacket, timeOutMS, requestResendOnTimeOut) && decodeMousePacket(&mousePacket, delta);
198 m_status.X =
width >> 1;
201 m_status.wheelDelta = 0;
202 m_status.buttons.left = 0;
203 m_status.buttons.middle = 0;
204 m_status.buttons.right = 0;
205 m_prevStatus = m_status;
207 m_updateDisplayController = updateDisplayController;
211 if (createAbsolutePositionsQueue && m_absoluteQueue ==
nullptr) {
215 if (m_updateDisplayController) {
217 m_updateDisplayController->setMouseCursorPos(m_status.X, m_status.Y);
220 m_absoluteUpdate = (m_updateDisplayController || createAbsolutePositionsQueue || m_uiApp);
224void Mouse::terminateAbsolutePositioner()
226 if (m_absoluteQueue) {
227 vQueueDelete(m_absoluteQueue);
228 m_absoluteQueue =
nullptr;
230 m_absoluteUpdate =
false;
231 m_updateDisplayController =
nullptr;
238 const int maxDeltaTimeUS = 500000;
244 int64_t now = esp_timer_get_time();
245 int deltaTime = now - m_prevDeltaTime;
247 if (deltaTime < maxDeltaTimeUS) {
250 if (dx != 0 || dy != 0) {
251 int deltaDist = isqrt(dx * dx + dy * dy);
252 float vel = (float)deltaDist / deltaTime;
253 float newVel = vel + m_movementAcceleration * vel * vel;
254 int newDeltaDist = newVel * deltaTime;
255 dx = dx * newDeltaDist / deltaDist;
256 dy = dy * newDeltaDist / deltaDist;
261 int deltaDist = abs(dz);
262 float vel = (float)deltaDist / deltaTime;
263 float newVel = vel + m_wheelAcceleration * vel * vel;
264 int newDeltaDist = newVel * deltaTime;
265 dz = dz * newDeltaDist / deltaDist;
270 m_status.X = tclamp((
int)m_status.X + dx, 0, m_area.width - 1);
271 m_status.Y = tclamp((
int)m_status.Y - dy, 0, m_area.height - 1);
272 m_status.wheelDelta = dz;
273 m_prevDeltaTime = now;
277void Mouse::mouseUpdateTask(
void * arg)
279 constexpr int MAX_TIME_BETWEEN_DATA_US = 500000;
283 int64_t prevDataTime = 0;
288 int mousePacketLen = 0;
289 while (mousePacketLen < mouse->getPacketSize()) {
290 int r = mouse->getData(-1);
291 if (mouse->parityError() || mouse->syncError()) {
295 int64_t now = esp_timer_get_time();
296 if (mousePacketLen > 0 && prevDataTime > 0 && (now - prevDataTime) > MAX_TIME_BETWEEN_DATA_US) {
301 mousePacket.data[mousePacketLen++] = r;
306 if (mouse->m_absoluteUpdate) {
308 if (mouse->decodeMousePacket(&mousePacket, &delta)) {
312 if (mouse->m_updateDisplayController)
316 if (mouse->m_absoluteQueue) {
317 xQueueSend(mouse->m_absoluteQueue, &mouse->m_status, 0);
320 if (mouse->m_uiApp) {
322 if (mouse->m_prevStatus.
X != mouse->m_status.
X || mouse->m_prevStatus.
Y != mouse->m_status.
Y) {
324 uiEvent evt = uiEvent(
nullptr, UIEVT_MOUSEMOVE);
325 evt.params.mouse.status = mouse->m_status;
326 evt.params.mouse.changedButton = 0;
331 uiEvent evt = uiEvent(
nullptr, UIEVT_MOUSEWHEEL);
332 evt.params.mouse.status = mouse->m_status;
333 evt.params.mouse.changedButton = 0;
338 uiEvent evt = uiEvent(
nullptr, mouse->m_status.
buttons.
left ? UIEVT_MOUSEBUTTONDOWN : UIEVT_MOUSEBUTTONUP);
339 evt.params.mouse.status = mouse->m_status;
340 evt.params.mouse.changedButton = 1;
345 uiEvent evt = uiEvent(
nullptr, mouse->m_status.
buttons.
middle ? UIEVT_MOUSEBUTTONDOWN : UIEVT_MOUSEBUTTONUP);
346 evt.params.mouse.status = mouse->m_status;
347 evt.params.mouse.changedButton = 2;
352 uiEvent evt = uiEvent(
nullptr, mouse->m_status.
buttons.
right ? UIEVT_MOUSEBUTTONDOWN : UIEVT_MOUSEBUTTONUP);
353 evt.params.mouse.status = mouse->m_status;
354 evt.params.mouse.changedButton = 3;
363 xQueueOverwrite(mouse->m_receivedPacket, &mousePacket);
371int Mouse::availableStatus()
373 return m_absoluteQueue ? uxQueueMessagesWaiting(m_absoluteQueue) : 0;
381 xQueueReceive(m_absoluteQueue, &status, msToTicks(timeOutMS));
386void Mouse::emptyQueue()
388 while (getData(0) != -1)
391 xQueueReset(m_absoluteQueue);
void setMouseCursorPos(int X, int Y)
Sets mouse cursor position.
Represents the base abstract class for bitmapped display controllers.
void updateAbsolutePosition(MouseDelta *delta)
Updates absolute position from the specified mouse delta event.
The PS2 Mouse controller class.
bool postEvent(uiEvent const *event)
Places an event in the event queue and returns without waiting for the receiver to process the event.
Represents the whole application base class.
This file contains fabgl::BitmappedDisplayController definition.
#define FABGLIB_MOUSE_EVENTS_QUEUE_SIZE
This file contains fabgl::Mouse definition.
This file contains fabgl::PS2Controller definition.
Describes mouse movement and buttons status.
Contains raw data received from mouse.
Describes mouse absolute position, scroll wheel delta and buttons status.
Represents a bidimensional size.