Rato

Pacotes PS/2, deltas de nove bits, comandos e deteção de gestos.

TLDR

Perguntar sobre esta página

ChatGPTClaudePerplexityGrokGeminiCopiar e abrirDeepSeekCopiar e abrir

O pacote 28 05 FB move o rato cinco unidades para a direita e cinco para baixo. Para chegar a estes deltas, é preciso juntar três bytes: o primeiro contém sinais e botões, os seguintes contêm os oito bits inferiores de X e Y. O rato PS/2 usa o i8042 e IRQ12; cada atendimento do laboratório recolhe um byte.

Anatomia do pacote

Os dois contadores de deslocamento do rato têm nove bits em complemento para dois. O primeiro byte contém o bit mais significativo de cada delta; os bytes seguintes contêm os oito bits inferiores.

ByteConteúdo
0, bit 7Overflow de Y
0, bit 6Overflow de X
0, bit 5Bit de sinal de Y
0, bit 4Bit de sinal de X
0, bit 3Sempre 1 no primeiro byte
0, bits 2, 1 e 0Botões do meio, direito e esquerdo
1Oito bits inferiores do delta X
2Oito bits inferiores do delta Y

Os botões indicam o estado no instante do pacote, não apenas uma mudança, por isso um botão a 1 em vários pacotes pode significar que continua premido; a aplicação deve por isso detetar a transição de solto para premido em vez de reagir a cada pacote com o botão ativo.

Reconstruir nove bits

Se o bit de sinal de X estiver a 0, Δx\Delta x é o valor sem sinal do segundo byte. Se estiver a 1, subtrai 256:

Δx=b1−256⋅sx,Δy=b2−256⋅sy.\Delta x=b_1-256\cdot s_x,\qquad\Delta y=b_2-256\cdot s_y.

Aqui b1b_1 e b2b_2 estão entre 0 e 255; sxs_x e sys_y são 0 ou 1 obtidos do primeiro byte. Isto representa o intervalo de nove bits, de -256 a 255, na ausência de overflow.

No pacote 28 05 FB, o primeiro byte 0x28 tem o bit 5 a 1 e o bit 4 a 0, por isso o sinal X é 0 e o sinal Y é 1. Obtemos Δx=5\Delta x=5 e Δy=251−256=−5\Delta y=251-256=-5.

No protocolo, Y positivo significa movimento para cima. Num ecrã onde Y cresce para baixo, atualiza screen_y -= delta_y, ou seja, partindo de (100, 100), o pacote do exemplo leva a (105, 105).

O programa seguinte imprime dx=5 dy=-5 x=105 y=105, porque aplica a fórmula de nove bits e a conversão para coordenadas de ecrã:

Deltas PS/2 de nove bits
#include <stdint.h>
#include <stdio.h>

int main(void) {
  uint8_t bytes[] = {0x28, 0x05, 0xFB};
  int dx = (int)bytes[1] - ((bytes[0] & 0x10u) ? 256 : 0);
  int dy = (int)bytes[2] - ((bytes[0] & 0x20u) ? 256 : 0);
  int x = 100 + dx;
  int y = 100 - dy;
  printf("dx=%d dy=%d x=%d y=%d\n", dx, dy, x, y);
  return 0;
}
Resultado

Executa o código para ver a saída e os gráficos.

Este exemplo assume ausência de overflow e não aplica limites do ecrã. Na aplicação, mantém a soma num tipo com sinal, limita às coordenadas permitidas e só depois converte para o tipo da posição.

Montagem e sincronização

Mantém um array de três bytes e um índice. Se o índice for 0, aceita apenas um byte com bit 3 a 1. Se não tiver esse bit, descarta-o. Nos índices 1 e 2, guarda o byte sem repetir o teste, porque os dados podem ter qualquer valor.

Quando o índice chega a 3, entrega o pacote completo e volta a 0, porque o bit 3 também pode estar ativo nos bytes de dados. É uma ajuda de sincronização, não uma prova de que nunca juntaste pedaços de dois pacotes.

Se uma leitura falhar ou houver erro de comunicação durante a montagem, invalida o pacote parcial e volta a procurar um primeiro byte. Um erro não deve produzir um movimento com bytes antigos. Se os bits de overflow estiverem ativos, a magnitude correspondente não é fiável. Define se ignoras esse eixo ou todo o movimento; ainda podes interpretar os botões se o pacote foi recebido validamente.

Stream, remote e reporting

Em stream mode, o rato envia pacotes quando há movimento ou mudança de botões, até à taxa de amostragem configurada. Ativar o modo não é o mesmo que ativar o envio: data reporting pode estar desligado.

Em remote mode, o programa pede um pacote com 0xEB. Isso é útil para uma experiência de polling. Cada byte do pacote continua a passar pelo output buffer do i8042; não chega um array de três bytes numa única leitura.

