You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1916 lines
59 KiB
1916 lines
59 KiB
// SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. <hello@foundationdevices.com>
|
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
//
|
|
// MP C foundation module, supports LCD, backlight, keypad and other devices as they are added
|
|
|
|
#include "py/builtin.h"
|
|
#include "py/obj.h"
|
|
#include "py/runtime.h"
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <math.h>
|
|
|
|
#include "bufhelper.h"
|
|
|
|
/* ADC related includes */
|
|
#include "adc.h"
|
|
|
|
// LCD related includes
|
|
#include "backlight.h"
|
|
#include "lcd-sharp-ls018B7dh02.h"
|
|
#include "spi.h"
|
|
|
|
// Keypad related includes
|
|
#include "keypad-adp-5587.h"
|
|
#include "py/objstr.h"
|
|
#include "ring_buffer.h"
|
|
|
|
// Camera related includes
|
|
#include "camera-ovm7690.h"
|
|
#include "image_conversion.h"
|
|
|
|
// QR related incldues
|
|
#include "quirc_internal.h"
|
|
|
|
// Main module includes
|
|
#include "modfoundation.h"
|
|
|
|
// BIP39 includes
|
|
#include "bip39_utils.h"
|
|
|
|
// QRCode includes
|
|
#include "qrcode.h"
|
|
|
|
#include "adc.h"
|
|
#include "busy_bar.h"
|
|
#include "dispatch.h"
|
|
#include "display.h"
|
|
#include "flash.h"
|
|
#include "frequency.h"
|
|
#include "fwheader.h"
|
|
#include "firmware-keys.h"
|
|
#include "gpio.h"
|
|
#include "pprng.h"
|
|
#include "se.h"
|
|
#include "stm32h7xx_hal.h"
|
|
#include "utils.h"
|
|
#include "sha256.h"
|
|
#include "se-config.h"
|
|
#include "pins.h"
|
|
#include "uECC.h"
|
|
#include "hash.h"
|
|
|
|
/* lcd class object, expand as needed with instance related details */
|
|
typedef struct _mp_obj_lcd_t
|
|
{
|
|
mp_obj_base_t base;
|
|
const spi_t* spi;
|
|
|
|
} mp_obj_lcd_t;
|
|
|
|
/* Backlight class object */
|
|
typedef struct _mp_obj_backlight_t
|
|
{
|
|
mp_obj_base_t base;
|
|
} mp_obj_backlight_t;
|
|
|
|
/* keypad class object */
|
|
typedef struct _mp_obj_keypad_t
|
|
{
|
|
mp_obj_base_t base;
|
|
} mp_obj_keypad_t;
|
|
|
|
/* Camera class object */
|
|
typedef struct _mp_obj_camera_t
|
|
{
|
|
mp_obj_base_t base;
|
|
} mp_obj_camera_t;
|
|
|
|
/* Board Revision object */
|
|
typedef struct _mp_obj_boardrev_t
|
|
{
|
|
mp_obj_base_t base;
|
|
} mp_obj_boardrev_t;
|
|
|
|
/* Power Monitor object */
|
|
typedef struct _mp_obj_powermon_t
|
|
{
|
|
mp_obj_base_t base;
|
|
uint16_t current;
|
|
uint16_t voltage;
|
|
} mp_obj_powermon_t;
|
|
|
|
/* Noise Output object */
|
|
typedef struct _mp_obj_noise_t
|
|
{
|
|
mp_obj_base_t base;
|
|
} mp_obj_noise_t;
|
|
|
|
/* QR decoder class object */
|
|
typedef struct _mp_obj_QR_t
|
|
{
|
|
mp_obj_base_t base;
|
|
struct quirc quirc;
|
|
unsigned int width;
|
|
unsigned int height;
|
|
} mp_obj_QR_t;
|
|
|
|
/* Internal flash class object */
|
|
typedef struct _mp_obj_SettingsFlash_t
|
|
{
|
|
mp_obj_base_t base;
|
|
} mp_obj_SettingsFlash_t;
|
|
|
|
/* System class object */
|
|
typedef struct _mp_obj_System_t
|
|
{
|
|
mp_obj_base_t base;
|
|
} mp_obj_System_t;
|
|
|
|
/* bip39 class object */
|
|
typedef struct _mp_obj_bip39_t
|
|
{
|
|
mp_obj_base_t base;
|
|
} mp_obj_bip39_t;
|
|
|
|
/* QRCode class object */
|
|
typedef struct _mp_obj_QRCode_t
|
|
{
|
|
mp_obj_base_t base;
|
|
QRCode code;
|
|
} mp_obj_QRCode_t;
|
|
|
|
// Defines
|
|
#define QR_IMAGE_SIZE (396 * 330)
|
|
#define VIEWFINDER_IMAGE_SIZE ((240 * 240) / 8)
|
|
|
|
#define SETTINGS_FLASH_START 0x81E0000
|
|
#define SETTINGS_FLASH_SIZE 0x20000
|
|
#define SETTINGS_FLASH_END (SETTINGS_FLASH_START + SETTINGS_FLASH_SIZE - 1)
|
|
|
|
// Forward prototypes
|
|
void
|
|
turbo(bool enable);
|
|
|
|
/*=============================================================================
|
|
* Start of keypad class
|
|
*=============================================================================*/
|
|
STATIC mp_obj_t
|
|
keypad_make_new(const mp_obj_type_t* type, size_t n_args, size_t n_kw, const mp_obj_t* args)
|
|
{
|
|
mp_obj_keypad_t* keypad = m_new_obj(mp_obj_keypad_t);
|
|
keypad->base.type = type;
|
|
|
|
keypad_init();
|
|
return MP_OBJ_FROM_PTR(keypad);
|
|
}
|
|
|
|
STATIC mp_obj_t
|
|
keypad_get_keycode(mp_obj_t self)
|
|
{
|
|
uint8_t buf[1];
|
|
|
|
if (ring_buffer_dequeue(&buf[0]) == 0) {
|
|
return mp_const_none;
|
|
}
|
|
// printf("keypad.get_keycode() 2: %d\n", buf[0]);
|
|
return mp_obj_new_int_from_uint(buf[0]);
|
|
}
|
|
STATIC MP_DEFINE_CONST_FUN_OBJ_1(keypad_get_keycode_obj, keypad_get_keycode);
|
|
|
|
STATIC mp_obj_t
|
|
keypad___del__(mp_obj_t self)
|
|
{
|
|
return mp_const_none;
|
|
}
|
|
|
|
STATIC MP_DEFINE_CONST_FUN_OBJ_1(keypad___del___obj, keypad___del__);
|
|
|
|
STATIC const mp_rom_map_elem_t keypad_locals_dict_table[] = {
|
|
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_foundation) },
|
|
{ MP_ROM_QSTR(MP_QSTR_get_keycode), MP_ROM_PTR(&keypad_get_keycode_obj) },
|
|
{ MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&keypad___del___obj) },
|
|
};
|
|
STATIC MP_DEFINE_CONST_DICT(keypad_locals_dict, keypad_locals_dict_table);
|
|
|
|
const mp_obj_type_t keypad_type = {
|
|
{ &mp_type_type },
|
|
.name = MP_QSTR_Keypad,
|
|
.make_new = keypad_make_new,
|
|
.locals_dict = (void*)&keypad_locals_dict,
|
|
};
|
|
|
|
/* End of Keypad class code */
|
|
|
|
/*=============================================================================
|
|
* Start of LCD class
|
|
*=============================================================================*/
|
|
void
|
|
lcd_obj_print(const mp_print_t* print, mp_obj_t self_in, mp_print_kind_t kind)
|
|
{
|
|
mp_printf(print, "foundation obj print");
|
|
}
|
|
|
|
/* Instantiation */
|
|
|
|
/// def __init__(self, mode: int, key: bytes, iv: bytes = None) -> None:
|
|
/// '''
|
|
/// Initialize LCD object context. Return a MP LCD object
|
|
/// '''
|
|
STATIC mp_obj_t
|
|
lcd_obj_make_new(const mp_obj_type_t* type, size_t n_args, size_t n_kw, const mp_obj_t* args)
|
|
{
|
|
mp_obj_lcd_t* lcd = m_new_obj(mp_obj_lcd_t);
|
|
lcd->base.type = &lcd_type;
|
|
lcd->spi = &spi_obj[0];
|
|
// lcd_init(false);
|
|
return MP_OBJ_FROM_PTR(lcd);
|
|
}
|
|
|
|
/* LCD object methods follow */
|
|
STATIC mp_obj_t
|
|
m_lcd_clear(mp_obj_t self_in, mp_obj_t invert_obj)
|
|
{
|
|
uint8_t invert = mp_obj_get_int(invert_obj);
|
|
lcd_clear(invert);
|
|
return mp_const_none;
|
|
}
|
|
STATIC MP_DEFINE_CONST_FUN_OBJ_2(m_lcd_clear_obj, m_lcd_clear);
|
|
|
|
STATIC mp_obj_t
|
|
m_lcd_update(mp_obj_t self_in, mp_obj_t lcd_data)
|
|
{
|
|
mp_uint_t interrupt_state;
|
|
mp_buffer_info_t data_info;
|
|
// Get the buffer info from the passed in object
|
|
mp_get_buffer_raise(lcd_data, &data_info, MP_BUFFER_READ);
|
|
|
|
interrupt_state = PASSPORT_KEYPAD_BEGIN_ATOMIC_SECTION();
|
|
lcd_update(data_info.buf, true);
|
|
PASSPORT_KEYPAD_END_ATOMIC_SECTION(interrupt_state);
|
|
|
|
return mp_const_none;
|
|
}
|
|
STATIC MP_DEFINE_CONST_FUN_OBJ_2(m_lcd_update_obj, m_lcd_update);
|
|
|
|
STATIC mp_obj_t
|
|
foundation___del__(mp_obj_t self)
|
|
{
|
|
lcd_deinit();
|
|
return mp_const_none;
|
|
}
|
|
STATIC MP_DEFINE_CONST_FUN_OBJ_1(foundation___del___obj, foundation___del__);
|
|
|
|
/* End of LCD object methods */
|
|
|
|
/*
|
|
* Class Locals Dictionary table for LCD class
|
|
*/
|
|
STATIC const mp_rom_map_elem_t lcd_locals_dict_table[] = {
|
|
{ MP_ROM_QSTR(MP_QSTR_clear), MP_ROM_PTR(&m_lcd_clear_obj) },
|
|
{ MP_ROM_QSTR(MP_QSTR_update), MP_ROM_PTR(&m_lcd_update_obj) },
|
|
};
|
|
STATIC MP_DEFINE_CONST_DICT(lcd_locals_dict, lcd_locals_dict_table);
|
|
|
|
const mp_obj_type_t lcd_type = {
|
|
{ &mp_type_type },
|
|
.name = MP_QSTR_LCD,
|
|
.print = lcd_obj_print,
|
|
.make_new = lcd_obj_make_new,
|
|
.locals_dict = (mp_obj_dict_t*)&lcd_locals_dict,
|
|
};
|
|
/* End of setup for LCD class */
|
|
|
|
/*=============================================================================
|
|
* Start of backlight class
|
|
*=============================================================================*/
|
|
STATIC mp_obj_t
|
|
backlight_obj_make_new(const mp_obj_type_t* type, size_t n_args, size_t n_kw, const mp_obj_t* args)
|
|
{
|
|
mp_obj_backlight_t* backlight = m_new_obj(mp_obj_backlight_t);
|
|
backlight->base.type = &backlight_type;
|
|
backlight_minimal_init();
|
|
return MP_OBJ_FROM_PTR(backlight);
|
|
}
|
|
|
|
/* LCD object methods follow */
|
|
STATIC mp_obj_t
|
|
m_backlight_intensity(mp_obj_t self_in, mp_obj_t intensity_obj)
|
|
{
|
|
uint16_t intensity = mp_obj_get_int(intensity_obj);
|
|
backlight_intensity(intensity);
|
|
|
|
return mp_const_none;
|
|
}
|
|
STATIC MP_DEFINE_CONST_FUN_OBJ_2(m_backlight_intensity_obj, m_backlight_intensity);
|
|
|
|
/*
|
|
* Class Locals Dictionary table for Backlight class
|
|
*/
|
|
STATIC const mp_rom_map_elem_t backlight_locals_dict_table[] = {
|
|
{ MP_ROM_QSTR(MP_QSTR_intensity), MP_ROM_PTR(&m_backlight_intensity_obj) },
|
|
};
|
|
STATIC MP_DEFINE_CONST_DICT(backlight_locals_dict, backlight_locals_dict_table);
|
|
|
|
const mp_obj_type_t backlight_type = {
|
|
{ &mp_type_type },
|
|
.name = MP_QSTR_Backlight,
|
|
// .print = lcd_obj_print,
|
|
.make_new = backlight_obj_make_new,
|
|
.locals_dict = (mp_obj_dict_t*)&backlight_locals_dict,
|
|
};
|
|
/* End of setup for Backlight class */
|
|
|
|
/*=============================================================================
|
|
* Start of Camera class
|
|
*=============================================================================*/
|
|
STATIC mp_obj_t
|
|
camera_make_new(const mp_obj_type_t* type, size_t n_args, size_t n_kw, const mp_obj_t* args)
|
|
{
|
|
mp_obj_camera_t* o = m_new_obj(mp_obj_camera_t);
|
|
o->base.type = type;
|
|
|
|
return MP_OBJ_FROM_PTR(o);
|
|
}
|
|
|
|
/// def enable(self, data: buffer) -> None
|
|
/// '''
|
|
/// Turn on the camera in preparation for calling snapshot().
|
|
/// '''
|
|
STATIC mp_obj_t
|
|
camera_enable(mp_obj_t self)
|
|
{
|
|
camera_on();
|
|
return mp_const_none;
|
|
}
|
|
|
|
/// def disable(self, data: buffer) -> None
|
|
/// '''
|
|
/// Turn off the camera.
|
|
/// '''
|
|
STATIC mp_obj_t
|
|
camera_disable(mp_obj_t self)
|
|
{
|
|
camera_off();
|
|
return mp_const_none;
|
|
}
|
|
|
|
/// def snapshot(self, image: buffer) -> BoolG
|
|
/// '''
|
|
/// Start a snapshot and wait for it to finish, then convert and copy it into the provided image buffers.
|
|
/// '''
|
|
STATIC mp_obj_t
|
|
camera_snapshot_(size_t n_args, const mp_obj_t* args)
|
|
{
|
|
mp_buffer_info_t qr_image_info;
|
|
mp_get_buffer_raise(args[1], &qr_image_info, MP_BUFFER_WRITE);
|
|
uint16_t qr_w = mp_obj_get_int(args[2]);
|
|
uint16_t qr_h = mp_obj_get_int(args[3]);
|
|
if (qr_image_info.len != qr_w * qr_h) {
|
|
printf("ERROR: QR buffer w/h not consistent with buffer size!\n");
|
|
return mp_const_false;
|
|
}
|
|
if (qr_image_info.len != QR_IMAGE_SIZE) {
|
|
printf("ERROR: QR buffer is the wrong size!\n");
|
|
return mp_const_false;
|
|
}
|
|
|
|
mp_buffer_info_t viewfinder_image_info;
|
|
mp_get_buffer_raise(args[4], &viewfinder_image_info, MP_BUFFER_WRITE);
|
|
uint16_t viewfinder_w = mp_obj_get_int(args[5]);
|
|
uint16_t viewfinder_h = mp_obj_get_int(args[6]);
|
|
if (viewfinder_image_info.len != viewfinder_w * viewfinder_h / 8) {
|
|
printf("ERROR: Viewfinder buffer w/h not consistent with buffer size!\n");
|
|
return mp_const_false;
|
|
}
|
|
if (viewfinder_w > qr_w || viewfinder_h > qr_h) {
|
|
// Viewfinder can't be larger than base image
|
|
printf("ERROR: Viewfinder buffer is larger than QR buffer!\n");
|
|
return mp_const_false;
|
|
}
|
|
|
|
if (camera_snapshot() < 0) {
|
|
return mp_const_false;
|
|
}
|
|
|
|
uint16_t* rgb565 = camera_get_frame_buffer();
|
|
|
|
//uint32_t start = HAL_GetTick();
|
|
convert_rgb565_to_grayscale_and_mono(
|
|
rgb565, qr_image_info.buf, qr_w, qr_h, viewfinder_image_info.buf, viewfinder_w, viewfinder_h);
|
|
//uint32_t end = HAL_GetTick();
|
|
//printf("conversion: %lums\n", end - start);
|
|
return mp_const_true;
|
|
}
|
|
|
|
STATIC mp_obj_t
|
|
camera_get_line_data(mp_obj_t self_in, mp_obj_t line, mp_obj_t _line_num)
|
|
{
|
|
// Get the buffer info from the passed in object
|
|
mp_buffer_info_t line_info;
|
|
mp_get_buffer_raise(line, &line_info, MP_BUFFER_WRITE);
|
|
|
|
int line_num = mp_obj_get_int(_line_num);
|
|
if (line_num < 0 || line_num >= CAMERA_HEIGHT || line_info.len < CAMERA_WIDTH * 2) {
|
|
printf("line_num = %d line_info.len = %u\n", line_num, line_info.len);
|
|
return mp_const_false;
|
|
}
|
|
|
|
uint16_t* rgb565 = camera_get_frame_buffer();
|
|
|
|
uint32_t pixels_per_line = CAMERA_WIDTH;
|
|
|
|
memcpy(line_info.buf, rgb565 + (line_num * pixels_per_line), pixels_per_line * 2); // Two bytes per pixel
|
|
|
|
return mp_const_true;
|
|
}
|
|
|
|
STATIC MP_DEFINE_CONST_FUN_OBJ_1(camera_enable_obj, camera_enable);
|
|
STATIC MP_DEFINE_CONST_FUN_OBJ_1(camera_disable_obj, camera_disable);
|
|
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(camera_snapshot_obj, 7, 7, camera_snapshot_);
|
|
STATIC MP_DEFINE_CONST_FUN_OBJ_3(camera_get_line_data_obj, camera_get_line_data);
|
|
|
|
STATIC mp_obj_t
|
|
camera___del__(mp_obj_t self)
|
|
{
|
|
// mp_obj_camera_t *o = MP_OBJ_TO_PTR(self);
|
|
return mp_const_none;
|
|
}
|
|
|
|
STATIC MP_DEFINE_CONST_FUN_OBJ_1(camera___del___obj, camera___del__);
|
|
|
|
STATIC const mp_rom_map_elem_t camera_locals_dict_table[] = {
|
|
{ MP_ROM_QSTR(MP_QSTR___name__),
|
|
MP_ROM_QSTR(MP_QSTR_foundation) },
|
|
{ MP_ROM_QSTR(MP_QSTR_enable), MP_ROM_PTR(&camera_enable_obj) },
|
|
{ MP_ROM_QSTR(MP_QSTR_disable), MP_ROM_PTR(&camera_disable_obj) },
|
|
{ MP_ROM_QSTR(MP_QSTR_snapshot), MP_ROM_PTR(&camera_snapshot_obj) },
|
|
{ MP_ROM_QSTR(MP_QSTR_get_line_data), MP_ROM_PTR(&camera_get_line_data_obj) },
|
|
{ MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&camera___del___obj) },
|
|
};
|
|
STATIC MP_DEFINE_CONST_DICT(camera_locals_dict, camera_locals_dict_table);
|
|
|
|
STATIC const mp_obj_type_t camera_type = {
|
|
{ &mp_type_type },
|
|
.name = MP_QSTR_camera,
|
|
.make_new = camera_make_new,
|
|
.locals_dict = (void*)&camera_locals_dict,
|
|
};
|
|
/* End of setup for Camera class */
|
|
|
|
/*=============================================================================
|
|
* Start of Power Monitor class
|
|
*=============================================================================*/
|
|
|
|
STATIC mp_obj_t
|
|
mod_foundation_powermon_make_new(const mp_obj_type_t* type, size_t n_args, size_t n_kw, const mp_obj_t* args)
|
|
{
|
|
mp_obj_powermon_t* powermon = m_new_obj(mp_obj_powermon_t);
|
|
powermon->base.type = type;
|
|
|
|
return MP_OBJ_FROM_PTR(powermon);
|
|
}
|
|
|
|
STATIC mp_obj_t
|
|
mod_foundation_powermon_read(mp_obj_t self)
|
|
{
|
|
int ret;
|
|
uint16_t current = 0;
|
|
uint16_t voltage = 0;
|
|
mp_obj_t tuple[2];
|
|
|
|
mp_obj_powermon_t* pPowerMon = (mp_obj_powermon_t*)self;
|
|
|
|
ret = adc_read_powermon(¤t, &voltage);
|
|
if (ret < 0) {
|
|
tuple[0] = mp_const_none;
|
|
tuple[1] = mp_const_none;
|
|
return mp_obj_new_tuple(2, tuple);
|
|
}
|
|
pPowerMon->current = current;
|
|
pPowerMon->voltage = voltage;
|
|
|
|
tuple[0] = mp_obj_new_int_from_uint(current);
|
|
tuple[1] = mp_obj_new_int_from_uint(voltage);
|
|
return mp_obj_new_tuple(2, tuple);
|
|
}
|
|
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_foundation_powermon_read_obj, mod_foundation_powermon_read);
|
|
|
|
STATIC mp_obj_t
|
|
mod_foundation_powermon___del__(mp_obj_t self)
|
|
{
|
|
return mp_const_none;
|
|
}
|
|
|
|
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_foundation_powermon___del___obj, mod_foundation_powermon___del__);
|
|
|
|
STATIC const mp_rom_map_elem_t mod_foundation_powermon_locals_dict_table[] = {
|
|
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_foundation) },
|
|
{ MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mod_foundation_powermon_read_obj) },
|
|
{ MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&mod_foundation_powermon___del___obj) },
|
|
};
|
|
STATIC MP_DEFINE_CONST_DICT(mod_foundation_powermon_locals_dict, mod_foundation_powermon_locals_dict_table);
|
|
|
|
const mp_obj_type_t powermon_type = {
|
|
{ &mp_type_type },
|
|
.name = MP_QSTR_PMon,
|
|
.make_new = mod_foundation_powermon_make_new,
|
|
.locals_dict = (void*)&mod_foundation_powermon_locals_dict,
|
|
};
|
|
|
|
/* End of power monitor class */
|
|
|
|
/*=============================================================================
|
|
* Start of Board Revision class
|
|
*=============================================================================*/
|
|
STATIC mp_obj_t
|
|
mod_foundation_boardrev_make_new(const mp_obj_type_t* type, size_t n_args, size_t n_kw, const mp_obj_t* args)
|
|
{
|
|
mp_obj_boardrev_t* boardrev = m_new_obj(mp_obj_boardrev_t);
|
|
boardrev->base.type = type;
|
|
|
|
return MP_OBJ_FROM_PTR(boardrev);
|
|
}
|
|
|
|
STATIC mp_obj_t
|
|
mod_foundation_boardrev_read(mp_obj_t self)
|
|
{
|
|
HAL_StatusTypeDef ret;
|
|
uint16_t board_rev = 0;
|
|
|
|
ret = adc_read_boardrev(&board_rev);
|
|
if (ret < 0) {
|
|
return mp_const_none;
|
|
}
|
|
return mp_obj_new_int_from_uint(board_rev);
|
|
}
|
|
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_foundation_boardrev_read_obj, mod_foundation_boardrev_read);
|
|
|
|
STATIC mp_obj_t
|
|
mod_foundation_boardrev___del__(mp_obj_t self)
|
|
{
|
|
return mp_const_none;
|
|
}
|
|
|
|
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_foundation_boardrev___del___obj, mod_foundation_boardrev___del__);
|
|
|
|
STATIC const mp_rom_map_elem_t mod_foundation_boardrev_locals_dict_table[] = {
|
|
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_foundation) },
|
|
{ MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mod_foundation_boardrev_read_obj) },
|
|
{ MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&mod_foundation_boardrev___del___obj) },
|
|
};
|
|
|
|
STATIC MP_DEFINE_CONST_DICT(mod_foundation_boardrev_locals_dict, mod_foundation_boardrev_locals_dict_table);
|
|
|
|
const mp_obj_type_t boardrev_type = {
|
|
{ &mp_type_type },
|
|
.name = MP_QSTR_Bdrev,
|
|
.make_new = mod_foundation_boardrev_make_new,
|
|
.locals_dict = (void*)&mod_foundation_boardrev_locals_dict,
|
|
};
|
|
|
|
/* End of board revision class */
|
|
|
|
/*=============================================================================
|
|
* Start of Noise Output class
|
|
*=============================================================================*/
|
|
|
|
STATIC mp_obj_t
|
|
mod_foundation_noise_make_new(const mp_obj_type_t* type, size_t n_args, size_t n_kw, const mp_obj_t* args)
|
|
{
|
|
mp_obj_noise_t* noise = m_new_obj(mp_obj_noise_t);
|
|
noise->base.type = type;
|
|
/*
|
|
* Need to enable the noise amp enables.
|
|
*/
|
|
adc_enable_noise();
|
|
|
|
return MP_OBJ_FROM_PTR(noise);
|
|
}
|
|
|
|
STATIC mp_obj_t
|
|
mod_foundation_noise_read(mp_obj_t self)
|
|
{
|
|
HAL_StatusTypeDef ret;
|
|
uint32_t noise1 = 0;
|
|
uint32_t noise2 = 0;
|
|
mp_obj_t tuple[2];
|
|
|
|
ret = adc_read_noise_inputs(&noise1, &noise2);
|
|
if (ret < 0) {
|
|
tuple[0] = mp_const_none;
|
|
tuple[1] = mp_const_none;
|
|
return mp_obj_new_tuple(2, tuple);
|
|
}
|
|
|
|
tuple[0] = mp_obj_new_int_from_uint(noise1);
|
|
tuple[1] = mp_obj_new_int_from_uint(noise2);
|
|
return mp_obj_new_tuple(2, tuple);
|
|
}
|
|
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_foundation_noise_read_obj, mod_foundation_noise_read);
|
|
|
|
bool
|
|
get_random_uint16(uint16_t* result)
|
|
{
|
|
HAL_StatusTypeDef ret;
|
|
uint32_t noise1 = 0;
|
|
uint32_t noise2 = 0;
|
|
uint16_t r = 0;
|
|
|
|
for (int i = 0; i < 4; i++) {
|
|
r = r << 4;
|
|
|
|
HAL_Delay(1);
|
|
|
|
ret = adc_read_noise_inputs(&noise1, &noise2);
|
|
if (ret < 0) {
|
|
return false;
|
|
}
|
|
|
|
r ^= noise1 ^ noise2;
|
|
}
|
|
*result = r;
|
|
return true;
|
|
}
|
|
|
|
// Flags to select which entroy sources to combine
|
|
#define AVALANCHE_SOURCE 1
|
|
#define MCU_RNG_SOURCE 2
|
|
#define SE_RNG_SOURCE 4
|
|
#define ALS_SOURCE 8
|
|
|
|
// Function to combine multiple sources of randomness together
|
|
STATIC mp_obj_t
|
|
mod_foundation_noise_random_bytes(mp_obj_t self, const mp_obj_t buf, mp_obj_t _sources)
|
|
{
|
|
mp_buffer_info_t buf_info;
|
|
mp_get_buffer_raise(buf, &buf_info, MP_BUFFER_WRITE);
|
|
|
|
// Buffer must be at least 4 bytes - if less is needed, caller can extract 1-3 bytes from a 4-byte buffer.
|
|
if (buf_info.len < 4) {
|
|
return false;
|
|
}
|
|
|
|
// Need to be fast for this
|
|
turbo(true);
|
|
|
|
int sources = mp_obj_get_int(_sources);
|
|
// printf("sources = 0x%02x buf_info.len=%d\n", sources, buf_info.len);
|
|
if (!(sources & AVALANCHE_SOURCE) && !(sources & MCU_RNG_SOURCE) && !(sources & SE_RNG_SOURCE)) {
|
|
// printf("Bad sources, so picking Avalanche!\n");
|
|
// Ensure we always use at least one high entropy source even if caller made a mistake.
|
|
// If you just want als value, you can read it separately.
|
|
sources |= AVALANCHE_SOURCE;
|
|
}
|
|
|
|
if (sources & AVALANCHE_SOURCE) {
|
|
uint8_t* pbuf8 = (uint8_t*)buf_info.buf;
|
|
for (int i = 0; i < buf_info.len;) {
|
|
uint8_t sample[2];
|
|
bool result = get_random_uint16((uint16_t*)sample);
|
|
if (!result) {
|
|
turbo(false);
|
|
// printf("failed to get Avalanche sample!\n");
|
|
return mp_const_false;
|
|
}
|
|
|
|
// printf("AVALANCHE SAMPLE: 0x%02x%02x\n", sample[0], sample[1]);
|
|
if (i < buf_info.len) {
|
|
pbuf8[i] = sample[0];
|
|
i++;
|
|
}
|
|
if (i < buf_info.len) {
|
|
pbuf8[i] = sample[1];
|
|
i++;
|
|
}
|
|
}
|
|
}
|
|
|
|
// MCU RNG
|
|
if (sources & MCU_RNG_SOURCE) {
|
|
// printf("Using MCU source\n");
|
|
uint32_t* pbuf32 = (uint32_t*)buf_info.buf;
|
|
|
|
// NOTE: We don't sample and mixin additional entropy into the final 1-3 bytes if buffer size
|
|
// is not a multiple of 4 bytes.
|
|
for (int i = 0; i < buf_info.len / 4; i++) {
|
|
uint32_t sample = rng_sample();
|
|
// printf("MCU SAMPLE: 0x%08lx\n", sample);
|
|
// XOR in the sample
|
|
*(pbuf32 + i) ^= sample;
|
|
}
|
|
}
|
|
|
|
// Secure Element RNG
|
|
if (sources & SE_RNG_SOURCE) {
|
|
uint8_t* pbuf8 = (uint8_t*)buf_info.buf;
|
|
uint8_t* pbuf8_end = pbuf8 + buf_info.len;
|
|
uint8_t num_in[20], sample[32];
|
|
memset(num_in, 0, 20);
|
|
|
|
for (int i = 0; i < buf_info.len / 32; i++) {
|
|
int rc = se_pick_nonce(num_in, sample);
|
|
if (rc < 0) {
|
|
se_show_error();
|
|
turbo(false);
|
|
return mp_const_false;
|
|
}
|
|
|
|
// uint32_t* s = (uint32_t*)sample;
|
|
// printf("SE SAMPLE: 0x%08lx %08lx %08lx %08lx\n", *s, *(s+1), *(s+2), *(s+3));
|
|
|
|
// Mixin the sample values - don't overflow output buffer
|
|
xor_mixin(pbuf8, sample, MIN(pbuf8_end - pbuf8, 32));
|
|
pbuf8 += 32;
|
|
}
|
|
}
|
|
|
|
// printf("1 buf: ");
|
|
// uint8_t* pbuf8 = (uint8_t*)buf_info.buf;
|
|
// for (int i=0; i<buf_info.len; i++) {
|
|
// printf("%02x", pbuf8[i]);
|
|
// }
|
|
// printf("\n");
|
|
|
|
// Ambient Light Sensor
|
|
if (sources & ALS_SOURCE) {
|
|
// printf("Using ALS source\n");
|
|
uint16_t* pbuf16 = (uint16_t*)buf_info.buf;
|
|
|
|
// Pick a random offset at which to insert the
|
|
uint16_t rnd_offset = rng_sample() % (buf_info.len / 2 - 2);
|
|
// printf("als rnd_offset=%d\n", rnd_offset);
|
|
|
|
// Just mix in one sample since it's not likely to vary by much sampled close together in time
|
|
uint16_t sample;
|
|
adc_read_als(&sample);
|
|
// printf("als sample=0x%04x\n", sample);
|
|
*(pbuf16 + rnd_offset) ^= sample;
|
|
}
|
|
|
|
// TODO: check final result for basic randomness
|
|
|
|
// print_hex_buf("Final buf: ", buf_info.buf, buf_info.len);
|
|
|
|
turbo(false);
|
|
return mp_const_true;
|
|
}
|
|
STATIC MP_DEFINE_CONST_FUN_OBJ_3(mod_foundation_noise_random_bytes_obj, mod_foundation_noise_random_bytes);
|
|
|
|
STATIC mp_obj_t
|
|
mod_foundation_noise___del__(mp_obj_t self)
|
|
{
|
|
adc_disable_noise();
|
|
return mp_const_none;
|
|
}
|
|
|
|
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_foundation_noise___del___obj, mod_foundation_noise___del__);
|
|
|
|
STATIC const mp_rom_map_elem_t mod_foundation_noise_locals_dict_table[] = {
|
|
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_foundation) },
|
|
{ MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mod_foundation_noise_read_obj) },
|
|
{ MP_ROM_QSTR(MP_QSTR_random_bytes), MP_ROM_PTR(&mod_foundation_noise_random_bytes_obj) },
|
|
{ MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&mod_foundation_noise___del___obj) },
|
|
};
|
|
STATIC MP_DEFINE_CONST_DICT(mod_foundation_noise_locals_dict, mod_foundation_noise_locals_dict_table);
|
|
|
|
const mp_obj_type_t noise_type = {
|
|
{ &mp_type_type },
|
|
.name = MP_QSTR_PMon,
|
|
.make_new = mod_foundation_noise_make_new,
|
|
.locals_dict = (void*)&mod_foundation_noise_locals_dict,
|
|
};
|
|
|
|
/* End of Noise output class */
|
|
|
|
/*=============================================================================
|
|
* Start of QR decoder class
|
|
*=============================================================================*/
|
|
|
|
/// def __init__(self, mode: int, key: bytes, iv: bytes = None) -> None:
|
|
/// '''
|
|
/// Initialize QR context.
|
|
/// '''
|
|
STATIC mp_obj_t
|
|
QR_make_new(const mp_obj_type_t* type, size_t n_args, size_t n_kw, const mp_obj_t* args)
|
|
{
|
|
mp_obj_QR_t* o = m_new_obj(mp_obj_QR_t);
|
|
o->base.type = type;
|
|
if (n_args != 3) {
|
|
printf("ERROR: QR called with wrong number of arguments!");
|
|
return mp_const_none;
|
|
}
|
|
|
|
o->width = mp_obj_get_int(args[0]);
|
|
o->height = mp_obj_get_int(args[1]);
|
|
mp_buffer_info_t image_info;
|
|
mp_get_buffer_raise(args[2], &image_info, MP_BUFFER_READ);
|
|
|
|
unsigned int expected_image_len = o->width * o->height;
|
|
if (image_info.len != expected_image_len) {
|
|
printf("ERROR: Invalid buffer size for this decoder. Expected %u\n", expected_image_len);
|
|
return mp_const_none;
|
|
}
|
|
|
|
if (quirc_init(&o->quirc, o->width, o->height, image_info.buf) < 0) {
|
|
printf("ERROR: Unable to initialize quirc!\n");
|
|
return mp_const_none;
|
|
}
|
|
|
|
return MP_OBJ_FROM_PTR(o);
|
|
}
|
|
|
|
struct quirc_code code;
|
|
struct quirc_data data;
|
|
|
|
//#define QR_DEBUG
|
|
/// def find_qr_codes(self, image: image) -> array of strings:
|
|
/// '''
|
|
/// Find QR codes in image.
|
|
/// '''
|
|
STATIC mp_obj_t
|
|
QR_find_qr_codes(mp_obj_t self)
|
|
{
|
|
mp_obj_QR_t* o = MP_OBJ_TO_PTR(self);
|
|
|
|
#ifdef QR_DEBUG
|
|
printf("find_qr_codes: %u, %u\n", o->width, o->height);
|
|
#endif
|
|
|
|
// Prepare to decode
|
|
quirc_begin(&o->quirc, NULL, NULL);
|
|
#ifdef QR_DEBUG
|
|
printf("w=%u, h=%u\n", o->width, o->height);
|
|
#endif
|
|
|
|
// This triggers the decoding of the image we just gave quirc
|
|
quirc_end(&o->quirc);
|
|
|
|
// Let's see if we got any results
|
|
int num_codes = quirc_count(&o->quirc);
|
|
#ifdef QR_DEBUG
|
|
printf("num_codes=%d\n", num_codes);
|
|
#endif
|
|
|
|
if (num_codes == 0) {
|
|
#ifdef QR_DEBUG
|
|
printf("No codes found\n");
|
|
#endif
|
|
return mp_const_none;
|
|
}
|
|
|
|
// Extract the first code found only, even if multiple were found
|
|
quirc_extract(&o->quirc, 0, &code);
|
|
#ifdef QR_DEBUG
|
|
printf("quirc_extract() done\n");
|
|
#endif
|
|
|
|
// Decoding stage
|
|
quirc_decode_error_t err = quirc_decode(&code, &data);
|
|
if (err) {
|
|
printf("ERROR: Decode failed: %s\n", quirc_strerror(err));
|
|
return mp_const_none;
|
|
} else {
|
|
#ifdef QR_DEBUG
|
|
printf("Data: %s\n", data.payload);
|
|
#endif
|
|
}
|
|
|
|
// Return the payload as the function result
|
|
// const char* payload = mp_obj_str_get_str(data.payload);
|
|
// printf("Data: %s\n", payload);
|
|
|
|
vstr_t vstr;
|
|
int code_len = strlen((const char*)data.payload);
|
|
|
|
vstr_init(&vstr, code_len + 1);
|
|
vstr_add_strn(&vstr, (const char*)data.payload, code_len); // Can append to vstr if necessary
|
|
|
|
return mp_obj_new_str_from_vstr(&mp_type_str, &vstr);
|
|
}
|
|
STATIC MP_DEFINE_CONST_FUN_OBJ_1(QR_find_qr_codes_obj, QR_find_qr_codes);
|
|
|
|
STATIC mp_obj_t
|
|
QR___del__(mp_obj_t self)
|
|
{
|
|
mp_obj_QR_t* o = MP_OBJ_TO_PTR(self);
|
|
quirc_destroy(&o->quirc);
|
|
return mp_const_none;
|
|
}
|
|
|
|
STATIC MP_DEFINE_CONST_FUN_OBJ_1(QR___del___obj, QR___del__);
|
|
|
|
STATIC const mp_rom_map_elem_t QR_locals_dict_table[] = {
|
|
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_foundation) },
|
|
{ MP_ROM_QSTR(MP_QSTR_find_qr_codes), MP_ROM_PTR(&QR_find_qr_codes_obj) },
|
|
{ MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&QR___del___obj) },
|
|
};
|
|
STATIC MP_DEFINE_CONST_DICT(QR_locals_dict, QR_locals_dict_table);
|
|
|
|
STATIC const mp_obj_type_t QR_type = {
|
|
{ &mp_type_type },
|
|
.name = MP_QSTR_QR,
|
|
.make_new = QR_make_new,
|
|
.locals_dict = (void*)&QR_locals_dict,
|
|
};
|
|
/* End of setup for QR decoder class */
|
|
|
|
/*=============================================================================
|
|
* Start of SettingsFlash class
|
|
*=============================================================================*/
|
|
|
|
/// def __init__(self, mode: int, key: bytes, iv: bytes = None) -> boolean:
|
|
/// '''
|
|
/// Initialize SettingsFlash context.
|
|
/// '''
|
|
STATIC mp_obj_t
|
|
SettingsFlash_make_new(const mp_obj_type_t* type, size_t n_args, size_t n_kw, const mp_obj_t* args)
|
|
{
|
|
mp_obj_SettingsFlash_t* o = m_new_obj(mp_obj_SettingsFlash_t);
|
|
o->base.type = type;
|
|
return MP_OBJ_FROM_PTR(o);
|
|
}
|
|
|
|
// #define FLASH_DEBUG
|
|
/// def write(self, dest_addr, data) -> boolean
|
|
/// '''
|
|
/// Write data to internal flash
|
|
/// '''
|
|
STATIC mp_obj_t
|
|
SettingsFlash_write(mp_obj_t self, mp_obj_t dest_addr, mp_obj_t data)
|
|
{
|
|
uint32_t flash_addr = mp_obj_get_int(dest_addr);
|
|
mp_buffer_info_t data_info;
|
|
mp_get_buffer_raise(data, &data_info, MP_BUFFER_READ);
|
|
|
|
if (flash_addr < SETTINGS_FLASH_START || flash_addr + data_info.len - 1 > SETTINGS_FLASH_END ||
|
|
data_info.len % 4 != 0) {
|
|
#ifdef FLASH_DEBUG
|
|
printf("ERROR: SettingsFlash_write: bad parameters: flash_addr=0x%08lx\nSETTINGS_FLASH_START=0x%08x\nSETTINGS_FLASH_END=0x%08x\ndata_info.len=0x%04x\n",
|
|
flash_addr,
|
|
SETTINGS_FLASH_START,
|
|
SETTINGS_FLASH_END,
|
|
data_info.len);
|
|
#endif
|
|
return mp_const_false;
|
|
}
|
|
|
|
#ifdef FLASH_DEBUG
|
|
printf("SettingsFlash_write: %u bytes to 0x%08lx\n", data_info.len, flash_addr);
|
|
|
|
// for (uint32_t i=0; i<data_info.len;) {
|
|
// printf("%02x ", ((uint8_t*)data_info.buf)[i]);
|
|
// i++;
|
|
// if (i % 32 == 0) {
|
|
// printf("\n");
|
|
// }
|
|
// }
|
|
#endif
|
|
|
|
// NOTE: This function doesn't return any error/success info
|
|
flash_write(flash_addr, data_info.buf, data_info.len / 4);
|
|
|
|
#ifdef FLASH_DEBUG
|
|
printf("write: DONE\n");
|
|
#endif
|
|
|
|
return mp_const_true;
|
|
}
|
|
|
|
/// def erase(self, buf) -> boolean
|
|
/// '''
|
|
/// Erase all of flash (H7 doesn't provide facility to erase less than the whole 128K)
|
|
/// '''
|
|
STATIC mp_obj_t
|
|
SettingsFlash_erase(mp_obj_t self)
|
|
{
|
|
#ifdef FLASH_DEBUG
|
|
printf("SettingsFlash_erase()\n");
|
|
#endif
|
|
|
|
// NOTE: This function doesn't return any error/success info
|
|
flash_erase(SETTINGS_FLASH_START, SETTINGS_FLASH_SIZE / 4);
|
|
|
|
return mp_const_true;
|
|
}
|
|
|
|
STATIC MP_DEFINE_CONST_FUN_OBJ_3(SettingsFlash_write_obj, SettingsFlash_write);
|
|
STATIC MP_DEFINE_CONST_FUN_OBJ_1(SettingsFlash_erase_obj, SettingsFlash_erase);
|
|
|
|
STATIC mp_obj_t
|
|
SettingsFlash___del__(mp_obj_t self)
|
|
{
|
|
return mp_const_none;
|
|
}
|
|
|
|
STATIC MP_DEFINE_CONST_FUN_OBJ_1(SettingsFlash___del___obj, SettingsFlash___del__);
|
|
|
|
STATIC const mp_rom_map_elem_t SettingsFlash_locals_dict_table[] = {
|
|
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_foundation) },
|
|
{ MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&SettingsFlash_write_obj) },
|
|
{ MP_ROM_QSTR(MP_QSTR_erase), MP_ROM_PTR(&SettingsFlash_erase_obj) },
|
|
{ MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&SettingsFlash___del___obj) },
|
|
};
|
|
STATIC MP_DEFINE_CONST_DICT(SettingsFlash_locals_dict, SettingsFlash_locals_dict_table);
|
|
|
|
STATIC const mp_obj_type_t SettingsFlash_type = {
|
|
{ &mp_type_type },
|
|
.name = MP_QSTR_SettingsFlash,
|
|
.make_new = SettingsFlash_make_new,
|
|
.locals_dict = (void*)&SettingsFlash_locals_dict,
|
|
};
|
|
/* End of setup for internal flash class */
|
|
|
|
/*=============================================================================
|
|
* Start of System class
|
|
*=============================================================================*/
|
|
|
|
/// def __init__(self, mode: int, key: bytes, iv: bytes = None) -> boolean:
|
|
/// '''
|
|
/// Initialize System context.
|
|
/// '''
|
|
STATIC mp_obj_t
|
|
System_make_new(const mp_obj_type_t* type, size_t n_args, size_t n_kw, const mp_obj_t* args)
|
|
{
|
|
mp_obj_System_t* o = m_new_obj(mp_obj_System_t);
|
|
o->base.type = type;
|
|
return MP_OBJ_FROM_PTR(o);
|
|
}
|
|
|
|
#define SYSTEM_DEBUG
|
|
/// def reset(self) -> None
|
|
/// '''
|
|
/// Perform a warm reset of the system (should be mostly the same as turning it off and then on)
|
|
/// '''
|
|
STATIC mp_obj_t
|
|
System_reset(mp_obj_t self)
|
|
{
|
|
passport_reset();
|
|
return mp_const_none;
|
|
}
|
|
|
|
/// def shutdown(self) -> None
|
|
/// '''
|
|
/// Shutdown power to the Passport
|
|
/// '''
|
|
STATIC mp_obj_t
|
|
System_shutdown(mp_obj_t self)
|
|
{
|
|
// We clear the memory display and then shutdown
|
|
display_clean_shutdown();
|
|
return mp_const_none;
|
|
}
|
|
|
|
/// def dispatch(self, command: int, buf: bytes, len: int, arg2: int, ) -> array of strings:
|
|
/// '''
|
|
/// Dispatch system function by command number. This is a carry-over from the old firewall
|
|
/// code. We can probably switch this to direct function calls instead. The only benefit is
|
|
/// that this gives us a nice single point to handle RDP level 2 checks and other security checks.
|
|
/// '''
|
|
STATIC mp_obj_t
|
|
System_dispatch(size_t n_args, const mp_obj_t* args)
|
|
{
|
|
int8_t command = mp_obj_get_int(args[1]);
|
|
uint16_t arg2 = mp_obj_get_int(args[3]);
|
|
int result;
|
|
|
|
turbo(true);
|
|
|
|
if (args[2] == mp_const_none) {
|
|
result = se_dispatch(command, NULL, 0, arg2, 0, 0);
|
|
} else {
|
|
mp_buffer_info_t buf_info; // Use MP_BUFFER_WRITE below so any updates are copied back up
|
|
mp_get_buffer_raise(args[2], &buf_info, MP_BUFFER_WRITE);
|
|
|
|
result = se_dispatch(command, buf_info.buf, buf_info.len, arg2, 0, 0);
|
|
}
|
|
|
|
turbo(false);
|
|
|
|
return mp_obj_new_int(result);
|
|
}
|
|
|
|
/// def show_busy_bar(self) -> None
|
|
/// '''
|
|
/// Start displaying the busy bar animation for long-running processes
|
|
/// Also, enable turbo mode since if we need to wait, speed it almost certainly helpful.
|
|
/// '''
|
|
STATIC mp_obj_t
|
|
System_show_busy_bar(mp_obj_t self)
|
|
{
|
|
turbo(true);
|
|
busy_bar_start();
|
|
return mp_const_none;
|
|
}
|
|
|
|
/// def hide_busy_bar(self) -> None
|
|
/// '''
|
|
/// Stop showing the busy bar and disable turbo mode
|
|
/// '''
|
|
STATIC mp_obj_t
|
|
System_hide_busy_bar(mp_obj_t self)
|
|
{
|
|
busy_bar_stop();
|
|
turbo(false);
|
|
return mp_const_none;
|
|
}
|
|
|
|
#define SECRETS_FLASH_START 0x81C0000
|
|
#define SECRETS_FLASH_SIZE 0x20000
|
|
|
|
|
|
|
|
/// def System_get_software_info(self) -> None
|
|
/// '''
|
|
/// Get version, timestamp & hash of the firmware and bootloader as a tuple
|
|
/// '''
|
|
STATIC mp_obj_t
|
|
System_get_software_info(mp_obj_t self)
|
|
{
|
|
passport_firmware_header_t* fwhdr = (passport_firmware_header_t*)FW_HDR;
|
|
|
|
mp_obj_t tuple[4];
|
|
|
|
// Firmware version
|
|
tuple[0] = mp_obj_new_str_copy(
|
|
&mp_type_str, (const uint8_t*)fwhdr->info.fwversion, strlen((const char*)fwhdr->info.fwversion));
|
|
|
|
// Firmware date
|
|
tuple[1] = mp_obj_new_int_from_uint(fwhdr->info.timestamp);
|
|
|
|
uint32_t boot_counter = 0;
|
|
se_get_counter(&boot_counter, 1);
|
|
tuple[2] = mp_obj_new_int_from_uint(boot_counter);
|
|
|
|
// User-signed firmware?
|
|
tuple[3] = (fwhdr->signature.pubkey1 == FW_USER_KEY) ? mp_const_true : mp_const_false;
|
|
|
|
return mp_obj_new_tuple(4, tuple);
|
|
}
|
|
|
|
/// def System_progress_bar(self, progress) -> None
|
|
/// '''
|
|
/// Draw a progress bar to the specified amount (0-1.0)
|
|
/// '''
|
|
STATIC mp_obj_t
|
|
System_progress_bar(mp_obj_t self, mp_obj_t _progress)
|
|
{
|
|
int8_t progress = mp_obj_get_int(_progress);
|
|
display_progress_bar(
|
|
PROGRESS_BAR_MARGIN, PROGRESS_BAR_Y, SCREEN_WIDTH - (PROGRESS_BAR_MARGIN * 2), PROGRESS_BAR_HEIGHT, progress);
|
|
|
|
// Showing just the lines that changed is much faster and avoids full-screen flicker
|
|
display_show_lines(PROGRESS_BAR_Y, PROGRESS_BAR_Y + PROGRESS_BAR_HEIGHT);
|
|
|
|
return mp_const_none;
|
|
}
|
|
|
|
/// def System_read_ambient(self) -> None
|
|
/// '''
|
|
/// Read the ambient light sensor and bucket it to a level from 0-100
|
|
/// '''
|
|
STATIC mp_obj_t
|
|
System_read_ambient(mp_obj_t self)
|
|
{
|
|
uint16_t millivolts;
|
|
adc_read_als(&millivolts);
|
|
millivolts = MIN(millivolts, 3200);
|
|
// printf("millivolts = %u\n", millivolts);
|
|
int level = millivolts / 32;
|
|
|
|
return mp_obj_new_int(level);
|
|
}
|
|
|
|
uint8_t turbo_count = 0;
|
|
void
|
|
turbo(bool enable)
|
|
{
|
|
if (enable) {
|
|
if (turbo_count == 0) {
|
|
frequency_turbo(true);
|
|
}
|
|
turbo_count++;
|
|
} else {
|
|
if (turbo_count == 0) {
|
|
// printf("ERROR: Tried to disable turbo mode when it was not already enabled!\n");
|
|
return;
|
|
}
|
|
if (turbo_count == 1) {
|
|
frequency_turbo(false);
|
|
}
|
|
turbo_count--;
|
|
}
|
|
}
|
|
|
|
/// def System_turbo(self, progress) -> None
|
|
/// '''
|
|
/// Enable or disable turbo mode (fastest MCU frequency)
|
|
/// '''
|
|
STATIC mp_obj_t
|
|
System_turbo(mp_obj_t self, mp_obj_t _enable)
|
|
{
|
|
bool enable = mp_obj_is_true(_enable);
|
|
|
|
turbo(enable);
|
|
// printf("%s: %lu, %lu, %lu, %lu, %lu\n", enable ? "enable" : "disabled", HAL_RCC_GetSysClockFreq(), SystemCoreClock, HAL_RCC_GetHCLKFreq(),
|
|
// HAL_RCC_GetPCLK1Freq(), HAL_RCC_GetPCLK2Freq());
|
|
|
|
return mp_const_none;
|
|
}
|
|
|
|
|
|
/// def System_sha256(self, buffer, digest) -> None
|
|
/// '''
|
|
/// Perform a sha256 hash on the given data (bytearray)
|
|
/// '''
|
|
STATIC mp_obj_t
|
|
System_sha256(mp_obj_t self, mp_obj_t data, mp_obj_t digest)
|
|
{
|
|
mp_buffer_info_t data_info;
|
|
mp_get_buffer_raise(data, &data_info, MP_BUFFER_READ);
|
|
|
|
mp_buffer_info_t digest_info;
|
|
mp_get_buffer_raise(digest, &digest_info, MP_BUFFER_WRITE);
|
|
|
|
SHA256_CTX ctx;
|
|
sha256_init(&ctx);
|
|
sha256_update(&ctx, (void *)data_info.buf, data_info.len);
|
|
sha256_final(&ctx, digest_info.buf);
|
|
|
|
return mp_const_none;
|
|
}
|
|
|
|
// Simple header verification
|
|
bool verify_header(passport_firmware_header_t *hdr)
|
|
{
|
|
if (hdr->info.magic != FW_HEADER_MAGIC) goto fail;
|
|
if (hdr->info.timestamp == 0) goto fail;
|
|
if (hdr->info.fwversion[0] == 0x0) goto fail;
|
|
if (hdr->info.fwlength < FW_HEADER_SIZE) goto fail;
|
|
|
|
if ((hdr->signature.pubkey1 != FW_USER_KEY) && (hdr->signature.pubkey1 > FW_MAX_PUB_KEYS)) goto fail;
|
|
if (hdr->signature.pubkey1 != FW_USER_KEY)
|
|
{
|
|
if (hdr->signature.pubkey2 > FW_MAX_PUB_KEYS) goto fail;
|
|
}
|
|
|
|
return true;
|
|
|
|
fail:
|
|
return false;
|
|
}
|
|
|
|
/// def System_validate_firmware_header(self, header) -> None
|
|
/// '''
|
|
/// Validate the given firmware header bytes as a potential candidate to be installed.
|
|
/// '''
|
|
STATIC mp_obj_t
|
|
System_validate_firmware_header(mp_obj_t self, mp_obj_t header)
|
|
{
|
|
mp_buffer_info_t header_info;
|
|
mp_get_buffer_raise(header, &header_info, MP_BUFFER_READ);
|
|
|
|
// Existing header
|
|
passport_firmware_header_t* fwhdr = (passport_firmware_header_t*)FW_HDR;
|
|
|
|
// New header
|
|
passport_firmware_header_t* new_fwhdr = (passport_firmware_header_t*)header_info.buf;
|
|
|
|
mp_obj_t tuple[3];
|
|
|
|
bool is_valid = verify_header(header_info.buf);
|
|
|
|
if (is_valid) {
|
|
// Ensure they are not trying to install an older version of firmware, but allow
|
|
// a reinstall of the same version. Also allow installation of user firmware regardless of
|
|
// timestamp and then allow installing a Foundation-signed build.
|
|
if ((new_fwhdr->signature.pubkey1 != FW_USER_KEY && fwhdr->signature.pubkey1 != FW_USER_KEY ) &&
|
|
(new_fwhdr->info.timestamp < fwhdr->info.timestamp)) {
|
|
tuple[0] = mp_const_false;
|
|
tuple[1] = mp_obj_new_str_copy(&mp_type_str, (const uint8_t*)new_fwhdr->info.fwversion, strlen((const char*)new_fwhdr->info.fwversion));
|
|
|
|
// Include an error string
|
|
vstr_t vstr;
|
|
vstr_init(&vstr, 80);
|
|
char* msg = "The selected firmware is older than the currently installed firmware and cannot be installed.\n\nCurrent Version:\n ";
|
|
vstr_add_strn(&vstr, (const char*)msg, strlen(msg));
|
|
|
|
vstr_add_strn(&vstr, (const char*)fwhdr->info.fwdate, strlen((const char*)new_fwhdr->info.fwdate));
|
|
|
|
msg = "\n\nSelected Version:\n ";
|
|
vstr_add_strn(&vstr, (const char*)msg, strlen(msg));
|
|
|
|
vstr_add_strn(&vstr, (const char*)new_fwhdr->info.fwdate, strlen((const char*)new_fwhdr->info.fwdate));
|
|
tuple[2] = mp_obj_new_str_from_vstr(&mp_type_str, &vstr);
|
|
|
|
return mp_obj_new_tuple(3, tuple);
|
|
}
|
|
} else {
|
|
// Invalid header
|
|
tuple[0] = mp_const_false;
|
|
tuple[1] = mp_obj_new_str_copy(&mp_type_str, (const uint8_t*)new_fwhdr->info.fwversion, strlen((const char*)new_fwhdr->info.fwversion));
|
|
|
|
// Include an error string
|
|
vstr_t vstr;
|
|
vstr_init(&vstr, 80);
|
|
char* msg = "The selected firmware header is invalid and cannot be installed.";
|
|
vstr_add_strn(&vstr, (const char*)msg, strlen(msg));
|
|
tuple[2] = mp_obj_new_str_from_vstr(&mp_type_str, &vstr);
|
|
|
|
return mp_obj_new_tuple(3, tuple);
|
|
}
|
|
|
|
// is_valid
|
|
tuple[0] = mp_const_true;
|
|
|
|
// Firmware version
|
|
tuple[1] = mp_obj_new_str_copy(&mp_type_str, (const uint8_t*)new_fwhdr->info.fwversion, strlen((const char*)new_fwhdr->info.fwversion));
|
|
|
|
// No error message
|
|
tuple[2] = mp_const_none;
|
|
|
|
return mp_obj_new_tuple(3, tuple);
|
|
}
|
|
|
|
/// def System_set_user_firmware_pubkey(self, pubkey) -> None
|
|
/// '''
|
|
/// Set the user firmware public key so the user can install custom firmware
|
|
/// '''
|
|
STATIC mp_obj_t
|
|
System_set_user_firmware_pubkey(mp_obj_t self, mp_obj_t pubkey)
|
|
{
|
|
uint8_t pin_hash[32];
|
|
|
|
mp_buffer_info_t pubkey_info;
|
|
mp_get_buffer_raise(pubkey, &pubkey_info, MP_BUFFER_READ);
|
|
// uint8_t* p = (uint8_t*)pubkey_info.buf;
|
|
// printf("WRITE: len=%d pubkey=%02x%02x%02x%02x...\n",pubkey_info.len, p[0], p[1], p[2], p[3]);
|
|
|
|
pinAttempt_t pa_args;
|
|
pa_args.magic_value = PA_MAGIC_V1;
|
|
memcpy(&pa_args.cached_main_pin, g_cached_main_pin, sizeof(g_cached_main_pin));
|
|
|
|
// Get the hash that proves user knows the PIN
|
|
int rv = pin_cache_restore(&pa_args, pin_hash);
|
|
if (rv) {
|
|
return mp_const_false;
|
|
}
|
|
|
|
// printf("pin hash=%02x%02x%02x%02x...", pin_hash[0], pin_hash[1], pin_hash[2],pin_hash[3]);
|
|
|
|
rv = se_encrypted_write(KEYNUM_user_fw_pubkey, KEYNUM_pin_hash, pin_hash, pubkey_info.buf, pubkey_info.len);
|
|
// printf("rv=%d\n", rv);
|
|
return rv == 0 ? mp_const_true : mp_const_false;
|
|
}
|
|
|
|
/// def System_get_user_firmware_pubkey(self, pubkey) -> None
|
|
/// '''
|
|
/// Get the user firmware public key
|
|
/// '''
|
|
STATIC mp_obj_t
|
|
System_get_user_firmware_pubkey(mp_obj_t self, mp_obj_t pubkey)
|
|
{
|
|
uint8_t buf[72];
|
|
|
|
mp_buffer_info_t pubkey_info;
|
|
mp_get_buffer_raise(pubkey, &pubkey_info, MP_BUFFER_READ);
|
|
|
|
if (pubkey_info.len < 64) {
|
|
return mp_const_false;
|
|
}
|
|
|
|
se_pair_unlock();
|
|
int rv = se_read_data_slot(KEYNUM_user_fw_pubkey, buf, sizeof(buf));
|
|
if (rv == 0) {
|
|
memcpy(pubkey_info.buf, buf, 64);
|
|
return mp_const_true;
|
|
}
|
|
return mp_const_false;
|
|
}
|
|
|
|
/// def System_supply_chain_challenge(self, challenge, response) -> None
|
|
/// '''
|
|
/// Perform the supply chain challenge (HMAC)
|
|
/// '''
|
|
STATIC mp_obj_t
|
|
System_supply_chain_challenge(mp_obj_t self, mp_obj_t challenge, mp_obj_t response)
|
|
{
|
|
mp_buffer_info_t challenge_info;
|
|
mp_get_buffer_raise(challenge, &challenge_info, MP_BUFFER_READ);
|
|
|
|
mp_buffer_info_t response_info;
|
|
mp_get_buffer_raise(response, &response_info, MP_BUFFER_WRITE);
|
|
|
|
se_pair_unlock();
|
|
int rc = se_hmac32(KEYNUM_supply_chain, challenge_info.buf, response_info.buf);
|
|
if (rc == 0) {
|
|
return mp_const_true;
|
|
}
|
|
return mp_const_false;
|
|
}
|
|
|
|
|
|
uint8_t supply_chain_validation_server_pubkey[64] = {
|
|
0x75, 0xF6, 0xCD, 0xDB, 0x93, 0x49, 0x59, 0x9D, 0x4B, 0xB2, 0xDF, 0x82, 0xBC, 0xF9, 0x8E, 0x85,
|
|
0x45, 0x6C, 0xFB, 0xE2, 0x87, 0x57, 0xFF, 0x77, 0x5D, 0xB0, 0x4C, 0xAE, 0x70, 0x1B, 0xDC, 0x00,
|
|
0x53, 0x4E, 0x0C, 0x70, 0x01, 0x90, 0x6C, 0x6F, 0xFB, 0xA6, 0x15, 0xAF, 0xDB, 0x67, 0xDE, 0xF9,
|
|
0x46, 0x96, 0x4B, 0xB4, 0x39, 0xD0, 0x02, 0x3E, 0xF6, 0x59, 0xF5, 0x80, 0xBB, 0x31, 0x11, 0x3E
|
|
};
|
|
|
|
/// def System_verify_supply_chain_server_signature(self, hash, signature) -> None
|
|
/// '''
|
|
/// Verify server signature
|
|
/// '''
|
|
STATIC mp_obj_t
|
|
System_verify_supply_chain_server_signature(mp_obj_t self, mp_obj_t hash, mp_obj_t signature)
|
|
{
|
|
mp_buffer_info_t hash_info;
|
|
mp_get_buffer_raise(hash, &hash_info, MP_BUFFER_READ);
|
|
|
|
mp_buffer_info_t signature_info;
|
|
mp_get_buffer_raise(signature, &signature_info, MP_BUFFER_READ);
|
|
|
|
int rc = uECC_verify(supply_chain_validation_server_pubkey,
|
|
hash_info.buf, hash_info.len,
|
|
signature_info.buf, uECC_secp256k1());
|
|
|
|
return rc == 0 ? mp_const_false : mp_const_true;
|
|
}
|
|
|
|
#define SHA256_BLOCK_LENGTH 64
|
|
#define SHA256_DIGEST_LENGTH 32
|
|
|
|
void _hmac_sha256(uint8_t* key, uint32_t key_len, uint8_t* msg, uint32_t msg_len, uint8_t* hmac) {
|
|
uint8_t i_key_pad[SHA256_BLOCK_LENGTH];
|
|
memset(i_key_pad, 0, SHA256_BLOCK_LENGTH);
|
|
memcpy(i_key_pad, key, key_len);
|
|
|
|
uint8_t o_key_pad[SHA256_BLOCK_LENGTH];
|
|
for (int i = 0; i < SHA256_BLOCK_LENGTH; i++) {
|
|
o_key_pad[i] = i_key_pad[i] ^ 0x5c;
|
|
i_key_pad[i] ^= 0x36;
|
|
}
|
|
|
|
// First hash
|
|
SHA256_CTX ctx;
|
|
sha256_init(&ctx);
|
|
sha256_update(&ctx, i_key_pad, SHA256_BLOCK_LENGTH);
|
|
memset(i_key_pad, 0, SHA256_BLOCK_LENGTH);
|
|
|
|
// Add the data
|
|
sha256_update(&ctx, msg, msg_len);
|
|
|
|
// Hash
|
|
sha256_final(&ctx, hmac);
|
|
|
|
// Second hash
|
|
sha256_init(&ctx);
|
|
sha256_update(&ctx, o_key_pad, SHA256_BLOCK_LENGTH);
|
|
sha256_update(&ctx, hmac, SHA256_DIGEST_LENGTH);
|
|
sha256_final(&ctx, hmac);
|
|
}
|
|
|
|
/// def System_hmac_sha256(self, key, msg, hmac) -> None
|
|
/// '''
|
|
/// Calculate an hmac using the given key and data
|
|
/// '''
|
|
STATIC mp_obj_t
|
|
System_hmac_sha256(size_t n_args, const mp_obj_t* args)
|
|
{
|
|
mp_buffer_info_t key_info;
|
|
mp_get_buffer_raise(args[1], &key_info, MP_BUFFER_READ);
|
|
// uint8_t* pkey = (uint8_t*)key_info.buf;
|
|
// printf("key: 0x%02x 0x%02x 0x%02x 0x%02x (len=%d)\n", pkey[0], pkey[1], pkey[2], pkey[3], key_info.len);
|
|
|
|
mp_buffer_info_t msg_info;
|
|
mp_get_buffer_raise(args[2], &msg_info, MP_BUFFER_READ);
|
|
// uint8_t* pmsg = (uint8_t*)msg_info.buf;
|
|
// printf("msg: 0x%02x 0x%02x 0x%02x 0x%02x (len=%d)\n", pmsg[0], pmsg[1], pmsg[2], pmsg[3], msg_info.len);
|
|
|
|
mp_buffer_info_t hmac_info;
|
|
mp_get_buffer_raise(args[3], &hmac_info, MP_BUFFER_WRITE);
|
|
// printf("hmac:(len=%d)\n", hmac_info.len);
|
|
|
|
_hmac_sha256(key_info.buf, key_info.len, msg_info.buf, msg_info.len, hmac_info.buf);
|
|
|
|
return mp_const_none;
|
|
}
|
|
|
|
#define MAX_SERIAL_NUMBER_LEN 20
|
|
/// def System_get_serial_number(self) -> None
|
|
/// '''
|
|
/// Get the serial number
|
|
/// '''
|
|
STATIC mp_obj_t
|
|
System_get_serial_number(mp_obj_t self)
|
|
{
|
|
char serial[MAX_SERIAL_NUMBER_LEN];
|
|
|
|
get_serial_number(serial, MAX_SERIAL_NUMBER_LEN);
|
|
|
|
return mp_obj_new_str_copy(&mp_type_str, (const uint8_t*)serial, strlen(serial));
|
|
}
|
|
|
|
/// def System_get_device_hash(self, hash) -> None
|
|
/// '''
|
|
/// Get the device hash
|
|
/// '''
|
|
STATIC mp_obj_t
|
|
System_get_device_hash(mp_obj_t self, mp_obj_t hash)
|
|
{
|
|
mp_buffer_info_t hash_info;
|
|
mp_get_buffer_raise(hash, &hash_info, MP_BUFFER_WRITE);
|
|
|
|
get_device_hash(hash_info.buf);
|
|
|
|
return mp_const_none;
|
|
}
|
|
|
|
/// def System_get_backup_pw_hash(self, hash) -> None
|
|
/// '''
|
|
/// Get the hash to use as the "entropy" for the backup password.
|
|
/// It's based on the device hash plus the seed.
|
|
/// '''
|
|
STATIC mp_obj_t
|
|
System_get_backup_pw_hash(mp_obj_t self, mp_obj_t hash)
|
|
{
|
|
uint8_t device_hash[32];
|
|
|
|
mp_buffer_info_t hash_info;
|
|
mp_get_buffer_raise(hash, &hash_info, MP_BUFFER_WRITE);
|
|
|
|
get_device_hash(device_hash);
|
|
pinAttempt_t pin_attempt;
|
|
memset(&pin_attempt, 0, sizeof(pinAttempt_t));
|
|
pin_fetch_secret(&pin_attempt);
|
|
|
|
SHA256_CTX ctx;
|
|
sha256_init(&ctx);
|
|
sha256_update(&ctx, (void *)device_hash, 32);
|
|
sha256_update(&ctx, (void *)pin_attempt.secret, SE_SECRET_LEN);
|
|
sha256_final(&ctx, hash_info.buf);
|
|
|
|
// Double SHA
|
|
sha256_init(&ctx);
|
|
sha256_update(&ctx, (void *)hash_info.buf, 32);
|
|
sha256_final(&ctx, hash_info.buf);
|
|
|
|
return mp_const_none;
|
|
}
|
|
|
|
|
|
STATIC MP_DEFINE_CONST_FUN_OBJ_1(System_reset_obj, System_reset);
|
|
STATIC MP_DEFINE_CONST_FUN_OBJ_1(System_shutdown_obj, System_shutdown);
|
|
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(System_dispatch_obj, 4, 4, System_dispatch);
|
|
STATIC MP_DEFINE_CONST_FUN_OBJ_1(System_show_busy_bar_obj, System_show_busy_bar);
|
|
STATIC MP_DEFINE_CONST_FUN_OBJ_1(System_hide_busy_bar_obj, System_hide_busy_bar);
|
|
STATIC MP_DEFINE_CONST_FUN_OBJ_1(System_get_software_info_obj, System_get_software_info);
|
|
STATIC MP_DEFINE_CONST_FUN_OBJ_2(System_progress_bar_obj, System_progress_bar);
|
|
STATIC MP_DEFINE_CONST_FUN_OBJ_1(System_read_ambient_obj, System_read_ambient);
|
|
STATIC MP_DEFINE_CONST_FUN_OBJ_2(System_turbo_obj, System_turbo);
|
|
STATIC MP_DEFINE_CONST_FUN_OBJ_3(System_sha256_obj, System_sha256);
|
|
STATIC MP_DEFINE_CONST_FUN_OBJ_2(System_validate_firmware_header_obj, System_validate_firmware_header);
|
|
STATIC MP_DEFINE_CONST_FUN_OBJ_2(System_set_user_firmware_pubkey_obj, System_set_user_firmware_pubkey);
|
|
STATIC MP_DEFINE_CONST_FUN_OBJ_2(System_get_user_firmware_pubkey_obj, System_get_user_firmware_pubkey);
|
|
STATIC MP_DEFINE_CONST_FUN_OBJ_3(System_supply_chain_challenge_obj, System_supply_chain_challenge);
|
|
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(System_hmac_sha256_obj, 4, 4, System_hmac_sha256);
|
|
STATIC MP_DEFINE_CONST_FUN_OBJ_3(System_verify_supply_chain_server_signature_obj, System_verify_supply_chain_server_signature);
|
|
STATIC MP_DEFINE_CONST_FUN_OBJ_1(System_get_serial_number_obj, System_get_serial_number);
|
|
STATIC MP_DEFINE_CONST_FUN_OBJ_2(System_get_device_hash_obj, System_get_device_hash);
|
|
STATIC MP_DEFINE_CONST_FUN_OBJ_2(System_get_backup_pw_hash_obj, System_get_backup_pw_hash);
|
|
|
|
|
|
STATIC mp_obj_t
|
|
System___del__(mp_obj_t self)
|
|
{
|
|
return mp_const_none;
|
|
}
|
|
|
|
STATIC MP_DEFINE_CONST_FUN_OBJ_1(System___del___obj, System___del__);
|
|
|
|
STATIC const mp_rom_map_elem_t System_locals_dict_table[] = {
|
|
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_foundation) },
|
|
{ MP_ROM_QSTR(MP_QSTR_reset), MP_ROM_PTR(&System_reset_obj) },
|
|
{ MP_ROM_QSTR(MP_QSTR_shutdown), MP_ROM_PTR(&System_shutdown_obj) },
|
|
{ MP_ROM_QSTR(MP_QSTR_dispatch), MP_ROM_PTR(&System_dispatch_obj) },
|
|
{ MP_ROM_QSTR(MP_QSTR_show_busy_bar), MP_ROM_PTR(&System_show_busy_bar_obj) },
|
|
{ MP_ROM_QSTR(MP_QSTR_hide_busy_bar), MP_ROM_PTR(&System_hide_busy_bar_obj) },
|
|
{ MP_ROM_QSTR(MP_QSTR_get_software_info), MP_ROM_PTR(&System_get_software_info_obj) },
|
|
{ MP_ROM_QSTR(MP_QSTR_progress_bar), MP_ROM_PTR(&System_progress_bar_obj) },
|
|
{ MP_ROM_QSTR(MP_QSTR_read_ambient), MP_ROM_PTR(&System_read_ambient_obj) },
|
|
{ MP_ROM_QSTR(MP_QSTR_turbo), MP_ROM_PTR(&System_turbo_obj) },
|
|
{ MP_ROM_QSTR(MP_QSTR_sha256), MP_ROM_PTR(&System_sha256_obj) },
|
|
{ MP_ROM_QSTR(MP_QSTR_validate_firmware_header), MP_ROM_PTR(&System_validate_firmware_header_obj) },
|
|
{ MP_ROM_QSTR(MP_QSTR_set_user_firmware_pubkey), MP_ROM_PTR(&System_set_user_firmware_pubkey_obj) },
|
|
{ MP_ROM_QSTR(MP_QSTR_get_user_firmware_pubkey), MP_ROM_PTR(&System_get_user_firmware_pubkey_obj) },
|
|
{ MP_ROM_QSTR(MP_QSTR_supply_chain_challenge), MP_ROM_PTR(&System_supply_chain_challenge_obj) },
|
|
{ MP_ROM_QSTR(MP_QSTR_verify_supply_chain_server_signature), MP_ROM_PTR(&System_verify_supply_chain_server_signature_obj) },
|
|
{ MP_ROM_QSTR(MP_QSTR_hmac_sha256), MP_ROM_PTR(&System_hmac_sha256_obj) },
|
|
{ MP_ROM_QSTR(MP_QSTR_get_serial_number), MP_ROM_PTR(&System_get_serial_number_obj) },
|
|
{ MP_ROM_QSTR(MP_QSTR_get_device_hash), MP_ROM_PTR(&System_get_device_hash_obj) },
|
|
{ MP_ROM_QSTR(MP_QSTR_get_backup_pw_hash), MP_ROM_PTR(&System_get_backup_pw_hash_obj) },
|
|
{ MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&System___del___obj) },
|
|
};
|
|
STATIC MP_DEFINE_CONST_DICT(System_locals_dict, System_locals_dict_table);
|
|
|
|
STATIC const mp_obj_type_t System_type = {
|
|
{ &mp_type_type },
|
|
.name = MP_QSTR_System,
|
|
.make_new = System_make_new,
|
|
.locals_dict = (void*)&System_locals_dict,
|
|
};
|
|
/* End of setup for System class */
|
|
|
|
/*=============================================================================
|
|
* Start of bip39 class
|
|
*=============================================================================*/
|
|
|
|
extern word_info_t bip39_word_info[];
|
|
extern word_info_t bytewords_word_info[]; // TODO: Restructure this so bip39 and bytewords are separate
|
|
|
|
/// def __init__(self, mode: int, key: bytes, iv: bytes = None) -> boolean:
|
|
/// '''
|
|
/// Initialize System context.
|
|
/// '''
|
|
STATIC mp_obj_t
|
|
bip39_make_new(const mp_obj_type_t* type, size_t n_args, size_t n_kw, const mp_obj_t* args)
|
|
{
|
|
mp_obj_bip39_t* o = m_new_obj(mp_obj_bip39_t);
|
|
o->base.type = type;
|
|
return MP_OBJ_FROM_PTR(o);
|
|
}
|
|
|
|
#define MATCHES_LEN 80
|
|
|
|
/// def get_words_matching_prefix(self, prefix, max_matches, word_list) -> None
|
|
/// '''
|
|
/// Return a comma-separated list of BIP39 seed words that match the given keypad
|
|
/// digits prefix (e.g., '222').
|
|
/// '''
|
|
STATIC mp_obj_t
|
|
bip39_get_words_matching_prefix(size_t n_args, const mp_obj_t* args)
|
|
{
|
|
mp_check_self(mp_obj_is_str_or_bytes(args[1]));
|
|
GET_STR_DATA_LEN(args[1], prefix_str, prefix_len);
|
|
|
|
int max_matches = mp_obj_get_int(args[2]);
|
|
|
|
// Must be "bip39" or "bytewords"
|
|
mp_check_self(mp_obj_is_str_or_bytes(args[3]));
|
|
GET_STR_DATA_LEN(args[3], word_list_str, word_list_len);
|
|
|
|
const word_info_t* word_info = NULL;
|
|
uint32_t num_words = 0;
|
|
if (strcmp("bip39", (char*)word_list_str) == 0) {
|
|
word_info = bip39_word_info;
|
|
num_words = 2048;
|
|
} else if (strcmp("bytewords", (char*)word_list_str) == 0) {
|
|
word_info = bytewords_word_info;
|
|
num_words = 256;
|
|
} else {
|
|
return mp_const_none;
|
|
}
|
|
|
|
char matches[MATCHES_LEN];
|
|
|
|
get_words_matching_prefix((char*)prefix_str, matches, MATCHES_LEN, max_matches, word_info, num_words);
|
|
|
|
// Return the string
|
|
vstr_t vstr;
|
|
int matches_len = strlen((const char*)matches);
|
|
|
|
vstr_init(&vstr, matches_len + 1);
|
|
vstr_add_strn(&vstr, (const char*)matches, matches_len);
|
|
|
|
return mp_obj_new_str_from_vstr(&mp_type_str, &vstr);
|
|
}
|
|
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(bip39_get_words_matching_prefix_obj, 4, 4, bip39_get_words_matching_prefix);
|
|
|
|
#include "bip39.h"
|
|
|
|
/// def mnemonic_to_entropy(self) -> None
|
|
/// '''
|
|
/// Call trezorcrypto's mnemonic_to_entropy() C function since it's not exposed through their
|
|
/// Python interface.
|
|
/// '''
|
|
STATIC mp_obj_t
|
|
bip39_mnemonic_to_entropy(mp_obj_t self, mp_obj_t mnemonic, mp_obj_t entropy)
|
|
{
|
|
mp_check_self(mp_obj_is_str_or_bytes(mnemonic));
|
|
GET_STR_DATA_LEN(mnemonic, mnemonic_str, mnemonic_len);
|
|
mp_buffer_info_t entropy_info;
|
|
mp_get_buffer_raise(entropy, &entropy_info, MP_BUFFER_WRITE);
|
|
|
|
int len = mnemonic_to_entropy((const char*)mnemonic_str, entropy_info.buf);
|
|
return mp_obj_new_int(len);
|
|
}
|
|
STATIC MP_DEFINE_CONST_FUN_OBJ_3(bip39_mnemonic_to_entropy_obj, bip39_mnemonic_to_entropy);
|
|
|
|
STATIC mp_obj_t
|
|
bip39___del__(mp_obj_t self)
|
|
{
|
|
return mp_const_none;
|
|
}
|
|
|
|
STATIC MP_DEFINE_CONST_FUN_OBJ_1(bip39___del___obj, bip39___del__);
|
|
|
|
STATIC const mp_rom_map_elem_t bip39_locals_dict_table[] = {
|
|
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_foundation) },
|
|
{ MP_ROM_QSTR(MP_QSTR_get_words_matching_prefix), MP_ROM_PTR(&bip39_get_words_matching_prefix_obj) },
|
|
{ MP_ROM_QSTR(MP_QSTR_mnemonic_to_entropy), MP_ROM_PTR(&bip39_mnemonic_to_entropy_obj) },
|
|
{ MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&bip39___del___obj) },
|
|
};
|
|
STATIC MP_DEFINE_CONST_DICT(bip39_locals_dict, bip39_locals_dict_table);
|
|
|
|
STATIC const mp_obj_type_t bip39_type = {
|
|
{ &mp_type_type },
|
|
.name = MP_QSTR_bip39,
|
|
.make_new = bip39_make_new,
|
|
.locals_dict = (void*)&bip39_locals_dict,
|
|
};
|
|
/* End of setup for bip39 class */
|
|
|
|
/*=============================================================================
|
|
* Start of QRCode class - renders QR codes to a buffer passed down from MP
|
|
*=============================================================================*/
|
|
|
|
// We only have versions here that can be rendered on Pasport's display
|
|
uint16_t version_capacity_alphanumeric[] = {
|
|
25, // 1
|
|
47, // 2
|
|
77, // 3
|
|
114, // 4
|
|
154, // 5
|
|
195, // 6
|
|
224, // 7
|
|
279, // 8
|
|
335, // 9
|
|
395, // 10
|
|
468, // 11
|
|
535, // 12
|
|
619, // 13
|
|
667, // 14
|
|
758, // 15
|
|
854, // 16
|
|
938, // 17
|
|
1046, // 18
|
|
1153, // 19
|
|
1249, // 20
|
|
1352, // 21
|
|
1460, // 22
|
|
1588, // 23
|
|
1704 // 24
|
|
};
|
|
|
|
uint16_t version_capacity_binary[] = {
|
|
17, // 1
|
|
32, // 2
|
|
53, // 3
|
|
78, // 4
|
|
106, // 5
|
|
134, // 6
|
|
154, // 7
|
|
192, // 8
|
|
230, // 9
|
|
271, // 10
|
|
321, // 11
|
|
367, // 12
|
|
425, // 13
|
|
458, // 14
|
|
520, // 15
|
|
586, // 16
|
|
644, // 17
|
|
718, // 18
|
|
792, // 19
|
|
858, // 20
|
|
929, // 21
|
|
1003, // 22
|
|
1091, // 23
|
|
1171 // 24
|
|
};
|
|
|
|
/// def __init__(self, mode: int, key: bytes, iv: bytes = None) -> boolean:
|
|
/// '''
|
|
/// Initialize QRCode context.
|
|
/// '''
|
|
STATIC mp_obj_t
|
|
QRCode_make_new(const mp_obj_type_t* type, size_t n_args, size_t n_kw, const mp_obj_t* args)
|
|
{
|
|
mp_obj_QRCode_t* o = m_new_obj(mp_obj_QRCode_t);
|
|
o->base.type = type;
|
|
return MP_OBJ_FROM_PTR(o);
|
|
}
|
|
|
|
QRCode qrcode;
|
|
#define QRCODE_DEBUG
|
|
|
|
/// def render(self) -> None
|
|
/// '''
|
|
/// Render a QR code with the given data, version and ecc level
|
|
/// '''
|
|
STATIC mp_obj_t
|
|
QRCode_render(size_t n_args, const mp_obj_t* args)
|
|
{
|
|
mp_check_self(mp_obj_is_str_or_bytes(args[1]));
|
|
GET_STR_DATA_LEN(args[1], text_str, text_len);
|
|
// printf("text_str=%s text_len=%d\n", text_str, text_len);
|
|
|
|
uint8_t version = mp_obj_get_int(args[2]);
|
|
uint8_t ecc = mp_obj_get_int(args[3]);
|
|
|
|
mp_buffer_info_t output_info;
|
|
mp_get_buffer_raise(args[4], &output_info, MP_BUFFER_WRITE);
|
|
|
|
uint8_t result = qrcode_initBytes(&qrcode, (uint8_t*)output_info.buf, version, ecc, (uint8_t*)text_str, text_len);
|
|
|
|
return result == 0 ? mp_const_false : mp_const_true;
|
|
}
|
|
|
|
/// def fit_to_version(self) -> None
|
|
/// '''
|
|
/// Return the QR code version that best fits this data (assumes ECC level 0 for now)
|
|
/// '''
|
|
STATIC mp_obj_t
|
|
QRCode_fit_to_version(mp_obj_t self, mp_obj_t data_size, mp_obj_t is_alphanumeric)
|
|
{
|
|
uint16_t size = mp_obj_get_int(data_size);
|
|
uint16_t is_alpha = mp_obj_get_int(is_alphanumeric);
|
|
uint16_t *lookup_table = is_alpha ? version_capacity_alphanumeric : version_capacity_binary;
|
|
|
|
int num_entries = sizeof(version_capacity_alphanumeric) / sizeof(uint16_t);
|
|
|
|
for (int i = 0; i < num_entries; i++) {
|
|
if (lookup_table[i] >= size) {
|
|
return mp_obj_new_int(i + 1);
|
|
}
|
|
}
|
|
|
|
// Data is too big
|
|
return mp_obj_new_int(0);
|
|
}
|
|
|
|
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(QRCode_render_obj, 5, 5, QRCode_render);
|
|
STATIC MP_DEFINE_CONST_FUN_OBJ_3(QRCode_fit_to_version_obj, QRCode_fit_to_version);
|
|
|
|
STATIC mp_obj_t
|
|
QRCode___del__(mp_obj_t self)
|
|
{
|
|
return mp_const_none;
|
|
}
|
|
|
|
STATIC MP_DEFINE_CONST_FUN_OBJ_1(QRCode___del___obj, QRCode___del__);
|
|
|
|
STATIC const mp_rom_map_elem_t QRCode_locals_dict_table[] = {
|
|
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_foundation) },
|
|
{ MP_ROM_QSTR(MP_QSTR_render), MP_ROM_PTR(&QRCode_render_obj) },
|
|
{ MP_ROM_QSTR(MP_QSTR_fit_to_version), MP_ROM_PTR(&QRCode_fit_to_version_obj) },
|
|
{ MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&QRCode___del___obj) },
|
|
};
|
|
STATIC MP_DEFINE_CONST_DICT(QRCode_locals_dict, QRCode_locals_dict_table);
|
|
|
|
STATIC const mp_obj_type_t QRCode_type = {
|
|
{ &mp_type_type },
|
|
.name = MP_QSTR_QRCode,
|
|
.make_new = QRCode_make_new,
|
|
.locals_dict = (void*)&QRCode_locals_dict,
|
|
};
|
|
/* End of setup for QRCode class */
|
|
|
|
/*
|
|
* Add additional class local dictionary table and data structure here
|
|
* And add the Class name and MP_ROM_PTR() to the globals table
|
|
* below
|
|
*/
|
|
|
|
/* Module Global configuration */
|
|
/* Define all properties of the module.
|
|
* Table entries are key/value pairs of the attribute name (a string)
|
|
* and the MicroPython object reference.
|
|
* All identifiers and strings are written as MP_QSTR_xxx and will be
|
|
* optimized to word-sized integers by the build system (interned strings).
|
|
*/
|
|
STATIC const mp_rom_map_elem_t foundation_module_globals_table[] = {
|
|
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_foundation) },
|
|
{ MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&foundation___del___obj) },
|
|
{ MP_ROM_QSTR(MP_QSTR_Backlight), MP_ROM_PTR(&backlight_type) },
|
|
{ MP_ROM_QSTR(MP_QSTR_Keypad), MP_ROM_PTR(&keypad_type) },
|
|
{ MP_ROM_QSTR(MP_QSTR_LCD), MP_ROM_PTR(&lcd_type) },
|
|
{ MP_ROM_QSTR(MP_QSTR_Camera), MP_ROM_PTR(&camera_type) },
|
|
{ MP_ROM_QSTR(MP_QSTR_Boardrev), MP_ROM_PTR(&boardrev_type) },
|
|
{ MP_ROM_QSTR(MP_QSTR_Powermon), MP_ROM_PTR(&powermon_type) },
|
|
{ MP_ROM_QSTR(MP_QSTR_Noise), MP_ROM_PTR(&noise_type) },
|
|
{ MP_ROM_QSTR(MP_QSTR_QR), MP_ROM_PTR(&QR_type) },
|
|
{ MP_ROM_QSTR(MP_QSTR_SettingsFlash), MP_ROM_PTR(&SettingsFlash_type) },
|
|
{ MP_ROM_QSTR(MP_QSTR_System), MP_ROM_PTR(&System_type) },
|
|
{ MP_ROM_QSTR(MP_QSTR_bip39), MP_ROM_PTR(&bip39_type) },
|
|
{ MP_ROM_QSTR(MP_QSTR_QRCode), MP_ROM_PTR(&QRCode_type) },
|
|
};
|
|
STATIC MP_DEFINE_CONST_DICT(foundation_module_globals, foundation_module_globals_table);
|
|
|
|
/* Define module object. */
|
|
const mp_obj_module_t foundation_user_cmodule = {
|
|
.base = { &mp_type_module },
|
|
.globals = (mp_obj_dict_t*)&foundation_module_globals,
|
|
};
|
|
|
|
MP_REGISTER_MODULE(MP_QSTR_foundation, foundation_user_cmodule, PASSPORT_FOUNDATION_ENABLED);
|
|
|