Show NFC unlock password
Signed-off-by: Markus Birth <markus@birth-online.de>
This commit is contained in:
@@ -1,4 +1,6 @@
|
||||
#include "../uk_mbirth_sonicare.h"
|
||||
#include "../sonicare_password.h"
|
||||
#include "core/string.h"
|
||||
#include "gui/canvas.h"
|
||||
#include "gui/modules/widget.h"
|
||||
#include "gui/modules/widget_elements/widget_element.h"
|
||||
@@ -7,17 +9,22 @@
|
||||
#include <nfc/nfc_device.h>
|
||||
#include <nfc/protocols/nfc_protocol.h>
|
||||
#include <nfc/protocols/iso14443_3a/iso14443_3a.h>
|
||||
#include "nfc/protocols/mf_ultralight/mf_ultralight.h"
|
||||
#include <nfc/protocols/mf_ultralight/mf_ultralight.h>
|
||||
#include <uk_mbirth_sonicare_icons.h>
|
||||
#include <dolphin/dolphin.h>
|
||||
|
||||
|
||||
void format_bytes(FuriString* str, const uint8_t* data, size_t size) {
|
||||
for(size_t i = 0; i < size; i++) {
|
||||
furi_string_cat_printf(str, " %02X", data[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void format_bytes_reverse(FuriString* str, const uint8_t* data, size_t size) {
|
||||
for(size_t i = size; i > 0; i--) {
|
||||
furi_string_cat_printf(str, " %02X", data[i-1]);
|
||||
}
|
||||
}
|
||||
|
||||
void sonicare_scene_read_complete_widget_callback(GuiButtonType result, InputType type, void* context) {
|
||||
furi_assert(context);
|
||||
Sonicare* app = context;
|
||||
@@ -36,6 +43,7 @@ void sonicare_scene_read_complete_on_enter(void* context) {
|
||||
FURI_LOG_D("sonicare_scene_read_complete", "Pulling Mifare Ultralight data from NFC device");
|
||||
const MfUltralightData* ul_data = app->nfc_data;
|
||||
|
||||
FURI_LOG_D("sonicare_scene_read_complete", "Alloc'ing temp_str for output");
|
||||
FuriString* temp_str = furi_string_alloc();
|
||||
|
||||
furi_string_cat_printf(temp_str, "\e#%s\n", nfc_device_get_name(nfc_device, NfcDeviceNameTypeFull));
|
||||
@@ -45,34 +53,55 @@ void sonicare_scene_read_complete_on_enter(void* context) {
|
||||
format_bytes(temp_str, ul_data->iso14443_3a_data->uid, ul_data->iso14443_3a_data->uid_len);
|
||||
furi_string_cat_printf(temp_str, "\n");
|
||||
|
||||
// Serial#
|
||||
furi_string_cat_str(temp_str, "Ser#: ");
|
||||
// Manufacturing Code
|
||||
furi_string_cat_str(temp_str, "MFG: ");
|
||||
FuriString* serial_no = furi_string_alloc();
|
||||
furi_string_cat_str(serial_no, (char*)(ul_data->page[0x21].data));
|
||||
furi_string_right(serial_no, 2);
|
||||
furi_string_cat(temp_str, serial_no);
|
||||
furi_string_free(serial_no);
|
||||
furi_string_cat_printf(temp_str, "\n");
|
||||
|
||||
// Usage
|
||||
furi_string_cat_printf(temp_str, "Timer:");
|
||||
const uint16_t seconds = ul_data->page[0x24].data[1]*256 + ul_data->page[0x24].data[0];
|
||||
uint16_t seconds = ul_data->page[0x24].data[1]*256 + ul_data->page[0x24].data[0];
|
||||
uint16_t brushes = seconds / 120; // one brush = 2 minutes
|
||||
if (seconds % 120 > 0) {
|
||||
// The official SoniCare app shows "remaining brushes" and if there's not at least
|
||||
// 2 minutes remaining, it doesn't count as a brush. So, let's include
|
||||
// unfinished brushes in the count.
|
||||
brushes++;
|
||||
}
|
||||
const uint8_t hours = seconds / 3600;
|
||||
const uint8_t minutes = (seconds % 3600) / 60;
|
||||
const uint8_t secs = seconds % 60;
|
||||
format_bytes(temp_str, ul_data->page[0x24].data, 4);
|
||||
furi_string_cat_printf(temp_str, "\n");
|
||||
furi_string_cat_printf(temp_str, "Usage: %u brushes (%u:%02u:%02u)\n", (int)brushes, (int)hours, (int)minutes, (int)secs);
|
||||
seconds %= 3600;
|
||||
const uint8_t minutes = seconds / 60;
|
||||
seconds %= 60;
|
||||
furi_string_cat_printf(temp_str, "Usage: %u brushes (%u:%02u:%02u)\n", (int)brushes, (int)hours, (int)minutes, (int)seconds);
|
||||
|
||||
// Max Usage
|
||||
uint16_t max_seconds = ul_data->page[0x21].data[1]*256 + ul_data->page[0x21].data[0];
|
||||
const uint16_t max_brushes = max_seconds / 120;
|
||||
const uint8_t max_hours = max_seconds / 3600;
|
||||
max_seconds %= 3600;
|
||||
const uint8_t max_minutes = max_seconds / 60;
|
||||
max_seconds %= 60;
|
||||
furi_string_cat_printf(temp_str, "Max: %u brushes (%u:%02u:%02u)\n", (int)max_brushes, (int)max_hours, (int)max_minutes, (int)max_seconds);
|
||||
|
||||
// TODO: Maybe show "replace soon" marker if 170 brushes or more?
|
||||
// TODO: Maybe show "replace head" marker if 180 brushes or more?
|
||||
|
||||
// NFC password
|
||||
uint32_t unlock_pwd_big = get_sonicare_password((uint8_t*)ul_data->iso14443_3a_data->uid, (uint8_t*)furi_string_get_cstr(serial_no));
|
||||
FURI_LOG_D("sonicare_scene_read_complete", "NFC unlock password: %04lx", unlock_pwd_big);
|
||||
uint8_t unlock_pwd[4];
|
||||
memcpy(unlock_pwd, &unlock_pwd_big, sizeof(unlock_pwd_big));
|
||||
furi_string_cat_printf(temp_str, "NFC pwd:");
|
||||
format_bytes_reverse(temp_str, unlock_pwd, 4);
|
||||
furi_string_cat_printf(temp_str, "\n");
|
||||
|
||||
// Output to widget
|
||||
widget_add_text_scroll_element(widget, 0, 0, 128, 64, furi_string_get_cstr(temp_str));
|
||||
|
||||
furi_string_free(temp_str);
|
||||
furi_string_free(serial_no);
|
||||
|
||||
widget_add_button_element(widget, GuiButtonTypeRight, "Change", sonicare_scene_read_complete_widget_callback, app);
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, SonicareViewWidget);
|
||||
|
||||
+13
-3
@@ -1,7 +1,8 @@
|
||||
// Thanks to atc1441
|
||||
// https://gist.github.com/atc1441/41af75048e4c22af1f5f0d4c1d94bb56
|
||||
|
||||
#include <stdint.h>
|
||||
#include "uk_mbirth_sonicare.h"
|
||||
#include <dolphin/dolphin.h>
|
||||
|
||||
uint16_t CRC16(uint16_t crc, uint8_t *buffer, int len) // Default CRC16 Algo
|
||||
{
|
||||
@@ -25,11 +26,20 @@ uint16_t CRC16(uint16_t crc, uint8_t *buffer, int len) // Default CRC16 Algo
|
||||
//uint8_t nfc_second[] = "221214 12K"; // Head MFG String, printed on Head and at memory location 0x23
|
||||
|
||||
uint32_t get_sonicare_password(uint8_t nfctag_uid[], uint8_t nfc_second[]) {
|
||||
for (uint16_t i=0; i<7; i++) {
|
||||
FURI_LOG_D("sonicare_password", "Input UID byte %i: %02x", i, nfctag_uid[i]);
|
||||
}
|
||||
for (uint16_t i=0; i<10; i++) {
|
||||
FURI_LOG_D("sonicare_password", "Input MFG byte %i: %02x", i, nfc_second[i]);
|
||||
}
|
||||
uint32_t crc_calc = CRC16(0x49A3, nfctag_uid, 7); // Calculate the NTAG UID CRC
|
||||
|
||||
FURI_LOG_D("sonicare_password", "CRC16 of UID: %04lx", crc_calc);
|
||||
|
||||
crc_calc = crc_calc | (CRC16(crc_calc, nfc_second, 10) << 16); // Calculate the MFG CRC
|
||||
FURI_LOG_D("sonicare_password", "CRC16 with MFG: %04lx", crc_calc);
|
||||
|
||||
crc_calc = ((((crc_calc >> 8) & 0x00FF00FF) | (crc_calc << 8)) & 0xFF00FF00); // Rotate the uin16_t bytes
|
||||
crc_calc = ((crc_calc >> 8) & 0x00FF00FF) | ((crc_calc << 8) & 0xFF00FF00); // Rotate the uin16_t bytes
|
||||
FURI_LOG_D("sonicare_password", "Final CRC16: %04lx", crc_calc);
|
||||
|
||||
return crc_calc;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
#include <dolphin/dolphin.h>
|
||||
|
||||
uint32_t get_sonicare_password(uint8_t nfctag_uid[], uint8_t nfc_second[]);
|
||||
Reference in New Issue
Block a user