Comando do ratoFunção
0xF4Ativar data reporting em stream mode
0xF5Desativar data reporting
0xEASelecionar stream mode
0xF0Selecionar remote mode
0xEBPedir dados em remote mode
0xF3Definir taxa de amostragem, com um argumento
0xF6Repor parâmetros por defeito

Subscreve IRQ12 com a política exclusiva apropriada ao laboratório, para o driver normal do Minix não disputar os bytes. Guarda a configuração relevante e repõe o modo e reporting ao sair.

Enviar um comando

Os comandos do rato não se escrevem diretamente na porta de comandos do KBC. Para enviar cada byte:

  1. Espera IBF a 0 e escreve 0xD4 em 0x64, a ordem ao KBC para encaminhar o byte seguinte ao rato.
  2. Espera IBF a 0 e escreve o byte em 0x60.
  3. Espera a resposta e lê-a de 0x60, tratando timeout e erros.

O rato confirma com 0xFA cada comando e cada argumento que aceita. A exceção documentada nos slides é o comando de reenvio: quando o byte recebido é o próprio 0xFE enviado pelo anfitrião, o rato não devolve ACK. No sentido contrário, 0xFE como resposta do rato pede reenvio e 0xFC assinala erro. Limita as tentativas. O ACK não é o conteúdo da resposta de um comando que devolve dados: essa resposta vem depois.

Para definir taxa de amostragem, há uma sequência para 0xF3 e outra para o argumento. Cada uma usa 0xD4 e recebe o seu ACK. Se o argumento provocar 0xFE, a regra apresentada nos slides pede repetir o comando completo, não apenas o argumento. Os dois bytes do rato precisam novamente de encaminhamento por 0xD4 e de confirmação; o próprio 0xD4 é uma ordem ao KBC e não recebe ACK do rato.

Em stream mode com reporting ativo, desativa reporting antes de enviar outros comandos para não misturar pacotes de movimento com respostas. A fase de comandos e a fase de receção de pacotes devem ter um dono claro do output buffer.

De pacotes a gestos

Um gesto depende de uma sequência, por isso precisa de estado. Num exemplo próprio, queremos um arrasto horizontal para a direita com botão esquerdo premido, comprimento de pelo menos 100 unidades e desvio vertical absoluto no máximo 5.

Começa em WAIT_PRESS. Na transição de botão solto para premido, passa a DRAWING e põe os acumulados a zero. Enquanto o botão continuar premido, soma os deltas. Se o movimento voltar para a esquerda ou o desvio ultrapassar a tolerância, passa a INVALID e ignora os movimentos até o botão ser largado. Só uma nova pressão inicia outro candidato. Se x≥100x\geq100 e ∣y∣≤5|y|\leq5, reconhece o gesto uma vez e passa a COMPLETE, onde espera pela libertação. Largar o botão antes disso cancela-o. Neste modelo, o pacote da pressão inicia o candidato, mas não acrescenta movimento; só os seguintes, ainda com o botão premido, entram na soma.

WAIT_PRESSEsperar nova pressão.

Premir leva a DRAWING, com x = y = 0. O pacote da pressão não soma deltas.

DRAWINGSomar os deltas seguintes enquanto o botão estiver premido.Δx ≥ 0, |y| ≤ 5 e x < 100: continuar aqui.

Se o movimento deixar de cumprir estas condições:

Δx < 0 ou |y| > 5INVALIDIgnorar movimento até largar.
Δx ≥ 0, |y| ≤ 5 e x ≥ 100COMPLETEReconhecer uma vez. Esperar libertação do botão.
Ao largar, DRAWING cancela o candidato; INVALID eCOMPLETE deixam de esperar. Os três regressam aWAIT_PRESS. Só uma nova pressão inicia outro candidato.

A decisão de usar desvio vertical acumulado é parte do enunciado. Aceitar cada pacote com ∣Δy∣≤5|\Delta y|\leq5 permitiria dez pacotes de +5 e um desvio final de 50. O parser de bytes e a máquina do gesto resolvem problemas distintos: a primeira produz pacotes completos; a segunda interpreta o seu significado ao longo do tempo.

Exercícios

Usar o nono bit

Um pacote válido sem overflow é 08 C8 00. Quanto vale delta X em decimal?

Pista
O bit de sinal de X está no primeiro byte.
Solução

O sinal X é 0, por isso delta X é o byte baixo 0xC8 sem sinal, ou +200. Não há overflow. Um cast para int8_t produziria um resultado diferente e incorreto para o protocolo.

Erros frequentes

Usar o bit 7 de C8 como sinal de um delta que tem nove bits.

Voltar à explicação
Converter para o ecrã

Um pacote válido é 28 00 05. O cursor tem screen_y = 100 e o ecrã cresce para baixo. Sem aplicar limites, qual é o novo screen_y?

Pista
O bit 5 de 0x28 é o sinal Y.
Solução

delta Y = -251 nas coordenadas físicas do rato. screen_y = 100 - (-251) = 351. O movimento físico foi para baixo, por isso a coordenada do ecrã aumenta.

