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.
 
 
 
 
 
 

1210 lines
38 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 "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 "stm32h7xx_hal.h"
#include "flash.h"
#include "gpio.h"
#include "dispatch.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;
/* Backlight class object and globals */
ring_buffer_t keybuf;
/* 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)
/*=============================================================================
* 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;
// uint32_t reg = *(uint32_t*)(0x580244d0);
// printf("======================================================\nREG = 0x%08lx\n======================================================\n", reg);
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(&keybuf, &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();
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_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;
// printf("new Camera()!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n");
// #camera_init();
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_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_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)}, // TODO: Is this right? Should it be "foundation_camera" or "camera"?
{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___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) {
HAL_StatusTypeDef 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 = read_powermon(&current, &voltage);
if (ret != HAL_OK) {
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 = read_boardrev(&board_rev);
if (ret != HAL_OK) {
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.
*/
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 = read_noise_inputs(&noise1, &noise2);
if (ret != HAL_OK) {
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); // TODO: How long should this be?
ret = read_noise_inputs(&noise1, &noise2);
if (ret != HAL_OK) {
return false;
}
r ^= noise1 ^ noise2;
}
*result = r;
return true;
}
STATIC mp_obj_t mod_foundation_noise_random_bytes(mp_obj_t self, const mp_obj_t buf) {
mp_buffer_info_t buf_info;
mp_get_buffer_raise(buf, &buf_info, MP_BUFFER_WRITE);
uint8_t* pbuf = (uint8_t*)buf_info.buf;
for (int i=0; i<buf_info.len;) {
uint8_t r[2];
bool result = get_random_uint16((uint16_t*)&r);
if (!result) {
return mp_const_false;
}
if (i<buf_info.len) {
pbuf[i] = r[0];
i++;
}
if (i<buf_info.len) {
pbuf[i] = r[1];
i++;
}
}
return mp_const_true;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_foundation_noise_random_bytes_obj, mod_foundation_noise_random_bytes);
STATIC mp_obj_t mod_foundation_noise___del__(mp_obj_t self) {
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 > SETTINGS_FLASH_END ||
data_info.len % 4 != 0) {
#ifdef FLASH_DEBUG
printf("ERROR: SettingsFlash_write: bad parameters\n");
#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);
printf("write: DONE\n");
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)
{
passport_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;
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);
// TODO: What are the incoming_sp and incoming_lr for?
result = se_dispatch(command, buf_info.buf, buf_info.len, arg2, 0, 0);
}
return mp_obj_new_int(result);
}
#define SECRETS_FLASH_START 0x81C0000
#define SECRETS_FLASH_SIZE 0x20000
/// def erase_rom_secrets(self) -> None
/// '''
/// Erase ROM secrets
/// TODO: This is a temporary function, since ROM secrets will be in the bootloader,
/// in this final bank of flash as they are here.
/// '''
STATIC mp_obj_t System_erase_rom_secrets(mp_obj_t self)
{
// NOTE: This function doesn't return any error/success info
flash_erase(SECRETS_FLASH_START, SECRETS_FLASH_SIZE / 4);
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_erase_rom_secrets_obj, System_erase_rom_secrets);
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_erase_rom_secrets), MP_ROM_PTR(&System_erase_rom_secrets_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
*=============================================================================*/
/// 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);
}
/// def get_words_matching_prefix(self) -> 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(mp_obj_t self, mp_obj_t prefix, mp_obj_t _max_matches)
{
uint32_t start = HAL_GetTick();
mp_check_self(mp_obj_is_str_or_bytes(prefix));
GET_STR_DATA_LEN(prefix, prefix_str, prefix_len);
printf("bip39_get_words_matching_prefix: prefix_str=%s len=%d\n", prefix_str, prefix_len);
int max_matches = mp_obj_get_int(_max_matches);
// TODO: change this to calculate dynamically based on max_matches and max seed word length,including comma separators
#define MATCHES_LEN 80
char matches[MATCHES_LEN];
get_words_matching_prefix((char*)prefix_str, matches, MATCHES_LEN, max_matches);
// 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);
uint32_t end = HAL_GetTick();
printf("bip39_get_words_matching_prefix: %lums\n", end - start);
return mp_obj_new_str_from_vstr(&mp_type_str, &vstr);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_3(bip39_get_words_matching_prefix_obj, 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 a
uint16_t version_capacity[] = {
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
};
/// 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);
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)
{
int num_entries = sizeof(version_capacity)/sizeof(uint16_t);
uint16_t size = mp_obj_get_int(data_size);
// printf("QRCode_fit_to_version: size=%u\n", size);
for (int i=0; i<num_entries; i++) {
if (version_capacity[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_2(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);