/*! \fn guiAskForConfirmation(const char* string) * \brief Ask for user confirmation for different things * \param nb_args Number of text lines (must be either 1 2 or 3/4 (depending on the MP version)) * \param text_object Pointer to the text object if more than 1 line, pointer to the string if not * \return User confirmation or not */ RET_TYPE guiAskForConfirmation(uint8_t nb_args, confirmationText_t* text_object) { uint8_t flash_flag_set = FALSE; uint8_t flash_flag = FALSE; uint8_t flash_sm = 0; // LED animation #ifdef LEDS_ENABLED_MINI miniLedsSetAnimation(ANIM_PULSE_UP_RAMP_DOWN); #endif // Check if we want to flash the screen if ((nb_args & 0xF0) != 0) { flash_flag_set = TRUE; nb_args = nb_args & 0x0F; // Check that the user didn't disable it if (getMooltipassParameterInEeprom(FLASH_SCREEN_PARAM) != FALSE) { flash_flag = TRUE; } } // Variables for scrolling uint8_t string_y_indexes[3]; uint8_t string_extra_chars[3]; uint8_t string_offset_cntrs[3] = {0,0,0}; // Display variables uint8_t approve_selected = TRUE; // Draw asking bitmap miniOledClearFrameBuffer(); miniOledSetMaxTextY(SSD1305_OLED_WIDTH-15); miniOledBitmapDrawFlash(SSD1305_OLED_WIDTH-15, 0, BITMAP_APPROVE, 0); // Display lines. // Note: line are truncated at the miniOled driver level when miniOledTextWritingYIncrement is set to FALSE (default) if (nb_args == 1) { miniOledPutCenteredString(THREE_LINE_TEXT_SECOND_POS, (char*)text_object); } else if (nb_args == 2) { string_y_indexes[0] = TWO_LINE_TEXT_FIRST_POS; string_y_indexes[1] = TWO_LINE_TEXT_SECOND_POS; } else { string_y_indexes[0] = THREE_LINE_TEXT_FIRST_POS; string_y_indexes[1] = THREE_LINE_TEXT_SECOND_POS; string_y_indexes[2] = THREE_LINE_TEXT_THIRD_POS; } // For loop to display lines when there is more than one arg if (nb_args > 1) { for (uint8_t i = 0; i < nb_args; i++) { string_extra_chars[i] = strlen(text_object->lines[i]) - miniOledPutCenteredString(string_y_indexes[i], text_object->lines[i]); } } miniOledFlushEntireBufferToDisplay(); miniOledResetMaxTextY(); // Wait for user input RET_TYPE input_answer = MINI_INPUT_RET_NONE; RET_TYPE detect_result; // Switch on lights activityDetectedRoutine(); // Clear possible remaining detection miniWheelClearDetections(); // Arm timer for scrolling (caps timer that isn't relevant here) activateTimer(TIMER_CAPS, SCROLLING_DEL); // Arm timer for flashing activateTimer(TIMER_FLASHING, 500); // Loop while no timeout occurs or no button is pressed while (input_answer == MINI_INPUT_RET_NONE) { // User interaction timeout or smartcard removed if ((hasTimerExpired(TIMER_USERINT, TRUE) == TIMER_EXPIRED) || (isSmartCardAbsent() == RETURN_OK)) { input_answer = MINI_INPUT_RET_TIMEOUT; } // Read usb comms as the plugin could ask to cancel the request if (usbCancelRequestReceived() == RETURN_OK) { input_answer = MINI_INPUT_RET_TIMEOUT; } // Screen flashing logic if ((hasTimerExpired(TIMER_FLASHING, TRUE) == TIMER_EXPIRED) && (flash_flag == TRUE) && (flash_sm < 4)) { // Look at the flash_sm LSb to know what is the display state if ((flash_sm++ & 0x01) != 0x00) { miniOledNormalDisplay(); } else { miniOledInvertedDisplay(); } // Re-arm timer activateTimer(TIMER_FLASHING, 500); } // Check if something has been pressed detect_result = miniGetWheelAction(FALSE, TRUE); if (detect_result == WHEEL_ACTION_SHORT_CLICK) { input_answer = MINI_INPUT_RET_YES; } else if (detect_result == WHEEL_ACTION_LONG_CLICK) { input_answer = MINI_INPUT_RET_BACK; } // Knock to approve #if defined(HARDWARE_MINI_CLICK_V2) if ((scanAndGetDoubleZTap(FALSE) == ACC_RET_KNOCK) && (flash_flag_set != FALSE)) { input_answer = MINI_INPUT_RET_YES; } #else (void)flash_flag_set; #endif // Text scrolling if ((hasTimerExpired(TIMER_CAPS, FALSE) == TIMER_EXPIRED) && (nb_args > 1)) { miniOledClearFrameBuffer(); activateTimer(TIMER_CAPS, SCROLLING_DEL); miniOledSetMaxTextY(SSD1305_OLED_WIDTH-15); if(approve_selected == FALSE) { miniOledBitmapDrawFlash(SSD1305_OLED_WIDTH-15, 0, BITMAP_DENY, 0); } else { miniOledBitmapDrawFlash(SSD1305_OLED_WIDTH-15, 0, BITMAP_APPROVE, 0); } for (uint8_t i = 0; i < nb_args; i++) { if (string_extra_chars[i] > 0) { miniOledPutCenteredString(string_y_indexes[i], (text_object->lines[i]) + string_offset_cntrs[i]); if (string_offset_cntrs[i]++ == string_extra_chars[i]) { string_offset_cntrs[i] = 0; } } else { miniOledPutCenteredString(string_y_indexes[i], text_object->lines[i]); } } miniOledFlushEntireBufferToDisplay(); miniOledResetMaxTextY(); } // Approve / deny display change if (getWheelCurrentIncrement() != 0) { if(approve_selected == FALSE) { miniOledBitmapDrawFlash(SSD1305_OLED_WIDTH-15, 0, BITMAP_APPROVE, 0); } else { miniOledBitmapDrawFlash(SSD1305_OLED_WIDTH-15, 0, BITMAP_DENY, 0); } approve_selected = !approve_selected; miniOledFlushEntireBufferToDisplay(); } } // In case display was inverted, set it normally miniOledNormalDisplay(); if ((input_answer == MINI_INPUT_RET_YES) && (approve_selected != FALSE)) { // LED animation #ifdef LEDS_ENABLED_MINI miniLedsSetAnimation(ANIM_NONE); #endif return RETURN_OK; } else if (input_answer == MINI_INPUT_RET_BACK) { // LED animation #ifdef LEDS_ENABLED_MINI miniLedsSetAnimation(ANIM_NONE); #endif return RETURN_BACK; } else { // LED animation #ifdef LEDS_ENABLED_MINI miniLedsSetAnimation(ANIM_NONE); #endif return RETURN_NOK; } }
/*! \fn guiAskForConfirmation(const char* string) * \brief Ask for user confirmation for different things * \param nb_args Number of text lines (must be either 1 2 or 3/4 (depending on the MP version)) * \param text_object Pointer to the text object if more than 1 line, pointer to the string if not * \return User confirmation or not */ RET_TYPE guiAskForConfirmation(uint8_t nb_args, confirmationText_t* text_object) { uint8_t flash_flag = FALSE; // Check if we want to flash the screen if ((nb_args & 0xF0) != 0) { nb_args = nb_args & 0x0F; // Check that the user didn't disable it if (getMooltipassParameterInEeprom(FLASH_SCREEN_PARAM) != FALSE) { flash_flag = TRUE; } } #if defined(HARDWARE_OLIVIER_V1) // Temp string for truncating char string_tbd[31]; string_tbd[30] = 0; // Draw asking bitmap oledClear(); oledBitmapDrawFlash(0, 0, BITMAP_YES_NO_INT_L, 0); oledBitmapDrawFlash(222, 0, BITMAP_YES_NO_INT_R, 0); // If more than one line if (nb_args == 1) { // Yeah, that's a bit dirty oledPutstrXY(0, 24, OLED_CENTRE, (char*)text_object); } else { while (nb_args--) { // Truncate and then display string memcpy(string_tbd, text_object->lines[nb_args], 30); oledPutstrXY(0, 2 + (nb_args << 4), OLED_CENTRE, string_tbd); } } // Display result oledDisplayOtherBuffer(); #elif defined(MINI_VERSION) // Variables for scrolling uint8_t string_y_indexes[3]; uint8_t string_extra_chars[3]; uint8_t string_offset_cntrs[3] = {0,0,0}; // Display variables uint8_t approve_selected = TRUE; // Draw asking bitmap oledClear(); miniOledSetMaxTextY(SSD1305_OLED_WIDTH-15); oledBitmapDrawFlash(SSD1305_OLED_WIDTH-15, 0, BITMAP_APPROVE, 0); // Display lines. // Note: line are truncated at the oled driver level when miniOledTextWritingYIncrement is set to FALSE if (nb_args == 1) { miniOledPutCenteredString(THREE_LINE_TEXT_SECOND_POS, (char*)text_object); } else if (nb_args == 2) { string_y_indexes[0] = TWO_LINE_TEXT_FIRST_POS; string_y_indexes[1] = TWO_LINE_TEXT_SECOND_POS; } else { string_y_indexes[0] = THREE_LINE_TEXT_FIRST_POS; string_y_indexes[1] = THREE_LINE_TEXT_SECOND_POS; string_y_indexes[2] = THREE_LINE_TEXT_THIRD_POS; } // For loop to display lines when there is more than one arg if (nb_args > 1) { for (uint8_t i = 0; i < nb_args; i++) { string_extra_chars[i] = strlen(text_object->lines[i]) - miniOledPutCenteredString(string_y_indexes[i], text_object->lines[i]); } } miniOledFlushEntireBufferToDisplay(); miniOledResetMaxTextY(); #endif // In case the display inverted, set it correctly if (flash_flag == TRUE) { activityDetectedRoutine(); oledInvertedDisplay(); timerBased500MsDelay(); oledNormalDisplay(); timerBased500MsDelay(); oledInvertedDisplay(); timerBased500MsDelay(); oledNormalDisplay(); } // Wait for user input #if defined(HARDWARE_OLIVIER_V1) if(getTouchedPositionAnswer(LED_MASK_WHEEL) == TOUCHPOS_RIGHT) { return RETURN_OK; } else { return RETURN_NOK; } #elif defined(MINI_VERSION) RET_TYPE input_answer = MINI_INPUT_RET_NONE; // Switch on lights activityDetectedRoutine(); // Clear possible remaining detection miniWheelClearDetections(); // Arm timer for scrolling (caps timer that isn't relevant here) activateTimer(TIMER_CAPS, SCROLLING_DEL); // Loop while no timeout occurs or no button is pressed while (input_answer == MINI_INPUT_RET_NONE) { input_answer = getYesNoAnswerInput(FALSE); // Text scrolling if ((hasTimerExpired(TIMER_CAPS, TRUE) == TIMER_EXPIRED) && (nb_args > 1)) { miniOledDrawRectangle(0, 0, SSD1305_OLED_WIDTH-15, SSD1305_OLED_HEIGHT, FALSE); activateTimer(TIMER_CAPS, SCROLLING_DEL); miniOledSetMaxTextY(SSD1305_OLED_WIDTH-15); for (uint8_t i = 0; i < nb_args; i++) { if (string_extra_chars[i] > 0) { miniOledPutCenteredString(string_y_indexes[i], (text_object->lines[i]) + string_offset_cntrs[i]); if (string_offset_cntrs[i]++ == string_extra_chars[i]) { string_offset_cntrs[i] = 0; } } else { miniOledPutCenteredString(string_y_indexes[i], text_object->lines[i]); } } miniOledFlushEntireBufferToDisplay(); miniOledResetMaxTextY(); } // Approve / deny display change if (getWheelCurrentIncrement() != 0) { if(approve_selected == FALSE) { oledBitmapDrawFlash(SSD1305_OLED_WIDTH-15, 0, BITMAP_APPROVE, 0); } else { oledBitmapDrawFlash(SSD1305_OLED_WIDTH-15, 0, BITMAP_DENY, 0); } approve_selected = !approve_selected; miniOledFlushEntireBufferToDisplay(); } } if ((input_answer == MINI_INPUT_RET_YES) && (approve_selected != FALSE)) { return RETURN_OK; } else { return RETURN_NOK; } #endif }