// ----------------------------------------------------------------------------- /// @file keypadMatrix.c /// @brief Description // ----------------------------------------------------------------------------- // Micro-Key bv // Industrieweg 28, 9804 TG Noordhorn // Postbus 92, 9800 AB Zuidhorn // The Netherlands // Tel: +31 594 503020 // Fax: +31 594 505825 // Email: support@microkey.nl // Web: www.microkey.nl // ----------------------------------------------------------------------------- /// $Revision$ /// $Author$ /// $Date$ // (c) 2017 Micro-Key bv // ----------------------------------------------------------------------------- /// @file keypadMatrix.c /// @ingroup {group_name} // ----------------------------------------------------------------------------- // Include files // ----------------------------------------------------------------------------- #include #include #include #include "FreeRTOSFixes.h" #include "Logger.h" #include "keypadMatrix.h" #include "platform.h" #include "stm32f10x_it.h" // ----------------------------------------------------------------------------- // Constant and macro definitions // ----------------------------------------------------------------------------- // ----------------------------------------------------------------------------- // Type definitions // ----------------------------------------------------------------------------- // ----------------------------------------------------------------------------- // File-scope variables // ----------------------------------------------------------------------------- // ----------------------------------------------------------------------------- // Function declarations // ----------------------------------------------------------------------------- // IO device without WRITE static ErrorStatus read(const struct IODevice* self, char* buffer, size_t length, size_t* actualLength); static void KeypadTask(void* parameters); // ----------------------------------------------------------------------------- // Function definitions // ----------------------------------------------------------------------------- ErrorStatus Keypad_construct(struct Keypad* self, size_t numberOfRows, size_t numberOfColumns, int debounceTime, int taskPriority, uint16_t stackSize, size_t rxQueueSize) { int rowCounter = 0; int colCounter = 0; ErrorStatus returnValue = SUCCESS; if(!self->initialized) { IODevice_construct(&self->device, read, NULL); if(returnValue == SUCCESS) { //! Create semaphore to synchronize with Keypad/EXTI interrupt handler vSemaphoreCreateBinary(self->scanSemaphore); } self->waitToDebounce_ms = debounceTime; self->rxQueueSize = rxQueueSize; self->stackSize = stackSize; self->taskPriority = taskPriority; self->numberOfRows = numberOfRows; self->numberOfColumns = numberOfColumns; // Initialize memory to keep track of state changes per key for (rowCounter = 0; rowCounter < self->numberOfRows; rowCounter++) { for (colCounter = 0; colCounter < self->numberOfColumns; colCounter++) { self->lastState[rowCounter][colCounter] = RELEASED; } } //! Create a new FREERTOS queue to handle data from Keypad input to app self->rxQueue = xQueueCreate(self->rxQueueSize, sizeof(struct KeypadQueueItem)); if (self->rxQueue == 0) { //! Queue identifier is 0 -> error returnValue = ERROR; //! Set error flag } if(returnValue == SUCCESS) { xTaskCreate(KeypadTask, (const char*)"keypadTask", self->stackSize, keypad, self->taskPriority, &self->taskHandle); } if(returnValue == SUCCESS) { //! take txSemaphore if (xSemaphoreTake(self->scanSemaphore, 0) == pdFALSE) { //! An error has occurred returnValue = ERROR; } } if(returnValue == SUCCESS) { LOGGER_INFO(mainLog, "Keypad task started"); self->initialized = true; // // TUBE REPAIR // struct KeypadQueueItem rxQueueItem; // rxQueueItem.rowCoordinate = 0; // rxQueueItem.columnCoordinate = 0; // rxQueueItem.keyEvent = PRESSED; // // Put event in queue // xQueueSend(self->rxQueue, &rxQueueItem, 0); // rxQueueItem.rowCoordinate = 0; // rxQueueItem.columnCoordinate = 0; // rxQueueItem.keyEvent = RELEASED; // // Put event in queue // xQueueSend(self->rxQueue, &rxQueueItem, 0); // // // SELECT CATHODE // rxQueueItem.rowCoordinate = 0; // rxQueueItem.columnCoordinate = 0; // rxQueueItem.keyEvent = PRESSED; // // Put event in queue // xQueueSend(self->rxQueue, &rxQueueItem, 0); // rxQueueItem.rowCoordinate = 0; // rxQueueItem.columnCoordinate = 0; // rxQueueItem.keyEvent = RELEASED; // // Put event in queue // xQueueSend(self->rxQueue, &rxQueueItem, 0); // // // SELECT PRESET // rxQueueItem.rowCoordinate = 0; // rxQueueItem.columnCoordinate = 0; // rxQueueItem.keyEvent = PRESSED; // // Put event in queue // xQueueSend(self->rxQueue, &rxQueueItem, 0); // rxQueueItem.rowCoordinate = 0; // rxQueueItem.columnCoordinate = 0; // rxQueueItem.keyEvent = RELEASED; // // Put event in queue // xQueueSend(self->rxQueue, &rxQueueItem, 0); // // // SELECT PRESET 7 // rxQueueItem.rowCoordinate = 2; // rxQueueItem.columnCoordinate = 0; // rxQueueItem.keyEvent = PRESSED; // // Put event in queue // xQueueSend(self->rxQueue, &rxQueueItem, 0); // rxQueueItem.rowCoordinate = 2; // rxQueueItem.columnCoordinate = 0; // rxQueueItem.keyEvent = RELEASED; // // Put event in queue // xQueueSend(self->rxQueue, &rxQueueItem, 0); // // // START // rxQueueItem.rowCoordinate = 0; // rxQueueItem.columnCoordinate = 1; // rxQueueItem.keyEvent = PRESSED; // // Put event in queue // xQueueSend(self->rxQueue, &rxQueueItem, 0); // rxQueueItem.rowCoordinate = 0; // rxQueueItem.columnCoordinate = 1; // rxQueueItem.keyEvent = RELEASED; // // Put event in queue // xQueueSend(self->rxQueue, &rxQueueItem, 0); } else { LOGGER_ERROR(mainLog, "Keypad task FAILED"); } } else { returnValue = ERROR; } return returnValue; } void Keypad_Destruct (const struct Keypad* self) { vTaskDelete(self->taskHandle); vQueueDelete(self->rxQueue); } static ErrorStatus read(const struct IODevice* self, char* buffer, size_t length, size_t* actualLength) { ErrorStatus returnValue = SUCCESS; const struct Keypad* keypad = (const struct Keypad*)self; if (keypad->initialized) { struct KeypadQueueItem rxQueueItem; if (xQueueReceive(keypad->rxQueue, &rxQueueItem, 0) == pdTRUE) { *actualLength = sizeof(struct KeypadQueueItem) / sizeof (char); memcpy(buffer, &rxQueueItem, sizeof(struct KeypadQueueItem) / sizeof (char)); } else { returnValue = ERROR; } } else { returnValue = ERROR; } return returnValue; } static void KeypadTask(void* parameters) { int rowCounter = 0; int colCounter = 0; struct Keypad* self = (struct Keypad*) parameters; while (1) { // Wait for an interrupt to occur on one of the keypad columns xSemaphoreTake(self->scanSemaphore, portMAX_DELAY); // Debounce the keypad and wait for debounceTime prior to do anything vTaskDelay(self->waitToDebounce_ms); // Set all row outputs for (rowCounter = 0; rowCounter < self->numberOfRows; rowCounter++) { GPIO_SetBits(self->row[rowCounter].gpio.GPIO_Typedef, self->row[rowCounter].gpio.GPIO_InitStruct.GPIO_Pin); } // Scan through each row individually by resetting it (output level low) and check all column levels for (rowCounter = 0; rowCounter < self->numberOfRows; rowCounter++) { GPIO_ResetBits(self->row[rowCounter].gpio.GPIO_Typedef, self->row[rowCounter].gpio.GPIO_InitStruct.GPIO_Pin); for (colCounter = 0; colCounter < self->numberOfColumns; colCounter++) { if (GPIO_ReadInputDataBit(self->column[colCounter].gpio.GPIO_Typedef, self->column[colCounter].gpio.GPIO_InitStruct.GPIO_Pin) == (uint8_t)Bit_SET) { if (self->lastState[rowCounter][colCounter] == PRESSED) { // Key has been released struct KeypadQueueItem rxQueueItem; rxQueueItem.rowCoordinate = rowCounter; rxQueueItem.columnCoordinate = colCounter; rxQueueItem.keyEvent = RELEASED; // Put event in queue xQueueSend(self->rxQueue, &rxQueueItem, 0); self->lastState[rowCounter][colCounter] = RELEASED; } else { // nothing changed } } else { if (self->lastState[rowCounter][colCounter] == RELEASED) { // Key has been pressed struct KeypadQueueItem rxQueueItem; rxQueueItem.rowCoordinate = rowCounter; rxQueueItem.columnCoordinate = colCounter; rxQueueItem.keyEvent = PRESSED; // Put event in queue xQueueSend(self->rxQueue, &rxQueueItem, 0); self->lastState[rowCounter][colCounter] = PRESSED; } else { // nothing changed } } } GPIO_SetBits(self->row[rowCounter].gpio.GPIO_Typedef, self->row[rowCounter].gpio.GPIO_InitStruct.GPIO_Pin); } // Reset all row outputs and return to IRQ status for (rowCounter = 0; rowCounter < self->numberOfRows; rowCounter++) { GPIO_ResetBits(self->row[rowCounter].gpio.GPIO_Typedef, self->row[rowCounter].gpio.GPIO_InitStruct.GPIO_Pin); } IRQ_setKeypadEXTI(self, ENABLE); } }