FabGL
ESP32 Display Controller and Graphics Library
ps2controller.cpp
1 /*
2  Created by Fabrizio Di Vittorio (fdivitto2013@gmail.com) - <http://www.fabgl.com>
3  Copyright (c) 2019-2020 Fabrizio Di Vittorio.
4  All rights reserved.
5 
6  This file is part of FabGL Library.
7 
8  FabGL is free software: you can redistribute it and/or modify
9  it under the terms of the GNU General Public License as published by
10  the Free Software Foundation, either version 3 of the License, or
11  (at your option) any later version.
12 
13  FabGL is distributed in the hope that it will be useful,
14  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  GNU General Public License for more details.
17 
18  You should have received a copy of the GNU General Public License
19  along with FabGL. If not, see <http://www.gnu.org/licenses/>.
20  */
21 
22 
23 #include <strings.h>
24 
25 #include "freertos/FreeRTOS.h"
26 
27 #include "esp32/ulp.h"
28 #include "driver/rtc_io.h"
29 #include "soc/sens_reg.h"
30 
31 #include "ps2controller.h"
32 #include "fabutils.h"
33 #include "ulp_macro_ex.h"
34 #include "devdrivers/keyboard.h"
35 #include "devdrivers/mouse.h"
36 
37 
38 
39 
40 
41 
42 namespace fabgl {
43 
44 
46 // Support for missing macros for operations on STAGE register
47 
48 #define ALU_SEL_STAGE_INC 0
49 #define ALU_SEL_STAGE_DEC 1
50 #define ALU_SEL_STAGE_RST 2
51 
52 #define SUB_OPCODE_STAGEB 2
53 
54 // Increment stage register by immediate value (8 bit)
55 #define I_STAGEINCI(imm_) { .alu_imm = { \
56  .dreg = 0, \
57  .sreg = 0, \
58  .imm = imm_, \
59  .unused = 0, \
60  .sel = ALU_SEL_STAGE_INC, \
61  .sub_opcode = SUB_OPCODE_ALU_CNT, \
62  .opcode = OPCODE_ALU } }
63 
64 // Decrement stage register by immediate value (8 bit)
65 #define I_STAGEDECI(imm_) { .alu_imm = { \
66  .dreg = 0, \
67  .sreg = 0, \
68  .imm = imm_, \
69  .unused = 0, \
70  .sel = ALU_SEL_STAGE_DEC, \
71  .sub_opcode = SUB_OPCODE_ALU_CNT, \
72  .opcode = OPCODE_ALU } }
73 
74 // Reset stage register to zero
75 #define I_STAGERSTI() { .alu_imm = { \
76  .dreg = 0, \
77  .sreg = 0, \
78  .imm = 0, \
79  .unused = 0, \
80  .sel = ALU_SEL_STAGE_RST, \
81  .sub_opcode = SUB_OPCODE_ALU_CNT, \
82  .opcode = OPCODE_ALU } }
83 
84 // Branch relative if STAGE less than immediate value (8 bit)
85 #define I_STAGEBL(pc_offset, imm_value) { .b = { \
86  .imm = imm_value, \
87  .cmp = 0, \
88  .offset = abs(pc_offset), \
89  .sign = (pc_offset >= 0) ? 0 : 1, \
90  .sub_opcode = SUB_OPCODE_STAGEB, \
91  .opcode = OPCODE_BRANCH } }
92 
93 // Branch relative if STAGE less or equal than immediate value (8 bit)
94 #define I_STAGEBLE(pc_offset, imm_value) { .b = { \
95  .imm = imm_value, \
96  .cmp = 1, \
97  .offset = abs(pc_offset), \
98  .sign = (pc_offset >= 0) ? 0 : 1, \
99  .sub_opcode = SUB_OPCODE_STAGEB, \
100  .opcode = OPCODE_BRANCH } }
101 
102 // Branch relative if STAGE greater or equal than immediate value (8 bit)
103 #define I_STAGEBGE(pc_offset, imm_value) { .b = { \
104  .imm = 0x8000 | imm_value, \
105  .cmp = 0, \
106  .offset = abs(pc_offset), \
107  .sign = (pc_offset >= 0) ? 0 : 1, \
108  .sub_opcode = SUB_OPCODE_STAGEB, \
109  .opcode = OPCODE_BRANCH } }
110 
111 // STAGE register branches to labels.
112 // ulp_process_macros_and_load() doesn't recognize labels on I_STAGEB## instructions, hence
113 // we use more than one instruction
114 
115 #define M_STAGEBL(label_num, imm_value) \
116  I_STAGEBGE(2, imm_value), \
117  M_BX(label_num)
118 
119 #define M_STAGEBGE(label_num, imm_value) \
120  I_STAGEBL(2, imm_value), \
121  M_BX(label_num)
122 
123 #define M_STAGEBLE(label_num, imm_value) \
124  I_STAGEBLE(2, imm_value), \
125  I_STAGEBGE(2, imm_value), \
126  M_BX(label_num)
127 
128 
130 // placeholders
131 
132 #define OPCODE_PLACEHOLDER 12 // 12 is an unused ULP opcode we can use as placeholder
133 
134 #define SUB_OPCODE_DAT_ENABLE_OUTPUT 0
135 #define SUB_OPCODE_DAT_ENABLE_INPUT 1
136 #define SUB_OPCODE_CLK_ENABLE_OUTPUT 2
137 #define SUB_OPCODE_CLK_ENABLE_INPUT 3
138 #define SUB_OPCODE_READ_CLK 4
139 #define SUB_OPCODE_READ_DAT 5
140 #define SUB_OPCODE_WRITE_CLK 6
141 #define SUB_OPCODE_WRITE_DAT 7
142 
143 #define PS2_PORT0 0
144 #define PS2_PORT1 1
145 
146 
147 #define DAT_ENABLE_OUTPUT(ps2port, value) { .macro = { \
148  .label = value, \
149  .unused = ps2port, \
150  .sub_opcode = SUB_OPCODE_DAT_ENABLE_OUTPUT, \
151  .opcode = OPCODE_PLACEHOLDER } }
152 
153 #define DAT_ENABLE_INPUT(ps2port, value) { .macro = { \
154  .label = value, \
155  .unused = ps2port, \
156  .sub_opcode = SUB_OPCODE_DAT_ENABLE_INPUT, \
157  .opcode = OPCODE_PLACEHOLDER } }
158 
159 #define CLK_ENABLE_OUTPUT(ps2port, value) { .macro = { \
160  .label = value, \
161  .unused = ps2port, \
162  .sub_opcode = SUB_OPCODE_CLK_ENABLE_OUTPUT, \
163  .opcode = OPCODE_PLACEHOLDER } }
164 
165 #define CLK_ENABLE_INPUT(ps2port, value) { .macro = { \
166  .label = value, \
167  .unused = ps2port, \
168  .sub_opcode = SUB_OPCODE_CLK_ENABLE_INPUT, \
169  .opcode = OPCODE_PLACEHOLDER } }
170 
171 // equivalent to rtc_gpio_get_level()
172 #define READ_CLK(ps2port) { .macro = { \
173  .label = 0, \
174  .unused = ps2port, \
175  .sub_opcode = SUB_OPCODE_READ_CLK, \
176  .opcode = OPCODE_PLACEHOLDER } }
177 
178 // equivalent to rtc_gpio_get_level()
179 #define READ_DAT(ps2port) { .macro = { \
180  .label = 0, \
181  .unused = ps2port, \
182  .sub_opcode = SUB_OPCODE_READ_DAT, \
183  .opcode = OPCODE_PLACEHOLDER } }
184 
185 // equivalent to rtc_gpio_set_level()
186 #define WRITE_CLK(ps2port, value) { .macro = { \
187  .label = value, \
188  .unused = ps2port, \
189  .sub_opcode = SUB_OPCODE_WRITE_CLK, \
190  .opcode = OPCODE_PLACEHOLDER } }
191 
192 // equivalent to rtc_gpio_set_level()
193 #define WRITE_DAT(ps2port, value) { .macro = { \
194  .label = value, \
195  .unused = ps2port, \
196  .sub_opcode = SUB_OPCODE_WRITE_DAT, \
197  .opcode = OPCODE_PLACEHOLDER } }
198 
199 
201 // macro instructions
202 
203 // equivalent to rtc_gpio_set_direction(..., RTC_GPIO_MODE_INPUT_ONLY)
204 #define CONFIGURE_DAT_INPUT(ps2port) \
205  DAT_ENABLE_OUTPUT(ps2port, 0), \
206  DAT_ENABLE_INPUT(ps2port, 1)
207 
208 // equivalent to rtc_gpio_set_direction(..., RTC_GPIO_MODE_OUTPUT_ONLY)
209 #define CONFIGURE_DAT_OUTPUT(ps2port) \
210  DAT_ENABLE_OUTPUT(ps2port, 1), \
211  DAT_ENABLE_INPUT(ps2port, 0)
212 
213 // equivalent to rtc_gpio_set_direction(..., RTC_GPIO_MODE_INPUT_ONLY)
214 #define CONFIGURE_CLK_INPUT(ps2port) \
215  CLK_ENABLE_OUTPUT(ps2port, 0), \
216  CLK_ENABLE_INPUT(ps2port, 1)
217 
218 // equivalent to rtc_gpio_set_direction(..., RTC_GPIO_MODE_OUTPUT_ONLY)
219 #define CONFIGURE_CLK_OUTPUT(ps2port) \
220  CLK_ENABLE_OUTPUT(ps2port, 1), \
221  CLK_ENABLE_INPUT(ps2port, 0)
222 
223 // equivalent to rtc_gpio_set_level()
224 // WRITE bit 0 of R0
225 #define WRITE_DAT_R0(ps2port) \
226  I_BL(3, 1), \
227  WRITE_DAT(ps2port, 1), \
228  I_BGE(2, 1), \
229  WRITE_DAT(ps2port, 0)
230 
231 // performs [addr] = value
232 // changes: R0, R1
233 #define MEM_WRITEI(addr, value) \
234  I_MOVI(R0, addr), \
235  I_MOVI(R1, value), \
236  I_ST(R1, R0, 0)
237 
238 // performs [[addr]] = value
239 // changes: R0, R1
240 #define MEM_INDWRITEI(addr, value) \
241  I_MOVI(R0, addr), \
242  I_LD(R0, R0, 0), \
243  I_MOVI(R1, value), \
244  I_ST(R1, R0, 0)
245 
246 // performs [addr] = reg (reg cannot be R0)
247 // changes R0
248 #define MEM_WRITER(addr, reg) \
249  I_MOVI(R0, addr), \
250  I_ST(reg, R0, 0)
251 
252 // performs [[addr]] = reg (reg cannot be R0)
253 // changes R0
254 #define MEM_INDWRITER(addr, reg) \
255  I_MOVI(R0, addr), \
256  I_LD(R0, R0, 0), \
257  I_ST(reg, R0, 0)
258 
259 // performs reg = [addr]
260 #define MEM_READR(reg, addr) \
261  I_MOVI(reg, addr), \
262  I_LD(reg, reg, 0)
263 
264 // performs reg = [[addr]] (reg cannot be R0)
265 #define MEM_INDREADR(reg, addr) \
266  I_MOVI(reg, addr), \
267  I_LD(reg, reg, 0), \
268  I_LD(reg, reg, 0)
269 
270 // performs [addr] = [addr] + 1
271 // changes: R0, R1
272 #define MEM_INC(addr) \
273  I_MOVI(R0, addr), \
274  I_LD(R1, R0, 0), \
275  I_ADDI(R1, R1, 1), \
276  I_ST(R1, R0, 0)
277 
278 // jump to "label" if [addr] < value
279 // changes: R0
280 #define MEM_BL(label, addr, value) \
281  I_MOVI(R0, addr), \
282  I_LD(R0, R0, 0), \
283  M_BL(label, value)
284 
285 // jump to "label" if [addr] >= value
286 // changes: R0
287 #define MEM_BGE(label, addr, value) \
288  I_MOVI(R0, addr), \
289  I_LD(R0, R0, 0), \
290  M_BGE(label, value)
291 
292 // long jump version of M_BGE
293 #define M_LONG_BGE(label, value) \
294  I_BL(2, value), \
295  M_BX(label)
296 
297 // long jump version of M_BL
298 #define M_LONG_BL(label, value) \
299  I_BGE(2, value), \
300  M_BX(label)
301 
302 
304 
305 
306 #define PORT0_RX_BUFFER_SIZE 128
307 #define PORT1_RX_BUFFER_SIZE 1644
308 
309 
310 // Locations inside RTC low speed memory
311 
312 #define RTCMEM_PROG_START 0x000 // where the program begins
313 #define RTCMEM_VARS_START 0x100 // where the variables begin
314 
315 #define RTCMEM_PORT0_ENABLED (RTCMEM_VARS_START + 0) // if 1 then port 0 is enabled
316 #define RTCMEM_PORT0_MODE (RTCMEM_VARS_START + 1) // MODE_RECEIVE or MODE_SEND
317 #define RTCMEM_PORT0_WRITE_POS (RTCMEM_VARS_START + 2) // position of the next word to receive
318 #define RTCMEM_PORT0_WORD_RX_READY (RTCMEM_VARS_START + 3) // 1 when a word has been received (reset by ISR)
319 #define RTCMEM_PORT0_BIT (RTCMEM_VARS_START + 4) // send bit counter
320 #define RTCMEM_PORT0_STATE (RTCMEM_VARS_START + 5) // STATE_WAIT_CLK_LOW or STATE_WAIT_CLK_HIGH
321 #define RTCMEM_PORT0_SEND_WORD (RTCMEM_VARS_START + 6) // contains the word to send
322 #define RTCMEM_PORT0_WORD_SENT_FLAG (RTCMEM_VARS_START + 7) // 1 when word has been sent (reset by ISR)
323 
324 #define RTCMEM_PORT1_ENABLED (RTCMEM_VARS_START + 8) // if 1 then port 1 is enabled
325 #define RTCMEM_PORT1_MODE (RTCMEM_VARS_START + 9) // MODE_RECEIVE or MODE_SEND
326 #define RTCMEM_PORT1_WRITE_POS (RTCMEM_VARS_START + 10) // position of the next word to receive
327 #define RTCMEM_PORT1_WORD_RX_READY (RTCMEM_VARS_START + 11) // 1 when a word has been received (reset by ISR)
328 #define RTCMEM_PORT1_BIT (RTCMEM_VARS_START + 12) // receive or send bit counter
329 #define RTCMEM_PORT1_STATE (RTCMEM_VARS_START + 13) // STATE_WAIT_CLK_LOW or STATE_WAIT_CLK_HIGH
330 #define RTCMEM_PORT1_SEND_WORD (RTCMEM_VARS_START + 14) // contains the word to send
331 #define RTCMEM_PORT1_WORD_SENT_FLAG (RTCMEM_VARS_START + 15) // 1 when word has been sent (reset by ISR)
332 
333 #define RTCMEM_PORT0_BUFFER_START (RTCMEM_VARS_START + 16) // where the receive buffer begins
334 #define RTCMEM_PORT0_BUFFER_END (RTCMEM_PORT0_BUFFER_START + PORT0_RX_BUFFER_SIZE) // where the receive buffer ends
335 
336 #define RTCMEM_PORT1_BUFFER_START RTCMEM_PORT0_BUFFER_END // where the receive buffer begins
337 #define RTCMEM_PORT1_BUFFER_END (RTCMEM_PORT1_BUFFER_START + PORT1_RX_BUFFER_SIZE) // where the receive buffer ends
338 
339 
340 // check RTC memory occupation
341 #if RTCMEM_PORT1_BUFFER_END >= 0x800
342 #error "Port 1 ending buffer overflow"
343 #endif
344 
345 
346 // values for RTCMEM_PORTX_MODE
347 #define MODE_RECEIVE 0
348 #define MODE_SEND 1
349 
350 // values for RTCMEM_PORTX_STATE
351 #define STATE_WAIT_CLK_HIGH 0
352 #define STATE_WAIT_CLK_LOW 1
353 
354 
355 // ULP program labels
356 #define READY_TO_RECEIVE 0
357 #define PORT0_RECEIVE_WORD_READY 1
358 #define PORT0_SEND_WORD 2
359 #define PORT0_SEND_NEXT_BIT 3
360 #define PORT0_SEND_WAIT_FOR_CLK_HIGH 4
361 #define PORT0_CLK_IS_HIGH 5
362 #define PORT1_RECEIVE_WORD_READY 6
363 #define PORT1_SEND_WORD 7
364 #define PORT1_SEND_NEXT_BIT 8
365 #define PORT1_SEND_WAIT_FOR_CLK_HIGH 9
366 #define PORT1_RECEIVE 10
367 #define PORT1_CLK_IS_HIGH 11
368 #define MAIN_LOOP 12
369 #define PORT1_INIT 13
370 
371 
372 
373 
374 
375 
376 
377 const ulp_insn_t ULP_code[] = {
378 
379  // Stop ULP timer, not necessary because this routine never ends
380  I_END(),
381 
382 M_LABEL(READY_TO_RECEIVE),
383 
385  // PORT0 Initialization
386 
387  // port 0 enabled?
388  MEM_READR(R0, RTCMEM_PORT0_ENABLED), // R0 = [RTCMEM_PORT0_ENABLED]
389  M_BL(PORT1_INIT, 1), // go PORT1_INIT if R0 < 1 (port 0 not enabled)
390 
391  // Configure CLK and DAT as inputs
392  CONFIGURE_CLK_INPUT(PS2_PORT0),
393  CONFIGURE_DAT_INPUT(PS2_PORT0),
394 
395  MEM_WRITEI(RTCMEM_PORT0_STATE, STATE_WAIT_CLK_LOW), // [RTCMEM_PORT0_STATE] = STATE_WAIT_CLK_LOW
396 
397  // reset the word that will contain the received data
398  MEM_INDWRITEI(RTCMEM_PORT0_WRITE_POS, 0), // [[RTCMEM_PORT0_WRITE_POS]] = 0
399 
400  // reset the bit counters (0 = start bit, 1 = data0 .... 9 = parity, 10 = stop bit)
401  MEM_WRITEI(RTCMEM_PORT0_BIT, 0), // [RTCMEM_PORT0_BIT] = 0
402  I_MOVI(R2, 0), // R2 = 0
403 
404  //
406 
407 
409  // PORT1 Initialization
410 
411 M_LABEL(PORT1_INIT),
412 
413  // port 1 enabled?
414  MEM_READR(R0, RTCMEM_PORT1_ENABLED), // R0 = [RTCMEM_PORT1_ENABLED]
415  M_BL(MAIN_LOOP, 1), // go MAIN_LOOP if R0 < 1 (port 1 not enabled)
416 
417  // Configure CLK and DAT as inputs
418  CONFIGURE_CLK_INPUT(PS2_PORT1),
419  CONFIGURE_DAT_INPUT(PS2_PORT1),
420 
421  MEM_WRITEI(RTCMEM_PORT1_STATE, STATE_WAIT_CLK_LOW), // [RTCMEM_PORT1_STATE] = STATE_WAIT_CLK_LOW
422 
423  // reset the word that will contain the received data
424  MEM_INDWRITEI(RTCMEM_PORT1_WRITE_POS, 0), // [[RTCMEM_PORT1_WRITE_POS]] = 0
425 
426  // reset the bit counters (0 = start bit, 1 = data0 .... 9 = parity, 10 = stop bit)
427  MEM_WRITEI(RTCMEM_PORT1_BIT, 0), // [RTCMEM_PORT1_BIT] = 0
428  I_MOVI(R3, 0), // R3 = 0
429 
430  //
432 
433 
434 M_LABEL(MAIN_LOOP),
435 
436  // is there something to SEND on port 0?
437  MEM_READR(R0, RTCMEM_PORT0_MODE), // R0 = [RTCMEM_PORT0_MODE]
438  M_LONG_BGE(PORT0_SEND_WORD, MODE_SEND), // jump to PORT0_SEND_WORD if R0 >= MODE_SEND
439 
440  // is there something to SEND on port 1?
441  MEM_READR(R0, RTCMEM_PORT1_MODE), // R0 = [RTCMEM_PORT1_MODE]
442  M_LONG_BGE(PORT1_SEND_WORD, MODE_SEND), // jump to PORT1_SEND_WORD if R0 >= MODE_SEND
443 
444 
446  // PORT0 Receive
447 
448  // port 0 enabled?
449  MEM_READR(R0, RTCMEM_PORT0_ENABLED), // R0 = [RTCMEM_PORT0_ENABLED]
450  M_BL(PORT1_RECEIVE, 1), // go PORT1_RECEIVE if R0 < 1 (port 0 not enabled)
451 
452  // wait for CLK low or high?
453  MEM_READR(R1, RTCMEM_PORT0_STATE), // R1 = [RTCMEM_PORT0_STATE]
454 
455  // read CLK
456  READ_CLK(PS2_PORT0), // R0 = CLK
457 
458  // ALU result is Zero when [RTCMEM_PORT0_STATE] = CLK, that means "need to wait"
459  I_SUBR(R1, R1, R0), // R1 = R1 - R0
460  M_BXZ(PORT1_RECEIVE), // bypass if ALU is ZERO
461 
462  // is CLK high?
463  M_BGE(PORT0_CLK_IS_HIGH, 1),
464 
465  // CLK is LOW
466  MEM_WRITEI(RTCMEM_PORT0_STATE, STATE_WAIT_CLK_HIGH), // [RTCMEM_PORT0_STATE] = STATE_WAIT_CLK_HIGH
467 
468  // get DAT value
469  READ_DAT(PS2_PORT0), // R0 = DAT
470 
471  // merge with data word and shift right by 1 the received word
472  I_LSHI(R0, R0, 11), // R0 = R0 << 11
473  MEM_INDREADR(R1, RTCMEM_PORT0_WRITE_POS), // R1 = [[RTCMEM_PORT0_WRITE_POS]]
474  I_ORR(R1, R1, R0), // R1 = R1 | R0
475  I_RSHI(R1, R1, 1), // R1 = R1 >> 1
476  MEM_INDWRITER(RTCMEM_PORT0_WRITE_POS, R1), // [[RTCMEM_PORT0_WRITE_POS]] = R1
477 
478  // check port 1
479  M_BX(PORT1_RECEIVE),
480 
481 M_LABEL(PORT0_CLK_IS_HIGH),
482 
483  // CLK is high
484  MEM_WRITEI(RTCMEM_PORT0_STATE, STATE_WAIT_CLK_LOW), // [RTCMEM_PORT0_STATE] = STATE_WAIT_CLK_LOW
485 
486  // increment bit count
487  I_ADDI(R2, R2, 1), // R2 = R2 + 1
488 
489  // end of word? if not get another bit
490  I_MOVR(R0, R2), // R0 = R2
491  M_BL(PORT1_RECEIVE, 11), // jump to PORT1_RECEIVE if R0 (=R2) < 11
492 
493  // End of word
494 
495  // increments RTCMEM_PORT0_WRITE_POS and check if reached the upper bound
496  MEM_INC(RTCMEM_PORT0_WRITE_POS), // [RTCMEM_PORT0_WRITE_POS] = [RTCMEM_PORT0_WRITE_POS] + 1
497  MEM_BL(PORT0_RECEIVE_WORD_READY, RTCMEM_PORT0_WRITE_POS, RTCMEM_PORT0_BUFFER_END), // jump to PORT0_RECEIVE_WORD_READY if RTCMEM_PORT0_WRITE_POS < RTCMEM_PORT0_BUFFER_END
498 
499  // reset RTCMEM_PORT0_WRITE_POS
500  MEM_WRITEI(RTCMEM_PORT0_WRITE_POS, RTCMEM_PORT0_BUFFER_START), // [RTCMEM_PORT0_WRITE_POS] = RTCMEM_PORT0_BUFFER_START
501 
502 M_LABEL(PORT0_RECEIVE_WORD_READY),
503 
504  // set word received flag (RTCMEM_PORT0_WORD_RX_READY)
505  MEM_WRITEI(RTCMEM_PORT0_WORD_RX_READY, 1), // [RTCMEM_PORT0_WORD_RX_READY] = 1
506 
507  // trig ETS_RTC_CORE_INTR_SOURCE interrupt
508  I_WAKE(),
509 
510  // reset the word that will contain the received data
511  MEM_INDWRITEI(RTCMEM_PORT0_WRITE_POS, 0), // [[RTCMEM_PORT0_WRITE_POS]] = 0
512 
513  // reset the bit counter (0 = start bit, 1 = data0 .... 9 = parity, 10 = stop bit)
514  I_MOVI(R2, 0), // R2 = 0
515 
516  // do the next job
517  //M_BX(PORT1_RECEIVE), // jump to PORT1_RECEIVE
518 
519  //
521 
522 
523 
525  // PORT1 Receive
526 
527 M_LABEL(PORT1_RECEIVE),
528 
529  // port 1 enabled?
530  MEM_READR(R0, RTCMEM_PORT1_ENABLED), // R0 = [RTCMEM_PORT1_ENABLED]
531  M_BL(MAIN_LOOP, 1), // go MAIN_LOOP if R0 < 1 (port 1 not enabled)
532 
533  // wait for CLK low or high?
534  MEM_READR(R1, RTCMEM_PORT1_STATE), // R1 = [RTCMEM_PORT1_STATE]
535 
536  // read CLK
537  READ_CLK(PS2_PORT1), // R0 = CLK
538 
539  // ALU result is Zero when [RTCMEM_PORT1_STATE] = CLK, that means "need to wait"
540  I_SUBR(R1, R1, R0), // R1 = R1 - R0
541  M_BXZ(MAIN_LOOP), // repeat if ALU is ZERO
542 
543  // is CLK high?
544  M_BGE(PORT1_CLK_IS_HIGH, 1),
545 
546  // CLK is LOW
547  MEM_WRITEI(RTCMEM_PORT1_STATE, STATE_WAIT_CLK_HIGH), // [RTCMEM_PORT1_STATE] = STATE_WAIT_CLK_HIGH
548 
549  // get DAT value
550  READ_DAT(PS2_PORT1), // R0 = DAT
551 
552  // merge with data word and shift right by 1 the received word
553  I_LSHI(R0, R0, 11), // R0 = R0 << 11
554  MEM_INDREADR(R1, RTCMEM_PORT1_WRITE_POS), // R1 = [[RTCMEM_PORT1_WRITE_POS]]
555  I_ORR(R1, R1, R0), // R1 = R1 | R0
556  I_RSHI(R1, R1, 1), // R1 = R1 >> 1
557  MEM_INDWRITER(RTCMEM_PORT1_WRITE_POS, R1), // [[RTCMEM_PORT1_WRITE_POS]] = R1
558 
559  // go to main loop
560  M_BX(MAIN_LOOP),
561 
562 M_LABEL(PORT1_CLK_IS_HIGH),
563 
564  // CLK is high
565  MEM_WRITEI(RTCMEM_PORT1_STATE, STATE_WAIT_CLK_LOW), // [RTCMEM_PORT1_STATE] = STATE_WAIT_CLK_LOW
566 
567  // increment bit count
568  I_ADDI(R3, R3, 1), // R3 = R3 + 1
569 
570  // end of word? if not get another bit
571  I_MOVR(R0, R3), // R0 = R3
572  M_BL(MAIN_LOOP, 11), // jump to MAIN_LOOP if R0 (=R3) < 11
573 
574  // End of word
575 
576  // increments RTCMEM_PORT1_WRITE_POS and check if reached the upper bound
577  MEM_INC(RTCMEM_PORT1_WRITE_POS), // [RTCMEM_PORT1_WRITE_POS] = [RTCMEM_PORT1_WRITE_POS] + 1
578  MEM_BL(PORT1_RECEIVE_WORD_READY, RTCMEM_PORT1_WRITE_POS, RTCMEM_PORT1_BUFFER_END), // jump to PORT1_RECEIVE_WORD_READY if RTCMEM_PORT1_WRITE_POS < RTCMEM_PORT1_BUFFER_END
579 
580  // reset RTCMEM_PORT1_WRITE_POS
581  MEM_WRITEI(RTCMEM_PORT1_WRITE_POS, RTCMEM_PORT1_BUFFER_START), // [RTCMEM_PORT1_WRITE_POS] = RTCMEM_PORT1_BUFFER_START
582 
583 M_LABEL(PORT1_RECEIVE_WORD_READY),
584 
585  // set word received flag (RTCMEM_PORT1_WORD_RX_READY)
586  MEM_WRITEI(RTCMEM_PORT1_WORD_RX_READY, 1), // [RTCMEM_PORT1_WORD_RX_READY] = 1
587 
588  // trig ETS_RTC_CORE_INTR_SOURCE interrupt
589  I_WAKE(),
590 
591  // reset the word that will contain the received data
592  MEM_INDWRITEI(RTCMEM_PORT1_WRITE_POS, 0), // [[RTCMEM_PORT1_WRITE_POS]] = 0
593 
594  // reset the bit counter (0 = start bit, 1 = data0 .... 9 = parity, 10 = stop bit)
595  I_MOVI(R3, 0), // R3 = 0
596 
597  // go to the main loop
598  M_BX(MAIN_LOOP),
599 
600  //
602 
603 
605  // PORT0 Send
606 
607 M_LABEL(PORT0_SEND_WORD),
608 
609  // Send the word in RTCMEM_PORT0_SEND_WORD
610 
611  // maintain CLK low for about 200us
612  CONFIGURE_CLK_OUTPUT(PS2_PORT0),
613  WRITE_CLK(PS2_PORT0, 0),
614  I_DELAY(1600),
615 
616  // set DAT low
617  CONFIGURE_DAT_OUTPUT(PS2_PORT0),
618  WRITE_DAT(PS2_PORT0, 0),
619 
620  // configure CLK as input
621  CONFIGURE_CLK_INPUT(PS2_PORT0),
622 
623  // put in R3 the word to send (10 bits: data, parity and stop bit)
624  MEM_READR(R3, RTCMEM_PORT0_SEND_WORD), // R3 = [RTCMEM_PORT0_SEND_WORD]
625 
626  // reset the bit counter (0...7 = data0, 8 = parity, 9 = stop bit)
627  MEM_WRITEI(RTCMEM_PORT0_BIT, 0), // [RTCMEM_PORT0_BIT] = 0
628 
629 M_LABEL(PORT0_SEND_NEXT_BIT),
630 
631  // wait for CLK = LOW
632 
633  // are still we in sending mode?
634  MEM_READR(R0, RTCMEM_PORT0_MODE), // R0 = [RTCMEM_PORT0_MODE]
635  M_LONG_BL(READY_TO_RECEIVE, MODE_SEND), // jump to READY_TO_RECEIVE if R0 != MODE_SEND
636 
637  // read CLK
638  READ_CLK(PS2_PORT0), // R0 = CLK
639 
640  // repeat if CLK is high
641  M_BGE(PORT0_SEND_NEXT_BIT, 1), // jump to PORT0_SEND_NEXT_BIT if R0 >= 1
642 
643  // bit 10 is the ACK from keyboard, don't send anything, just bypass
644  MEM_BGE(PORT0_SEND_WAIT_FOR_CLK_HIGH, RTCMEM_PORT0_BIT, 10), // jump to PORT0_SEND_WAIT_FOR_CLK_HIGH if [RTCMEM_PORT0_BIT] >= 10
645 
646  // CLK is LOW, we are ready to send the bit (LSB of R0)
647  I_ANDI(R0, R3, 1), // R0 = R3 & 1
648  WRITE_DAT_R0(PS2_PORT0), // DAT = LSB of R0
649 
650 M_LABEL(PORT0_SEND_WAIT_FOR_CLK_HIGH),
651 
652  // Wait for CLK = HIGH
653 
654  // are still we in sending mode?
655  MEM_READR(R0, RTCMEM_PORT0_MODE), // R0 = [RTCMEM_PORT0_MODE]
656  M_LONG_BL(READY_TO_RECEIVE, MODE_SEND), // jump to READY_TO_RECEIVE if R0 != MODE_SEND
657 
658  // read CLK
659  READ_CLK(PS2_PORT0), // R0 = CLK
660 
661  // repeat if CLK is low
662  M_BL(PORT0_SEND_WAIT_FOR_CLK_HIGH, 1), // jump to PORT0_SEND_WAIT_FOR_CLK_HIGH if R0 < 1
663 
664  // shift the sending word 1 bit to the right (prepare next bit to send)
665  I_RSHI(R3, R3, 1), // R3 = R3 >> 1
666 
667  // increment bit count
668  MEM_INC(RTCMEM_PORT0_BIT), // [RTCMEM_PORT0_BIT] = [RTCMEM_PORT0_BIT] + 1
669 
670  // end of word? if not send another bit
671  MEM_BL(PORT0_SEND_NEXT_BIT, RTCMEM_PORT0_BIT, 11), // jump to PORT0_SEND_NEXT_BIT if [RTCMEM_PORT0_BIT] < 11
672 
673  // switch to receive mode
674  MEM_WRITEI(RTCMEM_PORT0_MODE, MODE_RECEIVE), // [RTCMEM_PORT0_MODE] = MODE_RECEIVE
675 
676  // set word sent flag (RTCMEM_PORT0_WORD_SENT_FLAG)
677  MEM_WRITEI(RTCMEM_PORT0_WORD_SENT_FLAG, 1), // [RTCMEM_PORT0_WORD_SENT_FLAG] = 1
678 
679  // trig ETS_RTC_CORE_INTR_SOURCE interrupt
680  I_WAKE(),
681 
682  // perform another job
683  M_BX(READY_TO_RECEIVE), // jump to READY_TO_RECEIVE
684 
685  //
687 
688 
689 
691  // PORT1 SEND
692 
693 M_LABEL(PORT1_SEND_WORD),
694 
695  // Send the word in RTCMEM_PORT1_SEND_WORD
696 
697  // maintain CLK low for about 200us
698  CONFIGURE_CLK_OUTPUT(PS2_PORT1),
699  WRITE_CLK(PS2_PORT1, 0),
700  I_DELAY(1600),
701 
702  // set DAT low
703  CONFIGURE_DAT_OUTPUT(PS2_PORT1),
704  WRITE_DAT(PS2_PORT1, 0),
705 
706  // configure CLK as input
707  CONFIGURE_CLK_INPUT(PS2_PORT1),
708 
709  // put in R3 the word to send (10 bits: data, parity and stop bit)
710  MEM_READR(R3, RTCMEM_PORT1_SEND_WORD), // R3 = [RTCMEM_PORT1_SEND_WORD]
711 
712  // reset the bit counter (0...7 = data0, 8 = parity, 9 = stop bit)
713  MEM_WRITEI(RTCMEM_PORT1_BIT, 0), // [RTCMEM_PORT1_BIT] = 0
714 
715 M_LABEL(PORT1_SEND_NEXT_BIT),
716 
717  // wait for CLK = LOW
718 
719  // are still we in sending mode?
720  MEM_READR(R0, RTCMEM_PORT1_MODE), // R0 = [RTCMEM_PORT1_MODE]
721  M_LONG_BL(READY_TO_RECEIVE, MODE_SEND), // jump to READY_TO_RECEIVE if R0 != MODE_SEND
722 
723  // read CLK
724  READ_CLK(PS2_PORT1), // R0 = CLK
725 
726  // repeat if CLK is high
727  M_BGE(PORT1_SEND_NEXT_BIT, 1), // jump to PORT1_SEND_NEXT_BIT if R0 >= 1
728 
729  // bit 10 is the ACK from keyboard, don't send anything, just bypass
730  MEM_BGE(PORT1_SEND_WAIT_FOR_CLK_HIGH, RTCMEM_PORT1_BIT, 10), // jump to PORT1_SEND_WAIT_FOR_CLK_HIGH if [RTCMEM_PORT1_BIT] >= 10
731 
732  // CLK is LOW, we are ready to send the bit (LSB of R0)
733  I_ANDI(R0, R3, 1), // R0 = R3 & 1
734  WRITE_DAT_R0(PS2_PORT1), // DAT = LSB of R0
735 
736 M_LABEL(PORT1_SEND_WAIT_FOR_CLK_HIGH),
737 
738  // Wait for CLK = HIGH
739 
740  // are still we in sending mode?
741  MEM_READR(R0, RTCMEM_PORT1_MODE), // R0 = [RTCMEM_PORT1_MODE]
742  M_LONG_BL(READY_TO_RECEIVE, MODE_SEND), // jump to READY_TO_RECEIVE if R0 != MODE_SEND
743 
744  // read CLK
745  READ_CLK(PS2_PORT1), // R0 = CLK
746 
747  // repeat if CLK is low
748  M_BL(PORT1_SEND_WAIT_FOR_CLK_HIGH, 1), // jump to PORT1_SEND_WAIT_FOR_CLK_HIGH if R0 < 1
749 
750  // shift the sending word 1 bit to the right (prepare next bit to send)
751  I_RSHI(R3, R3, 1), // R3 = R3 >> 1
752 
753  // increment bit count
754  MEM_INC(RTCMEM_PORT1_BIT), // [RTCMEM_PORT1_BIT] = [RTCMEM_PORT1_BIT] + 1
755 
756  // end of word? if not send another bit
757  MEM_BL(PORT1_SEND_NEXT_BIT, RTCMEM_PORT1_BIT, 11), // jump to PORT1_SEND_NEXT_BIT if [RTCMEM_PORT1_BIT] < 11
758 
759  // switch to receive mode
760  MEM_WRITEI(RTCMEM_PORT1_MODE, MODE_RECEIVE), // [RTCMEM_PORT1_MODE] = MODE_RECEIVE
761 
762  // set word sent flag (RTCMEM_PORT1_WORD_SENT_FLAG)
763  MEM_WRITEI(RTCMEM_PORT1_WORD_SENT_FLAG, 1), // [RTCMEM_PORT1_WORD_SENT_FLAG] = 1
764 
765  // trig ETS_RTC_CORE_INTR_SOURCE interrupt
766  I_WAKE(),
767 
768  // perform another job
769  M_BX(READY_TO_RECEIVE), // jump to READY_TO_RECEIVE
770 
771  //
773 
774 };
775 
776 
777 
778 
779 // Allowed GPIOs: GPIO_NUM_0, GPIO_NUM_2, GPIO_NUM_4, GPIO_NUM_12, GPIO_NUM_13, GPIO_NUM_14, GPIO_NUM_15, GPIO_NUM_25, GPIO_NUM_26, GPIO_NUM_27, GPIO_NUM_32, GPIO_NUM_33
780 // Not allowed from GPIO_NUM_34 to GPIO_NUM_39
781 // prg_start in 32 bit words
782 // size in 32 bit words
783 void replace_placeholders(uint32_t prg_start, int size, bool port0Enabled, gpio_num_t port0_clkGPIO, gpio_num_t port0_datGPIO, bool port1Enabled, gpio_num_t port1_clkGPIO, gpio_num_t port1_datGPIO)
784 {
785  uint32_t CLK_rtc_gpio_num[2], CLK_rtc_gpio_reg[2], CLK_rtc_gpio_ie_s[2];
786  uint32_t DAT_rtc_gpio_num[2], DAT_rtc_gpio_reg[2], DAT_rtc_gpio_ie_s[2];
787 
788  if (port0Enabled) {
789  CLK_rtc_gpio_num[0] = (uint32_t) rtc_gpio_desc[port0_clkGPIO].rtc_num;
790  CLK_rtc_gpio_reg[0] = rtc_gpio_desc[port0_clkGPIO].reg;
791  CLK_rtc_gpio_ie_s[0] = (uint32_t) ffs(rtc_gpio_desc[port0_clkGPIO].ie) - 1;
792  DAT_rtc_gpio_num[0] = (uint32_t) rtc_gpio_desc[port0_datGPIO].rtc_num;
793  DAT_rtc_gpio_reg[0] = rtc_gpio_desc[port0_datGPIO].reg;
794  DAT_rtc_gpio_ie_s[0] = (uint32_t) ffs(rtc_gpio_desc[port0_datGPIO].ie) - 1;
795  }
796 
797  if (port1Enabled) {
798  CLK_rtc_gpio_num[1] = (uint32_t) rtc_gpio_desc[port1_clkGPIO].rtc_num;
799  CLK_rtc_gpio_reg[1] = rtc_gpio_desc[port1_clkGPIO].reg;
800  CLK_rtc_gpio_ie_s[1] = (uint32_t) ffs(rtc_gpio_desc[port1_clkGPIO].ie) - 1;
801  DAT_rtc_gpio_num[1] = (uint32_t) rtc_gpio_desc[port1_datGPIO].rtc_num;
802  DAT_rtc_gpio_reg[1] = rtc_gpio_desc[port1_datGPIO].reg;
803  DAT_rtc_gpio_ie_s[1] = (uint32_t) ffs(rtc_gpio_desc[port1_datGPIO].ie) - 1;
804  }
805 
806  for (uint32_t i = 0; i < size; ++i) {
807  ulp_insn_t * ins = (ulp_insn_t *) RTC_SLOW_MEM + i;
808  if (ins->macro.opcode == OPCODE_PLACEHOLDER) {
809  int ps2port = ins->macro.unused;
810  if ((port0Enabled && ps2port == 0) || (port1Enabled && ps2port == 1)) {
811  ins->macro.unused = 0;
812  switch (ins->macro.sub_opcode) {
813  case SUB_OPCODE_DAT_ENABLE_OUTPUT:
814  if (ins->macro.label)
815  *ins = (ulp_insn_t) I_WR_REG_BIT(RTC_GPIO_ENABLE_W1TS_REG, DAT_rtc_gpio_num[ps2port] + RTC_GPIO_ENABLE_W1TS_S, 1);
816  else
817  *ins = (ulp_insn_t) I_WR_REG_BIT(RTC_GPIO_ENABLE_W1TC_REG, DAT_rtc_gpio_num[ps2port] + RTC_GPIO_ENABLE_W1TC_S, 1);
818  break;
819  case SUB_OPCODE_DAT_ENABLE_INPUT:
820  *ins = (ulp_insn_t) I_WR_REG_BIT(DAT_rtc_gpio_reg[ps2port], DAT_rtc_gpio_ie_s[ps2port], ins->macro.label);
821  break;
822  case SUB_OPCODE_CLK_ENABLE_OUTPUT:
823  if (ins->macro.label)
824  *ins = (ulp_insn_t) I_WR_REG_BIT(RTC_GPIO_ENABLE_W1TS_REG, CLK_rtc_gpio_num[ps2port] + RTC_GPIO_ENABLE_W1TS_S, 1);
825  else
826  *ins = (ulp_insn_t) I_WR_REG_BIT(RTC_GPIO_ENABLE_W1TC_REG, CLK_rtc_gpio_num[ps2port] + RTC_GPIO_ENABLE_W1TC_S, 1);
827  break;
828  case SUB_OPCODE_CLK_ENABLE_INPUT:
829  *ins = (ulp_insn_t) I_WR_REG_BIT(CLK_rtc_gpio_reg[ps2port], CLK_rtc_gpio_ie_s[ps2port], ins->macro.label);
830  break;
831  case SUB_OPCODE_READ_CLK:
832  *ins = (ulp_insn_t) I_RD_REG(RTC_GPIO_IN_REG, CLK_rtc_gpio_num[ps2port] + RTC_GPIO_IN_NEXT_S, CLK_rtc_gpio_num[ps2port] + RTC_GPIO_IN_NEXT_S);
833  break;
834  case SUB_OPCODE_READ_DAT:
835  *ins = (ulp_insn_t) I_RD_REG(RTC_GPIO_IN_REG, DAT_rtc_gpio_num[ps2port] + RTC_GPIO_IN_NEXT_S, DAT_rtc_gpio_num[ps2port] + RTC_GPIO_IN_NEXT_S);
836  break;
837  case SUB_OPCODE_WRITE_CLK:
838  *ins = (ulp_insn_t) I_WR_REG_BIT(RTC_GPIO_OUT_REG, CLK_rtc_gpio_num[ps2port] + RTC_GPIO_IN_NEXT_S, ins->macro.label);
839  break;
840  case SUB_OPCODE_WRITE_DAT:
841  *ins = (ulp_insn_t) I_WR_REG_BIT(RTC_GPIO_OUT_REG, DAT_rtc_gpio_num[ps2port] + RTC_GPIO_IN_NEXT_S, ins->macro.label);
842  break;
843  }
844  }
845  }
846  }
847 }
848 
849 
850 PS2Controller * PS2Controller::s_instance = nullptr;
851 
852 
853 PS2Controller::PS2Controller()
854  : m_keyboard(nullptr),
855  m_mouse(nullptr),
856  m_suspendCount(0)
857 {
858  s_instance = this;
859 }
860 
861 
862 // Note: GPIO_UNUSED is a placeholder used to disable PS/2 port 1.
863 void PS2Controller::begin(gpio_num_t port0_clkGPIO, gpio_num_t port0_datGPIO, gpio_num_t port1_clkGPIO, gpio_num_t port1_datGPIO)
864 {
865  bool port0Enabled = (port0_clkGPIO != GPIO_UNUSED && port0_datGPIO != GPIO_UNUSED);
866  bool port1Enabled = (port1_clkGPIO != GPIO_UNUSED && port1_datGPIO != GPIO_UNUSED);
867 
868  m_TXWaitTask[0] = m_TXWaitTask[1] = nullptr;
869  m_RXWaitTask[0] = m_RXWaitTask[1] = nullptr;
870 
871  if (port0Enabled) {
872  rtc_gpio_init(port0_clkGPIO);
873  rtc_gpio_init(port0_datGPIO);
874  }
875 
876  if (port1Enabled) {
877  rtc_gpio_init(port1_clkGPIO);
878  rtc_gpio_init(port1_datGPIO);
879  }
880 
881  // clear ULP memory (without this may fail to run ULP on softreset)
882  for (int i = RTCMEM_PROG_START; i < RTCMEM_PORT1_BUFFER_END; ++i)
883  RTC_SLOW_MEM[i] = 0x0000;
884 
885  // PS/2 port 1 enabled?
886  RTC_SLOW_MEM[RTCMEM_PORT0_ENABLED] = port0Enabled;
887  RTC_SLOW_MEM[RTCMEM_PORT1_ENABLED] = port1Enabled;
888 
889  warmInit();
890 
891  // process, load and execute ULP program
892  size_t size = sizeof(ULP_code) / sizeof(ulp_insn_t);
893  ulp_process_macros_and_load_ex(RTCMEM_PROG_START, ULP_code, &size); // convert macros to ULP code
894  replace_placeholders(RTCMEM_PROG_START, size, port0Enabled, port0_clkGPIO, port0_datGPIO, port1Enabled, port1_clkGPIO, port1_datGPIO); // replace GPIO placeholders
895  assert(size < RTCMEM_VARS_START && "ULP Program too long, increase RTCMEM_VARS_START");
896  REG_SET_FIELD(SENS_SAR_START_FORCE_REG, SENS_PC_INIT, RTCMEM_PROG_START); // set entry point
897  SET_PERI_REG_MASK(SENS_SAR_START_FORCE_REG, SENS_ULP_CP_FORCE_START_TOP); // enable FORCE START
898  SET_PERI_REG_MASK(SENS_SAR_START_FORCE_REG, SENS_ULP_CP_START_TOP); // start
899 
900  // install RTC interrupt handler (on ULP Wake() instruction)
901  // note about ESP_INTR_FLAG_LEVEL2: this is necessary in order to work reliably with interrupt intensive VGATextController, when running on the same core
902  // must be core "1" due the RTC
903  esp_intr_alloc_pinnedToCore(ETS_RTC_CORE_INTR_SOURCE, ESP_INTR_FLAG_LEVEL2, rtc_isr, this, &m_isrHandle, 1);
904  SET_PERI_REG_MASK(RTC_CNTL_INT_ENA_REG, RTC_CNTL_ULP_CP_INT_ENA);
905 }
906 
907 
908 void PS2Controller::begin(PS2Preset preset, KbdMode keyboardMode)
909 {
910  bool generateVirtualKeys = (keyboardMode == KbdMode::GenerateVirtualKeys || keyboardMode == KbdMode::CreateVirtualKeysQueue);
911  bool createVKQueue = (keyboardMode == KbdMode::CreateVirtualKeysQueue);
912  switch (preset) {
914  // both keyboard (port 0) and mouse configured (port 1)
915  begin(GPIO_NUM_33, GPIO_NUM_32, GPIO_NUM_26, GPIO_NUM_27);
916  setKeyboard(new Keyboard);
917  keyboard()->begin(generateVirtualKeys, createVKQueue, 0);
918  setMouse(new Mouse);
919  mouse()->begin(1);
920  break;
922  // only keyboard configured on port 0
923  // this will call setKeyboard and begin()
924  (new Keyboard)->begin(GPIO_NUM_33, GPIO_NUM_32, generateVirtualKeys, createVKQueue);
925  break;
927  // only mouse configured on port 0
928  // this will call setMouse and begin()
929  (new Mouse)->begin(GPIO_NUM_33, GPIO_NUM_32);
930  break;
931  };
932 }
933 
934 
936 {
937  if (m_suspendCount == 0) {
938  CLEAR_PERI_REG_MASK(RTC_CNTL_INT_ENA_REG, RTC_CNTL_ULP_CP_INT_ENA);
939  ets_delay_us(50);
940  WRITE_PERI_REG(RTC_CNTL_INT_CLR_REG, READ_PERI_REG(RTC_CNTL_INT_ST_REG));
941  }
942  ++m_suspendCount;
943 }
944 
946 {
947  --m_suspendCount;
948  if (m_suspendCount <= 0) {
949  m_suspendCount = 0;
950  SET_PERI_REG_MASK(RTC_CNTL_INT_ENA_REG, RTC_CNTL_ULP_CP_INT_ENA);
951  }
952 }
953 
954 
956 {
957  uint32_t RTCMEM_PORTX_WRITE_POS = (PS2Port == 0 ? RTCMEM_PORT0_WRITE_POS : RTCMEM_PORT1_WRITE_POS);
958  uint32_t RTCMEM_PORTX_BUFFER_END = (PS2Port == 0 ? RTCMEM_PORT0_BUFFER_END : RTCMEM_PORT1_BUFFER_END);
959  uint32_t RTCMEM_PORTX_BUFFER_START = (PS2Port == 0 ? RTCMEM_PORT0_BUFFER_START : RTCMEM_PORT1_BUFFER_START);
960 
961  int writePos = RTC_SLOW_MEM[RTCMEM_PORTX_WRITE_POS] & 0xFFFF;
962  if (m_readPos[PS2Port] <= writePos)
963  return writePos - m_readPos[PS2Port];
964  else
965  return (RTCMEM_PORTX_BUFFER_END - m_readPos[PS2Port]) + (writePos - RTCMEM_PORTX_BUFFER_START);
966 }
967 
968 
969 // return -1 when no data is available
970 int PS2Controller::getData(int PS2Port)
971 {
972  uint32_t RTCMEM_PORTX_WRITE_POS = (PS2Port == 0 ? RTCMEM_PORT0_WRITE_POS : RTCMEM_PORT1_WRITE_POS);
973  uint32_t RTCMEM_PORTX_BUFFER_END = (PS2Port == 0 ? RTCMEM_PORT0_BUFFER_END : RTCMEM_PORT1_BUFFER_END);
974  uint32_t RTCMEM_PORTX_BUFFER_START = (PS2Port == 0 ? RTCMEM_PORT0_BUFFER_START : RTCMEM_PORT1_BUFFER_START);
975 
976  int data = -1;
977 
978  int writePos = RTC_SLOW_MEM[RTCMEM_PORTX_WRITE_POS] & 0xFFFF;
979  if (m_readPos[PS2Port] != writePos) {
980  uint16_t data16 = (RTC_SLOW_MEM[m_readPos[PS2Port]] & 0xFFFF);
981  data = data16 >> 1 & 0xFF;
982  // check parity
983  if ((data16 >> 9 & 1) != !calcParity(data)) {
984  // parity error
985  warmInit();
986  sendData(0xFE, PS2Port); // request to resend last byte
987  data = -1;
988  m_parityError[PS2Port] = true;
989  } else {
990  // parity OK
991  ++m_readPos[PS2Port];
992  if (m_readPos[PS2Port] == RTCMEM_PORTX_BUFFER_END)
993  m_readPos[PS2Port] = RTCMEM_PORTX_BUFFER_START;
994  m_parityError[PS2Port] = false;
995  }
996  }
997 
998  return data;
999 }
1000 
1001 
1002 void PS2Controller::warmInit()
1003 {
1004  m_readPos[0] = RTCMEM_PORT0_BUFFER_START;
1005  m_readPos[1] = RTCMEM_PORT1_BUFFER_START;
1006 
1007  // initialize the receiving word pointer at the bottom of the buffer
1008  RTC_SLOW_MEM[RTCMEM_PORT0_WRITE_POS] = RTCMEM_PORT0_BUFFER_START;
1009  RTC_SLOW_MEM[RTCMEM_PORT1_WRITE_POS] = RTCMEM_PORT1_BUFFER_START;
1010 
1011  // select receive mode
1012  RTC_SLOW_MEM[RTCMEM_PORT0_MODE] = MODE_RECEIVE;
1013  RTC_SLOW_MEM[RTCMEM_PORT1_MODE] = MODE_RECEIVE;
1014 
1015  // initialize flags
1016  RTC_SLOW_MEM[RTCMEM_PORT0_WORD_SENT_FLAG] = 0;
1017  RTC_SLOW_MEM[RTCMEM_PORT1_WORD_SENT_FLAG] = 0;
1018  RTC_SLOW_MEM[RTCMEM_PORT0_WORD_RX_READY] = 0;
1019  RTC_SLOW_MEM[RTCMEM_PORT1_WORD_RX_READY] = 0;
1020 
1021  // delay required to take ULP time to resume
1022  vTaskDelay(20 / portTICK_PERIOD_MS);
1023 
1024  m_parityError[0] = false;
1025  m_parityError[1] = false;
1026 }
1027 
1028 
1029 void PS2Controller::injectInRXBuffer(int value, int PS2Port)
1030 {
1031  uint32_t RTCMEM_PORTX_WRITE_POS = (PS2Port == 0 ? RTCMEM_PORT0_WRITE_POS : RTCMEM_PORT1_WRITE_POS);
1032  uint32_t RTCMEM_PORTX_BUFFER_END = (PS2Port == 0 ? RTCMEM_PORT0_BUFFER_END : RTCMEM_PORT1_BUFFER_END);
1033  uint32_t RTCMEM_PORTX_BUFFER_START = (PS2Port == 0 ? RTCMEM_PORT0_BUFFER_START : RTCMEM_PORT1_BUFFER_START);
1034 
1035  int writePos = RTC_SLOW_MEM[RTCMEM_PORTX_WRITE_POS] & 0xFFFF;
1036  RTC_SLOW_MEM[writePos] = value << 1;
1037  ++writePos;
1038  if (writePos == RTCMEM_PORTX_BUFFER_END)
1039  writePos = RTCMEM_PORTX_BUFFER_START;
1040  RTC_SLOW_MEM[RTCMEM_PORTX_WRITE_POS] = writePos;
1041 }
1042 
1043 
1044 bool PS2Controller::waitData(int timeOutMS, int PS2Port)
1045 {
1046  m_RXWaitTask[PS2Port] = xTaskGetCurrentTaskHandle();
1047  return ulTaskNotifyTake(pdTRUE, msToTicks(timeOutMS));
1048 }
1049 
1050 
1051 void PS2Controller::sendData(uint8_t data, int PS2Port)
1052 {
1053  uint32_t RTCMEM_PORTX_SEND_WORD = (PS2Port == 0 ? RTCMEM_PORT0_SEND_WORD : RTCMEM_PORT1_SEND_WORD);
1054  uint32_t RTCMEM_PORTX_MODE = (PS2Port == 0 ? RTCMEM_PORT0_MODE : RTCMEM_PORT1_MODE);
1055 
1056  RTC_SLOW_MEM[RTCMEM_PORTX_SEND_WORD] = 0x200 | ((~calcParity(data) & 1) << 8) | data; // 0x200 = stop bit. Start bit is not specified here.
1057  RTC_SLOW_MEM[RTCMEM_PORTX_MODE] = MODE_SEND;
1058  m_TXWaitTask[PS2Port] = xTaskGetCurrentTaskHandle();
1059  if (ulTaskNotifyTake(pdTRUE, pdMS_TO_TICKS(10)) == pdFALSE) {
1060  warmInit();
1061  }
1062 }
1063 
1064 
1065 void IRAM_ATTR PS2Controller::rtc_isr(void * arg)
1066 {
1067  uint32_t rtc_intr = READ_PERI_REG(RTC_CNTL_INT_ST_REG);
1068 
1069  if (rtc_intr & RTC_CNTL_SAR_INT_ST) {
1070 
1071  PS2Controller * ctrl = (PS2Controller*) arg;
1072  for (int PS2Port = 0; PS2Port < 2; ++PS2Port) {
1073 
1074  uint32_t RTCMEM_PORTX_WORD_SENT_FLAG = (PS2Port == 0 ? RTCMEM_PORT0_WORD_SENT_FLAG : RTCMEM_PORT1_WORD_SENT_FLAG);
1075  uint32_t RTCMEM_PORTX_WRITE_POS = (PS2Port == 0 ? RTCMEM_PORT0_WRITE_POS : RTCMEM_PORT1_WRITE_POS);
1076  uint32_t RTCMEM_PORTX_WORD_RX_READY = (PS2Port == 0 ? RTCMEM_PORT0_WORD_RX_READY : RTCMEM_PORT1_WORD_RX_READY);
1077 
1078  // Received end of send interrupt?
1079  if (RTC_SLOW_MEM[RTCMEM_PORTX_WORD_SENT_FLAG]) {
1080  // reset flag and awake waiting task
1081  RTC_SLOW_MEM[RTCMEM_PORTX_WORD_SENT_FLAG] = 0;
1082  ctrl->m_readPos[PS2Port] = RTC_SLOW_MEM[RTCMEM_PORTX_WRITE_POS] & 0xFFFF;
1083  if (ctrl->m_TXWaitTask[PS2Port]) {
1084  vTaskNotifyGiveFromISR(ctrl->m_TXWaitTask[PS2Port], nullptr);
1085  ctrl->m_TXWaitTask[PS2Port] = nullptr;
1086  }
1087  }
1088 
1089  // Received new RX word interrupt?
1090  if (RTC_SLOW_MEM[RTCMEM_PORTX_WORD_RX_READY]) {
1091  // reset flag and awake waiting task
1092  RTC_SLOW_MEM[RTCMEM_PORTX_WORD_RX_READY] = 0;
1093  if (ctrl->m_RXWaitTask[PS2Port]) {
1094  vTaskNotifyGiveFromISR(ctrl->m_RXWaitTask[PS2Port], nullptr);
1095  ctrl->m_RXWaitTask[PS2Port] = nullptr;
1096  }
1097  }
1098 
1099  }
1100 
1101  }
1102 
1103  // clear interrupt
1104  WRITE_PERI_REG(RTC_CNTL_INT_CLR_REG, rtc_intr);
1105 }
1106 
1107 
1108 
1109 
1110 } // end of namespace
1111 
1112 
This file contains fabgl::PS2Controller definition.
int dataAvailable(int PS2Port)
Gets the number of scancodes available in the controller buffer.
Keyboard * keyboard()
Returns the instance of Keyboard object automatically created by PS2Controller.
void injectInRXBuffer(int value, int PS2Port)
Injects a byte into the RX buffer.
This file contains fabgl::Keyboard definition.
uint8_t const * data
The PS2 Keyboard controller class.
Definition: keyboard.h:166
This file contains fabgl::Mouse definition.
void sendData(uint8_t data, int PS2Port)
Sends a command to the device.
void begin(gpio_num_t clkGPIO, gpio_num_t dataGPIO, bool generateVirtualKeys=true, bool createVKQueue=true)
Initializes Keyboard specifying CLOCK and DATA GPIOs.
Definition: keyboard.cpp:641
This file contains some utility classes and functions.
Definition: canvas.cpp:31
KbdMode
This enum defines how handle keyboard virtual keys.
Definition: ps2controller.h:57
The PS2 device controller class.
Definition: ps2controller.h:74
int getData(int PS2Port)
Gets a scancode from the queue.
void suspend()
Suspends PS/2 ports operations.
void begin(gpio_num_t clkGPIO, gpio_num_t dataGPIO)
Initializes Mouse specifying CLOCK and DATA GPIOs.
Definition: mouse.cpp:69
PS2Preset
This enum defines what is connected to PS/2 ports.
Definition: ps2controller.h:47
The PS2 Mouse controller class.
Definition: mouse.h:99
Mouse * mouse()
Returns the instance of Mouse object automatically created by PS2Controller.
void resume()
Resumes PS/2 ports operations.
void begin(gpio_num_t port0_clkGPIO, gpio_num_t port0_datGPIO, gpio_num_t port1_clkGPIO=GPIO_UNUSED, gpio_num_t port1_datGPIO=GPIO_UNUSED)
Initializes PS2 device controller.