#include "X\xl.h" #include using namespace std; // Estrutura para descrever o estado de uma chave struct KeyState { int key_number; // Número da chave bool state; // Estado da chave AbsoluteTime when; // Horário em que a chave mudou de estado }; // Funções Externas. Precisam ser implementadas em outros arquivos. extern bool OpenConnection(void); // Abre a conexão (retorna false se falhar) extern void CloseConnection(void); // Fecha a conexão extern bool ReadKey (int key); // Lê o estado da tecla "key" extern void Init (void); // Inicia o hardware (interrup, timer, etc). extern void SendKeyState(KeyState *e); // Envia o estado de uma tecla pelo canal // Cria e inicia o objeto "sistema operacional" X os(10,10,0); // Cria a fila de mensagens para comunicar as duas threads. // Cada mensagem inserida nesta fila é um "KeyState" Pipe MessageQueue(100,0); //------------------------------------------------------------------------ // Thread DebounceKeys // Periodicamente lê o estado das teclas. Se uma tecla mudar de estado // e permanecer neste estado por 20 ms, insere uma mensagem no // pipe "MessageQueue". //------------------------------------------------------------------------ void DebounceKeys (Word a, Word b) { const int c_number_of_keys = 3; // Registrador de debounce. Cada elemento do vetor representa uma chave. // Os 4 bits menos significativos de cada elemento armazenam as 4 últimas // leituras das chaves. int key_status[c_number_of_keys]; memset( key_status, 0, sizeof(key_status) ); while (1) { // A thread dorme durante 20 ms (período de leitura das chaves) os.SleepFor(20*MSEC); // Verifica cada uma das teclas for (int i=0; ikey_number = i; e->state = state; e->when = os.GetTime(); MessageQueue.Put(e); } // Deixa o registrador preparado para receber a próxima amostra key_status[i] <<= 1; key_status[i] &= 0xF; } } } //------------------------------------------------------------------------ // Thread CommChannel // Controla o canal de comunicação e envia as mensagens de estado das // teclas a medida que são recebidas da thread DebounceKeys. //------------------------------------------------------------------------ void CommChannel (Word a, Word b) { KeyState* e; PutMsg msg_in_pipe; while (1) { // Permanece sem conexão enquanto não houver mensagem para transmitir // O pipe "MessageQueue" vai liberar este Receive quando a primeira // mensagem for inserida. os.Receive(&msg_in_pipe, sizeof(msg_in_pipe)); while (OpenConnection() == false) { // Não conseguiu conectar. Aguarda para tentar novamente os.SleepFor(2*MIN); } do { // Envia as mensagens que estão aguardando no pipe while (MessageQueue.IsEmpty() == false) { e = (KeyState *) MessageQueue.Get(); SendKeyState(e); delete e; } // Aguarda uma nova mensagem ser inserida no pipe // por no máximo 3 minutos. os.ReceiveTO ( &msg_in_pipe, sizeof(msg_in_pipe), 3*MIN ); } while (msg_in_pipe.command != TIME_OUT_MSG); // Conexão passou muito tempo ociosa (o pipe ficou vazio) CloseConnection(); } } //------------------------------------------------------------------------ // main // Inicia as threads e ativa o sistema operacional. //------------------------------------------------------------------------ int main( ) { os.Init(); // Inicia o sistema operacional Init(); // Inicia o hardware // Cria a thread de debounce TId debounce; debounce = os.CreateThread (DebounceKeys, 0, 0, "DebounceKeys", 1024, ARM_CODE | FIQ_ENABLE | IRQ_ENABLE, 5); // Cria a thread do canal de comunicação TId channel; channel = os.CreateThread (CommChannel, 0, 0, "CommChannel", 1024, ARM_CODE | FIQ_ENABLE | IRQ_ENABLE, 4); // Conecta o pipe entre as duas threads (debounce -> channel) MessageQueue.Init(debounce, channel); // Inicia o escalonamento os.Start(); }