Erros frequentes

Interpretar 0x05 sempre como +5 ou somar delta Y numa coordenada de ecrã que cresce para baixo.

Voltar à explicação
Não reiniciar no byte de dados

A montagem começa com índice 0 e recebe 08 18 00. Um programa reinicia o pacote sempre que vê bit 3 a 1, mesmo a meio. Explica por que falha e interpreta o pacote corretamente.

Pista
O bit 3 pode também estar ativo num byte de dados.
Solução

Depois de aceitar 0x08, o índice é 1. 0x18 deve ocupar o byte X e 0x00 o byte Y. O pacote tem delta X +24, delta Y 0, sem botões. O teste de sincronização só deve escolher o primeiro byte quando o índice é 0; reiniciar em 0x18 perde o pacote.

Confere a tua resposta:

  • Aceitei 0x08 como primeiro byte.
  • Guardei 0x18 como dado X.
  • Completei o pacote com 0x00 sem reiniciar.

Erros frequentes

Assumir que bit 3 a 1 identifica exclusivamente um cabeçalho em qualquer posição.

Voltar à explicação
Acumular o desvio de um gesto

Num arrasto horizontal para a direita, exige-se comprimento de pelo menos 100 unidades e desvio vertical acumulado absoluto no máximo 5 em todos os passos. Movimento para a esquerda ou desvio excessivo invalida o candidato até largar o botão. O botão esquerdo acabou de ser premido e os acumulados são zero. Chegam movimentos (40, 3), (40, 3) e (30, -2), mantendo o botão premido. O gesto deve ser reconhecido? Indica em que passo se decide.

Pista

A tolerância vale para o desvio acumulado em todo o candidato.

Solução

Não. O primeiro movimento deixa (40, 3), dentro da tolerância. O segundo deixa (80, 6), ultrapassa 5 e invalida o candidato. O terceiro não recupera esse gesto, apesar de a soma dos três dar (110, 4). Um novo candidato exige largar e voltar a premir o botão.

Confere a tua resposta:

  • Somei y até 6 no segundo movimento.
  • Invalidei antes de atingir comprimento 100.
  • Não reativei o candidato no terceiro movimento.

Erros frequentes

Testar apenas cada delta ou só a soma final aceita uma sequência que saiu da tolerância a meio.

Voltar à explicação
Repetir o comando após reenvio

Enviaste 0xF3 com ACK e o argumento recebe 0xFE. Segue a regra dos slides de rato para este erro: indica que bytes reenvias e quais recebem ACK. O KBC também confirma 0xD4 com ACK do rato?

Pista
O rato pode pedir a retransmissão total.
Mais uma pista
O argumento sozinho não refaz o comando.
Solução

Repete o comando completo. Espera IBF vazio e envia 0xD4 ao KBC, depois 0xF3 ao rato, que deve responder com ACK. Para o argumento, envia outro 0xD4 e depois o argumento, com outro ACK do rato. O KBC não devolve um ACK de rato por receber 0xD4; essa ordem só encaminha o byte seguinte. Limita as tentativas e trata 0xFC como erro. Repetir apenas o argumento não segue a regra de recuperação dada.

Confere a tua resposta:

  • Identifiquei 0xFE como pedido de reenvio.
  • Repeti comando e argumento completos.
  • Limitei as tentativas.

Erros frequentes

Tratar o ACK do comando como resposta ou repetir bytes sem limite.

Voltar à explicação

À tua maneira

Aparência

Modo de cor
Tema
Cor de destaque

Leitura

Fonte de leitura

Álgebra, lógica e uma ideia de cada vez.

Código

Fonte do código

Navegação

Cursor de leitura, sem edição. h, j, k, l movem; / pesquisa nesta página. v seleciona caracteres; V seleciona linhas; y copia. Tab permite destacar ou comentar. Espaço ou Enter abre blocos recolhíveis. Nos cartões, h, j, k, l mudam o foco.

CSS personalizado

Ativa uma sugestão ou guarda o teu CSS. Só muda este navegador.

Usa --page, --text e --accent para acompanhar o tema.

Seletores e recuperação

.site-header, .prose, .course-card, [data-reading-history], [data-playground] e .page-actions.

Abre a aparência com a tecla vírgula ou no rodapé. Se o CSS esconder os controlos, abre esta página sem CSS personalizado.

Pesquisar

Escreve para pesquisar em todo o site.

para escolher · Enter para abrir · Esc para fechar

Copiar fórmula

A cópia automática não está disponível. Copia o LaTeX abaixo.

Pesquisar nesta página

Enter procura · n / N repetem · Esc cancela. Ctrl / Cmd K pesquisa todo o site.

Atalhos de teclado

Clica numa tecla para a mudar. Esc cancela. Backspace desativa.

PesquisarCtrl / Cmd K

Os atalhos não interferem enquanto escreves. Tab e Enter funcionam sempre.