Browse Source

Import from working prototype

Daniele Lacamera 11 months ago
parent
commit
5e6c11ca93

+ 2 - 0
.gitignore

@@ -6,3 +6,5 @@ core
 *.bin
 *.elf
 *.uf2
+CMakeCache.txt
+elf2uf2/boot_uf2_headers/CMakeFiles

+ 3 - 0
.gitmodules

@@ -0,0 +1,3 @@
+[submodule "lib/wolfssl"]
+	path = lib/wolfssl
+	url = https://github.com/wolfssl/wolfssl.git

+ 289 - 0
CMakeDoxyfile.in

@@ -0,0 +1,289 @@
+#
+# DO NOT EDIT! THIS FILE WAS GENERATED BY CMAKE!
+#
+
+DOXYFILE_ENCODING      = @DOXYGEN_DOXYFILE_ENCODING@
+PROJECT_NAME           = @DOXYGEN_PROJECT_NAME@
+PROJECT_NUMBER         = @DOXYGEN_PROJECT_NUMBER@
+PROJECT_BRIEF          = @DOXYGEN_PROJECT_BRIEF@
+PROJECT_LOGO           = @DOXYGEN_PROJECT_LOGO@
+OUTPUT_DIRECTORY       = @DOXYGEN_OUTPUT_DIRECTORY@
+CREATE_SUBDIRS         = @DOXYGEN_CREATE_SUBDIRS@
+CREATE_SUBDIRS_LEVEL   = @DOXYGEN_CREATE_SUBDIRS_LEVEL@
+ALLOW_UNICODE_NAMES    = @DOXYGEN_ALLOW_UNICODE_NAMES@
+OUTPUT_LANGUAGE        = @DOXYGEN_OUTPUT_LANGUAGE@
+BRIEF_MEMBER_DESC      = @DOXYGEN_BRIEF_MEMBER_DESC@
+REPEAT_BRIEF           = @DOXYGEN_REPEAT_BRIEF@
+ABBREVIATE_BRIEF       = @DOXYGEN_ABBREVIATE_BRIEF@
+ALWAYS_DETAILED_SEC    = @DOXYGEN_ALWAYS_DETAILED_SEC@
+INLINE_INHERITED_MEMB  = @DOXYGEN_INLINE_INHERITED_MEMB@
+FULL_PATH_NAMES        = @DOXYGEN_FULL_PATH_NAMES@
+STRIP_FROM_PATH        = @DOXYGEN_STRIP_FROM_PATH@
+STRIP_FROM_INC_PATH    = @DOXYGEN_STRIP_FROM_INC_PATH@
+SHORT_NAMES            = @DOXYGEN_SHORT_NAMES@
+JAVADOC_AUTOBRIEF      = @DOXYGEN_JAVADOC_AUTOBRIEF@
+JAVADOC_BANNER         = @DOXYGEN_JAVADOC_BANNER@
+QT_AUTOBRIEF           = @DOXYGEN_QT_AUTOBRIEF@
+MULTILINE_CPP_IS_BRIEF = @DOXYGEN_MULTILINE_CPP_IS_BRIEF@
+PYTHON_DOCSTRING       = @DOXYGEN_PYTHON_DOCSTRING@
+INHERIT_DOCS           = @DOXYGEN_INHERIT_DOCS@
+SEPARATE_MEMBER_PAGES  = @DOXYGEN_SEPARATE_MEMBER_PAGES@
+TAB_SIZE               = @DOXYGEN_TAB_SIZE@
+ALIASES                = @DOXYGEN_ALIASES@
+OPTIMIZE_OUTPUT_FOR_C  = @DOXYGEN_OPTIMIZE_OUTPUT_FOR_C@
+OPTIMIZE_OUTPUT_JAVA   = @DOXYGEN_OPTIMIZE_OUTPUT_JAVA@
+OPTIMIZE_FOR_FORTRAN   = @DOXYGEN_OPTIMIZE_FOR_FORTRAN@
+OPTIMIZE_OUTPUT_VHDL   = @DOXYGEN_OPTIMIZE_OUTPUT_VHDL@
+OPTIMIZE_OUTPUT_SLICE  = @DOXYGEN_OPTIMIZE_OUTPUT_SLICE@
+EXTENSION_MAPPING      = @DOXYGEN_EXTENSION_MAPPING@
+MARKDOWN_SUPPORT       = @DOXYGEN_MARKDOWN_SUPPORT@
+TOC_INCLUDE_HEADINGS   = @DOXYGEN_TOC_INCLUDE_HEADINGS@
+AUTOLINK_SUPPORT       = @DOXYGEN_AUTOLINK_SUPPORT@
+BUILTIN_STL_SUPPORT    = @DOXYGEN_BUILTIN_STL_SUPPORT@
+CPP_CLI_SUPPORT        = @DOXYGEN_CPP_CLI_SUPPORT@
+SIP_SUPPORT            = @DOXYGEN_SIP_SUPPORT@
+IDL_PROPERTY_SUPPORT   = @DOXYGEN_IDL_PROPERTY_SUPPORT@
+DISTRIBUTE_GROUP_DOC   = @DOXYGEN_DISTRIBUTE_GROUP_DOC@
+GROUP_NESTED_COMPOUNDS = @DOXYGEN_GROUP_NESTED_COMPOUNDS@
+SUBGROUPING            = @DOXYGEN_SUBGROUPING@
+INLINE_GROUPED_CLASSES = @DOXYGEN_INLINE_GROUPED_CLASSES@
+INLINE_SIMPLE_STRUCTS  = @DOXYGEN_INLINE_SIMPLE_STRUCTS@
+TYPEDEF_HIDES_STRUCT   = @DOXYGEN_TYPEDEF_HIDES_STRUCT@
+LOOKUP_CACHE_SIZE      = @DOXYGEN_LOOKUP_CACHE_SIZE@
+NUM_PROC_THREADS       = @DOXYGEN_NUM_PROC_THREADS@
+EXTRACT_ALL            = @DOXYGEN_EXTRACT_ALL@
+EXTRACT_PRIVATE        = @DOXYGEN_EXTRACT_PRIVATE@
+EXTRACT_PRIV_VIRTUAL   = @DOXYGEN_EXTRACT_PRIV_VIRTUAL@
+EXTRACT_PACKAGE        = @DOXYGEN_EXTRACT_PACKAGE@
+EXTRACT_STATIC         = @DOXYGEN_EXTRACT_STATIC@
+EXTRACT_LOCAL_CLASSES  = @DOXYGEN_EXTRACT_LOCAL_CLASSES@
+EXTRACT_LOCAL_METHODS  = @DOXYGEN_EXTRACT_LOCAL_METHODS@
+EXTRACT_ANON_NSPACES   = @DOXYGEN_EXTRACT_ANON_NSPACES@
+RESOLVE_UNNAMED_PARAMS = @DOXYGEN_RESOLVE_UNNAMED_PARAMS@
+HIDE_UNDOC_MEMBERS     = @DOXYGEN_HIDE_UNDOC_MEMBERS@
+HIDE_UNDOC_CLASSES     = @DOXYGEN_HIDE_UNDOC_CLASSES@
+HIDE_FRIEND_COMPOUNDS  = @DOXYGEN_HIDE_FRIEND_COMPOUNDS@
+HIDE_IN_BODY_DOCS      = @DOXYGEN_HIDE_IN_BODY_DOCS@
+INTERNAL_DOCS          = @DOXYGEN_INTERNAL_DOCS@
+CASE_SENSE_NAMES       = @DOXYGEN_CASE_SENSE_NAMES@
+HIDE_SCOPE_NAMES       = @DOXYGEN_HIDE_SCOPE_NAMES@
+HIDE_COMPOUND_REFERENCE= @DOXYGEN_HIDE_COMPOUND_REFERENCE@
+SHOW_HEADERFILE        = @DOXYGEN_SHOW_HEADERFILE@
+SHOW_INCLUDE_FILES     = @DOXYGEN_SHOW_INCLUDE_FILES@
+SHOW_GROUPED_MEMB_INC  = @DOXYGEN_SHOW_GROUPED_MEMB_INC@
+FORCE_LOCAL_INCLUDES   = @DOXYGEN_FORCE_LOCAL_INCLUDES@
+INLINE_INFO            = @DOXYGEN_INLINE_INFO@
+SORT_MEMBER_DOCS       = @DOXYGEN_SORT_MEMBER_DOCS@
+SORT_BRIEF_DOCS        = @DOXYGEN_SORT_BRIEF_DOCS@
+SORT_MEMBERS_CTORS_1ST = @DOXYGEN_SORT_MEMBERS_CTORS_1ST@
+SORT_GROUP_NAMES       = @DOXYGEN_SORT_GROUP_NAMES@
+SORT_BY_SCOPE_NAME     = @DOXYGEN_SORT_BY_SCOPE_NAME@
+STRICT_PROTO_MATCHING  = @DOXYGEN_STRICT_PROTO_MATCHING@
+GENERATE_TODOLIST      = @DOXYGEN_GENERATE_TODOLIST@
+GENERATE_TESTLIST      = @DOXYGEN_GENERATE_TESTLIST@
+GENERATE_BUGLIST       = @DOXYGEN_GENERATE_BUGLIST@
+GENERATE_DEPRECATEDLIST= @DOXYGEN_GENERATE_DEPRECATEDLIST@
+ENABLED_SECTIONS       = @DOXYGEN_ENABLED_SECTIONS@
+MAX_INITIALIZER_LINES  = @DOXYGEN_MAX_INITIALIZER_LINES@
+SHOW_USED_FILES        = @DOXYGEN_SHOW_USED_FILES@
+SHOW_FILES             = @DOXYGEN_SHOW_FILES@
+SHOW_NAMESPACES        = @DOXYGEN_SHOW_NAMESPACES@
+FILE_VERSION_FILTER    = @DOXYGEN_FILE_VERSION_FILTER@
+LAYOUT_FILE            = @DOXYGEN_LAYOUT_FILE@
+CITE_BIB_FILES         = @DOXYGEN_CITE_BIB_FILES@
+QUIET                  = @DOXYGEN_QUIET@
+WARNINGS               = @DOXYGEN_WARNINGS@
+WARN_IF_UNDOCUMENTED   = @DOXYGEN_WARN_IF_UNDOCUMENTED@
+WARN_IF_DOC_ERROR      = @DOXYGEN_WARN_IF_DOC_ERROR@
+WARN_IF_INCOMPLETE_DOC = @DOXYGEN_WARN_IF_INCOMPLETE_DOC@
+WARN_NO_PARAMDOC       = @DOXYGEN_WARN_NO_PARAMDOC@
+WARN_AS_ERROR          = @DOXYGEN_WARN_AS_ERROR@
+WARN_FORMAT            = @DOXYGEN_WARN_FORMAT@
+WARN_LINE_FORMAT       = @DOXYGEN_WARN_LINE_FORMAT@
+WARN_LOGFILE           = @DOXYGEN_WARN_LOGFILE@
+INPUT                  = @DOXYGEN_INPUT@
+INPUT_ENCODING         = @DOXYGEN_INPUT_ENCODING@
+FILE_PATTERNS          = @DOXYGEN_FILE_PATTERNS@
+RECURSIVE              = @DOXYGEN_RECURSIVE@
+EXCLUDE                = @DOXYGEN_EXCLUDE@
+EXCLUDE_SYMLINKS       = @DOXYGEN_EXCLUDE_SYMLINKS@
+EXCLUDE_PATTERNS       = @DOXYGEN_EXCLUDE_PATTERNS@
+EXCLUDE_SYMBOLS        = @DOXYGEN_EXCLUDE_SYMBOLS@
+EXAMPLE_PATH           = @DOXYGEN_EXAMPLE_PATH@
+EXAMPLE_PATTERNS       = @DOXYGEN_EXAMPLE_PATTERNS@
+EXAMPLE_RECURSIVE      = @DOXYGEN_EXAMPLE_RECURSIVE@
+IMAGE_PATH             = @DOXYGEN_IMAGE_PATH@
+INPUT_FILTER           = @DOXYGEN_INPUT_FILTER@
+FILTER_PATTERNS        = @DOXYGEN_FILTER_PATTERNS@
+FILTER_SOURCE_FILES    = @DOXYGEN_FILTER_SOURCE_FILES@
+FILTER_SOURCE_PATTERNS = @DOXYGEN_FILTER_SOURCE_PATTERNS@
+USE_MDFILE_AS_MAINPAGE = @DOXYGEN_USE_MDFILE_AS_MAINPAGE@
+SOURCE_BROWSER         = @DOXYGEN_SOURCE_BROWSER@
+INLINE_SOURCES         = @DOXYGEN_INLINE_SOURCES@
+STRIP_CODE_COMMENTS    = @DOXYGEN_STRIP_CODE_COMMENTS@
+REFERENCED_BY_RELATION = @DOXYGEN_REFERENCED_BY_RELATION@
+REFERENCES_RELATION    = @DOXYGEN_REFERENCES_RELATION@
+REFERENCES_LINK_SOURCE = @DOXYGEN_REFERENCES_LINK_SOURCE@
+SOURCE_TOOLTIPS        = @DOXYGEN_SOURCE_TOOLTIPS@
+USE_HTAGS              = @DOXYGEN_USE_HTAGS@
+VERBATIM_HEADERS       = @DOXYGEN_VERBATIM_HEADERS@
+CLANG_ASSISTED_PARSING = @DOXYGEN_CLANG_ASSISTED_PARSING@
+CLANG_ADD_INC_PATHS    = @DOXYGEN_CLANG_ADD_INC_PATHS@
+CLANG_OPTIONS          = @DOXYGEN_CLANG_OPTIONS@
+CLANG_DATABASE_PATH    = @DOXYGEN_CLANG_DATABASE_PATH@
+ALPHABETICAL_INDEX     = @DOXYGEN_ALPHABETICAL_INDEX@
+IGNORE_PREFIX          = @DOXYGEN_IGNORE_PREFIX@
+GENERATE_HTML          = @DOXYGEN_GENERATE_HTML@
+HTML_OUTPUT            = @DOXYGEN_HTML_OUTPUT@
+HTML_FILE_EXTENSION    = @DOXYGEN_HTML_FILE_EXTENSION@
+HTML_HEADER            = @DOXYGEN_HTML_HEADER@
+HTML_FOOTER            = @DOXYGEN_HTML_FOOTER@
+HTML_STYLESHEET        = @DOXYGEN_HTML_STYLESHEET@
+HTML_EXTRA_STYLESHEET  = @DOXYGEN_HTML_EXTRA_STYLESHEET@
+HTML_EXTRA_FILES       = @DOXYGEN_HTML_EXTRA_FILES@
+HTML_COLORSTYLE_HUE    = @DOXYGEN_HTML_COLORSTYLE_HUE@
+HTML_COLORSTYLE_SAT    = @DOXYGEN_HTML_COLORSTYLE_SAT@
+HTML_COLORSTYLE_GAMMA  = @DOXYGEN_HTML_COLORSTYLE_GAMMA@
+HTML_TIMESTAMP         = @DOXYGEN_HTML_TIMESTAMP@
+HTML_DYNAMIC_MENUS     = @DOXYGEN_HTML_DYNAMIC_MENUS@
+HTML_DYNAMIC_SECTIONS  = @DOXYGEN_HTML_DYNAMIC_SECTIONS@
+HTML_INDEX_NUM_ENTRIES = @DOXYGEN_HTML_INDEX_NUM_ENTRIES@
+GENERATE_DOCSET        = @DOXYGEN_GENERATE_DOCSET@
+DOCSET_FEEDNAME        = @DOXYGEN_DOCSET_FEEDNAME@
+DOCSET_FEEDURL         = @DOXYGEN_DOCSET_FEEDURL@
+DOCSET_BUNDLE_ID       = @DOXYGEN_DOCSET_BUNDLE_ID@
+DOCSET_PUBLISHER_ID    = @DOXYGEN_DOCSET_PUBLISHER_ID@
+DOCSET_PUBLISHER_NAME  = @DOXYGEN_DOCSET_PUBLISHER_NAME@
+GENERATE_HTMLHELP      = @DOXYGEN_GENERATE_HTMLHELP@
+CHM_FILE               = @DOXYGEN_CHM_FILE@
+HHC_LOCATION           = @DOXYGEN_HHC_LOCATION@
+GENERATE_CHI           = @DOXYGEN_GENERATE_CHI@
+CHM_INDEX_ENCODING     = @DOXYGEN_CHM_INDEX_ENCODING@
+BINARY_TOC             = @DOXYGEN_BINARY_TOC@
+TOC_EXPAND             = @DOXYGEN_TOC_EXPAND@
+GENERATE_QHP           = @DOXYGEN_GENERATE_QHP@
+QCH_FILE               = @DOXYGEN_QCH_FILE@
+QHP_NAMESPACE          = @DOXYGEN_QHP_NAMESPACE@
+QHP_VIRTUAL_FOLDER     = @DOXYGEN_QHP_VIRTUAL_FOLDER@
+QHP_CUST_FILTER_NAME   = @DOXYGEN_QHP_CUST_FILTER_NAME@
+QHP_CUST_FILTER_ATTRS  = @DOXYGEN_QHP_CUST_FILTER_ATTRS@
+QHP_SECT_FILTER_ATTRS  = @DOXYGEN_QHP_SECT_FILTER_ATTRS@
+QHG_LOCATION           = @DOXYGEN_QHG_LOCATION@
+GENERATE_ECLIPSEHELP   = @DOXYGEN_GENERATE_ECLIPSEHELP@
+ECLIPSE_DOC_ID         = @DOXYGEN_ECLIPSE_DOC_ID@
+DISABLE_INDEX          = @DOXYGEN_DISABLE_INDEX@
+GENERATE_TREEVIEW      = @DOXYGEN_GENERATE_TREEVIEW@
+FULL_SIDEBAR           = @DOXYGEN_FULL_SIDEBAR@
+ENUM_VALUES_PER_LINE   = @DOXYGEN_ENUM_VALUES_PER_LINE@
+TREEVIEW_WIDTH         = @DOXYGEN_TREEVIEW_WIDTH@
+EXT_LINKS_IN_WINDOW    = @DOXYGEN_EXT_LINKS_IN_WINDOW@
+OBFUSCATE_EMAILS       = @DOXYGEN_OBFUSCATE_EMAILS@
+HTML_FORMULA_FORMAT    = @DOXYGEN_HTML_FORMULA_FORMAT@
+FORMULA_FONTSIZE       = @DOXYGEN_FORMULA_FONTSIZE@
+FORMULA_TRANSPARENT    = @DOXYGEN_FORMULA_TRANSPARENT@
+FORMULA_MACROFILE      = @DOXYGEN_FORMULA_MACROFILE@
+USE_MATHJAX            = @DOXYGEN_USE_MATHJAX@
+MATHJAX_VERSION        = @DOXYGEN_MATHJAX_VERSION@
+MATHJAX_FORMAT         = @DOXYGEN_MATHJAX_FORMAT@
+MATHJAX_RELPATH        = @DOXYGEN_MATHJAX_RELPATH@
+MATHJAX_EXTENSIONS     = @DOXYGEN_MATHJAX_EXTENSIONS@
+MATHJAX_CODEFILE       = @DOXYGEN_MATHJAX_CODEFILE@
+SEARCHENGINE           = @DOXYGEN_SEARCHENGINE@
+SERVER_BASED_SEARCH    = @DOXYGEN_SERVER_BASED_SEARCH@
+EXTERNAL_SEARCH        = @DOXYGEN_EXTERNAL_SEARCH@
+SEARCHENGINE_URL       = @DOXYGEN_SEARCHENGINE_URL@
+SEARCHDATA_FILE        = @DOXYGEN_SEARCHDATA_FILE@
+EXTERNAL_SEARCH_ID     = @DOXYGEN_EXTERNAL_SEARCH_ID@
+EXTRA_SEARCH_MAPPINGS  = @DOXYGEN_EXTRA_SEARCH_MAPPINGS@
+GENERATE_LATEX         = @DOXYGEN_GENERATE_LATEX@
+LATEX_OUTPUT           = @DOXYGEN_LATEX_OUTPUT@
+LATEX_CMD_NAME         = @DOXYGEN_LATEX_CMD_NAME@
+MAKEINDEX_CMD_NAME     = @DOXYGEN_MAKEINDEX_CMD_NAME@
+LATEX_MAKEINDEX_CMD    = @DOXYGEN_LATEX_MAKEINDEX_CMD@
+COMPACT_LATEX          = @DOXYGEN_COMPACT_LATEX@
+PAPER_TYPE             = @DOXYGEN_PAPER_TYPE@
+EXTRA_PACKAGES         = @DOXYGEN_EXTRA_PACKAGES@
+LATEX_HEADER           = @DOXYGEN_LATEX_HEADER@
+LATEX_FOOTER           = @DOXYGEN_LATEX_FOOTER@
+LATEX_EXTRA_STYLESHEET = @DOXYGEN_LATEX_EXTRA_STYLESHEET@
+LATEX_EXTRA_FILES      = @DOXYGEN_LATEX_EXTRA_FILES@
+PDF_HYPERLINKS         = @DOXYGEN_PDF_HYPERLINKS@
+USE_PDFLATEX           = @DOXYGEN_USE_PDFLATEX@
+LATEX_BATCHMODE        = @DOXYGEN_LATEX_BATCHMODE@
+LATEX_HIDE_INDICES     = @DOXYGEN_LATEX_HIDE_INDICES@
+LATEX_BIB_STYLE        = @DOXYGEN_LATEX_BIB_STYLE@
+LATEX_TIMESTAMP        = @DOXYGEN_LATEX_TIMESTAMP@
+LATEX_EMOJI_DIRECTORY  = @DOXYGEN_LATEX_EMOJI_DIRECTORY@
+GENERATE_RTF           = @DOXYGEN_GENERATE_RTF@
+RTF_OUTPUT             = @DOXYGEN_RTF_OUTPUT@
+COMPACT_RTF            = @DOXYGEN_COMPACT_RTF@
+RTF_HYPERLINKS         = @DOXYGEN_RTF_HYPERLINKS@
+RTF_STYLESHEET_FILE    = @DOXYGEN_RTF_STYLESHEET_FILE@
+RTF_EXTENSIONS_FILE    = @DOXYGEN_RTF_EXTENSIONS_FILE@
+GENERATE_MAN           = @DOXYGEN_GENERATE_MAN@
+MAN_OUTPUT             = @DOXYGEN_MAN_OUTPUT@
+MAN_EXTENSION          = @DOXYGEN_MAN_EXTENSION@
+MAN_SUBDIR             = @DOXYGEN_MAN_SUBDIR@
+MAN_LINKS              = @DOXYGEN_MAN_LINKS@
+GENERATE_XML           = @DOXYGEN_GENERATE_XML@
+XML_OUTPUT             = @DOXYGEN_XML_OUTPUT@
+XML_PROGRAMLISTING     = @DOXYGEN_XML_PROGRAMLISTING@
+XML_NS_MEMB_FILE_SCOPE = @DOXYGEN_XML_NS_MEMB_FILE_SCOPE@
+GENERATE_DOCBOOK       = @DOXYGEN_GENERATE_DOCBOOK@
+DOCBOOK_OUTPUT         = @DOXYGEN_DOCBOOK_OUTPUT@
+GENERATE_AUTOGEN_DEF   = @DOXYGEN_GENERATE_AUTOGEN_DEF@
+GENERATE_PERLMOD       = @DOXYGEN_GENERATE_PERLMOD@
+PERLMOD_LATEX          = @DOXYGEN_PERLMOD_LATEX@
+PERLMOD_PRETTY         = @DOXYGEN_PERLMOD_PRETTY@
+PERLMOD_MAKEVAR_PREFIX = @DOXYGEN_PERLMOD_MAKEVAR_PREFIX@
+ENABLE_PREPROCESSING   = @DOXYGEN_ENABLE_PREPROCESSING@
+MACRO_EXPANSION        = @DOXYGEN_MACRO_EXPANSION@
+EXPAND_ONLY_PREDEF     = @DOXYGEN_EXPAND_ONLY_PREDEF@
+SEARCH_INCLUDES        = @DOXYGEN_SEARCH_INCLUDES@
+INCLUDE_PATH           = @DOXYGEN_INCLUDE_PATH@
+INCLUDE_FILE_PATTERNS  = @DOXYGEN_INCLUDE_FILE_PATTERNS@
+PREDEFINED             = @DOXYGEN_PREDEFINED@
+EXPAND_AS_DEFINED      = @DOXYGEN_EXPAND_AS_DEFINED@
+SKIP_FUNCTION_MACROS   = @DOXYGEN_SKIP_FUNCTION_MACROS@
+TAGFILES               = @DOXYGEN_TAGFILES@
+GENERATE_TAGFILE       = @DOXYGEN_GENERATE_TAGFILE@
+ALLEXTERNALS           = @DOXYGEN_ALLEXTERNALS@
+EXTERNAL_GROUPS        = @DOXYGEN_EXTERNAL_GROUPS@
+EXTERNAL_PAGES         = @DOXYGEN_EXTERNAL_PAGES@
+DIA_PATH               = @DOXYGEN_DIA_PATH@
+HIDE_UNDOC_RELATIONS   = @DOXYGEN_HIDE_UNDOC_RELATIONS@
+HAVE_DOT               = @DOXYGEN_HAVE_DOT@
+DOT_NUM_THREADS        = @DOXYGEN_DOT_NUM_THREADS@
+DOT_FONTNAME           = @DOXYGEN_DOT_FONTNAME@
+DOT_FONTSIZE           = @DOXYGEN_DOT_FONTSIZE@
+DOT_FONTPATH           = @DOXYGEN_DOT_FONTPATH@
+CLASS_GRAPH            = @DOXYGEN_CLASS_GRAPH@
+COLLABORATION_GRAPH    = @DOXYGEN_COLLABORATION_GRAPH@
+GROUP_GRAPHS           = @DOXYGEN_GROUP_GRAPHS@
+UML_LOOK               = @DOXYGEN_UML_LOOK@
+UML_LIMIT_NUM_FIELDS   = @DOXYGEN_UML_LIMIT_NUM_FIELDS@
+DOT_UML_DETAILS        = @DOXYGEN_DOT_UML_DETAILS@
+DOT_WRAP_THRESHOLD     = @DOXYGEN_DOT_WRAP_THRESHOLD@
+TEMPLATE_RELATIONS     = @DOXYGEN_TEMPLATE_RELATIONS@
+INCLUDE_GRAPH          = @DOXYGEN_INCLUDE_GRAPH@
+INCLUDED_BY_GRAPH      = @DOXYGEN_INCLUDED_BY_GRAPH@
+CALL_GRAPH             = @DOXYGEN_CALL_GRAPH@
+CALLER_GRAPH           = @DOXYGEN_CALLER_GRAPH@
+GRAPHICAL_HIERARCHY    = @DOXYGEN_GRAPHICAL_HIERARCHY@
+DIRECTORY_GRAPH        = @DOXYGEN_DIRECTORY_GRAPH@
+DIR_GRAPH_MAX_DEPTH    = @DOXYGEN_DIR_GRAPH_MAX_DEPTH@
+DOT_IMAGE_FORMAT       = @DOXYGEN_DOT_IMAGE_FORMAT@
+INTERACTIVE_SVG        = @DOXYGEN_INTERACTIVE_SVG@
+DOT_PATH               = @DOXYGEN_DOT_PATH@
+DOTFILE_DIRS           = @DOXYGEN_DOTFILE_DIRS@
+MSCFILE_DIRS           = @DOXYGEN_MSCFILE_DIRS@
+DIAFILE_DIRS           = @DOXYGEN_DIAFILE_DIRS@
+PLANTUML_JAR_PATH      = @DOXYGEN_PLANTUML_JAR_PATH@
+PLANTUML_CFG_FILE      = @DOXYGEN_PLANTUML_CFG_FILE@
+PLANTUML_INCLUDE_PATH  = @DOXYGEN_PLANTUML_INCLUDE_PATH@
+DOT_GRAPH_MAX_NODES    = @DOXYGEN_DOT_GRAPH_MAX_NODES@
+MAX_DOT_GRAPH_DEPTH    = @DOXYGEN_MAX_DOT_GRAPH_DEPTH@
+DOT_TRANSPARENT        = @DOXYGEN_DOT_TRANSPARENT@
+DOT_MULTI_TARGETS      = @DOXYGEN_DOT_MULTI_TARGETS@
+GENERATE_LEGEND        = @DOXYGEN_GENERATE_LEGEND@
+DOT_CLEANUP            = @DOXYGEN_DOT_CLEANUP@

+ 695 - 0
CMakeDoxygenDefaults.cmake

@@ -0,0 +1,695 @@
+#
+# DO NOT EDIT! THIS FILE WAS GENERATED BY CMAKE!
+#
+
+if(NOT DEFINED DOXYGEN_DOXYFILE_ENCODING)
+    set(DOXYGEN_DOXYFILE_ENCODING UTF-8)
+endif()
+if(NOT DEFINED DOXYGEN_PROJECT_NAME)
+    set(DOXYGEN_PROJECT_NAME "My Project")
+endif()
+if(NOT DEFINED DOXYGEN_CREATE_SUBDIRS)
+    set(DOXYGEN_CREATE_SUBDIRS NO)
+endif()
+if(NOT DEFINED DOXYGEN_CREATE_SUBDIRS_LEVEL)
+    set(DOXYGEN_CREATE_SUBDIRS_LEVEL 8)
+endif()
+if(NOT DEFINED DOXYGEN_ALLOW_UNICODE_NAMES)
+    set(DOXYGEN_ALLOW_UNICODE_NAMES NO)
+endif()
+if(NOT DEFINED DOXYGEN_OUTPUT_LANGUAGE)
+    set(DOXYGEN_OUTPUT_LANGUAGE English)
+endif()
+if(NOT DEFINED DOXYGEN_BRIEF_MEMBER_DESC)
+    set(DOXYGEN_BRIEF_MEMBER_DESC YES)
+endif()
+if(NOT DEFINED DOXYGEN_REPEAT_BRIEF)
+    set(DOXYGEN_REPEAT_BRIEF YES)
+endif()
+if(NOT DEFINED DOXYGEN_ABBREVIATE_BRIEF)
+    set(DOXYGEN_ABBREVIATE_BRIEF "The $name class" 
+                         "The $name widget" 
+                         "The $name file" 
+                         is 
+                         provides 
+                         specifies 
+                         contains 
+                         represents 
+                         a 
+                         an 
+                         the)
+endif()
+if(NOT DEFINED DOXYGEN_ALWAYS_DETAILED_SEC)
+    set(DOXYGEN_ALWAYS_DETAILED_SEC NO)
+endif()
+if(NOT DEFINED DOXYGEN_INLINE_INHERITED_MEMB)
+    set(DOXYGEN_INLINE_INHERITED_MEMB NO)
+endif()
+if(NOT DEFINED DOXYGEN_FULL_PATH_NAMES)
+    set(DOXYGEN_FULL_PATH_NAMES YES)
+endif()
+if(NOT DEFINED DOXYGEN_SHORT_NAMES)
+    set(DOXYGEN_SHORT_NAMES NO)
+endif()
+if(NOT DEFINED DOXYGEN_JAVADOC_AUTOBRIEF)
+    set(DOXYGEN_JAVADOC_AUTOBRIEF NO)
+endif()
+if(NOT DEFINED DOXYGEN_JAVADOC_BANNER)
+    set(DOXYGEN_JAVADOC_BANNER NO)
+endif()
+if(NOT DEFINED DOXYGEN_QT_AUTOBRIEF)
+    set(DOXYGEN_QT_AUTOBRIEF NO)
+endif()
+if(NOT DEFINED DOXYGEN_MULTILINE_CPP_IS_BRIEF)
+    set(DOXYGEN_MULTILINE_CPP_IS_BRIEF NO)
+endif()
+if(NOT DEFINED DOXYGEN_PYTHON_DOCSTRING)
+    set(DOXYGEN_PYTHON_DOCSTRING YES)
+endif()
+if(NOT DEFINED DOXYGEN_INHERIT_DOCS)
+    set(DOXYGEN_INHERIT_DOCS YES)
+endif()
+if(NOT DEFINED DOXYGEN_SEPARATE_MEMBER_PAGES)
+    set(DOXYGEN_SEPARATE_MEMBER_PAGES NO)
+endif()
+if(NOT DEFINED DOXYGEN_TAB_SIZE)
+    set(DOXYGEN_TAB_SIZE 4)
+endif()
+if(NOT DEFINED DOXYGEN_OPTIMIZE_OUTPUT_FOR_C)
+    set(DOXYGEN_OPTIMIZE_OUTPUT_FOR_C NO)
+endif()
+if(NOT DEFINED DOXYGEN_OPTIMIZE_OUTPUT_JAVA)
+    set(DOXYGEN_OPTIMIZE_OUTPUT_JAVA NO)
+endif()
+if(NOT DEFINED DOXYGEN_OPTIMIZE_FOR_FORTRAN)
+    set(DOXYGEN_OPTIMIZE_FOR_FORTRAN NO)
+endif()
+if(NOT DEFINED DOXYGEN_OPTIMIZE_OUTPUT_VHDL)
+    set(DOXYGEN_OPTIMIZE_OUTPUT_VHDL NO)
+endif()
+if(NOT DEFINED DOXYGEN_OPTIMIZE_OUTPUT_SLICE)
+    set(DOXYGEN_OPTIMIZE_OUTPUT_SLICE NO)
+endif()
+if(NOT DEFINED DOXYGEN_MARKDOWN_SUPPORT)
+    set(DOXYGEN_MARKDOWN_SUPPORT YES)
+endif()
+if(NOT DEFINED DOXYGEN_TOC_INCLUDE_HEADINGS)
+    set(DOXYGEN_TOC_INCLUDE_HEADINGS 5)
+endif()
+if(NOT DEFINED DOXYGEN_AUTOLINK_SUPPORT)
+    set(DOXYGEN_AUTOLINK_SUPPORT YES)
+endif()
+if(NOT DEFINED DOXYGEN_BUILTIN_STL_SUPPORT)
+    set(DOXYGEN_BUILTIN_STL_SUPPORT NO)
+endif()
+if(NOT DEFINED DOXYGEN_CPP_CLI_SUPPORT)
+    set(DOXYGEN_CPP_CLI_SUPPORT NO)
+endif()
+if(NOT DEFINED DOXYGEN_SIP_SUPPORT)
+    set(DOXYGEN_SIP_SUPPORT NO)
+endif()
+if(NOT DEFINED DOXYGEN_IDL_PROPERTY_SUPPORT)
+    set(DOXYGEN_IDL_PROPERTY_SUPPORT YES)
+endif()
+if(NOT DEFINED DOXYGEN_DISTRIBUTE_GROUP_DOC)
+    set(DOXYGEN_DISTRIBUTE_GROUP_DOC NO)
+endif()
+if(NOT DEFINED DOXYGEN_GROUP_NESTED_COMPOUNDS)
+    set(DOXYGEN_GROUP_NESTED_COMPOUNDS NO)
+endif()
+if(NOT DEFINED DOXYGEN_SUBGROUPING)
+    set(DOXYGEN_SUBGROUPING YES)
+endif()
+if(NOT DEFINED DOXYGEN_INLINE_GROUPED_CLASSES)
+    set(DOXYGEN_INLINE_GROUPED_CLASSES NO)
+endif()
+if(NOT DEFINED DOXYGEN_INLINE_SIMPLE_STRUCTS)
+    set(DOXYGEN_INLINE_SIMPLE_STRUCTS NO)
+endif()
+if(NOT DEFINED DOXYGEN_TYPEDEF_HIDES_STRUCT)
+    set(DOXYGEN_TYPEDEF_HIDES_STRUCT NO)
+endif()
+if(NOT DEFINED DOXYGEN_LOOKUP_CACHE_SIZE)
+    set(DOXYGEN_LOOKUP_CACHE_SIZE 0)
+endif()
+if(NOT DEFINED DOXYGEN_NUM_PROC_THREADS)
+    set(DOXYGEN_NUM_PROC_THREADS 1)
+endif()
+if(NOT DEFINED DOXYGEN_EXTRACT_ALL)
+    set(DOXYGEN_EXTRACT_ALL NO)
+endif()
+if(NOT DEFINED DOXYGEN_EXTRACT_PRIVATE)
+    set(DOXYGEN_EXTRACT_PRIVATE NO)
+endif()
+if(NOT DEFINED DOXYGEN_EXTRACT_PRIV_VIRTUAL)
+    set(DOXYGEN_EXTRACT_PRIV_VIRTUAL NO)
+endif()
+if(NOT DEFINED DOXYGEN_EXTRACT_PACKAGE)
+    set(DOXYGEN_EXTRACT_PACKAGE NO)
+endif()
+if(NOT DEFINED DOXYGEN_EXTRACT_STATIC)
+    set(DOXYGEN_EXTRACT_STATIC NO)
+endif()
+if(NOT DEFINED DOXYGEN_EXTRACT_LOCAL_CLASSES)
+    set(DOXYGEN_EXTRACT_LOCAL_CLASSES YES)
+endif()
+if(NOT DEFINED DOXYGEN_EXTRACT_LOCAL_METHODS)
+    set(DOXYGEN_EXTRACT_LOCAL_METHODS NO)
+endif()
+if(NOT DEFINED DOXYGEN_EXTRACT_ANON_NSPACES)
+    set(DOXYGEN_EXTRACT_ANON_NSPACES NO)
+endif()
+if(NOT DEFINED DOXYGEN_RESOLVE_UNNAMED_PARAMS)
+    set(DOXYGEN_RESOLVE_UNNAMED_PARAMS YES)
+endif()
+if(NOT DEFINED DOXYGEN_HIDE_UNDOC_MEMBERS)
+    set(DOXYGEN_HIDE_UNDOC_MEMBERS NO)
+endif()
+if(NOT DEFINED DOXYGEN_HIDE_UNDOC_CLASSES)
+    set(DOXYGEN_HIDE_UNDOC_CLASSES NO)
+endif()
+if(NOT DEFINED DOXYGEN_HIDE_FRIEND_COMPOUNDS)
+    set(DOXYGEN_HIDE_FRIEND_COMPOUNDS NO)
+endif()
+if(NOT DEFINED DOXYGEN_HIDE_IN_BODY_DOCS)
+    set(DOXYGEN_HIDE_IN_BODY_DOCS NO)
+endif()
+if(NOT DEFINED DOXYGEN_INTERNAL_DOCS)
+    set(DOXYGEN_INTERNAL_DOCS NO)
+endif()
+if(NOT DEFINED DOXYGEN_CASE_SENSE_NAMES)
+    set(DOXYGEN_CASE_SENSE_NAMES YES)
+endif()
+if(NOT DEFINED DOXYGEN_HIDE_SCOPE_NAMES)
+    set(DOXYGEN_HIDE_SCOPE_NAMES NO)
+endif()
+if(NOT DEFINED DOXYGEN_HIDE_COMPOUND_REFERENCE)
+    set(DOXYGEN_HIDE_COMPOUND_REFERENCE NO)
+endif()
+if(NOT DEFINED DOXYGEN_SHOW_HEADERFILE)
+    set(DOXYGEN_SHOW_HEADERFILE YES)
+endif()
+if(NOT DEFINED DOXYGEN_SHOW_INCLUDE_FILES)
+    set(DOXYGEN_SHOW_INCLUDE_FILES YES)
+endif()
+if(NOT DEFINED DOXYGEN_SHOW_GROUPED_MEMB_INC)
+    set(DOXYGEN_SHOW_GROUPED_MEMB_INC NO)
+endif()
+if(NOT DEFINED DOXYGEN_FORCE_LOCAL_INCLUDES)
+    set(DOXYGEN_FORCE_LOCAL_INCLUDES NO)
+endif()
+if(NOT DEFINED DOXYGEN_INLINE_INFO)
+    set(DOXYGEN_INLINE_INFO YES)
+endif()
+if(NOT DEFINED DOXYGEN_SORT_MEMBER_DOCS)
+    set(DOXYGEN_SORT_MEMBER_DOCS YES)
+endif()
+if(NOT DEFINED DOXYGEN_SORT_BRIEF_DOCS)
+    set(DOXYGEN_SORT_BRIEF_DOCS NO)
+endif()
+if(NOT DEFINED DOXYGEN_SORT_MEMBERS_CTORS_1ST)
+    set(DOXYGEN_SORT_MEMBERS_CTORS_1ST NO)
+endif()
+if(NOT DEFINED DOXYGEN_SORT_GROUP_NAMES)
+    set(DOXYGEN_SORT_GROUP_NAMES NO)
+endif()
+if(NOT DEFINED DOXYGEN_SORT_BY_SCOPE_NAME)
+    set(DOXYGEN_SORT_BY_SCOPE_NAME NO)
+endif()
+if(NOT DEFINED DOXYGEN_STRICT_PROTO_MATCHING)
+    set(DOXYGEN_STRICT_PROTO_MATCHING NO)
+endif()
+if(NOT DEFINED DOXYGEN_GENERATE_TODOLIST)
+    set(DOXYGEN_GENERATE_TODOLIST YES)
+endif()
+if(NOT DEFINED DOXYGEN_GENERATE_TESTLIST)
+    set(DOXYGEN_GENERATE_TESTLIST YES)
+endif()
+if(NOT DEFINED DOXYGEN_GENERATE_BUGLIST)
+    set(DOXYGEN_GENERATE_BUGLIST YES)
+endif()
+if(NOT DEFINED DOXYGEN_GENERATE_DEPRECATEDLIST)
+    set(DOXYGEN_GENERATE_DEPRECATEDLIST YES)
+endif()
+if(NOT DEFINED DOXYGEN_MAX_INITIALIZER_LINES)
+    set(DOXYGEN_MAX_INITIALIZER_LINES 30)
+endif()
+if(NOT DEFINED DOXYGEN_SHOW_USED_FILES)
+    set(DOXYGEN_SHOW_USED_FILES YES)
+endif()
+if(NOT DEFINED DOXYGEN_SHOW_FILES)
+    set(DOXYGEN_SHOW_FILES YES)
+endif()
+if(NOT DEFINED DOXYGEN_SHOW_NAMESPACES)
+    set(DOXYGEN_SHOW_NAMESPACES YES)
+endif()
+if(NOT DEFINED DOXYGEN_QUIET)
+    set(DOXYGEN_QUIET NO)
+endif()
+if(NOT DEFINED DOXYGEN_WARNINGS)
+    set(DOXYGEN_WARNINGS YES)
+endif()
+if(NOT DEFINED DOXYGEN_WARN_IF_UNDOCUMENTED)
+    set(DOXYGEN_WARN_IF_UNDOCUMENTED YES)
+endif()
+if(NOT DEFINED DOXYGEN_WARN_IF_DOC_ERROR)
+    set(DOXYGEN_WARN_IF_DOC_ERROR YES)
+endif()
+if(NOT DEFINED DOXYGEN_WARN_IF_INCOMPLETE_DOC)
+    set(DOXYGEN_WARN_IF_INCOMPLETE_DOC YES)
+endif()
+if(NOT DEFINED DOXYGEN_WARN_NO_PARAMDOC)
+    set(DOXYGEN_WARN_NO_PARAMDOC NO)
+endif()
+if(NOT DEFINED DOXYGEN_WARN_AS_ERROR)
+    set(DOXYGEN_WARN_AS_ERROR NO)
+endif()
+if(NOT DEFINED DOXYGEN_WARN_FORMAT)
+    set(DOXYGEN_WARN_FORMAT "$file:$line: $text")
+endif()
+if(NOT DEFINED DOXYGEN_WARN_LINE_FORMAT)
+    set(DOXYGEN_WARN_LINE_FORMAT "at line $line of file $file")
+endif()
+if(NOT DEFINED DOXYGEN_INPUT_ENCODING)
+    set(DOXYGEN_INPUT_ENCODING UTF-8)
+endif()
+if(NOT DEFINED DOXYGEN_FILE_PATTERNS)
+    set(DOXYGEN_FILE_PATTERNS *.c 
+                         *.cc 
+                         *.cxx 
+                         *.cpp 
+                         *.c++ 
+                         *.java 
+                         *.ii 
+                         *.ixx 
+                         *.ipp 
+                         *.i++ 
+                         *.inl 
+                         *.idl 
+                         *.ddl 
+                         *.odl 
+                         *.h 
+                         *.hh 
+                         *.hxx 
+                         *.hpp 
+                         *.h++ 
+                         *.l 
+                         *.cs 
+                         *.d 
+                         *.php 
+                         *.php4 
+                         *.php5 
+                         *.phtml 
+                         *.inc 
+                         *.m 
+                         *.markdown 
+                         *.md 
+                         *.mm 
+                         *.dox 
+                         *.py 
+                         *.pyw 
+                         *.f90 
+                         *.f95 
+                         *.f03 
+                         *.f08 
+                         *.f18 
+                         *.f 
+                         *.for 
+                         *.vhd 
+                         *.vhdl 
+                         *.ucf 
+                         *.qsf 
+                         *.ice)
+endif()
+if(NOT DEFINED DOXYGEN_RECURSIVE)
+    set(DOXYGEN_RECURSIVE NO)
+endif()
+if(NOT DEFINED DOXYGEN_EXCLUDE_SYMLINKS)
+    set(DOXYGEN_EXCLUDE_SYMLINKS NO)
+endif()
+if(NOT DEFINED DOXYGEN_EXAMPLE_PATTERNS)
+    set(DOXYGEN_EXAMPLE_PATTERNS *)
+endif()
+if(NOT DEFINED DOXYGEN_EXAMPLE_RECURSIVE)
+    set(DOXYGEN_EXAMPLE_RECURSIVE NO)
+endif()
+if(NOT DEFINED DOXYGEN_FILTER_SOURCE_FILES)
+    set(DOXYGEN_FILTER_SOURCE_FILES NO)
+endif()
+if(NOT DEFINED DOXYGEN_SOURCE_BROWSER)
+    set(DOXYGEN_SOURCE_BROWSER NO)
+endif()
+if(NOT DEFINED DOXYGEN_INLINE_SOURCES)
+    set(DOXYGEN_INLINE_SOURCES NO)
+endif()
+if(NOT DEFINED DOXYGEN_STRIP_CODE_COMMENTS)
+    set(DOXYGEN_STRIP_CODE_COMMENTS YES)
+endif()
+if(NOT DEFINED DOXYGEN_REFERENCED_BY_RELATION)
+    set(DOXYGEN_REFERENCED_BY_RELATION NO)
+endif()
+if(NOT DEFINED DOXYGEN_REFERENCES_RELATION)
+    set(DOXYGEN_REFERENCES_RELATION NO)
+endif()
+if(NOT DEFINED DOXYGEN_REFERENCES_LINK_SOURCE)
+    set(DOXYGEN_REFERENCES_LINK_SOURCE YES)
+endif()
+if(NOT DEFINED DOXYGEN_SOURCE_TOOLTIPS)
+    set(DOXYGEN_SOURCE_TOOLTIPS YES)
+endif()
+if(NOT DEFINED DOXYGEN_USE_HTAGS)
+    set(DOXYGEN_USE_HTAGS NO)
+endif()
+if(NOT DEFINED DOXYGEN_VERBATIM_HEADERS)
+    set(DOXYGEN_VERBATIM_HEADERS YES)
+endif()
+if(NOT DEFINED DOXYGEN_CLANG_ASSISTED_PARSING)
+    set(DOXYGEN_CLANG_ASSISTED_PARSING NO)
+endif()
+if(NOT DEFINED DOXYGEN_CLANG_ADD_INC_PATHS)
+    set(DOXYGEN_CLANG_ADD_INC_PATHS YES)
+endif()
+if(NOT DEFINED DOXYGEN_ALPHABETICAL_INDEX)
+    set(DOXYGEN_ALPHABETICAL_INDEX YES)
+endif()
+if(NOT DEFINED DOXYGEN_GENERATE_HTML)
+    set(DOXYGEN_GENERATE_HTML YES)
+endif()
+if(NOT DEFINED DOXYGEN_HTML_OUTPUT)
+    set(DOXYGEN_HTML_OUTPUT html)
+endif()
+if(NOT DEFINED DOXYGEN_HTML_FILE_EXTENSION)
+    set(DOXYGEN_HTML_FILE_EXTENSION .html)
+endif()
+if(NOT DEFINED DOXYGEN_HTML_COLORSTYLE_HUE)
+    set(DOXYGEN_HTML_COLORSTYLE_HUE 220)
+endif()
+if(NOT DEFINED DOXYGEN_HTML_COLORSTYLE_SAT)
+    set(DOXYGEN_HTML_COLORSTYLE_SAT 100)
+endif()
+if(NOT DEFINED DOXYGEN_HTML_COLORSTYLE_GAMMA)
+    set(DOXYGEN_HTML_COLORSTYLE_GAMMA 80)
+endif()
+if(NOT DEFINED DOXYGEN_HTML_TIMESTAMP)
+    set(DOXYGEN_HTML_TIMESTAMP NO)
+endif()
+if(NOT DEFINED DOXYGEN_HTML_DYNAMIC_MENUS)
+    set(DOXYGEN_HTML_DYNAMIC_MENUS YES)
+endif()
+if(NOT DEFINED DOXYGEN_HTML_DYNAMIC_SECTIONS)
+    set(DOXYGEN_HTML_DYNAMIC_SECTIONS NO)
+endif()
+if(NOT DEFINED DOXYGEN_HTML_INDEX_NUM_ENTRIES)
+    set(DOXYGEN_HTML_INDEX_NUM_ENTRIES 100)
+endif()
+if(NOT DEFINED DOXYGEN_GENERATE_DOCSET)
+    set(DOXYGEN_GENERATE_DOCSET NO)
+endif()
+if(NOT DEFINED DOXYGEN_DOCSET_FEEDNAME)
+    set(DOXYGEN_DOCSET_FEEDNAME "Doxygen generated docs")
+endif()
+if(NOT DEFINED DOXYGEN_DOCSET_BUNDLE_ID)
+    set(DOXYGEN_DOCSET_BUNDLE_ID org.doxygen.Project)
+endif()
+if(NOT DEFINED DOXYGEN_DOCSET_PUBLISHER_ID)
+    set(DOXYGEN_DOCSET_PUBLISHER_ID org.doxygen.Publisher)
+endif()
+if(NOT DEFINED DOXYGEN_DOCSET_PUBLISHER_NAME)
+    set(DOXYGEN_DOCSET_PUBLISHER_NAME Publisher)
+endif()
+if(NOT DEFINED DOXYGEN_GENERATE_HTMLHELP)
+    set(DOXYGEN_GENERATE_HTMLHELP NO)
+endif()
+if(NOT DEFINED DOXYGEN_GENERATE_CHI)
+    set(DOXYGEN_GENERATE_CHI NO)
+endif()
+if(NOT DEFINED DOXYGEN_BINARY_TOC)
+    set(DOXYGEN_BINARY_TOC NO)
+endif()
+if(NOT DEFINED DOXYGEN_TOC_EXPAND)
+    set(DOXYGEN_TOC_EXPAND NO)
+endif()
+if(NOT DEFINED DOXYGEN_GENERATE_QHP)
+    set(DOXYGEN_GENERATE_QHP NO)
+endif()
+if(NOT DEFINED DOXYGEN_QHP_NAMESPACE)
+    set(DOXYGEN_QHP_NAMESPACE org.doxygen.Project)
+endif()
+if(NOT DEFINED DOXYGEN_QHP_VIRTUAL_FOLDER)
+    set(DOXYGEN_QHP_VIRTUAL_FOLDER doc)
+endif()
+if(NOT DEFINED DOXYGEN_GENERATE_ECLIPSEHELP)
+    set(DOXYGEN_GENERATE_ECLIPSEHELP NO)
+endif()
+if(NOT DEFINED DOXYGEN_ECLIPSE_DOC_ID)
+    set(DOXYGEN_ECLIPSE_DOC_ID org.doxygen.Project)
+endif()
+if(NOT DEFINED DOXYGEN_DISABLE_INDEX)
+    set(DOXYGEN_DISABLE_INDEX NO)
+endif()
+if(NOT DEFINED DOXYGEN_GENERATE_TREEVIEW)
+    set(DOXYGEN_GENERATE_TREEVIEW NO)
+endif()
+if(NOT DEFINED DOXYGEN_FULL_SIDEBAR)
+    set(DOXYGEN_FULL_SIDEBAR NO)
+endif()
+if(NOT DEFINED DOXYGEN_ENUM_VALUES_PER_LINE)
+    set(DOXYGEN_ENUM_VALUES_PER_LINE 4)
+endif()
+if(NOT DEFINED DOXYGEN_TREEVIEW_WIDTH)
+    set(DOXYGEN_TREEVIEW_WIDTH 250)
+endif()
+if(NOT DEFINED DOXYGEN_EXT_LINKS_IN_WINDOW)
+    set(DOXYGEN_EXT_LINKS_IN_WINDOW NO)
+endif()
+if(NOT DEFINED DOXYGEN_OBFUSCATE_EMAILS)
+    set(DOXYGEN_OBFUSCATE_EMAILS YES)
+endif()
+if(NOT DEFINED DOXYGEN_HTML_FORMULA_FORMAT)
+    set(DOXYGEN_HTML_FORMULA_FORMAT png)
+endif()
+if(NOT DEFINED DOXYGEN_FORMULA_FONTSIZE)
+    set(DOXYGEN_FORMULA_FONTSIZE 10)
+endif()
+if(NOT DEFINED DOXYGEN_FORMULA_TRANSPARENT)
+    set(DOXYGEN_FORMULA_TRANSPARENT YES)
+endif()
+if(NOT DEFINED DOXYGEN_USE_MATHJAX)
+    set(DOXYGEN_USE_MATHJAX NO)
+endif()
+if(NOT DEFINED DOXYGEN_MATHJAX_VERSION)
+    set(DOXYGEN_MATHJAX_VERSION MathJax_2)
+endif()
+if(NOT DEFINED DOXYGEN_MATHJAX_FORMAT)
+    set(DOXYGEN_MATHJAX_FORMAT HTML-CSS)
+endif()
+if(NOT DEFINED DOXYGEN_SEARCHENGINE)
+    set(DOXYGEN_SEARCHENGINE YES)
+endif()
+if(NOT DEFINED DOXYGEN_SERVER_BASED_SEARCH)
+    set(DOXYGEN_SERVER_BASED_SEARCH NO)
+endif()
+if(NOT DEFINED DOXYGEN_EXTERNAL_SEARCH)
+    set(DOXYGEN_EXTERNAL_SEARCH NO)
+endif()
+if(NOT DEFINED DOXYGEN_SEARCHDATA_FILE)
+    set(DOXYGEN_SEARCHDATA_FILE searchdata.xml)
+endif()
+if(NOT DEFINED DOXYGEN_GENERATE_LATEX)
+    set(DOXYGEN_GENERATE_LATEX YES)
+endif()
+if(NOT DEFINED DOXYGEN_LATEX_OUTPUT)
+    set(DOXYGEN_LATEX_OUTPUT latex)
+endif()
+if(NOT DEFINED DOXYGEN_MAKEINDEX_CMD_NAME)
+    set(DOXYGEN_MAKEINDEX_CMD_NAME makeindex)
+endif()
+if(NOT DEFINED DOXYGEN_LATEX_MAKEINDEX_CMD)
+    set(DOXYGEN_LATEX_MAKEINDEX_CMD makeindex)
+endif()
+if(NOT DEFINED DOXYGEN_COMPACT_LATEX)
+    set(DOXYGEN_COMPACT_LATEX NO)
+endif()
+if(NOT DEFINED DOXYGEN_PAPER_TYPE)
+    set(DOXYGEN_PAPER_TYPE a4)
+endif()
+if(NOT DEFINED DOXYGEN_PDF_HYPERLINKS)
+    set(DOXYGEN_PDF_HYPERLINKS YES)
+endif()
+if(NOT DEFINED DOXYGEN_USE_PDFLATEX)
+    set(DOXYGEN_USE_PDFLATEX YES)
+endif()
+if(NOT DEFINED DOXYGEN_LATEX_BATCHMODE)
+    set(DOXYGEN_LATEX_BATCHMODE NO)
+endif()
+if(NOT DEFINED DOXYGEN_LATEX_HIDE_INDICES)
+    set(DOXYGEN_LATEX_HIDE_INDICES NO)
+endif()
+if(NOT DEFINED DOXYGEN_LATEX_BIB_STYLE)
+    set(DOXYGEN_LATEX_BIB_STYLE plain)
+endif()
+if(NOT DEFINED DOXYGEN_LATEX_TIMESTAMP)
+    set(DOXYGEN_LATEX_TIMESTAMP NO)
+endif()
+if(NOT DEFINED DOXYGEN_GENERATE_RTF)
+    set(DOXYGEN_GENERATE_RTF NO)
+endif()
+if(NOT DEFINED DOXYGEN_RTF_OUTPUT)
+    set(DOXYGEN_RTF_OUTPUT rtf)
+endif()
+if(NOT DEFINED DOXYGEN_COMPACT_RTF)
+    set(DOXYGEN_COMPACT_RTF NO)
+endif()
+if(NOT DEFINED DOXYGEN_RTF_HYPERLINKS)
+    set(DOXYGEN_RTF_HYPERLINKS NO)
+endif()
+if(NOT DEFINED DOXYGEN_GENERATE_MAN)
+    set(DOXYGEN_GENERATE_MAN NO)
+endif()
+if(NOT DEFINED DOXYGEN_MAN_OUTPUT)
+    set(DOXYGEN_MAN_OUTPUT man)
+endif()
+if(NOT DEFINED DOXYGEN_MAN_EXTENSION)
+    set(DOXYGEN_MAN_EXTENSION .3)
+endif()
+if(NOT DEFINED DOXYGEN_MAN_LINKS)
+    set(DOXYGEN_MAN_LINKS NO)
+endif()
+if(NOT DEFINED DOXYGEN_GENERATE_XML)
+    set(DOXYGEN_GENERATE_XML NO)
+endif()
+if(NOT DEFINED DOXYGEN_XML_OUTPUT)
+    set(DOXYGEN_XML_OUTPUT xml)
+endif()
+if(NOT DEFINED DOXYGEN_XML_PROGRAMLISTING)
+    set(DOXYGEN_XML_PROGRAMLISTING YES)
+endif()
+if(NOT DEFINED DOXYGEN_XML_NS_MEMB_FILE_SCOPE)
+    set(DOXYGEN_XML_NS_MEMB_FILE_SCOPE NO)
+endif()
+if(NOT DEFINED DOXYGEN_GENERATE_DOCBOOK)
+    set(DOXYGEN_GENERATE_DOCBOOK NO)
+endif()
+if(NOT DEFINED DOXYGEN_DOCBOOK_OUTPUT)
+    set(DOXYGEN_DOCBOOK_OUTPUT docbook)
+endif()
+if(NOT DEFINED DOXYGEN_GENERATE_AUTOGEN_DEF)
+    set(DOXYGEN_GENERATE_AUTOGEN_DEF NO)
+endif()
+if(NOT DEFINED DOXYGEN_GENERATE_PERLMOD)
+    set(DOXYGEN_GENERATE_PERLMOD NO)
+endif()
+if(NOT DEFINED DOXYGEN_PERLMOD_LATEX)
+    set(DOXYGEN_PERLMOD_LATEX NO)
+endif()
+if(NOT DEFINED DOXYGEN_PERLMOD_PRETTY)
+    set(DOXYGEN_PERLMOD_PRETTY YES)
+endif()
+if(NOT DEFINED DOXYGEN_ENABLE_PREPROCESSING)
+    set(DOXYGEN_ENABLE_PREPROCESSING YES)
+endif()
+if(NOT DEFINED DOXYGEN_MACRO_EXPANSION)
+    set(DOXYGEN_MACRO_EXPANSION NO)
+endif()
+if(NOT DEFINED DOXYGEN_EXPAND_ONLY_PREDEF)
+    set(DOXYGEN_EXPAND_ONLY_PREDEF NO)
+endif()
+if(NOT DEFINED DOXYGEN_SEARCH_INCLUDES)
+    set(DOXYGEN_SEARCH_INCLUDES YES)
+endif()
+if(NOT DEFINED DOXYGEN_SKIP_FUNCTION_MACROS)
+    set(DOXYGEN_SKIP_FUNCTION_MACROS YES)
+endif()
+if(NOT DEFINED DOXYGEN_ALLEXTERNALS)
+    set(DOXYGEN_ALLEXTERNALS NO)
+endif()
+if(NOT DEFINED DOXYGEN_EXTERNAL_GROUPS)
+    set(DOXYGEN_EXTERNAL_GROUPS YES)
+endif()
+if(NOT DEFINED DOXYGEN_EXTERNAL_PAGES)
+    set(DOXYGEN_EXTERNAL_PAGES YES)
+endif()
+if(NOT DEFINED DOXYGEN_HIDE_UNDOC_RELATIONS)
+    set(DOXYGEN_HIDE_UNDOC_RELATIONS YES)
+endif()
+if(NOT DEFINED DOXYGEN_HAVE_DOT)
+    set(DOXYGEN_HAVE_DOT YES)
+endif()
+if(NOT DEFINED DOXYGEN_DOT_NUM_THREADS)
+    set(DOXYGEN_DOT_NUM_THREADS 0)
+endif()
+if(NOT DEFINED DOXYGEN_DOT_FONTNAME)
+    set(DOXYGEN_DOT_FONTNAME Helvetica)
+endif()
+if(NOT DEFINED DOXYGEN_DOT_FONTSIZE)
+    set(DOXYGEN_DOT_FONTSIZE 10)
+endif()
+if(NOT DEFINED DOXYGEN_CLASS_GRAPH)
+    set(DOXYGEN_CLASS_GRAPH YES)
+endif()
+if(NOT DEFINED DOXYGEN_COLLABORATION_GRAPH)
+    set(DOXYGEN_COLLABORATION_GRAPH YES)
+endif()
+if(NOT DEFINED DOXYGEN_GROUP_GRAPHS)
+    set(DOXYGEN_GROUP_GRAPHS YES)
+endif()
+if(NOT DEFINED DOXYGEN_UML_LOOK)
+    set(DOXYGEN_UML_LOOK NO)
+endif()
+if(NOT DEFINED DOXYGEN_UML_LIMIT_NUM_FIELDS)
+    set(DOXYGEN_UML_LIMIT_NUM_FIELDS 10)
+endif()
+if(NOT DEFINED DOXYGEN_DOT_UML_DETAILS)
+    set(DOXYGEN_DOT_UML_DETAILS NO)
+endif()
+if(NOT DEFINED DOXYGEN_DOT_WRAP_THRESHOLD)
+    set(DOXYGEN_DOT_WRAP_THRESHOLD 17)
+endif()
+if(NOT DEFINED DOXYGEN_TEMPLATE_RELATIONS)
+    set(DOXYGEN_TEMPLATE_RELATIONS NO)
+endif()
+if(NOT DEFINED DOXYGEN_INCLUDE_GRAPH)
+    set(DOXYGEN_INCLUDE_GRAPH YES)
+endif()
+if(NOT DEFINED DOXYGEN_INCLUDED_BY_GRAPH)
+    set(DOXYGEN_INCLUDED_BY_GRAPH YES)
+endif()
+if(NOT DEFINED DOXYGEN_CALL_GRAPH)
+    set(DOXYGEN_CALL_GRAPH NO)
+endif()
+if(NOT DEFINED DOXYGEN_CALLER_GRAPH)
+    set(DOXYGEN_CALLER_GRAPH NO)
+endif()
+if(NOT DEFINED DOXYGEN_GRAPHICAL_HIERARCHY)
+    set(DOXYGEN_GRAPHICAL_HIERARCHY YES)
+endif()
+if(NOT DEFINED DOXYGEN_DIRECTORY_GRAPH)
+    set(DOXYGEN_DIRECTORY_GRAPH YES)
+endif()
+if(NOT DEFINED DOXYGEN_DIR_GRAPH_MAX_DEPTH)
+    set(DOXYGEN_DIR_GRAPH_MAX_DEPTH 1)
+endif()
+if(NOT DEFINED DOXYGEN_DOT_IMAGE_FORMAT)
+    set(DOXYGEN_DOT_IMAGE_FORMAT png)
+endif()
+if(NOT DEFINED DOXYGEN_INTERACTIVE_SVG)
+    set(DOXYGEN_INTERACTIVE_SVG NO)
+endif()
+if(NOT DEFINED DOXYGEN_DOT_GRAPH_MAX_NODES)
+    set(DOXYGEN_DOT_GRAPH_MAX_NODES 50)
+endif()
+if(NOT DEFINED DOXYGEN_MAX_DOT_GRAPH_DEPTH)
+    set(DOXYGEN_MAX_DOT_GRAPH_DEPTH 0)
+endif()
+if(NOT DEFINED DOXYGEN_DOT_TRANSPARENT)
+    set(DOXYGEN_DOT_TRANSPARENT NO)
+endif()
+if(NOT DEFINED DOXYGEN_DOT_MULTI_TARGETS)
+    set(DOXYGEN_DOT_MULTI_TARGETS NO)
+endif()
+if(NOT DEFINED DOXYGEN_GENERATE_LEGEND)
+    set(DOXYGEN_GENERATE_LEGEND YES)
+endif()
+if(NOT DEFINED DOXYGEN_DOT_CLEANUP)
+    set(DOXYGEN_DOT_CLEANUP YES)
+endif()

+ 63 - 0
CMakeLists.txt

@@ -0,0 +1,63 @@
+cmake_minimum_required(VERSION 3.5)
+
+include(${CMAKE_CURRENT_SOURCE_DIR}/pico-sdk/lib/tinyusb/hw/bsp/family_support.cmake)
+
+# gets PROJECT name for the example (e.g. <BOARD>-<DIR_NAME>)
+family_get_project_name(PROJECT ${CMAKE_CURRENT_LIST_DIR})
+
+project(${PROJECT})
+
+# Checks this example is valid for the family and initializes the project
+family_initialize_project(${PROJECT} ${CMAKE_CURRENT_LIST_DIR})
+
+add_executable(${PROJECT})
+
+# Example source
+target_sources(${PROJECT} PUBLIC
+        ${CMAKE_CURRENT_SOURCE_DIR}/src/password_safe.c
+        ${CMAKE_CURRENT_SOURCE_DIR}/src/usb_descriptors.c
+        ${CMAKE_CURRENT_SOURCE_DIR}/src/ui.c
+        ${CMAKE_CURRENT_SOURCE_DIR}/src/display.c 
+        ${CMAKE_CURRENT_SOURCE_DIR}/src/font_twisted.c 
+        ${CMAKE_CURRENT_SOURCE_DIR}/src/msc_disk.c 
+        ${CMAKE_CURRENT_SOURCE_DIR}/src/cryptoengine.c 
+        ${CMAKE_CURRENT_SOURCE_DIR}/src/cdc-protocol.c 
+        ${CMAKE_CURRENT_SOURCE_DIR}/src/fsm.c
+        ${CMAKE_CURRENT_SOURCE_DIR}/src/flash.c
+        ${CMAKE_CURRENT_SOURCE_DIR}/src/hid.c
+        ${CMAKE_CURRENT_SOURCE_DIR}/lib/wolfssl/wolfcrypt/src/wc_port.c
+        ${CMAKE_CURRENT_SOURCE_DIR}/lib/wolfssl/wolfcrypt/src/wolfmath.c
+        ${CMAKE_CURRENT_SOURCE_DIR}/lib/wolfssl/wolfcrypt/src/hash.c
+        ${CMAKE_CURRENT_SOURCE_DIR}/lib/wolfssl/wolfcrypt/src/memory.c
+        ${CMAKE_CURRENT_SOURCE_DIR}/lib/wolfssl/wolfcrypt/src/misc.c
+        ${CMAKE_CURRENT_SOURCE_DIR}/lib/wolfssl/wolfcrypt/src/ecc.c
+        ${CMAKE_CURRENT_SOURCE_DIR}/lib/wolfssl/wolfcrypt/src/curve25519.c
+        ${CMAKE_CURRENT_SOURCE_DIR}/lib/wolfssl/wolfcrypt/src/pwdbased.c
+        ${CMAKE_CURRENT_SOURCE_DIR}/lib/wolfssl/wolfcrypt/src/hmac.c
+        ${CMAKE_CURRENT_SOURCE_DIR}/lib/wolfssl/wolfcrypt/src/chacha.c
+        ${CMAKE_CURRENT_SOURCE_DIR}/lib/wolfssl/wolfcrypt/src/sha.c
+        ${CMAKE_CURRENT_SOURCE_DIR}/lib/wolfssl/wolfcrypt/src/sha256.c
+        ${CMAKE_CURRENT_SOURCE_DIR}/lib/wolfssl/wolfcrypt/src/sha512.c
+        ${CMAKE_CURRENT_SOURCE_DIR}/lib/wolfssl/wolfcrypt/src/ge_low_mem.c
+        ${CMAKE_CURRENT_SOURCE_DIR}/lib/wolfssl/wolfcrypt/src/fe_low_mem.c
+        ${CMAKE_CURRENT_SOURCE_DIR}/lib/wolfssl/wolfcrypt/src/ge_operations.c
+        ${CMAKE_CURRENT_SOURCE_DIR}/lib/wolfssl/wolfcrypt/src/sp_int.c
+        #${CMAKE_CURRENT_SOURCE_DIR}/lib/wolfssl/wolfcrypt/src/sp_armthumb.c
+        ${CMAKE_CURRENT_SOURCE_DIR}/lib/wolfssl/wolfcrypt/src/sp_c32.c
+        )
+
+# Example include
+target_include_directories(${PROJECT} PUBLIC
+        ${CMAKE_CURRENT_SOURCE_DIR}/src 
+        ${CMAKE_CURRENT_SOURCE_DIR}/lib/wolfssl
+        )
+
+        target_compile_definitions( ${PROJECT} PUBLIC WOLFSSL_USER_SETTINGS)
+
+
+        target_link_libraries(${PROJECT} PUBLIC pico_stdlib)
+        target_link_libraries(${PROJECT} PUBLIC pico_multicore)
+
+# Configure compilation flags and libraries for the example... see the corresponding function
+# in hw/bsp/FAMILY/family.cmake for details.
+family_configure_device_example(${PROJECT})

+ 141 - 0
README.md

@@ -0,0 +1,141 @@
+# Motenpoche
+
+Motenpoche ([mot-ɑ̃-pɔʃ] - French for "word in your pocket") is a physical password
+vault to carry around your secrets securely. It can be unlocked with a main
+passphrase and it will automatically paste passwords selected from your collection.
+
+Passwords can be provisioned with the help of a host-side command line tool that
+can be run on a GNU/Linux PC.
+
+## Status
+
+This project is still in an early alpha phase and has not been properly tested yet.
+Use at your own risk, no guarantee provided on loss of secret information, service
+profiles, bank details or other relevant information. The author and the 
+contributors recommends not to use this software for any purpose rather than 
+security auditing, research and study, and they cannot be held responsible or any
+damage of any kind resulting from any proper or improper use.
+
+## Software License
+
+The software distributed in this project is uniquely released under the terms of
+GNU GPL v.2.
+
+## What is this for
+
+I'm lazy and skeptical when it comes to distributed password managers. I don't
+like the idea of keeping a wallet of passwords on a cloud server. On the other
+hand, I'm oftern traveling and carrying a laptop, where I must periodically update
+my password database if I want to access services when I'm abroad.
+
+This system was created to have a temporary physical storage that can be carried
+around (and lost, or forgotten on a public transportation...) with reduced risk.
+
+## Hardware design
+
+## How it works
+
+The siple idea behind it is that the device does not carry any secret in plain
+text. The passwords are stored on an external SPI flash, encrypted and signed with
+unique keys created when the device is initialized.
+The encryption key is symmetrical (ChaCha) and can be derived on board using the
+main passphrase, which is entered through the rotary and the confirm button.
+
+The signature key (Ecc256) is created during device initialization on the PC. The
+key is used to sign the passwords to be added to the vault.
+
+Passwords can be provisioned using the host tool, either manually or importing
+them from a CSV file, previously exported from e.g. a software password manager
+or a web browser.
+
+When the device is unlocked, selecting the service needed from the "Services" menu
+will paste the password onto the PC. The user should ensureto select the right 
+password box before activating the service on the device to prevent password leaks 
+in clear text on the PC screen.
+
+Multiple paste modes are available from the "Settings" menu onboard. The device
+can for example fill username + password web forms automatically, by typing in the
+username, then the TAB key, then the password and finally ENTER.
+
+### Initialization
+
+The device can be initialized using a TOFU (Trust on First Use) mechanism. When
+the device is in "factory mode", it can be initialized using the host command line
+application, selecting the "TOFU" function. The application will then ask to input
+(and confirm) the main password that will be used to unlock the device.
+As mentioned, this procedure also creates the main signature key to provision 
+passwords. If you want to be able to add passwords to the vault from different
+PCs, ensure that you carry a copy of the key generated in `~/.pvault/`.
+
+### Adding password services
+
+Passwords can be provisioned using the host tool, either manually or importing
+them from a CSV file. The information is then encrypted on the PC using the main
+password, signed using the signature key and transmitted to the device.
+
+The device must be unlocked in order to receive password services to add to the
+database. Uploading a single password may take a few seconds because the device
+verifies that the source of the information is trusted.
+
+
+### What does the PC see
+
+When you connect motenpoche to your PC, it will show up as three different
+devices:
+
+- A USB drive, containing the source and the binary of the host command line tool  `mep` [TODO]
+
+- A serial port (typically /dev/ttyACM0), used by the host command line tool to communicate
+with the device, initialize it after factory reset and upload passwords.
+
+- A HID keyboard device. Motenpoche will use a 'fake' keyboard to input the selected
+password when requested.
+
+### Security considerations
+
+- The algorithm used to generate the encryption key is PBKDF2, using SHA512 for 
+hashing, and a random salt generated when the device is initialized
+
+- Neither the passwords, nor the main secret, or any private key is ever stored
+on the device. When the device is turned off, the storage is encrypted.
+
+- Password checking is performed on board by decrypting the signature stored in the 
+initial settings page, and then checking for the integrity (sha) and
+authenticity (ecc signature) of the page itself.
+Each password is then decrypted on demand and sent to the PC through the HID
+keyboard device.
+
+- Passwords can still be intercepted by a keylogger, e.g. using a USB sniffer.
+(This is not very different from an actual USB keyboard).
+
+- Main keys and passwords are never transmitted via USB.
+
+
+### Future development
+ 
+- The command line tool `mep` might have a function to "rekey" the device, changing
+the salt and the constant part of the IV used for the encryption
+
+- Store private keys / custom secret files in the storage device. Those would be
+invisible until the device is unlocked.
+
+## Compiling and flashing to Raspberry-pi pico:
+
+To compile the firmware run the following from the source directory:
+
+```
+mkdir build
+cd build
+cmake .. -DFAMILY=rp2040 -DPICO_SDK_PATH=/path/to/motenpoche/pico-sdk
+```
+
+### Host tool
+
+A copy of the host tool `mep` is in the `msc_content` directory. Compile using
+"make", then run the tool pointing it to the correct USB serial device, e.g.:
+
+```
+ ./mep /dev/ttyACM0
+```
+
+

+ 55 - 0
cmake_install.cmake

@@ -0,0 +1,55 @@
+# Install script for directory: /home/dan/src/rp2040-mixer
+
+# Set the install prefix
+if(NOT DEFINED CMAKE_INSTALL_PREFIX)
+  set(CMAKE_INSTALL_PREFIX "/usr/local")
+endif()
+string(REGEX REPLACE "/$" "" CMAKE_INSTALL_PREFIX "${CMAKE_INSTALL_PREFIX}")
+
+# Set the install configuration name.
+if(NOT DEFINED CMAKE_INSTALL_CONFIG_NAME)
+  if(BUILD_TYPE)
+    string(REGEX REPLACE "^[^A-Za-z0-9_]+" ""
+           CMAKE_INSTALL_CONFIG_NAME "${BUILD_TYPE}")
+  else()
+    set(CMAKE_INSTALL_CONFIG_NAME "Release")
+  endif()
+  message(STATUS "Install configuration: \"${CMAKE_INSTALL_CONFIG_NAME}\"")
+endif()
+
+# Set the component getting installed.
+if(NOT CMAKE_INSTALL_COMPONENT)
+  if(COMPONENT)
+    message(STATUS "Install component: \"${COMPONENT}\"")
+    set(CMAKE_INSTALL_COMPONENT "${COMPONENT}")
+  else()
+    set(CMAKE_INSTALL_COMPONENT)
+  endif()
+endif()
+
+# Is this installation the result of a crosscompile?
+if(NOT DEFINED CMAKE_CROSSCOMPILING)
+  set(CMAKE_CROSSCOMPILING "TRUE")
+endif()
+
+# Set default install directory permissions.
+if(NOT DEFINED CMAKE_OBJDUMP)
+  set(CMAKE_OBJDUMP "/usr/bin/arm-none-eabi-objdump")
+endif()
+
+if(NOT CMAKE_INSTALL_LOCAL_ONLY)
+  # Include the install script for each subdirectory.
+  include("/home/dan/src/rp2040-mixer/pico-sdk/cmake_install.cmake")
+
+endif()
+
+if(CMAKE_INSTALL_COMPONENT)
+  set(CMAKE_INSTALL_MANIFEST "install_manifest_${CMAKE_INSTALL_COMPONENT}.txt")
+else()
+  set(CMAKE_INSTALL_MANIFEST "install_manifest.txt")
+endif()
+
+string(REPLACE ";" "\n" CMAKE_INSTALL_MANIFEST_CONTENT
+       "${CMAKE_INSTALL_MANIFEST_FILES}")
+file(WRITE "/home/dan/src/rp2040-mixer/${CMAKE_INSTALL_MANIFEST}"
+     "${CMAKE_INSTALL_MANIFEST_CONTENT}")

+ 374 - 0
elf2uf2/CMakeCache.txt

@@ -0,0 +1,374 @@
+# This is the CMakeCache file.
+# For build in directory: /home/dan/src/rp2040-mixer/elf2uf2
+# It was generated by CMake: /usr/bin/cmake
+# You can edit this file to change values found and used by cmake.
+# If you do not want to change any of the values, simply exit the editor.
+# If you do want to change a value, simply edit, save, and exit the editor.
+# The syntax for the file is as follows:
+# KEY:TYPE=VALUE
+# KEY is the name of a variable in the cache.
+# TYPE is a hint to GUIs for the type of VALUE, DO NOT EDIT TYPE!.
+# VALUE is the current value for the KEY.
+
+########################
+# EXTERNAL cache entries
+########################
+
+//Path to a program.
+CMAKE_ADDR2LINE:FILEPATH=/usr/bin/addr2line
+
+//Path to a program.
+CMAKE_AR:FILEPATH=/usr/bin/ar
+
+//Choose the type of build, options are: None Debug Release RelWithDebInfo
+// MinSizeRel ...
+CMAKE_BUILD_TYPE:STRING=
+
+//Enable/Disable color output during build.
+CMAKE_COLOR_MAKEFILE:BOOL=ON
+
+//CXX compiler
+CMAKE_CXX_COMPILER:FILEPATH=/usr/bin/c++
+
+//A wrapper around 'ar' adding the appropriate '--plugin' option
+// for the GCC compiler
+CMAKE_CXX_COMPILER_AR:FILEPATH=/usr/bin/gcc-ar-12
+
+//A wrapper around 'ranlib' adding the appropriate '--plugin' option
+// for the GCC compiler
+CMAKE_CXX_COMPILER_RANLIB:FILEPATH=/usr/bin/gcc-ranlib-12
+
+//Flags used by the CXX compiler during all build types.
+CMAKE_CXX_FLAGS:STRING=
+
+//Flags used by the CXX compiler during DEBUG builds.
+CMAKE_CXX_FLAGS_DEBUG:STRING=-g
+
+//Flags used by the CXX compiler during MINSIZEREL builds.
+CMAKE_CXX_FLAGS_MINSIZEREL:STRING=-Os -DNDEBUG
+
+//Flags used by the CXX compiler during RELEASE builds.
+CMAKE_CXX_FLAGS_RELEASE:STRING=-O3 -DNDEBUG
+
+//Flags used by the CXX compiler during RELWITHDEBINFO builds.
+CMAKE_CXX_FLAGS_RELWITHDEBINFO:STRING=-O2 -g -DNDEBUG
+
+//C compiler
+CMAKE_C_COMPILER:FILEPATH=/usr/bin/cc
+
+//A wrapper around 'ar' adding the appropriate '--plugin' option
+// for the GCC compiler
+CMAKE_C_COMPILER_AR:FILEPATH=/usr/bin/gcc-ar-12
+
+//A wrapper around 'ranlib' adding the appropriate '--plugin' option
+// for the GCC compiler
+CMAKE_C_COMPILER_RANLIB:FILEPATH=/usr/bin/gcc-ranlib-12
+
+//Flags used by the C compiler during all build types.
+CMAKE_C_FLAGS:STRING=
+
+//Flags used by the C compiler during DEBUG builds.
+CMAKE_C_FLAGS_DEBUG:STRING=-g
+
+//Flags used by the C compiler during MINSIZEREL builds.
+CMAKE_C_FLAGS_MINSIZEREL:STRING=-Os -DNDEBUG
+
+//Flags used by the C compiler during RELEASE builds.
+CMAKE_C_FLAGS_RELEASE:STRING=-O3 -DNDEBUG
+
+//Flags used by the C compiler during RELWITHDEBINFO builds.
+CMAKE_C_FLAGS_RELWITHDEBINFO:STRING=-O2 -g -DNDEBUG
+
+//Path to a program.
+CMAKE_DLLTOOL:FILEPATH=CMAKE_DLLTOOL-NOTFOUND
+
+//Flags used by the linker during all build types.
+CMAKE_EXE_LINKER_FLAGS:STRING=
+
+//Flags used by the linker during DEBUG builds.
+CMAKE_EXE_LINKER_FLAGS_DEBUG:STRING=
+
+//Flags used by the linker during MINSIZEREL builds.
+CMAKE_EXE_LINKER_FLAGS_MINSIZEREL:STRING=
+
+//Flags used by the linker during RELEASE builds.
+CMAKE_EXE_LINKER_FLAGS_RELEASE:STRING=
+
+//Flags used by the linker during RELWITHDEBINFO builds.
+CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO:STRING=
+
+//Enable/Disable output of compile commands during generation.
+CMAKE_EXPORT_COMPILE_COMMANDS:BOOL=
+
+//Value Computed by CMake.
+CMAKE_FIND_PACKAGE_REDIRECTS_DIR:STATIC=/home/dan/src/rp2040-mixer/elf2uf2/CMakeFiles/pkgRedirects
+
+//Install path prefix, prepended onto install directories.
+CMAKE_INSTALL_PREFIX:PATH=/usr/local
+
+//Path to a program.
+CMAKE_LINKER:FILEPATH=/usr/bin/ld
+
+//Path to a program.
+CMAKE_MAKE_PROGRAM:FILEPATH=/usr/bin/gmake
+
+//Flags used by the linker during the creation of modules during
+// all build types.
+CMAKE_MODULE_LINKER_FLAGS:STRING=
+
+//Flags used by the linker during the creation of modules during
+// DEBUG builds.
+CMAKE_MODULE_LINKER_FLAGS_DEBUG:STRING=
+
+//Flags used by the linker during the creation of modules during
+// MINSIZEREL builds.
+CMAKE_MODULE_LINKER_FLAGS_MINSIZEREL:STRING=
+
+//Flags used by the linker during the creation of modules during
+// RELEASE builds.
+CMAKE_MODULE_LINKER_FLAGS_RELEASE:STRING=
+
+//Flags used by the linker during the creation of modules during
+// RELWITHDEBINFO builds.
+CMAKE_MODULE_LINKER_FLAGS_RELWITHDEBINFO:STRING=
+
+//Path to a program.
+CMAKE_NM:FILEPATH=/usr/bin/nm
+
+//Path to a program.
+CMAKE_OBJCOPY:FILEPATH=/usr/bin/objcopy
+
+//Path to a program.
+CMAKE_OBJDUMP:FILEPATH=/usr/bin/objdump
+
+//Value Computed by CMake
+CMAKE_PROJECT_DESCRIPTION:STATIC=
+
+//Value Computed by CMake
+CMAKE_PROJECT_HOMEPAGE_URL:STATIC=
+
+//Value Computed by CMake
+CMAKE_PROJECT_NAME:STATIC=elf2uf2
+
+//Path to a program.
+CMAKE_RANLIB:FILEPATH=/usr/bin/ranlib
+
+//Path to a program.
+CMAKE_READELF:FILEPATH=/usr/bin/readelf
+
+//Flags used by the linker during the creation of shared libraries
+// during all build types.
+CMAKE_SHARED_LINKER_FLAGS:STRING=
+
+//Flags used by the linker during the creation of shared libraries
+// during DEBUG builds.
+CMAKE_SHARED_LINKER_FLAGS_DEBUG:STRING=
+
+//Flags used by the linker during the creation of shared libraries
+// during MINSIZEREL builds.
+CMAKE_SHARED_LINKER_FLAGS_MINSIZEREL:STRING=
+
+//Flags used by the linker during the creation of shared libraries
+// during RELEASE builds.
+CMAKE_SHARED_LINKER_FLAGS_RELEASE:STRING=
+
+//Flags used by the linker during the creation of shared libraries
+// during RELWITHDEBINFO builds.
+CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO:STRING=
+
+//If set, runtime paths are not added when installing shared libraries,
+// but are added when building.
+CMAKE_SKIP_INSTALL_RPATH:BOOL=NO
+
+//If set, runtime paths are not added when using shared libraries.
+CMAKE_SKIP_RPATH:BOOL=NO
+
+//Flags used by the linker during the creation of static libraries
+// during all build types.
+CMAKE_STATIC_LINKER_FLAGS:STRING=
+
+//Flags used by the linker during the creation of static libraries
+// during DEBUG builds.
+CMAKE_STATIC_LINKER_FLAGS_DEBUG:STRING=
+
+//Flags used by the linker during the creation of static libraries
+// during MINSIZEREL builds.
+CMAKE_STATIC_LINKER_FLAGS_MINSIZEREL:STRING=
+
+//Flags used by the linker during the creation of static libraries
+// during RELEASE builds.
+CMAKE_STATIC_LINKER_FLAGS_RELEASE:STRING=
+
+//Flags used by the linker during the creation of static libraries
+// during RELWITHDEBINFO builds.
+CMAKE_STATIC_LINKER_FLAGS_RELWITHDEBINFO:STRING=
+
+//Path to a program.
+CMAKE_STRIP:FILEPATH=/usr/bin/strip
+
+//If this value is on, makefiles will be generated without the
+// .SILENT directive, and all commands will be echoed to the console
+// during the make.  This is useful for debugging only. With Visual
+// Studio IDE projects all commands are done without /nologo.
+CMAKE_VERBOSE_MAKEFILE:BOOL=FALSE
+
+//Value Computed by CMake
+elf2uf2_BINARY_DIR:STATIC=/home/dan/src/rp2040-mixer/elf2uf2
+
+//Value Computed by CMake
+elf2uf2_IS_TOP_LEVEL:STATIC=ON
+
+//Value Computed by CMake
+elf2uf2_SOURCE_DIR:STATIC=/home/dan/src/rp2040-mixer/pico-sdk/tools/elf2uf2
+
+
+########################
+# INTERNAL cache entries
+########################
+
+//ADVANCED property for variable: CMAKE_ADDR2LINE
+CMAKE_ADDR2LINE-ADVANCED:INTERNAL=1
+//ADVANCED property for variable: CMAKE_AR
+CMAKE_AR-ADVANCED:INTERNAL=1
+//This is the directory where this CMakeCache.txt was created
+CMAKE_CACHEFILE_DIR:INTERNAL=/home/dan/src/rp2040-mixer/elf2uf2
+//Major version of cmake used to create the current loaded cache
+CMAKE_CACHE_MAJOR_VERSION:INTERNAL=3
+//Minor version of cmake used to create the current loaded cache
+CMAKE_CACHE_MINOR_VERSION:INTERNAL=24
+//Patch version of cmake used to create the current loaded cache
+CMAKE_CACHE_PATCH_VERSION:INTERNAL=2
+//ADVANCED property for variable: CMAKE_COLOR_MAKEFILE
+CMAKE_COLOR_MAKEFILE-ADVANCED:INTERNAL=1
+//Path to CMake executable.
+CMAKE_COMMAND:INTERNAL=/usr/bin/cmake
+//Path to cpack program executable.
+CMAKE_CPACK_COMMAND:INTERNAL=/usr/bin/cpack
+//Path to ctest program executable.
+CMAKE_CTEST_COMMAND:INTERNAL=/usr/bin/ctest
+//ADVANCED property for variable: CMAKE_CXX_COMPILER
+CMAKE_CXX_COMPILER-ADVANCED:INTERNAL=1
+//ADVANCED property for variable: CMAKE_CXX_COMPILER_AR
+CMAKE_CXX_COMPILER_AR-ADVANCED:INTERNAL=1
+//ADVANCED property for variable: CMAKE_CXX_COMPILER_RANLIB
+CMAKE_CXX_COMPILER_RANLIB-ADVANCED:INTERNAL=1
+//ADVANCED property for variable: CMAKE_CXX_FLAGS
+CMAKE_CXX_FLAGS-ADVANCED:INTERNAL=1
+//ADVANCED property for variable: CMAKE_CXX_FLAGS_DEBUG
+CMAKE_CXX_FLAGS_DEBUG-ADVANCED:INTERNAL=1
+//ADVANCED property for variable: CMAKE_CXX_FLAGS_MINSIZEREL
+CMAKE_CXX_FLAGS_MINSIZEREL-ADVANCED:INTERNAL=1
+//ADVANCED property for variable: CMAKE_CXX_FLAGS_RELEASE
+CMAKE_CXX_FLAGS_RELEASE-ADVANCED:INTERNAL=1
+//ADVANCED property for variable: CMAKE_CXX_FLAGS_RELWITHDEBINFO
+CMAKE_CXX_FLAGS_RELWITHDEBINFO-ADVANCED:INTERNAL=1
+//ADVANCED property for variable: CMAKE_C_COMPILER
+CMAKE_C_COMPILER-ADVANCED:INTERNAL=1
+//ADVANCED property for variable: CMAKE_C_COMPILER_AR
+CMAKE_C_COMPILER_AR-ADVANCED:INTERNAL=1
+//ADVANCED property for variable: CMAKE_C_COMPILER_RANLIB
+CMAKE_C_COMPILER_RANLIB-ADVANCED:INTERNAL=1
+//ADVANCED property for variable: CMAKE_C_FLAGS
+CMAKE_C_FLAGS-ADVANCED:INTERNAL=1
+//ADVANCED property for variable: CMAKE_C_FLAGS_DEBUG
+CMAKE_C_FLAGS_DEBUG-ADVANCED:INTERNAL=1
+//ADVANCED property for variable: CMAKE_C_FLAGS_MINSIZEREL
+CMAKE_C_FLAGS_MINSIZEREL-ADVANCED:INTERNAL=1
+//ADVANCED property for variable: CMAKE_C_FLAGS_RELEASE
+CMAKE_C_FLAGS_RELEASE-ADVANCED:INTERNAL=1
+//ADVANCED property for variable: CMAKE_C_FLAGS_RELWITHDEBINFO
+CMAKE_C_FLAGS_RELWITHDEBINFO-ADVANCED:INTERNAL=1
+//ADVANCED property for variable: CMAKE_DLLTOOL
+CMAKE_DLLTOOL-ADVANCED:INTERNAL=1
+//Executable file format
+CMAKE_EXECUTABLE_FORMAT:INTERNAL=ELF
+//ADVANCED property for variable: CMAKE_EXE_LINKER_FLAGS
+CMAKE_EXE_LINKER_FLAGS-ADVANCED:INTERNAL=1
+//ADVANCED property for variable: CMAKE_EXE_LINKER_FLAGS_DEBUG
+CMAKE_EXE_LINKER_FLAGS_DEBUG-ADVANCED:INTERNAL=1
+//ADVANCED property for variable: CMAKE_EXE_LINKER_FLAGS_MINSIZEREL
+CMAKE_EXE_LINKER_FLAGS_MINSIZEREL-ADVANCED:INTERNAL=1
+//ADVANCED property for variable: CMAKE_EXE_LINKER_FLAGS_RELEASE
+CMAKE_EXE_LINKER_FLAGS_RELEASE-ADVANCED:INTERNAL=1
+//ADVANCED property for variable: CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO
+CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO-ADVANCED:INTERNAL=1
+//ADVANCED property for variable: CMAKE_EXPORT_COMPILE_COMMANDS
+CMAKE_EXPORT_COMPILE_COMMANDS-ADVANCED:INTERNAL=1
+//Name of external makefile project generator.
+CMAKE_EXTRA_GENERATOR:INTERNAL=
+//Name of generator.
+CMAKE_GENERATOR:INTERNAL=Unix Makefiles
+//Generator instance identifier.
+CMAKE_GENERATOR_INSTANCE:INTERNAL=
+//Name of generator platform.
+CMAKE_GENERATOR_PLATFORM:INTERNAL=
+//Name of generator toolset.
+CMAKE_GENERATOR_TOOLSET:INTERNAL=
+//Source directory with the top level CMakeLists.txt file for this
+// project
+CMAKE_HOME_DIRECTORY:INTERNAL=/home/dan/src/rp2040-mixer/pico-sdk/tools/elf2uf2
+//Install .so files without execute permission.
+CMAKE_INSTALL_SO_NO_EXE:INTERNAL=1
+//ADVANCED property for variable: CMAKE_LINKER
+CMAKE_LINKER-ADVANCED:INTERNAL=1
+//ADVANCED property for variable: CMAKE_MAKE_PROGRAM
+CMAKE_MAKE_PROGRAM-ADVANCED:INTERNAL=1
+//ADVANCED property for variable: CMAKE_MODULE_LINKER_FLAGS
+CMAKE_MODULE_LINKER_FLAGS-ADVANCED:INTERNAL=1
+//ADVANCED property for variable: CMAKE_MODULE_LINKER_FLAGS_DEBUG
+CMAKE_MODULE_LINKER_FLAGS_DEBUG-ADVANCED:INTERNAL=1
+//ADVANCED property for variable: CMAKE_MODULE_LINKER_FLAGS_MINSIZEREL
+CMAKE_MODULE_LINKER_FLAGS_MINSIZEREL-ADVANCED:INTERNAL=1
+//ADVANCED property for variable: CMAKE_MODULE_LINKER_FLAGS_RELEASE
+CMAKE_MODULE_LINKER_FLAGS_RELEASE-ADVANCED:INTERNAL=1
+//ADVANCED property for variable: CMAKE_MODULE_LINKER_FLAGS_RELWITHDEBINFO
+CMAKE_MODULE_LINKER_FLAGS_RELWITHDEBINFO-ADVANCED:INTERNAL=1
+//ADVANCED property for variable: CMAKE_NM
+CMAKE_NM-ADVANCED:INTERNAL=1
+//number of local generators
+CMAKE_NUMBER_OF_MAKEFILES:INTERNAL=2
+//ADVANCED property for variable: CMAKE_OBJCOPY
+CMAKE_OBJCOPY-ADVANCED:INTERNAL=1
+//ADVANCED property for variable: CMAKE_OBJDUMP
+CMAKE_OBJDUMP-ADVANCED:INTERNAL=1
+//Platform information initialized
+CMAKE_PLATFORM_INFO_INITIALIZED:INTERNAL=1
+//ADVANCED property for variable: CMAKE_RANLIB
+CMAKE_RANLIB-ADVANCED:INTERNAL=1
+//ADVANCED property for variable: CMAKE_READELF
+CMAKE_READELF-ADVANCED:INTERNAL=1
+//Path to CMake installation.
+CMAKE_ROOT:INTERNAL=/usr/share/cmake-3.24
+//ADVANCED property for variable: CMAKE_SHARED_LINKER_FLAGS
+CMAKE_SHARED_LINKER_FLAGS-ADVANCED:INTERNAL=1
+//ADVANCED property for variable: CMAKE_SHARED_LINKER_FLAGS_DEBUG
+CMAKE_SHARED_LINKER_FLAGS_DEBUG-ADVANCED:INTERNAL=1
+//ADVANCED property for variable: CMAKE_SHARED_LINKER_FLAGS_MINSIZEREL
+CMAKE_SHARED_LINKER_FLAGS_MINSIZEREL-ADVANCED:INTERNAL=1
+//ADVANCED property for variable: CMAKE_SHARED_LINKER_FLAGS_RELEASE
+CMAKE_SHARED_LINKER_FLAGS_RELEASE-ADVANCED:INTERNAL=1
+//ADVANCED property for variable: CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO
+CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO-ADVANCED:INTERNAL=1
+//ADVANCED property for variable: CMAKE_SKIP_INSTALL_RPATH
+CMAKE_SKIP_INSTALL_RPATH-ADVANCED:INTERNAL=1
+//ADVANCED property for variable: CMAKE_SKIP_RPATH
+CMAKE_SKIP_RPATH-ADVANCED:INTERNAL=1
+//ADVANCED property for variable: CMAKE_STATIC_LINKER_FLAGS
+CMAKE_STATIC_LINKER_FLAGS-ADVANCED:INTERNAL=1
+//ADVANCED property for variable: CMAKE_STATIC_LINKER_FLAGS_DEBUG
+CMAKE_STATIC_LINKER_FLAGS_DEBUG-ADVANCED:INTERNAL=1
+//ADVANCED property for variable: CMAKE_STATIC_LINKER_FLAGS_MINSIZEREL
+CMAKE_STATIC_LINKER_FLAGS_MINSIZEREL-ADVANCED:INTERNAL=1
+//ADVANCED property for variable: CMAKE_STATIC_LINKER_FLAGS_RELEASE
+CMAKE_STATIC_LINKER_FLAGS_RELEASE-ADVANCED:INTERNAL=1
+//ADVANCED property for variable: CMAKE_STATIC_LINKER_FLAGS_RELWITHDEBINFO
+CMAKE_STATIC_LINKER_FLAGS_RELWITHDEBINFO-ADVANCED:INTERNAL=1
+//ADVANCED property for variable: CMAKE_STRIP
+CMAKE_STRIP-ADVANCED:INTERNAL=1
+//uname command
+CMAKE_UNAME:INTERNAL=/bin/uname
+//ADVANCED property for variable: CMAKE_VERBOSE_MAKEFILE
+CMAKE_VERBOSE_MAKEFILE-ADVANCED:INTERNAL=1
+//linker supports push/pop state
+_CMAKE_LINKER_PUSHPOP_STATE_SUPPORTED:INTERNAL=TRUE
+

+ 181 - 0
elf2uf2/Makefile

@@ -0,0 +1,181 @@
+# CMAKE generated file: DO NOT EDIT!
+# Generated by "Unix Makefiles" Generator, CMake Version 3.24
+
+# Default target executed when no arguments are given to make.
+default_target: all
+.PHONY : default_target
+
+# Allow only one "make -f Makefile2" at a time, but pass parallelism.
+.NOTPARALLEL:
+
+#=============================================================================
+# Special targets provided by cmake.
+
+# Disable implicit rules so canonical targets will work.
+.SUFFIXES:
+
+# Disable VCS-based implicit rules.
+% : %,v
+
+# Disable VCS-based implicit rules.
+% : RCS/%
+
+# Disable VCS-based implicit rules.
+% : RCS/%,v
+
+# Disable VCS-based implicit rules.
+% : SCCS/s.%
+
+# Disable VCS-based implicit rules.
+% : s.%
+
+.SUFFIXES: .hpux_make_needs_suffix_list
+
+# Command-line flag to silence nested $(MAKE).
+$(VERBOSE)MAKESILENT = -s
+
+#Suppress display of executed commands.
+$(VERBOSE).SILENT:
+
+# A target that is always out of date.
+cmake_force:
+.PHONY : cmake_force
+
+#=============================================================================
+# Set environment variables for the build.
+
+# The shell in which to execute make rules.
+SHELL = /bin/sh
+
+# The CMake executable.
+CMAKE_COMMAND = /usr/bin/cmake
+
+# The command to remove a file.
+RM = /usr/bin/cmake -E rm -f
+
+# Escaping for special characters.
+EQUALS = =
+
+# The top-level source directory on which CMake was run.
+CMAKE_SOURCE_DIR = /home/dan/src/rp2040-mixer/pico-sdk/tools/elf2uf2
+
+# The top-level build directory on which CMake was run.
+CMAKE_BINARY_DIR = /home/dan/src/rp2040-mixer/elf2uf2
+
+#=============================================================================
+# Targets provided globally by CMake.
+
+# Special rule for the target edit_cache
+edit_cache:
+	@$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "No interactive CMake dialog available..."
+	/usr/bin/cmake -E echo No\ interactive\ CMake\ dialog\ available.
+.PHONY : edit_cache
+
+# Special rule for the target edit_cache
+edit_cache/fast: edit_cache
+.PHONY : edit_cache/fast
+
+# Special rule for the target rebuild_cache
+rebuild_cache:
+	@$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Running CMake to regenerate build system..."
+	/usr/bin/cmake --regenerate-during-build -S$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR)
+.PHONY : rebuild_cache
+
+# Special rule for the target rebuild_cache
+rebuild_cache/fast: rebuild_cache
+.PHONY : rebuild_cache/fast
+
+# The main all target
+all: cmake_check_build_system
+	$(CMAKE_COMMAND) -E cmake_progress_start /home/dan/src/rp2040-mixer/elf2uf2/CMakeFiles /home/dan/src/rp2040-mixer/elf2uf2//CMakeFiles/progress.marks
+	$(MAKE) $(MAKESILENT) -f CMakeFiles/Makefile2 all
+	$(CMAKE_COMMAND) -E cmake_progress_start /home/dan/src/rp2040-mixer/elf2uf2/CMakeFiles 0
+.PHONY : all
+
+# The main clean target
+clean:
+	$(MAKE) $(MAKESILENT) -f CMakeFiles/Makefile2 clean
+.PHONY : clean
+
+# The main clean target
+clean/fast: clean
+.PHONY : clean/fast
+
+# Prepare targets for installation.
+preinstall: all
+	$(MAKE) $(MAKESILENT) -f CMakeFiles/Makefile2 preinstall
+.PHONY : preinstall
+
+# Prepare targets for installation.
+preinstall/fast:
+	$(MAKE) $(MAKESILENT) -f CMakeFiles/Makefile2 preinstall
+.PHONY : preinstall/fast
+
+# clear depends
+depend:
+	$(CMAKE_COMMAND) -S$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) --check-build-system CMakeFiles/Makefile.cmake 1
+.PHONY : depend
+
+#=============================================================================
+# Target rules for targets named elf2uf2
+
+# Build rule for target.
+elf2uf2: cmake_check_build_system
+	$(MAKE) $(MAKESILENT) -f CMakeFiles/Makefile2 elf2uf2
+.PHONY : elf2uf2
+
+# fast build rule for target.
+elf2uf2/fast:
+	$(MAKE) $(MAKESILENT) -f CMakeFiles/elf2uf2.dir/build.make CMakeFiles/elf2uf2.dir/build
+.PHONY : elf2uf2/fast
+
+main.o: main.cpp.o
+.PHONY : main.o
+
+# target to build an object file
+main.cpp.o:
+	$(MAKE) $(MAKESILENT) -f CMakeFiles/elf2uf2.dir/build.make CMakeFiles/elf2uf2.dir/main.cpp.o
+.PHONY : main.cpp.o
+
+main.i: main.cpp.i
+.PHONY : main.i
+
+# target to preprocess a source file
+main.cpp.i:
+	$(MAKE) $(MAKESILENT) -f CMakeFiles/elf2uf2.dir/build.make CMakeFiles/elf2uf2.dir/main.cpp.i
+.PHONY : main.cpp.i
+
+main.s: main.cpp.s
+.PHONY : main.s
+
+# target to generate assembly for a file
+main.cpp.s:
+	$(MAKE) $(MAKESILENT) -f CMakeFiles/elf2uf2.dir/build.make CMakeFiles/elf2uf2.dir/main.cpp.s
+.PHONY : main.cpp.s
+
+# Help Target
+help:
+	@echo "The following are some of the valid targets for this Makefile:"
+	@echo "... all (the default if no target is provided)"
+	@echo "... clean"
+	@echo "... depend"
+	@echo "... edit_cache"
+	@echo "... rebuild_cache"
+	@echo "... elf2uf2"
+	@echo "... main.o"
+	@echo "... main.i"
+	@echo "... main.s"
+.PHONY : help
+
+
+
+#=============================================================================
+# Special targets to cleanup operation of make.
+
+# Special rule to run CMake to check the build system integrity.
+# No rule that depends on this can have commands that come from listfiles
+# because they might be regenerated.
+cmake_check_build_system:
+	$(CMAKE_COMMAND) -S$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) --check-build-system CMakeFiles/Makefile.cmake 0
+.PHONY : cmake_check_build_system
+

+ 140 - 0
elf2uf2/boot_uf2_headers/Makefile

@@ -0,0 +1,140 @@
+# CMAKE generated file: DO NOT EDIT!
+# Generated by "Unix Makefiles" Generator, CMake Version 3.24
+
+# Default target executed when no arguments are given to make.
+default_target: all
+.PHONY : default_target
+
+# Allow only one "make -f Makefile2" at a time, but pass parallelism.
+.NOTPARALLEL:
+
+#=============================================================================
+# Special targets provided by cmake.
+
+# Disable implicit rules so canonical targets will work.
+.SUFFIXES:
+
+# Disable VCS-based implicit rules.
+% : %,v
+
+# Disable VCS-based implicit rules.
+% : RCS/%
+
+# Disable VCS-based implicit rules.
+% : RCS/%,v
+
+# Disable VCS-based implicit rules.
+% : SCCS/s.%
+
+# Disable VCS-based implicit rules.
+% : s.%
+
+.SUFFIXES: .hpux_make_needs_suffix_list
+
+# Command-line flag to silence nested $(MAKE).
+$(VERBOSE)MAKESILENT = -s
+
+#Suppress display of executed commands.
+$(VERBOSE).SILENT:
+
+# A target that is always out of date.
+cmake_force:
+.PHONY : cmake_force
+
+#=============================================================================
+# Set environment variables for the build.
+
+# The shell in which to execute make rules.
+SHELL = /bin/sh
+
+# The CMake executable.
+CMAKE_COMMAND = /usr/bin/cmake
+
+# The command to remove a file.
+RM = /usr/bin/cmake -E rm -f
+
+# Escaping for special characters.
+EQUALS = =
+
+# The top-level source directory on which CMake was run.
+CMAKE_SOURCE_DIR = /home/dan/src/rp2040-mixer/pico-sdk/tools/elf2uf2
+
+# The top-level build directory on which CMake was run.
+CMAKE_BINARY_DIR = /home/dan/src/rp2040-mixer/elf2uf2
+
+#=============================================================================
+# Targets provided globally by CMake.
+
+# Special rule for the target edit_cache
+edit_cache:
+	@$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "No interactive CMake dialog available..."
+	/usr/bin/cmake -E echo No\ interactive\ CMake\ dialog\ available.
+.PHONY : edit_cache
+
+# Special rule for the target edit_cache
+edit_cache/fast: edit_cache
+.PHONY : edit_cache/fast
+
+# Special rule for the target rebuild_cache
+rebuild_cache:
+	@$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Running CMake to regenerate build system..."
+	/usr/bin/cmake --regenerate-during-build -S$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR)
+.PHONY : rebuild_cache
+
+# Special rule for the target rebuild_cache
+rebuild_cache/fast: rebuild_cache
+.PHONY : rebuild_cache/fast
+
+# The main all target
+all: cmake_check_build_system
+	cd /home/dan/src/rp2040-mixer/elf2uf2 && $(CMAKE_COMMAND) -E cmake_progress_start /home/dan/src/rp2040-mixer/elf2uf2/CMakeFiles /home/dan/src/rp2040-mixer/elf2uf2/boot_uf2_headers//CMakeFiles/progress.marks
+	cd /home/dan/src/rp2040-mixer/elf2uf2 && $(MAKE) $(MAKESILENT) -f CMakeFiles/Makefile2 boot_uf2_headers/all
+	$(CMAKE_COMMAND) -E cmake_progress_start /home/dan/src/rp2040-mixer/elf2uf2/CMakeFiles 0
+.PHONY : all
+
+# The main clean target
+clean:
+	cd /home/dan/src/rp2040-mixer/elf2uf2 && $(MAKE) $(MAKESILENT) -f CMakeFiles/Makefile2 boot_uf2_headers/clean
+.PHONY : clean
+
+# The main clean target
+clean/fast: clean
+.PHONY : clean/fast
+
+# Prepare targets for installation.
+preinstall: all
+	cd /home/dan/src/rp2040-mixer/elf2uf2 && $(MAKE) $(MAKESILENT) -f CMakeFiles/Makefile2 boot_uf2_headers/preinstall
+.PHONY : preinstall
+
+# Prepare targets for installation.
+preinstall/fast:
+	cd /home/dan/src/rp2040-mixer/elf2uf2 && $(MAKE) $(MAKESILENT) -f CMakeFiles/Makefile2 boot_uf2_headers/preinstall
+.PHONY : preinstall/fast
+
+# clear depends
+depend:
+	cd /home/dan/src/rp2040-mixer/elf2uf2 && $(CMAKE_COMMAND) -S$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) --check-build-system CMakeFiles/Makefile.cmake 1
+.PHONY : depend
+
+# Help Target
+help:
+	@echo "The following are some of the valid targets for this Makefile:"
+	@echo "... all (the default if no target is provided)"
+	@echo "... clean"
+	@echo "... depend"
+	@echo "... edit_cache"
+	@echo "... rebuild_cache"
+.PHONY : help
+
+
+
+#=============================================================================
+# Special targets to cleanup operation of make.
+
+# Special rule to run CMake to check the build system integrity.
+# No rule that depends on this can have commands that come from listfiles
+# because they might be regenerated.
+cmake_check_build_system:
+	cd /home/dan/src/rp2040-mixer/elf2uf2 && $(CMAKE_COMMAND) -S$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) --check-build-system CMakeFiles/Makefile.cmake 0
+.PHONY : cmake_check_build_system
+

+ 44 - 0
elf2uf2/boot_uf2_headers/cmake_install.cmake

@@ -0,0 +1,44 @@
+# Install script for directory: /home/dan/src/rp2040-mixer/pico-sdk/src/common/boot_uf2
+
+# Set the install prefix
+if(NOT DEFINED CMAKE_INSTALL_PREFIX)
+  set(CMAKE_INSTALL_PREFIX "/usr/local")
+endif()
+string(REGEX REPLACE "/$" "" CMAKE_INSTALL_PREFIX "${CMAKE_INSTALL_PREFIX}")
+
+# Set the install configuration name.
+if(NOT DEFINED CMAKE_INSTALL_CONFIG_NAME)
+  if(BUILD_TYPE)
+    string(REGEX REPLACE "^[^A-Za-z0-9_]+" ""
+           CMAKE_INSTALL_CONFIG_NAME "${BUILD_TYPE}")
+  else()
+    set(CMAKE_INSTALL_CONFIG_NAME "")
+  endif()
+  message(STATUS "Install configuration: \"${CMAKE_INSTALL_CONFIG_NAME}\"")
+endif()
+
+# Set the component getting installed.
+if(NOT CMAKE_INSTALL_COMPONENT)
+  if(COMPONENT)
+    message(STATUS "Install component: \"${COMPONENT}\"")
+    set(CMAKE_INSTALL_COMPONENT "${COMPONENT}")
+  else()
+    set(CMAKE_INSTALL_COMPONENT)
+  endif()
+endif()
+
+# Install shared libraries without execute permission?
+if(NOT DEFINED CMAKE_INSTALL_SO_NO_EXE)
+  set(CMAKE_INSTALL_SO_NO_EXE "1")
+endif()
+
+# Is this installation the result of a crosscompile?
+if(NOT DEFINED CMAKE_CROSSCOMPILING)
+  set(CMAKE_CROSSCOMPILING "FALSE")
+endif()
+
+# Set default install directory permissions.
+if(NOT DEFINED CMAKE_OBJDUMP)
+  set(CMAKE_OBJDUMP "/usr/bin/objdump")
+endif()
+

+ 60 - 0
elf2uf2/cmake_install.cmake

@@ -0,0 +1,60 @@
+# Install script for directory: /home/dan/src/rp2040-mixer/pico-sdk/tools/elf2uf2
+
+# Set the install prefix
+if(NOT DEFINED CMAKE_INSTALL_PREFIX)
+  set(CMAKE_INSTALL_PREFIX "/usr/local")
+endif()
+string(REGEX REPLACE "/$" "" CMAKE_INSTALL_PREFIX "${CMAKE_INSTALL_PREFIX}")
+
+# Set the install configuration name.
+if(NOT DEFINED CMAKE_INSTALL_CONFIG_NAME)
+  if(BUILD_TYPE)
+    string(REGEX REPLACE "^[^A-Za-z0-9_]+" ""
+           CMAKE_INSTALL_CONFIG_NAME "${BUILD_TYPE}")
+  else()
+    set(CMAKE_INSTALL_CONFIG_NAME "")
+  endif()
+  message(STATUS "Install configuration: \"${CMAKE_INSTALL_CONFIG_NAME}\"")
+endif()
+
+# Set the component getting installed.
+if(NOT CMAKE_INSTALL_COMPONENT)
+  if(COMPONENT)
+    message(STATUS "Install component: \"${COMPONENT}\"")
+    set(CMAKE_INSTALL_COMPONENT "${COMPONENT}")
+  else()
+    set(CMAKE_INSTALL_COMPONENT)
+  endif()
+endif()
+
+# Install shared libraries without execute permission?
+if(NOT DEFINED CMAKE_INSTALL_SO_NO_EXE)
+  set(CMAKE_INSTALL_SO_NO_EXE "1")
+endif()
+
+# Is this installation the result of a crosscompile?
+if(NOT DEFINED CMAKE_CROSSCOMPILING)
+  set(CMAKE_CROSSCOMPILING "FALSE")
+endif()
+
+# Set default install directory permissions.
+if(NOT DEFINED CMAKE_OBJDUMP)
+  set(CMAKE_OBJDUMP "/usr/bin/objdump")
+endif()
+
+if(NOT CMAKE_INSTALL_LOCAL_ONLY)
+  # Include the install script for each subdirectory.
+  include("/home/dan/src/rp2040-mixer/elf2uf2/boot_uf2_headers/cmake_install.cmake")
+
+endif()
+
+if(CMAKE_INSTALL_COMPONENT)
+  set(CMAKE_INSTALL_MANIFEST "install_manifest_${CMAKE_INSTALL_COMPONENT}.txt")
+else()
+  set(CMAKE_INSTALL_MANIFEST "install_manifest.txt")
+endif()
+
+string(REPLACE ";" "\n" CMAKE_INSTALL_MANIFEST_CONTENT
+       "${CMAKE_INSTALL_MANIFEST_FILES}")
+file(WRITE "/home/dan/src/rp2040-mixer/elf2uf2/${CMAKE_INSTALL_MANIFEST}"
+     "${CMAKE_INSTALL_MANIFEST_CONTENT}")

BIN
elf2uf2/elf2uf2


+ 0 - 0
elf2uf2/src/ELF2UF2Build-stamp/ELF2UF2Build-done


+ 9 - 0
elf2uf2/src/ELF2UF2Build-stamp/ELF2UF2Build-source_dirinfo.txt

@@ -0,0 +1,9 @@
+# This is a generated file and its contents are an internal implementation detail.
+# The download step will be re-executed if anything in this file changes.
+# No other meaning or use of this file is supported.
+
+method=source_dir
+command=
+source_dir=/home/dan/src/rp2040-mixer/pico-sdk/tools/elf2uf2
+work_dir=
+

+ 1 - 0
elf2uf2/tmp/ELF2UF2Build-cfgcmd.txt

@@ -0,0 +1 @@
+cmd='/usr/bin/cmake;-GUnix Makefiles;<SOURCE_DIR><SOURCE_SUBDIR>'

+ 22 - 0
elf2uf2/tmp/ELF2UF2Build-mkdirs.cmake

@@ -0,0 +1,22 @@
+# Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+cmake_minimum_required(VERSION 3.5)
+
+file(MAKE_DIRECTORY
+  "/home/dan/src/rp2040-mixer/pico-sdk/tools/elf2uf2"
+  "/home/dan/src/rp2040-mixer/elf2uf2"
+  "/home/dan/src/rp2040-mixer/elf2uf2"
+  "/home/dan/src/rp2040-mixer/elf2uf2/tmp"
+  "/home/dan/src/rp2040-mixer/elf2uf2/src/ELF2UF2Build-stamp"
+  "/home/dan/src/rp2040-mixer/elf2uf2/src"
+  "/home/dan/src/rp2040-mixer/elf2uf2/src/ELF2UF2Build-stamp"
+)
+
+set(configSubDirs )
+foreach(subDir IN LISTS configSubDirs)
+    file(MAKE_DIRECTORY "/home/dan/src/rp2040-mixer/elf2uf2/src/ELF2UF2Build-stamp/${subDir}")
+endforeach()
+if(cfgdir)
+  file(MAKE_DIRECTORY "/home/dan/src/rp2040-mixer/elf2uf2/src/ELF2UF2Build-stamp${cfgdir}") # cfgdir has leading slash
+endif()

+ 11 - 0
generated/pico_base/pico/config_autogen.h

@@ -0,0 +1,11 @@
+// AUTOGENERATED FROM PICO_CONFIG_HEADER_FILES and then PICO_<PLATFORM>_CONFIG_HEADER_FILES
+// DO NOT EDIT!
+
+
+// based on PICO_CONFIG_HEADER_FILES:
+
+#include "/home/dan/src/rp2040-mixer/pico-sdk/src/boards/include/boards/pico.h"
+
+// based on PICO_RP2040_CONFIG_HEADER_FILES:
+
+#include "/home/dan/src/rp2040-mixer/pico-sdk/src/rp2_common/cmsis/include/cmsis/rename_exceptions.h"

+ 19 - 0
generated/pico_base/pico/version.h

@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+// ---------------------------------------
+// THIS FILE IS AUTOGENERATED; DO NOT EDIT
+// ---------------------------------------
+
+#ifndef _PICO_VERSION_H
+#define _PICO_VERSION_H
+
+#define PICO_SDK_VERSION_MAJOR    1
+#define PICO_SDK_VERSION_MINOR    3
+#define PICO_SDK_VERSION_REVISION 0
+#define PICO_SDK_VERSION_STRING   "1.3.0"
+
+#endif

+ 1 - 0
lib/wolfssl

@@ -0,0 +1 @@
+Subproject commit 5a49b8c4366fbf45890fbf991c8a7ee50548596e

+ 7 - 0
msc_content/Makefile

@@ -0,0 +1,7 @@
+all: mep 
+	
+mep: mep.c
+	gcc -g -ggdb -o mep mep.c -lwolfssl
+
+clean:
+	rm -f mep

+ 896 - 0
msc_content/mep.c

@@ -0,0 +1,896 @@
+#include <stdint.h>
+#include <wolfssl/options.h>
+#include <wolfssl/wolfcrypt/settings.h>
+#include <wolfssl/wolfcrypt/ecc.h>
+#include <wolfssl/wolfcrypt/pwdbased.h>
+#include <wolfssl/wolfcrypt/sha512.h>
+#include <wolfssl/wolfcrypt/chacha.h>
+
+#include "../src/cryptoengine.h"
+
+#include <fcntl.h>
+#include <err.h>
+#include <termio.h>
+#include <linux/serial.h>
+#include <stdio.h>
+#include <errno.h>
+#include <sys/poll.h>
+
+#define HOMEPATH_PREFIX "~/.pvault"
+//#define HOMEPATH_PREFIX "/root/.pvault"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define MAX_SVC_NAME_LEN 16
+
+static char pass_prompt[200] = "";
+static char pass_confirm[200] = "";
+static const char pass_prompt_phrase[] = "Enter your passphrase: ";
+static const char pass_confirm_phrase[] = "Confirm your passphrase : ";
+
+static const char pass_prompt_svc[] = "Password: ";
+static const char pass_confirm_svc[] = "Confirm Password: ";
+
+static int sfd = -1;;
+static int pk_fd = -1;
+
+static struct vault_status Status = { };
+static int get_vault_status(void);
+
+
+struct __attribute__((packed)) tofu_packet {
+    uint32_t cdc_magic; /* 0x5afeca5e */
+    uint16_t cdc_cmd;
+    uint16_t cdc_len;
+    struct vault_header vh;
+};
+
+void clearScreen() {
+    system("clear");
+}
+
+void disableEcho() {
+    struct termios term;
+    tcgetattr(0, &term);
+    term.c_lflag &= ~ECHO;
+    tcsetattr(0, TCSANOW, &term);
+}
+
+void enableEcho() {
+    struct termios term;
+    tcgetattr(0, &term);
+    term.c_lflag |= ECHO;
+    tcsetattr(0, TCSANOW, &term);
+}
+
+void printPrompt() {
+    printf(pass_prompt);
+}
+
+static void getPassword(char *password, int size) {
+    int i = 0;
+    char c;
+
+    while (i < size - 1) {
+        c = getchar();
+        if (c == '\n') {
+            break;
+        }
+        password[i++] = c;
+        if (i >= 99)
+            break;
+    }
+
+    password[i] = '\0';
+}
+
+int confirmPassphrase(const char *passphrase) {
+    char confirmation[100];
+
+    printf(pass_confirm);
+    getPassword(confirmation, sizeof(confirmation));
+
+    return strcmp(passphrase, confirmation) == 0;
+}
+
+static char passphrase[100];
+static int askpass(void)
+{
+    int ret = 0;
+    disableEcho();
+    printPrompt();
+    getPassword(passphrase, sizeof(passphrase));
+    printf("\n");
+
+    if (confirmPassphrase(passphrase)) {
+        printf("\nConfirmed.\n");
+        ret = 1;
+    } else {
+        printf("These passwords don't match. Please try again.\n");
+    }
+    enableEcho();
+    return ret;
+}
+
+
+
+static int rate_to_constant(int baudrate) {
+#ifdef __MACH__
+#define B(x) case x: return x
+#else
+#define B(x) case x: return B##x
+#endif
+    switch(baudrate) {
+        B(50);     B(75);     B(110);    B(134);    B(150);
+        B(200);    B(300);    B(600);    B(1200);   B(1800);
+        B(2400);   B(4800);   B(9600);   B(19200);  B(38400);
+        B(57600);  B(115200); B(230400); B(460800); B(500000);
+        B(576000); B(921600); B(1000000);B(1152000);B(1500000);
+default: return 0;
+}
+#undef B
+}
+
+/* Open serial port in raw mode, with custom baudrate if necessary */
+static int serial_open(const char *device, int rate)
+{
+	struct termios options;
+	int fd;
+	int speed = 0;
+
+	/* Open and configure serial port */
+	if ((fd = open(device,O_RDWR|O_NOCTTY)) == -1)
+		return -1;
+
+	speed = rate_to_constant(rate);
+
+#ifndef __MACH__
+	if (speed == 0) {
+		/* Custom divisor */
+        struct serial_struct serinfo;
+		serinfo.reserved_char[0] = 0;
+		if (ioctl(fd, TIOCGSERIAL, &serinfo) < 0)
+			return -1;
+		serinfo.flags &= ~ASYNC_SPD_MASK;
+		serinfo.flags |= ASYNC_SPD_CUST;
+		serinfo.custom_divisor = (serinfo.baud_base + (rate / 2)) / rate;
+		if (serinfo.custom_divisor < 1)
+			serinfo.custom_divisor = 1;
+		if (ioctl(fd, TIOCSSERIAL, &serinfo) < 0)
+			return -1;
+		if (ioctl(fd, TIOCGSERIAL, &serinfo) < 0)
+			return -1;
+		if (serinfo.custom_divisor * rate != serinfo.baud_base) {
+			warnx("actual baudrate is %d / %d = %f",
+			      serinfo.baud_base, serinfo.custom_divisor,
+			      (float)serinfo.baud_base / serinfo.custom_divisor);
+		}
+	}
+#endif
+
+	fcntl(fd, F_SETFL, 0);
+	tcgetattr(fd, &options);
+	cfsetispeed(&options, speed ?: 460800);
+	cfsetospeed(&options, speed ?: 460800);
+	cfmakeraw(&options);
+	options.c_cflag |= (CLOCAL | CREAD);
+	options.c_cflag &= ~CRTSCTS;
+	if (tcsetattr(fd, TCSANOW, &options) != 0)
+		return -1;
+
+	return fd;
+}
+
+static int tofu(const char *password)
+{
+    int ret = 0, i;
+    int outlen = CRYPTO_KEY_SIZE;
+    int siglen = PK_SIGNATURE_SIZE;
+    uint8_t clr_sig[PK_SIGNATURE_SIZE];
+    struct tofu_packet tofu;
+    uint8_t Ke[CRYPTO_KEY_SIZE], Sm[CRYPTO_KEY_SIZE];
+    uint8_t resp[256];
+    char privkey_fname[32];
+    uint32_t mgc = 0xffffffff;
+    int hash, hash_len;
+    uint8_t iv[24];
+    uint8_t sig_dec_verify[64];
+    struct pollfd pfd;
+    uint32_t qxLen = CRYPTO_KEY_SIZE, qyLen = CRYPTO_KEY_SIZE,
+             dLen = CRYPTO_KEY_SIZE;
+
+
+    tofu.cdc_magic = VAULT_MAGIC;
+    tofu.cdc_cmd = CDC_TOFU_INIT;
+    tofu.cdc_len = sizeof(struct tofu_packet) - 8;
+    
+    tofu.vh.magic = VAULT_MAGIC;
+    tofu.vh.size = sizeof(struct tofu_packet) - 8;
+    
+
+    ecc_key ecc;
+    ChaCha cha;
+    RNG rng;
+    
+    Sha512 sha;
+
+
+    /* Initialize Rng (needed for master key + salt + secret */
+    wc_InitRng(&rng);
+    
+    /* Generate ID */
+    wc_RNG_GenerateBlock(&rng, (void *)tofu.vh.id, 8);
+    sprintf(privkey_fname, "%08x-%08x.der", tofu.vh.id[0], tofu.vh.id[1]);
+    printf("ID: %s\n", privkey_fname);
+
+    /* Generate salt */
+    wc_RNG_GenerateBlock(&rng, tofu.vh.host_salt, SALT_LEN);
+    printf("Salt: ");
+    for (i = 0; i < SALT_LEN; i++) {
+        printf("%02x", tofu.vh.host_salt[i]);
+    }
+    printf("\n");
+
+    /* Derive device key (password based) to create encryption key */
+    ret = wc_PBKDF2(Ke, password, strlen(password), tofu.vh.host_salt, SALT_LEN, 1000, CRYPTO_KEY_SIZE, WC_SHA512);
+    wc_Chacha_SetKey(&cha, Ke, CRYPTO_KEY_SIZE);
+    wc_Chacha_SetIV(&cha, tofu.vh.host_seed, 0);
+
+    /* Generate master signing key */
+    wc_ecc_init(&ecc);
+    wc_ecc_make_key(&rng, CRYPTO_KEY_SIZE, &ecc);
+    qxLen = CRYPTO_KEY_SIZE;
+    qyLen = CRYPTO_KEY_SIZE;
+    wc_ecc_export_public_raw(&ecc, tofu.vh.auth_pubkey, &qxLen, tofu.vh.auth_pubkey + CRYPTO_KEY_SIZE, &qyLen);
+    printf("Public signing key %d: ", qxLen + qyLen);
+    for (i = 0; i < qxLen + qyLen; i++) {
+        printf("%02x", tofu.vh.auth_pubkey[i]);
+    }
+    printf("\n");
+
+    
+    /* Generate key seed */
+    wc_RNG_GenerateBlock(&rng, tofu.vh.host_seed, SEED_LEN);
+    printf("Seed: ");
+    for (i = 0; i < SEED_LEN; i++) {
+        printf("%02x", tofu.vh.host_seed[i]);
+    }
+    printf("\n");
+
+    wc_InitSha512(&sha);
+    for (hash = 0; hash < SHA_PAYLOAD_SIZE;) {
+        hash_len = WC_SHA512_BLOCK_SIZE;
+        if ((SHA_PAYLOAD_SIZE - hash) < hash_len)
+            hash_len = SHA_PAYLOAD_SIZE - hash;
+        wc_Sha512Update(&sha, ((uint8_t*)&tofu.vh) + hash, hash_len);
+        hash += hash_len;
+        printf("update %d/%d\n", hash, SHA_PAYLOAD_SIZE);
+    }
+    wc_Sha512Final(&sha, tofu.vh.digest);
+    printf("Digest (%d): ", sizeof(tofu.vh.digest));
+    for (i = 0; i < sizeof(tofu.vh.digest); i++) {
+        printf("%02x ", tofu.vh.digest[i]);
+        if ((i % 16) == 15)
+            printf("\n");
+    }
+    printf("\n");
+    wc_Sha512Free(&sha);
+
+    {
+        mp_int r, s;
+        mp_init(&r); mp_init(&s);
+        ret = wc_ecc_sign_hash_ex(tofu.vh.digest, VAULT_DIGEST_SIZE, &rng, &ecc,
+                &r, &s); 
+        mp_to_unsigned_bin(&r, &clr_sig[0]);
+        mp_to_unsigned_bin(&s, &clr_sig[CRYPTO_KEY_SIZE]);
+        mp_clear(&r);
+        mp_clear(&s);
+    }
+    printf("Signature (%d) returned %d:\n", PK_SIGNATURE_SIZE, ret);
+    for (i = 0; i < PK_SIGNATURE_SIZE; i++) {
+        printf("%02x ", clr_sig[i]);
+        if ((i % 16) == 15)
+            printf("\n");
+    }
+    printf("\n");
+    {
+        int vr, vres;
+        mp_int r, s;
+        mp_init(&r); mp_init(&s);
+        mp_read_unsigned_bin(&r, &clr_sig[0], CRYPTO_KEY_SIZE);
+        mp_read_unsigned_bin(&s, &clr_sig[CRYPTO_KEY_SIZE], CRYPTO_KEY_SIZE);
+        vr = wc_ecc_verify_hash_ex(&r, &s, tofu.vh.digest, VAULT_DIGEST_SIZE,
+            &vres, &ecc);
+        mp_clear(&r);
+        mp_clear(&s);
+        printf("sanity check verify ret %d res %d\n", vr, vres);
+    }
+
+
+    wc_Chacha_SetIV(&cha, tofu.vh.host_seed, 0);
+    wc_Chacha_Process(&cha, tofu.vh.signature, clr_sig, siglen);
+    wc_Chacha_SetIV(&cha, tofu.vh.host_seed, 0);
+    wc_Chacha_Process(&cha, sig_dec_verify, tofu.vh.signature, siglen);
+
+    if (memcmp(clr_sig, sig_dec_verify, siglen) != 0) {
+        printf("Error verifying chacha encryption\n");
+        return 4;
+    }
+
+    printf("Packet (%d): ", sizeof(tofu));
+    for (i = 0; i < sizeof(tofu); i++) {
+        printf("%02x ", *(((uint8_t*)(&tofu)) + i));
+        if ((i % 16) == 15)
+            printf("\n");
+    }
+    printf("\n");
+
+    pfd.fd = sfd;
+    pfd.events = POLLIN;
+    for(i = 0; i < 10; i++) {
+        char buf[8];
+        ret = poll(&pfd, 1, 100);
+        if (ret > 0) {
+            read(sfd, buf, 8);
+        } 
+    }
+
+    ret = write(sfd, &tofu, sizeof(tofu));
+    printf("Sent %d/%d bvtes (tofu) \r\n", ret, sizeof(tofu));
+    do {
+        ret = read(sfd, &mgc, 4);
+    } while (mgc != 0x5afeca5e);
+
+    memcpy (resp, &mgc, 4);
+    ret = read(sfd, resp + 4, 64 + 4);
+    if (ret >= 4) {
+        uint16_t code = *((uint16_t *)(resp + 4));
+        uint16_t len = *((uint16_t *)(resp + 6));
+
+        printf("received %d bytes: resp %04x len %04x\n", ret + 4, *((uint16_t *)(resp + 4)), *((uint16_t *)(resp + 6)));
+        if (ret > 4) {
+            printf("MSG: %s\r\n", resp + 8);
+        }
+        if (code == CDC_OK) {
+            int fd;
+            uint8_t privkey_buf[2 * CRYPTO_KEY_SIZE];
+            char pkfname[MAX_PATH];
+            char *homedir;
+            homedir = getenv("HOME");
+            if (!homedir || strlen(homedir) == 0) {
+                perror("getenv(HOME)");
+                exit(1);
+            }
+
+            snprintf(pkfname, MAX_PATH - 1, "%s/.pvault/%s", homedir, privkey_fname);
+            printf("Saving private key %s\n", privkey_fname);
+            fd = open(pkfname, O_WRONLY | O_CREAT | O_EXCL, 0600);
+            if (fd < 0) {
+                printf("FATAL Error opening private key: %s\n", strerror(errno));
+                return 6;
+            }
+            outlen = 2 * CRYPTO_KEY_SIZE;
+            if (wc_ecc_export_private_raw(&ecc, privkey_buf, &qxLen,
+                        privkey_buf + qxLen, &qyLen,
+                        privkey_buf + qxLen + qyLen, &dLen) != 0) {
+                fprintf(stderr, "Unable to export private key to DER\n");
+                exit(2);
+            }
+            outlen = qxLen + qyLen + dLen;
+            printf("Exporting private key (%d bytes)\n", outlen);
+            write(fd, privkey_buf, outlen); 
+            wc_ecc_free(&ecc);
+            close(fd);
+        }
+    }
+    return 0;
+}
+
+static void addservice(struct vault_service *vs, uint8_t *Ke)
+{
+    struct vault_service vs_local;
+    char gadget_passphrase[64];
+    int ret;
+    uint8_t Ke_local[CRYPTO_KEY_SIZE];
+    uint8_t eccRawKey[CRYPTO_KEY_SIZE * 3];
+    uint8_t snd_buffer[sizeof(struct cdc_packet_hdr) + SVC_SIZE];
+    struct cdc_packet_hdr *hdr = (struct cdc_packet_hdr *)snd_buffer;
+    int i;
+    struct pollfd pfd;
+    uint32_t mgc = 0;
+    int interactive = 0;
+    uint32_t slot = 0;
+    Sha512 sha;
+    ecc_key ecc;
+    ChaCha cha;
+    RNG rng;
+    strcpy(pass_prompt, pass_prompt_svc);
+    strcpy(pass_confirm, pass_confirm_svc);
+
+
+    if (!vs) {
+        vs = &vs_local;
+        Ke = Ke_local;
+        interactive = 1;
+        printf("Service name (max 16 char.) : ");
+        scanf("%s", vs->name); 
+        printf("\n");
+        printf("Username (empty = none) : ");
+        if (scanf("%s", vs->user) <= 0)
+            vs->user[0] = '\0';
+        getchar();
+        while(!askpass()) {
+            printf("Press a key to continue...\r\n");
+            getchar();
+        }
+        strcpy((char *)(vs->pass), passphrase); 
+    }
+    vs->flags = SVC_FLAG_ACTIVE;
+    vs->reserved = 0;
+
+    if (!Ke) {
+        printf("Unspecified key\n");
+        return;
+    }
+
+
+    wc_InitSha512(&sha);
+    wc_Sha512Update(&sha, (uint8_t *)vs, WC_SHA512_BLOCK_SIZE);
+    wc_Sha512Final(&sha, vs->dig);
+
+    printf("\n----- RECAP -----\n");
+    printf("Service name: %s\n", vs->name);
+    printf("Username: %s\n", vs->user);
+    printf("Password: ******\n");
+    printf("Sha: ");
+    for (i = 0; i < VAULT_DIGEST_SIZE; i++) {
+        printf("%02x", vs->dig[i]);
+    }
+    printf("\n-----------------\n\n");
+
+
+    if (interactive)  {
+        printf("Service configured, press a key to send, ctrl+c to abort...\r\n");
+        disableEcho();
+        printf("Enter gadget passphrase to encrypt and send info: ");
+        getPassword(gadget_passphrase, 64);
+        enableEcho();
+        printf("\n");
+        /* Derive device key (password based) to create encryption key */
+        ret = wc_PBKDF2(Ke, gadget_passphrase, strlen(gadget_passphrase),
+                Status.salt, SALT_LEN, 1000, CRYPTO_KEY_SIZE, WC_SHA512);
+
+        if (ret < 0) {
+            printf("Failed to derive password.\n");
+            return;
+        }
+    }
+
+
+    lseek(pk_fd, SEEK_SET, 0);
+    ret = read(pk_fd, eccRawKey, CRYPTO_KEY_SIZE * 3);
+    if (ret != CRYPTO_KEY_SIZE * 3) {
+        printf("Error reading signing key\n");
+        return;
+    }
+
+    wc_ecc_init(&ecc);
+    if (wc_ecc_import_unsigned(&ecc, eccRawKey, eccRawKey + CRYPTO_KEY_SIZE,
+              eccRawKey + 2 * CRYPTO_KEY_SIZE, ECC_SECP256R1) < 0) { 
+        printf("Failed importing signing key\n");
+        return;
+    }
+
+    slot = Status.first_avail;
+
+    /* Initialize Rng (needed for sign)*/
+    wc_InitRng(&rng);
+
+    printf("Slot is %u\n", slot);
+    {
+        mp_int r, s;
+        mp_init(&r); mp_init(&s);
+        ret = wc_ecc_sign_hash_ex(vs->dig, VAULT_DIGEST_SIZE, &rng, &ecc,
+                &r, &s);
+        mp_to_unsigned_bin(&r, &vs->sig[0]);
+        mp_to_unsigned_bin(&s, &vs->sig[CRYPTO_KEY_SIZE]);
+        mp_clear(&r);
+        mp_clear(&s);
+    }
+
+    printf("Signature (%d):\n", PK_SIGNATURE_SIZE);
+    for (i = 0; i < PK_SIGNATURE_SIZE; i++) {
+        printf("%02x ", vs->sig[i]);
+        if ((i % 16) == 15)
+            printf("\n");
+    }
+    printf("\n");
+
+    wc_ecc_free(&ecc);
+
+    /* Copy the part in clear (flags, reserved) */
+    memcpy(snd_buffer + sizeof(struct cdc_packet_hdr), vs, SVC_ENC_OFF);
+
+    /* Set Key and IV */
+    wc_Chacha_SetKey(&cha, Ke, CRYPTO_KEY_SIZE);
+    wc_Chacha_SetIV(&cha, Status.seed, SVC_FLASH_OFFSET + slot * SVC_SIZE);
+    wc_Chacha_Process(&cha, snd_buffer + sizeof(struct cdc_packet_hdr) + SVC_ENC_OFF, 
+            ((uint8_t *)(vs)) + SVC_ENC_OFF, SVC_ENC_SIZE);
+
+    hdr->magic = VAULT_MAGIC;
+    hdr->cmd = CDC_ADDSERV;
+    hdr->len = SVC_SIZE;
+
+    pfd.fd = sfd;
+    pfd.events = POLLIN;
+    for (i = 0; i < 10; i++) {
+        char buf[8];
+        ret = poll(&pfd, 1, 10);
+        if (ret > 0) {
+            read(sfd, buf, 8);
+        } 
+    }
+    
+    printf("Packet (%d): ", sizeof(snd_buffer));
+    for (i = 0; i < sizeof(snd_buffer); i++) {
+        printf("%02x ", snd_buffer[i]);
+        if ((i % 16) == 15)
+            printf("\n");
+    }
+    printf("\n");
+
+    printf("Sending svc packet... \n");
+    write(sfd, snd_buffer, sizeof(snd_buffer));
+
+    for (i = 0; i < 3; i++) {
+        char buf[256];
+        ret = poll(&pfd, 1, 5000);
+        if (ret > 0) {
+            uint16_t code;
+            do {
+                ret = read(sfd, &mgc, 4);
+            } while (mgc != 0x5afeca5e);
+            ret = read(sfd, buf, 256);
+            code = *((uint16_t *)(buf));
+           
+            printf("Received response (code %02x, len %d): %s\n",
+                    code, ret, (code == CDC_FAIL)?(buf + 4):""); 
+            if ((code == CDC_FAIL) || ((code == CDC_OK) && ret == 4))
+                break;
+        } 
+    }
+
+}
+
+
+char* removeQuotes(char* str) {
+    int len = strlen(str);
+    int i;
+
+    for (i = 0; i < len; i++)
+        if (str[i] != '\"')
+            break;
+    str = str + i;
+
+    len = strlen(str);
+
+    for (i = len -1; i > 0; i--)
+        if (str[i] == '\"')
+            str[i] = '\0';
+    return str;
+}
+
+static void parseCSV(const char* filename) {
+    struct vault_service svc;
+    FILE* file = fopen(filename, "r");
+    uint8_t cKe[CRYPTO_KEY_SIZE];
+    int ret;
+    char gadget_passphrase[64 + 1];
+    char line[1024];
+    int header_line_skipped = 0;
+    if (file == NULL) {
+        printf("Failed to open the file.\n");
+        return;
+    }
+
+    printf("Enter gadget passphrase to encrypt and send info: ");
+    disableEcho();
+    getPassword(gadget_passphrase, 64);
+    enableEcho();
+    printf("\n");
+    /* Derive device key (password based) to create encryption key */
+    ret = wc_PBKDF2(cKe, gadget_passphrase, strlen(gadget_passphrase),
+            Status.salt, SALT_LEN, 1000, CRYPTO_KEY_SIZE, WC_SHA512);
+
+    if (ret < 0) {
+        printf("Failed to derive password.\n");
+        return;
+    }
+
+    while (fgets(line, sizeof(line), file)) {
+        int i;
+
+        // Skip header line
+        if (!header_line_skipped) {
+            header_line_skipped = 1;
+            continue;
+        }
+
+        // Parse each line of the CSV
+        char* token = strtok(line, ",");
+        if (token == NULL) {
+            continue;
+        }
+
+        // Remove quotes from the fields
+        token = removeQuotes(token);
+        char* url = token;
+
+        // Strip "https:" if present
+        if (strncmp(url, "https:", 6) == 0) {
+            url += 6;
+        }
+        
+        // Strip "http:" if present
+        if (strncmp(url, "http:", 5) == 0) {
+            url += 6;
+        }
+
+        // Strip slashes ("/") if present
+        while (*url == '/') {
+            url++;
+        }
+
+        // Strip content after the domain name if present
+        char* slash = strchr(url, '/');
+        if (slash != NULL) {
+            *slash = '\0';
+        }
+
+        // Parse the domain from right to left
+        char* domainStart = NULL;
+        char domain[MAX_SVC_NAME_LEN + 1] = "";
+        char *domainDot = strrchr(url, '.');
+
+        if (domainDot != NULL) {
+            *domainDot=',';
+            domainStart = strrchr(url, '.');
+            *domainDot='.';
+        }
+        if (domainStart == NULL) {
+            strncpy(domain, url, MAX_SVC_NAME_LEN);
+            domain[strlen(url)] = '\0';
+        } else {
+            int domainLen = strlen(domainStart + 1);
+            strncpy(domain, domainStart + 1, domainLen);
+        }
+
+        // Store the extracted domain, user, and pass fields
+        memset(&svc, 0, sizeof(svc));
+        printf("Domain: %s\n", domain);
+        strncpy(svc.name,domain, 16); 
+
+        token = strtok(NULL, ",");
+        if (token != NULL) {
+            token = removeQuotes(token);
+            strncpy(svc.user, token, sizeof(svc.user) - 1);
+        }
+
+        token = strtok(NULL, ",");
+        if (token != NULL) {
+            token = removeQuotes(token);
+            strncpy(svc.pass, token, sizeof(svc.pass));
+        }
+        for (i = 0; i < 3; i++) { 
+            ret = get_vault_status();
+            if (ret == 0)
+                break;
+        }
+        if (ret < 0) {
+            printf("Adding service: failed.\n");
+            getchar();
+            return;
+        }
+        addservice(&svc, cKe);
+    }
+    fclose(file);
+}
+
+
+void printMenu() {
+    printf("\n");
+    printf("0) Device status\n");
+    printf("1) TOFU\n");
+    printf("2) Add service\n");
+    printf("3) Import passwords from CSV\n");
+    printf("q) Quit\n\n");
+}
+
+char getUserInput() {
+    char input;
+    printf("Choice: ");
+    scanf(" %c", &input);
+    getchar(); // Consume the newline character
+    return input;
+}
+
+void processChoice(char choice) {
+    char csv_filename[PATH_MAX];
+    switch (choice) {
+        case '0':
+            // Handle option 0 (Device status)
+            clearScreen();
+            printf("Device status selected.\n");
+            break;
+        case '1':
+            // Handle option 1 (TOFU)
+            clearScreen();
+            printf("TOFU selected.\n");
+            strcpy(pass_prompt, pass_prompt_phrase);
+            strcpy(pass_confirm, pass_confirm_phrase);
+            memset(passphrase, 0, sizeof(passphrase));
+            while(!askpass()) {
+                printf("Press a key to continue...\r\n");
+                getchar();
+            }
+
+            tofu(passphrase);
+            break;
+        case '2':
+            // Handle option 2 (Add service)
+            clearScreen();
+            printf("Add service selected.\n");
+            strcpy(pass_prompt, pass_prompt_phrase);
+            strcpy(pass_confirm, pass_confirm_phrase);
+            if (Status.state < 0x02) {
+                printf("Cannot add service: device not initialized.\n");
+                break;
+            }
+            if (pk_fd < 0) {
+                printf("Cannot add service: private key not present for this device.\n");
+                break;
+            }
+            addservice(NULL, NULL);
+            break;
+        case '3':
+            // Handle option 3 (Import CSV)
+            clearScreen();
+            printf("CSV file: ");
+            scanf("%s", csv_filename);
+            getchar();
+            parseCSV(csv_filename);
+            break;
+        case 'q':
+        case 'Q':
+            // Quit the program
+            printf("Quitting...\n");
+            exit(0);
+        default:
+            printf("Invalid choice.\n");
+            break;
+    }
+
+    printf("Press Enter to continue...\n");
+    getchar(); // Wait for Enter key
+}
+
+
+static int get_vault_status(void)
+{
+    uint32_t rcount = 0;
+    struct cdc_packet_hdr hdr;
+    int ret;
+    int i;
+    struct pollfd pfd;
+    uint8_t rxbuf[sizeof(struct cdc_packet_hdr) + sizeof(struct vault_status)];
+    pfd.fd = sfd;
+    pfd.events = POLLIN;
+
+    hdr.magic = VAULT_MAGIC;
+    hdr.cmd = CDC_STATUS;
+    hdr.len = 0;
+    for (i = 0; i < 3; i++) {
+        ret = write(sfd, &hdr, sizeof(hdr));
+        if (ret <= 0)
+            return ret;
+    
+        ret = poll(&pfd, 1, 1000);
+        if (ret == 0) {
+            printf("Get status: timeout");
+            continue;
+        }
+        if (ret < 0) {
+            perror("get_status(): polling device");
+            return -1;
+        }
+        do {
+            ret = read(sfd, rxbuf + rcount, sizeof(rxbuf) - rcount);
+            if (ret < 0) {
+                return -1;
+            }
+            rcount += ret;
+        } while (rcount < sizeof(rxbuf));
+        break;
+    }
+    if (rcount > 0) {
+        if (*(uint32_t *)(rxbuf) != VAULT_MAGIC)
+            return -2;
+        if (*(uint16_t *)(rxbuf + 4) != CDC_STATUS)
+            return -3;
+        memcpy(&Status, rxbuf + sizeof(struct cdc_packet_hdr), sizeof(Status));
+        return 0;
+    }
+    return -1;
+}
+
+
+static const char vstatenames[][32] = {
+    "OFF",
+    "TOFU",
+    "BOOTUP",
+    "VERIFY_PASSPHRASE",
+    "VERIFY_FAILED",
+    "MAIN_MENU",
+    "SETTINGS_MENU",
+    "SERVICE_LIST"
+};
+
+
+
+
+int main(int argc, char *argv[]) 
+{
+    clearScreen();
+    system("mkdir -p " HOMEPATH_PREFIX);
+    
+    if (argc != 2) {
+        fprintf(stderr, "Usage: %s TTY\n", argv[0]);
+        return 2;
+    }
+
+    sfd = serial_open(argv[1], 115200);
+    if (sfd < 0) {
+        perror("serial_open");
+        if (errno == EACCES) {
+            printf("\n\nPerhaps you should review your permission for %s, or 'sudo adduser $YOUR_USER dialout'\r\n", argv[1]);
+        }
+        return 1;
+    }
+    while (1) {
+        char choice;
+        if (get_vault_status() < 0) {
+            printf("Not connected\n");
+        } else {
+            char pkfname[MAX_PATH];
+            char *homedir;
+            homedir = getenv("HOME");
+            if (!homedir || strlen(homedir) == 0) {
+                perror("getenv(HOME)");
+                exit(1);
+            }
+
+            snprintf(pkfname, MAX_PATH - 1, "%s/.pvault/%08x-%08x.der", homedir, Status.id[0], Status.id[1]);
+            printf("Device %08x-%08x Connected.\n", Status.id[0], Status.id[1]);
+            pk_fd = open(pkfname, O_RDONLY);
+            if (pk_fd < 0) {
+                perror("open");
+                printf(pkfname);
+                printf("\n");
+
+                printf("Private key not available.\n");
+            } else {
+                printf("Private key loaded.\n");
+            }
+            printf("State: %s - Services: %hu. Spot: %hu\n", 
+                    vstatenames[Status.state], Status.services_active, Status.first_avail);
+        }
+        printMenu();
+        choice = getUserInput();
+        processChoice(choice);
+    }
+
+    return 0;
+}
+

+ 1 - 0
pico-sdk

@@ -0,0 +1 @@
+Subproject commit 2062372d203b372849d573f252cf7c6dc2800c0a

+ 62 - 0
pico_sdk_import.cmake

@@ -0,0 +1,62 @@
+# This is a copy of <PICO_SDK_PATH>/external/pico_sdk_import.cmake
+
+# This can be dropped into an external project to help locate this SDK
+# It should be include()ed prior to project()
+
+if (DEFINED ENV{PICO_SDK_PATH} AND (NOT PICO_SDK_PATH))
+    set(PICO_SDK_PATH $ENV{PICO_SDK_PATH})
+    message("Using PICO_SDK_PATH from environment ('${PICO_SDK_PATH}')")
+endif ()
+
+if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT} AND (NOT PICO_SDK_FETCH_FROM_GIT))
+    set(PICO_SDK_FETCH_FROM_GIT $ENV{PICO_SDK_FETCH_FROM_GIT})
+    message("Using PICO_SDK_FETCH_FROM_GIT from environment ('${PICO_SDK_FETCH_FROM_GIT}')")
+endif ()
+
+if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT_PATH} AND (NOT PICO_SDK_FETCH_FROM_GIT_PATH))
+    set(PICO_SDK_FETCH_FROM_GIT_PATH $ENV{PICO_SDK_FETCH_FROM_GIT_PATH})
+    message("Using PICO_SDK_FETCH_FROM_GIT_PATH from environment ('${PICO_SDK_FETCH_FROM_GIT_PATH}')")
+endif ()
+
+set(PICO_SDK_PATH "${PICO_SDK_PATH}" CACHE PATH "Path to the Raspberry Pi Pico SDK")
+set(PICO_SDK_FETCH_FROM_GIT "${PICO_SDK_FETCH_FROM_GIT}" CACHE BOOL "Set to ON to fetch copy of SDK from git if not otherwise locatable")
+set(PICO_SDK_FETCH_FROM_GIT_PATH "${PICO_SDK_FETCH_FROM_GIT_PATH}" CACHE FILEPATH "location to download SDK")
+
+if (NOT PICO_SDK_PATH)
+    if (PICO_SDK_FETCH_FROM_GIT)
+        include(FetchContent)
+        set(FETCHCONTENT_BASE_DIR_SAVE ${FETCHCONTENT_BASE_DIR})
+        if (PICO_SDK_FETCH_FROM_GIT_PATH)
+            get_filename_component(FETCHCONTENT_BASE_DIR "${PICO_SDK_FETCH_FROM_GIT_PATH}" REALPATH BASE_DIR "${CMAKE_SOURCE_DIR}")
+        endif ()
+        FetchContent_Declare(
+                pico_sdk
+                GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk
+                GIT_TAG master
+        )
+        if (NOT pico_sdk)
+            message("Downloading Raspberry Pi Pico SDK")
+            FetchContent_Populate(pico_sdk)
+            set(PICO_SDK_PATH ${pico_sdk_SOURCE_DIR})
+        endif ()
+        set(FETCHCONTENT_BASE_DIR ${FETCHCONTENT_BASE_DIR_SAVE})
+    else ()
+        message(FATAL_ERROR
+                "SDK location was not specified. Please set PICO_SDK_PATH or set PICO_SDK_FETCH_FROM_GIT to on to fetch from git."
+                )
+    endif ()
+endif ()
+
+get_filename_component(PICO_SDK_PATH "${PICO_SDK_PATH}" REALPATH BASE_DIR "${CMAKE_BINARY_DIR}")
+if (NOT EXISTS ${PICO_SDK_PATH})
+    message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' not found")
+endif ()
+
+set(PICO_SDK_INIT_CMAKE_FILE ${PICO_SDK_PATH}/pico_sdk_init.cmake)
+if (NOT EXISTS ${PICO_SDK_INIT_CMAKE_FILE})
+    message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' does not appear to contain the Raspberry Pi Pico SDK")
+endif ()
+
+set(PICO_SDK_PATH ${PICO_SDK_PATH} CACHE PATH "Path to the Raspberry Pi Pico SDK" FORCE)
+
+include(${PICO_SDK_INIT_CMAKE_FILE})

+ 260 - 0
src/cdc-protocol.c

@@ -0,0 +1,260 @@
+/* Motenpoche 
+ *
+ * (c) 2023 Daniele Lacamera <root@danielinux.net>
+ *
+ *
+ * Motenpoche is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Motenpoche is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
+ *
+ */
+
+#include <stdint.h>
+#include "class/cdc/cdc.h"
+#include "class/cdc/cdc_device.h"
+#include "bsp/board.h"
+#include "wolfssl/wolfcrypt/settings.h"
+#include "cryptoengine.h"
+#include "flash.h"
+#include "fsm.h"
+#include "hardware/gpio.h"
+
+#include "display.h"
+
+
+extern uint16_t flash_info;
+extern int thread_control_ui;
+extern void system_reboot(void);
+
+extern uint8_t checked_digest[];
+
+
+
+// Invoked when cdc when line state changed e.g connected/disconnected
+void tud_cdc_line_state_cb(uint8_t itf, bool dtr, bool rts)
+{
+  (void) itf;
+  (void) rts;
+
+  // TODO set some indicator
+  if ( dtr )
+  {
+    // Terminal connected
+
+  }else
+  {
+    // Terminal disconnected
+  }
+}
+
+
+static uint8_t cdc_rxbuf[MAX_CDC_CMD];
+static uint32_t cdc_rx_idx = 0;
+static uint32_t cdc_rx_expected = 0xFFFFFFFF;
+static int rx_busy = 0;
+
+static void send_OK(void)
+{
+    struct cdc_packet_hdr OKhdr;
+    OKhdr.magic = VAULT_MAGIC;
+    OKhdr.cmd = CDC_OK;
+    OKhdr.len = 0;
+    tud_cdc_write((void *)&OKhdr, 8);
+    tud_cdc_write_flush();
+}
+
+static void send_fail(char *errmsg)
+{
+    uint8_t failbuf[256 + 8];
+    struct cdc_packet_hdr *hdr = (struct cdc_packet_hdr*)failbuf;
+
+    memset(failbuf, 0, 256 + 8);
+    snprintf(failbuf + 8, 256, "%s", errmsg);
+    hdr->magic = VAULT_MAGIC;
+    hdr->cmd = CDC_FAIL;
+    hdr->len = strlen(failbuf + 8);
+    tud_cdc_write((void *)hdr, 8 + strlen(failbuf + 8));
+    tud_cdc_write_flush();
+}
+
+static void parse_cmd(int rxbuf_size)
+{
+    struct cdc_packet_hdr *hdr;
+    uint16_t svc_active, svc_avail;
+    hdr = (struct cdc_packet_hdr *)(cdc_rxbuf);
+    switch(hdr->cmd & 0xFF) {
+        case CDC_STATUS:
+            int i;
+            enum vault_state st = fsm_get();
+            struct vault_status *vst;
+            uint32_t n_st = (uint32_t)st;
+            uint8_t status_buffer[sizeof(struct cdc_packet_hdr) +
+                sizeof(struct vault_status)];
+
+            hdr = (struct cdc_packet_hdr *)status_buffer;
+            vst = (struct vault_status *)(status_buffer +
+                    sizeof(struct cdc_packet_hdr));
+
+            hdr->magic = VAULT_MAGIC;
+            hdr->cmd = CDC_STATUS;
+            hdr->len = sizeof(struct cdc_packet_hdr) + sizeof(struct vault_status);
+
+            memset(vst, 0, sizeof(struct vault_status));
+            vst->state = fsm_get(); 
+            if (cryptoengine_check_vault() == 0) {
+                cryptoengine_fill_vault_status(vst);
+            }
+            svc_active = 0;
+            svc_avail = 0;
+            cryptoengine_service_count(&svc_active, &svc_avail);
+            vst->services_active = svc_active;
+            vst->first_avail = svc_avail;
+            for (i = 0; i < sizeof(status_buffer);) {
+                int len = 64;
+                if ((sizeof(status_buffer) - i) < len)
+                    len = (sizeof(status_buffer) - i);
+                tud_cdc_write((void *)status_buffer + i, len);
+                tud_cdc_write_flush();
+                i += len;
+            }
+            break;
+        case CDC_TOFU_INIT:
+            if (fsm_get() != VAULT_TOFU) {
+                send_fail("Already provisioned");
+                break;
+            }
+            if (hdr->len == sizeof(struct vault_header)) {
+                struct vault_header *vh = (struct vault_header *)
+                    (cdc_rxbuf + sizeof(struct cdc_packet_hdr));
+                if (rxbuf_size != (hdr->len + sizeof(struct cdc_packet_hdr))) {
+                    char msg[64];
+                    sprintf(msg, "packet len mismatch exp: %d got %d",
+                            (hdr->len + sizeof(struct cdc_packet_hdr)),
+                             rxbuf_size);
+                    send_fail(msg);
+                }
+                if (vh->magic != VAULT_MAGIC) {
+                    send_fail("TOFU Rejected.");
+                    break;
+                }
+                if (cryptoengine_hdr_sha_check(vh) < 0) {
+                    send_fail("TOFU Rejected.");
+                    break;
+                }
+
+                /*  Take control of display/buttons */
+                thread_control_ui = 1;
+                sleep_ms(100);
+                display_clear();
+                display_text(0, "Provisioning...");
+
+                flash_sector_erase(VAULT_FLASH_OFFSET);
+                flash_write(VAULT_FLASH_OFFSET, cdc_rxbuf + sizeof(struct cdc_packet_hdr), sizeof(struct vault_header));
+
+                display_text(1, "Confirming...  ");
+                send_OK();
+                display_text(2, "Rebooting...   ");
+                system_reboot();
+                break;
+            } else {
+                send_fail("TOFU Rejected.");
+                break;
+            }
+            break;
+        case CDC_CHALLENGE:
+            break;
+
+        case CDC_REKEY:
+            break;
+        case CDC_ADDSERV:
+            int ret;
+            uint16_t count, idx;
+            struct vault_service *vs;
+            gpio_put(16,1);
+            if (rxbuf_size != SVC_SIZE + sizeof(struct cdc_packet_hdr)) {
+                char msg[64];
+                sprintf(msg, "packet len mismatch exp: %d got %d", hdr->len, rxbuf_size);
+                send_fail(msg);
+                break;
+            } 
+            vs = (struct vault_service *)(cdc_rxbuf +sizeof(struct cdc_packet_hdr));
+            /* Retrieve the implicit destination slot (current first slot available) */
+            cryptoengine_service_count(&count, &idx);
+            if (cryptoengine_check_vault() < 0)
+                break;
+            ret = cryptoengine_import_service(vs, idx);
+            if (ret == 0)
+                send_OK();
+            else {
+                char msg[40];
+                sprintf(msg, "failed import: svc %s retval %d", vs->name, ret);
+                send_fail(msg);
+            }
+            break;
+
+        case CDC_DELSERV:
+            break;
+        default:
+            send_fail("Bad cmd");
+
+    }
+    rx_busy = 0;
+
+}
+
+
+// Invoked when CDC interface received data from host
+void tud_cdc_rx_cb(uint8_t itf)
+{
+  (void) itf;
+  char buf[64];
+  uint32_t count;
+  struct cdc_packet_hdr *hdr;
+
+  if (rx_busy) {
+      tud_cdc_read_flush();
+      return;
+  }
+  count = tud_cdc_read(buf, sizeof(buf));
+
+
+  if (count > 0) {
+      if (count + cdc_rx_idx > MAX_CDC_CMD) {
+          cdc_rx_idx = 0;
+      }
+      memcpy(cdc_rxbuf + cdc_rx_idx, buf, count);
+      hdr = (struct cdc_packet_hdr *)cdc_rxbuf;
+      if (cdc_rx_idx == 0) {
+          if (hdr->magic != VAULT_MAGIC) {
+              send_fail("Bad magic");
+              cdc_rx_idx = 0;
+              return;
+          }
+          if (hdr->len > MAX_CDC_CMD) {
+              send_fail("Bad cmd: too big");
+              cdc_rx_idx = 0;
+              return;
+          }
+          cdc_rx_expected = hdr->len + sizeof(struct cdc_packet_hdr);
+      }
+      cdc_rx_idx += count;
+      if (cdc_rx_idx >= cdc_rx_expected) {
+          rx_busy = 1;
+          parse_cmd(cdc_rx_expected);
+          if (cdc_rx_expected < cdc_rx_idx) {
+              memcpy(cdc_rxbuf, cdc_rxbuf + cdc_rx_expected, cdc_rx_idx - cdc_rx_expected);
+          }
+          cdc_rx_idx-=cdc_rx_expected;
+      }
+  }
+}

+ 246 - 0
src/cryptoengine.c

@@ -0,0 +1,246 @@
+/* Motenpoche 
+ *
+ * (c) 2023 Daniele Lacamera <root@danielinux.net>
+ *
+ *
+ * Motenpoche is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Motenpoche is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
+ *
+ */
+#include "user_settings.h"
+#include <stdint.h>
+#include "cryptoengine.h"
+#include "fsm.h"
+#include "flash.h"
+#include "class/cdc/cdc.h"
+#include "class/cdc/cdc_device.h"
+#include "bsp/board.h"
+#include "wolfssl/wolfcrypt/sha512.h"
+#include "wolfssl/wolfcrypt/pwdbased.h"
+#include "wolfssl/wolfcrypt/chacha.h"
+#include "wolfssl/wolfcrypt/ecc.h"
+#include "hardware/gpio.h"
+
+static struct vault_header hdr_cache;
+
+uint32_t sector_cache_id = 0xFFFFFFFF;
+static ChaCha cha;
+static ecc_key ecc;
+
+static struct vault_service svc_cache;
+static int svc_cache_id = -1;
+
+int flash_decrypt_read_svc(struct vault_service *out, uint32_t addr)
+{
+    if (cryptoengine_check_vault() < 0)
+        return -1;
+    flash_read(addr, &svc_cache, SVC_SIZE);
+    memcpy(out, (uint8_t *)(&svc_cache), SVC_ENC_OFF);
+    wc_Chacha_SetIV(&cha, hdr_cache.host_seed, addr);
+    wc_Chacha_Process(&cha, (uint8_t *)out + SVC_ENC_OFF, ((uint8_t *)&svc_cache) + SVC_ENC_OFF, SVC_ENC_SIZE); 
+    return 0;
+}
+
+static int flash_encrypt_write_svc(const struct vault_service *svc, uint32_t idx)
+{
+    uint32_t addr = idx * SVC_SIZE + SVC_FLASH_OFFSET;
+    if (cryptoengine_check_vault() < 0)
+        return -1;
+    wc_Chacha_SetIV(&cha, hdr_cache.host_seed, addr);
+    wc_Chacha_Process(&cha, (uint8_t *)&svc_cache, (uint8_t *)svc, SVC_SIZE); 
+    flash_write_svc(&svc_cache, idx);
+}
+
+int cryptoengine_verify_passphrase(const char *passphrase, int *res)
+{
+    int ret = -1;
+    int i;
+    uint8_t SecretKey[CRYPTO_KEY_SIZE];
+    uint8_t DecryptedSignature[PK_SIGNATURE_SIZE];
+    mp_int r, s;
+    mp_init(&r);
+    mp_init(&s);
+    *res = 0;
+
+    if (cryptoengine_check_vault() < 0) {
+        return -1;
+    }
+
+    ret = wc_PBKDF2(SecretKey, passphrase, strlen(passphrase), hdr_cache.host_salt, SALT_LEN, 1000, 32, SHA512);
+    if (ret < 0)
+        return ret;
+    wc_Chacha_SetKey(&cha, SecretKey, CRYPTO_KEY_SIZE);
+    wc_Chacha_SetIV(&cha, hdr_cache.host_seed, 0);
+    wc_Chacha_Process(&cha, DecryptedSignature, hdr_cache.signature, PK_SIGNATURE_SIZE); 
+
+    wc_ecc_init(&ecc);
+    if (wc_ecc_import_unsigned(&ecc, hdr_cache.auth_pubkey,
+            hdr_cache.auth_pubkey + CRYPTO_KEY_SIZE,
+            NULL, ECC_SECP256R1) < 0) {
+        mp_free(&r);
+        mp_free(&s);
+        wc_ecc_free(&ecc);
+        return -1;
+    }
+    mp_read_unsigned_bin(&r, DecryptedSignature, CRYPTO_KEY_SIZE);
+    mp_read_unsigned_bin(&s, DecryptedSignature + CRYPTO_KEY_SIZE,
+            CRYPTO_KEY_SIZE);
+
+    ret = wc_ecc_verify_hash_ex(&r, &s, hdr_cache.digest, VAULT_DIGEST_SIZE,
+            res, &ecc);
+    mp_free(&r);
+    mp_free(&s);
+    if ((ret < 0) || (*res != 1)) {
+        if (*res == 0)
+            gpio_put(16, 0);
+
+        wc_ecc_free(&ecc);
+    }
+    return ret;
+}
+
+
+static void hdr_cache_load(void)
+{
+    flash_read(VAULT_FLASH_OFFSET, &hdr_cache, sizeof(struct vault_header));
+}
+
+
+uint8_t checked_digest[VAULT_DIGEST_SIZE];
+int cryptoengine_hdr_sha_check(const struct vault_header *vh)
+{
+    Sha512 sha;
+    int hash, hash_len;
+    wc_InitSha512(&sha);
+    for (hash = 0; hash < SHA_PAYLOAD_SIZE;) {
+        hash_len = WC_SHA512_BLOCK_SIZE;
+        if ((SHA_PAYLOAD_SIZE - hash) < hash_len)
+            hash_len = SHA_PAYLOAD_SIZE - hash;
+        wc_Sha512Update(&sha, ((uint8_t*)vh) + hash, hash_len);
+        hash += hash_len;
+    }
+    wc_Sha512Final(&sha, checked_digest);
+    if(memcmp(checked_digest, vh->digest, VAULT_DIGEST_SIZE) != 0) {
+        return -1;
+    }
+    wc_Sha512Free(&sha);
+    return 0;
+}
+
+int cryptoengine_svc_sha_check(const struct vault_service *vs)
+{
+    Sha512 sha;
+    int hash, hash_len;
+    const uint32_t svc_sha_payload_size = (sizeof(struct vault_service) - (VAULT_DIGEST_SIZE + PK_SIGNATURE_SIZE));
+    wc_InitSha512(&sha);
+    for (hash = 0; hash < svc_sha_payload_size;) {
+        hash_len = WC_SHA512_BLOCK_SIZE;
+        if ((svc_sha_payload_size - hash) < hash_len)
+            hash_len = svc_sha_payload_size - hash;
+        wc_Sha512Update(&sha, ((uint8_t*)vs) + hash, hash_len);
+        hash += hash_len;
+    }
+    wc_Sha512Final(&sha, checked_digest);
+    if(memcmp(checked_digest, vs->dig, VAULT_DIGEST_SIZE) != 0) {
+        return -1;
+    }
+    wc_Sha512Free(&sha);
+    return 0;
+}
+
+int cryptoengine_svc_sig_verify(const struct vault_service *vs, int *res)
+{
+    int ret;
+    mp_int r, s;
+    mp_init(&r);
+    mp_init(&s);
+
+    mp_read_unsigned_bin(&r, vs->sig, CRYPTO_KEY_SIZE);
+    mp_read_unsigned_bin(&s, vs->sig + CRYPTO_KEY_SIZE, CRYPTO_KEY_SIZE);
+
+    ret = wc_ecc_verify_hash_ex(&r, &s, vs->dig, VAULT_DIGEST_SIZE, res, &ecc);
+    mp_free(&r);
+    mp_free(&s);
+    return ret;
+}
+
+int cryptoengine_check_vault(void)
+{
+    hdr_cache_load();
+    if (hdr_cache.magic != VAULT_MAGIC) {
+        return -1;
+    }
+    /* Checking hdr integrity */
+    if (cryptoengine_hdr_sha_check(&hdr_cache) < 0)
+        return -1;
+
+    /* Vault seems valid, integrity check OK */
+    return 0;
+}
+
+int cryptoengine_import_service(struct vault_service *vs, uint32_t idx)
+{
+    uint32_t address = SVC_FLASH_OFFSET + SVC_SIZE * idx;
+    int res;
+    if (cryptoengine_check_vault() < 0)
+        return -1;
+    memcpy(&svc_cache, ((uint8_t *)vs), SVC_ENC_OFF);
+    wc_Chacha_SetIV(&cha, hdr_cache.host_seed, address);
+    wc_Chacha_Process(&cha, ((uint8_t *)&svc_cache) + SVC_ENC_OFF, 
+            ((uint8_t *)vs) + SVC_ENC_OFF, SVC_ENC_SIZE);
+    if (cryptoengine_svc_sha_check(&svc_cache) < 0) {
+        return -1;
+    }
+    if ((cryptoengine_svc_sig_verify(&svc_cache, &res) < 0) || (res != 1))
+    {
+        return -2;
+    }
+    flash_write_svc(vs, idx);
+    return 0;
+}
+
+int cryptoengine_service_count(uint16_t *n_srv, uint16_t *first_avail)
+{
+    int i = 0;
+    *first_avail = (uint16_t)-1;
+    *n_srv = 0;
+    
+    struct vault_service svc;
+    if (cryptoengine_check_vault() < 0)
+        return -1;
+
+    while (1) {
+        flash_read(SVC_FLASH_OFFSET + (i * SVC_SIZE), &svc, SVC_SIZE);
+        if (svc.flags == SVC_FLAG_ACTIVE)
+            (*n_srv)++;
+        else if (svc.flags == SVC_FLAG_ERASED)
+            *first_avail = i;
+        else if (svc.flags == SVC_FLAG_UNUSED) {
+            if (*first_avail == ((uint16_t)-1))
+                *first_avail = i;
+            break;
+        }
+        i++;
+    }
+    return *n_srv;
+}
+                
+int cryptoengine_fill_vault_status(struct vault_status *vst)
+{
+    if (cryptoengine_check_vault() < 0)
+        return -1;
+    memcpy(vst->id, &hdr_cache.id, 2 * sizeof(uint32_t));
+    memcpy(vst->salt, &hdr_cache.host_salt, SALT_LEN);
+    memcpy(vst->seed, &hdr_cache.host_seed, SEED_LEN);
+}

+ 119 - 0
src/cryptoengine.h

@@ -0,0 +1,119 @@
+/* Motenpoche 
+ *
+ * (c) 2023 Daniele Lacamera <root@danielinux.net>
+ *
+ *
+ * Motenpoche is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Motenpoche is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
+ *
+ */
+#ifndef CRYPTOENGINE_H
+#define CRYPTOENGINE_H
+#include <wolfssl/wolfcrypt/ecc.h>
+#include <wolfssl/wolfcrypt/sha512.h>
+#define CRYPTO_KEY_SIZE 32
+#define PK_SIGNATURE_SIZE 64
+#define SEED_LEN 24
+
+#define SALT_LEN 64
+
+/* Use lower half of flash */
+#define VAULT_FLASH_OFFSET 0x00000000
+#define VAULT_FLASH_SIZE   (512 * 1024)
+
+#define VAULT_DIGEST_SIZE WC_SHA512_DIGEST_SIZE
+#define SHA_PAYLOAD_SIZE (sizeof(struct vault_header) - (PK_SIGNATURE_SIZE + VAULT_DIGEST_SIZE))
+
+
+#define VAULT_MAGIC 0x5AFECA5E
+int cryptoengine_verify_passphrase(const char *passphrase, int *res);
+int cryptoengine_check_vault(void);
+struct __attribute__((packed)) vault_header {
+    uint32_t magic; /* 0x5afeca5e */
+    uint32_t size; /* Including magic and size */
+    uint32_t id[2];
+    uint8_t  auth_pubkey[2 * CRYPTO_KEY_SIZE]; /* pc-signP, used to authenticate header on rekey/changes */
+    uint8_t  host_salt[SALT_LEN]; /* current PBKDF2 salt. vS = PBKDF2(passphrase, SALT) */
+    uint8_t  host_seed[SEED_LEN]; /* current 'seed' used for IV */
+    uint8_t  digest[VAULT_DIGEST_SIZE]; /* SHA digest of this header */
+    uint8_t  signature[PK_SIGNATURE_SIZE]; /* Signature of the digest */
+};
+
+
+struct __attribute__((packed)) vault_status {
+    uint32_t id[2];
+    uint8_t salt[SALT_LEN];
+    uint8_t seed[SEED_LEN];
+    uint16_t state;
+    uint16_t services_active;
+    uint16_t first_avail;
+};
+
+struct __attribute__((packed)) cdc_packet_hdr
+{
+    uint32_t magic; /* 0x5AFECA5E */
+    uint16_t cmd;
+    uint16_t len;
+};
+
+#define CDC_STATUS    0x0000
+#define CDC_TOFU_INIT 0x0001
+#define CDC_CHALLENGE 0x0002
+#define CDC_REKEY     0x0003
+#define CDC_ADDSERV   0x0004
+#define CDC_DELSERV   0x0005
+
+#define CDC_OK        0x0100
+#define CDC_FAIL      0x0800
+
+#define MAX_CDC_CMD   512
+
+
+#define SETTINGS_FLASH_OFFSET       0x300
+#define SVC_FLASH_OFFSET            0x400
+
+#define SVC_NAME_SIZE_LIMIT 16
+#define SVC_USER_NAME_MAX 32
+#define SVC_PASSWORD_MAX  64
+
+#define SVC_FLAG_UNUSED  0xFFFFFFFF
+#define SVC_FLAG_ERASED  0xDEADC0DE
+#define SVC_FLAG_ACTIVE  0xAAAAAAAA
+
+
+struct __attribute__((packed)) vault_service
+{
+    uint32_t flags;
+    uint32_t reserved;
+    char name[24];
+    char user[32];
+    char pass[64];
+    uint8_t dig[64];
+    uint8_t sig[64];
+};
+
+#define SVC_ENC_SIZE (256 - 8)
+#define SVC_ENC_OFF  (8)
+#define SVC_SIZE (256)
+
+int cryptoengine_hdr_sha_check(const struct vault_header *vh);
+int cryptoengine_svc_sha_check(const struct vault_service *vs);
+int cryptoengine_svc_sig_verify(const struct vault_service *vs, int *res);
+int cryptoengine_import_service(struct vault_service *vs, uint32_t idx);
+
+int cryptoengine_service_count(uint16_t *n_srv, uint16_t *first_avail);
+int cryptoengine_fill_vault_status(struct vault_status *vst);
+int flash_decrypt_read_svc(struct vault_service *out, uint32_t addr);
+
+#endif

+ 180 - 0
src/display.c

@@ -0,0 +1,180 @@
+/* Motenpoche 
+ *
+ * (c) 2023 Daniele Lacamera <root@danielinux.net>
+ *
+ *
+ * Motenpoche is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Motenpoche is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
+ *
+ */
+#include <stdlib.h>
+#include <string.h>
+#include "display.h"
+#include "hardware/i2c.h"
+#include "bsp/board.h"
+
+#define DISPLAY_I2C_ADDR 0x3C   
+
+static uint8_t contrast = 0xcf;
+static i2c_inst_t *i2c_inst = NULL;
+
+
+static void display_send_data(const uint8_t *buf, int len)
+{
+    const uint8_t start_data = 0x40;
+    int i;
+    uint8_t data_buf[200];
+    data_buf[0] = 0x40;
+    if (len > 199)
+        len = 199;
+    memcpy(data_buf + 1, buf, len);
+    if (!i2c_inst)
+        return;
+    i2c_write_blocking(i2c_inst, DISPLAY_I2C_ADDR, data_buf, len+1, 0);
+}
+
+static void display_send_cmd(uint8_t cmd)
+{
+    uint8_t buf[2] = {0x00, cmd};
+    if (!i2c_inst)
+        return;
+    i2c_write_blocking(i2c_inst, DISPLAY_I2C_ADDR, buf, 2, 0);
+}
+
+static void display_send_cmd1(uint8_t cmd, uint8_t arg1)
+{
+    uint8_t buf[3] = {0x00, cmd, arg1};
+    if (!i2c_inst)
+        return;
+    i2c_write_blocking(i2c_inst, DISPLAY_I2C_ADDR, buf, 3, 0);
+}
+static void display_send_cmd2(uint8_t cmd, uint8_t arg1, uint8_t arg2)
+{
+    uint8_t buf[4] = {0x00, cmd, arg1, arg2};
+    if (!i2c_inst)
+        return;
+    i2c_write_blocking(i2c_inst, DISPLAY_I2C_ADDR, buf, 4, 0);
+}
+
+
+void display_scroll(uint8_t line)
+{
+    display_send_cmd1(SSD1306_SETSTARTLINE, (line % 0x40) + 0x40);
+}
+
+void display_setcontrast(uint8_t c)
+{
+    contrast = c; 
+    display_send_cmd1(SSD1306_SETCONTRAST, contrast);
+}
+
+uint8_t display_getcontrast(void)
+{
+    return contrast;
+}
+
+void display_clear(void)
+{
+
+    int i,j;
+    uint8_t zeros[8] = {0, 0, 0, 0, 0, 0, 0, 0 };
+    display_send_cmd(0x00);
+    display_send_cmd(0x10);
+
+    for (i = 0; i < 8; i++)
+    {
+        display_send_cmd2(SSD1306_PAGEADDR, i, 0xFF);
+        for (j = 0; j < WIDTH; j++)
+            display_send_data(zeros, 8);
+    }
+}
+
+void display_text(int row, const char *text)
+{
+    int k;
+    display_send_cmd(0x00);
+    display_send_cmd(0x10);
+    display_send_cmd2(SSD1306_PAGEADDR, 7 - row, 0xFF);
+    for(k = 0; k < strlen(text); k++)
+        display_send_data(fb_font[text[k]], 8);
+}
+
+void display_text_inverse(int row, int col, const char *text)
+{
+    int k, j;
+    uint8_t inv_buf[8];
+    uint8_t ones[8] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
+    int len = strlen(text);
+    if (len > 15)
+        len = 15;
+    display_send_cmd(0x00);
+    display_send_cmd(0x10);
+    sleep_us(1000);
+    display_send_cmd2(SSD1306_PAGEADDR, 7 - row, 0x00);
+    display_send_cmd2(SSD1306_COLUMNADDR, col << 3, WIDTH - 1);
+    for(k = 0; k < len; k++) {
+        for (j = 0; j < 8; j++)
+            inv_buf[j] = ~fb_font[text[k]][j];
+        display_send_data(inv_buf, 8);
+    }
+    display_send_cmd2(SSD1306_COLUMNADDR, 0, WIDTH - 1);
+}
+
+
+int display_init(void *priv)
+{
+    int i;
+    int k = 0;
+    int row = 0;
+    volatile int j;
+    uint8_t dbuf2[64] = {};
+    int page = 0;
+    int seg = 0;
+    volatile uint32_t now;
+
+    i2c_inst = (i2c_inst_t *)priv;
+
+
+    for (i = 1; i < 64; i++) {
+        dbuf2[i] = 0;
+    }
+    display_send_cmd(SSD1306_DISPLAYOFF);
+    display_send_cmd1(0xD6, 0x01);
+    display_send_cmd(0xA1);
+    display_setcontrast(contrast);
+    display_send_cmd1(SSD1306_CHARGEPUMP,  0x14);
+    display_send_cmd1(SSD1306_MEMORYMODE,  0x00);
+    display_send_cmd1(SSD1306_SETCOMPINS, 0x12);
+    display_send_cmd1(SSD1306_SETDISPLAYOFFSET, 0x00);
+    display_send_cmd1(SSD1306_SETVCOMDETECT, 0x00);
+    display_send_cmd1(SSD1306_SETMULTIPLEX, 63);
+    display_send_cmd(SSD1306_COMSCANINC);
+    display_send_cmd(SSD1306_DISPLAYALLON_RESUME);
+    display_send_cmd(SSD1306_DISPLAYON);
+    display_send_cmd(0x2E);
+    
+    display_send_cmd2(SSD1306_PAGEADDR, 0, 0xFF);
+    display_send_cmd2(SSD1306_COLUMNADDR, 0, WIDTH - 1);
+    display_send_cmd1(SSD1306_SETSTARTLINE, 0);
+    display_send_cmd(0x00);
+    display_send_cmd(0x10);
+    for (page = 0; page < 8; page++) {
+        display_send_cmd2(SSD1306_PAGEADDR, page, 0xFF);
+        for (seg= 0; seg < 32; seg++) {
+            display_send_data(dbuf2, 8);
+        }
+        display_send_cmd1(SSD1306_SETSTARTLINE, row);
+    }
+    return 0;
+}

+ 71 - 0
src/display.h

@@ -0,0 +1,71 @@
+/* Motenpoche 
+ *
+ * (c) 2023 Daniele Lacamera <root@danielinux.net>
+ *
+ *
+ * Motenpoche is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Motenpoche is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
+ *
+ */
+#ifndef DISPLAY_H_INCLUDED
+#define DISPLAY_H_INCLUDED
+#include <stdint.h>
+
+#define WIDTH 128
+#define PIXEL_HEIGHT 64
+#define HEIGHT (PIXEL_HEIGHT / 8)
+extern const unsigned char fb_font[256][8];
+#define SSD1306_MEMORYMODE                              0x20
+#define SSD1306_COLUMNADDR                              0x21
+#define SSD1306_PAGEADDR                                0x22
+#define SSD1306_SETCONTRAST                             0x81
+#define SSD1306_CHARGEPUMP                              0x8D
+#define SSD1306_SEGREMAP                                0xA0
+#define SSD1306_DISPLAYALLON_RESUME                     0xA4
+#define SSD1306_DISPLAYALLON                            0xA5
+#define SSD1306_NORMALDISPLAY                           0xA6
+#define SSD1306_INVERTDISPLAY                           0xA7
+#define SSD1306_SETMULTIPLEX                            0xA8
+#define SSD1306_DISPLAYOFF                              0xAE
+#define SSD1306_DISPLAYON                               0xAF
+#define SSD1306_COMSCANINC                              0xC0
+#define SSD1306_COMSCANDEC                              0xC8
+#define SSD1306_SETDISPLAYOFFSET                        0xD3
+#define SSD1306_SETDISPLAYCLOCKDIV                      0xD5
+#define SSD1306_SETPRECHARGE                            0xD9
+#define SSD1306_SETCOMPINS                              0xDA
+#define SSD1306_SETVCOMDETECT                           0xDB
+#define SSD1306_SETLOWCOLUMN                            0x00
+#define SSD1306_SETHIGHCOLUMN                           0x10
+#define SSD1306_SETSTARTLINE                            0x40
+#define SSD1306_RIGHT_HORIZONTAL_SCROLL                 0x26
+#define SSD1306_LEFT_HORIZONTAL_SCROLL                  0x27
+#define SSD1306_VERTICAL_AND_RIGHT_HORIZONTAL_SCROLL    0x29
+#define SSD1306_VERTICAL_AND_LEFT_HORIZONTAL_SCROLL     0x2A
+#define SSD1306_DEACTIVATE_SCROLL                       0x2E
+#define SSD1306_ACTIVATE_SCROLL                         0x2F
+#define SSD1306_SET_VERTICAL_SCROLL_AREA                0xA3
+
+
+
+
+int display_init(void *priv);
+void display_text(int row, const char *text);
+void display_text_inverse(int row, int col, const char *text);
+void display_scroll(uint8_t line);
+void display_setcontrast(uint8_t c);
+uint8_t display_getcontrast();
+void display_clear();
+    
+#endif

+ 228 - 0
src/flash.c

@@ -0,0 +1,228 @@
+/* Motenpoche 
+ *
+ * (c) 2023 Daniele Lacamera <root@danielinux.net>
+ *
+ *
+ * Motenpoche is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Motenpoche is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
+ *
+ */
+#include <stdio.h>
+#include <stdint.h>
+#include "hardware/gpio.h"
+#include "flash.h"
+#include "cryptoengine.h"
+
+#include "bsp/board.h"
+
+
+
+#define MDID            0x90
+#define RDSR            0x05
+#define WRSR            0x01
+#   define ST_BUSY (1 << 0)
+#   define ST_WEL  (1 << 1)
+#   define ST_BP0  (1 << 2)
+#   define ST_BP1  (1 << 3)
+#   define ST_BP2  (1 << 4)
+#   define ST_BP3  (1 << 5)
+#   define ST_AAI  (1 << 6)
+#   define ST_BRO  (1 << 7)
+#define WREN            0x06
+#define WRDI            0x04
+#define SECTOR_ERASE    0x20
+#define BYTE_READ       0x03
+#define BYTE_WRITE      0x02
+#define EWSR            0x50
+#define EBSY            0x70
+#define DBSY            0x80
+
+
+#define SPI_FLASH_CS_PIN 5
+
+static spi_inst_t *SPI = NULL;
+
+static void write_address(uint32_t address)
+{
+    uint8_t a0 = (uint8_t)((address & 0xFF0000) >> 16),
+        a1 = (uint8_t)((address & 0xFF00) >> 8),
+        a2 = (uint8_t)((address & 0xFF));
+    spi_write_blocking(SPI, &a0, 1);
+    spi_write_blocking(SPI, &a1, 1);
+    spi_write_blocking(SPI, &a2, 1);
+}
+
+static uint8_t read_status(void)
+{
+    uint8_t status;
+    uint8_t rdsr = RDSR;
+    gpio_put(SPI_FLASH_CS_PIN, 0);
+    spi_write_blocking(SPI, &rdsr, 1);
+    spi_read_blocking(SPI, 0xFF, &status, 1);
+    gpio_put(SPI_FLASH_CS_PIN, 1);
+    return status;
+}
+
+uint8_t flash_read_status(void)
+{
+    return read_status();
+}
+
+static void spi_cmd(uint8_t cmd)
+{
+    gpio_put(SPI_FLASH_CS_PIN, 0);
+    spi_write_blocking(SPI, &cmd, 1);
+    gpio_put(SPI_FLASH_CS_PIN, 1);
+}
+
+#ifndef GREEN_LED
+#define GREEN_LED 16
+#endif
+volatile uint8_t flash_status;
+static void flash_write_enable(void)
+{
+    do {
+        spi_cmd(WREN);
+        flash_status = read_status();
+    } while ((flash_status & ST_WEL) == 0);
+}
+
+static void flash_write_disable(void)
+{
+    spi_cmd(WRDI);
+}
+
+static void wait_busy(void)
+{
+    do {
+        flash_status = read_status();
+    } while((flash_status & ST_BUSY) != 0);
+}
+
+static int spi_flash_write_sb(uint32_t address, const void *data, int len)
+{
+    const uint8_t *buf = data;
+    uint8_t verify = 0;
+    int j = 0;
+
+    wait_busy();
+    if (len < 1)
+        return -1;
+    while (len > 0) {
+        uint8_t cmd = BYTE_WRITE;
+        flash_write_enable();
+        gpio_put(SPI_FLASH_CS_PIN, 0);
+        spi_write_blocking(SPI, &cmd, 1);
+        write_address(address);
+        spi_write_blocking(SPI, &buf[j], 1);
+        gpio_put(SPI_FLASH_CS_PIN, 1);
+
+        wait_busy();
+        j++;
+        len--;
+        address++;
+    }
+    return 0;
+}
+
+/* --- */
+
+static uint16_t spi_flash_probe(void)
+{
+    uint8_t manuf, product, cmd[2];
+    int i;
+    wait_busy();
+    gpio_put(SPI_FLASH_CS_PIN, 0);
+    cmd[0] = MDID;
+    spi_write_blocking(SPI, cmd, 1);
+    write_address(0);
+    spi_read_blocking(SPI, 0xFF, &manuf, 1);
+    spi_read_blocking(SPI, 0xFF, &product, 1);
+    gpio_put(SPI_FLASH_CS_PIN, 1);
+    wait_busy();
+    flash_write_enable();
+    gpio_put(SPI_FLASH_CS_PIN, 0);
+    cmd[0] = WRSR;
+    cmd[1] = 0x00;
+    spi_write_blocking(SPI, cmd, 2);
+    gpio_put(SPI_FLASH_CS_PIN, 1);
+    return (uint16_t)(manuf << 8 | product);
+}
+
+uint16_t flash_init(spi_inst_t *spi)
+{
+    uint16_t ret;
+    //uint32_t mgc = VAULT_MAGIC - 1;
+    SPI = spi;
+    ret = spi_flash_probe();
+    return ret;
+}
+
+
+
+int flash_sector_erase(uint32_t address)
+{
+    uint8_t cmd;
+    address &= (~(SPI_FLASH_SECTOR_SIZE - 1));
+
+    wait_busy();
+    flash_write_enable();
+    gpio_put(SPI_FLASH_CS_PIN, 0);
+    cmd = SECTOR_ERASE;
+    spi_write_blocking(SPI, &cmd, 1);
+    write_address(address);
+    gpio_put(SPI_FLASH_CS_PIN, 1);
+    wait_busy();
+    return 0;
+}
+
+int flash_read(uint32_t address, void *data, int len)
+{
+    uint8_t *buf = data, cmd;
+    int i = 0;
+    wait_busy();
+    gpio_put(SPI_FLASH_CS_PIN, 0);
+    cmd = BYTE_READ;
+    spi_write_blocking(SPI, &cmd, 1);
+    write_address(address);
+    spi_read_blocking(SPI, 0xFF, buf, len);
+    gpio_put(SPI_FLASH_CS_PIN, 1);
+    return len;
+}
+
+int flash_write(uint32_t address, const void *data, int len)
+{
+    int ret;
+    ret =  spi_flash_write_sb(address, data, len);
+    wait_busy();
+    return ret;
+}
+
+static uint8_t flash_sector_write_cache[SPI_FLASH_SECTOR_SIZE];
+int flash_write_svc(struct vault_service *svc, int idx)
+{
+    const int svc_per_sector = SPI_FLASH_SECTOR_SIZE / SVC_SIZE;
+    uint32_t addr = SVC_FLASH_OFFSET + SVC_SIZE * idx;
+    uint32_t sector = addr / SPI_FLASH_SECTOR_SIZE;
+    uint32_t offset = addr - (sector * SPI_FLASH_SECTOR_SIZE);
+
+    flash_read(sector * SPI_FLASH_SECTOR_SIZE, flash_sector_write_cache,
+            SPI_FLASH_SECTOR_SIZE);
+    memcpy(flash_sector_write_cache + offset, (uint8_t *)svc, SVC_SIZE);
+    flash_sector_erase(sector * SPI_FLASH_SECTOR_SIZE);
+    flash_write(sector * SPI_FLASH_SECTOR_SIZE, flash_sector_write_cache,
+            SPI_FLASH_SECTOR_SIZE); 
+    return 0;
+} 
+

+ 32 - 0
src/flash.h

@@ -0,0 +1,32 @@
+/* Motenpoche 
+ *
+ * (c) 2023 Daniele Lacamera <root@danielinux.net>
+ *
+ *
+ * Motenpoche is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Motenpoche is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
+ *
+ */
+#ifndef FLASH_H
+#define FLASH_H
+#include "hardware/spi.h"
+#include "cryptoengine.h"
+#define SPI_FLASH_SECTOR_SIZE 0x1000
+uint16_t flash_init(spi_inst_t *spi);
+int flash_sector_erase(uint32_t address);
+int flash_read(uint32_t address, void *data, int len);
+int flash_write(uint32_t address, const void *data, int len);
+int flash_write_svc(struct vault_service *svc, int idx);
+uint8_t flash_read_status(void);
+#endif

BIN
src/font_twisted.c


+ 56 - 0
src/fsm.c

@@ -0,0 +1,56 @@
+/* Motenpoche 
+ *
+ * (c) 2023 Daniele Lacamera <root@danielinux.net>
+ *
+ *
+ * Motenpoche is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Motenpoche is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
+ *
+ */
+#include <stdint.h>
+#include "ui.h"
+#include "display.h"
+#include "bsp/board.h"
+#include "fsm.h"
+#include "ui.h"
+
+static enum vault_state vault_state = VAULT_OFF;
+static volatile int ui_event_pending = 0;
+static enum vault_state old_st = 0;
+
+void fsm_event_task(void)
+{
+    /* UI trigger */
+    if (ui_event_pending) {
+        ui_event_pending = 0;
+        ui_event_cb(old_st, fsm_get());
+    }
+}
+
+/* state transactions: actions */
+void fsm_set(enum vault_state st)
+{
+    old_st = vault_state;
+
+    if (st == vault_state)
+        return;
+    /* Change state */
+    vault_state = st;
+    ui_event_cb(old_st, fsm_get());
+}
+
+enum vault_state fsm_get(void)
+{
+    return vault_state;
+}

+ 38 - 0
src/fsm.h

@@ -0,0 +1,38 @@
+/* Motenpoche 
+ *
+ * (c) 2023 Daniele Lacamera <root@danielinux.net>
+ *
+ *
+ * Motenpoche is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Motenpoche is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
+ *
+ */
+#ifndef VAULT_FSM_H
+#define VAULT_FSM_H
+enum vault_state {
+    VAULT_OFF   = 0,
+    VAULT_TOFU,
+    VAULT_BOOTUP,
+    VAULT_VERIFY_PASSPHRASE,
+    VAULT_VERIFY_FAILED,
+    /* From here on: Authenticated */
+    VAULT_MAIN_MENU,
+    VAULT_SETTINGS_MENU,
+    VAULT_SERVICE_LIST
+};
+
+void fsm_set(enum vault_state st);
+enum vault_state fsm_get(void);
+void fsm_event_task(void);
+#endif

+ 240 - 0
src/hid.c

@@ -0,0 +1,240 @@
+/* Motenpoche 
+ *
+ * (c) 2023 Daniele Lacamera <root@danielinux.net>
+ *
+ *
+ * Motenpoche is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Motenpoche is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
+ *
+ */
+#include <stdio.h>
+#include <stdint.h>
+#include "pico/stdlib.h"
+#include "pico/multicore.h"
+#include "hardware/gpio.h"
+#include "hardware/adc.h"
+#include "hardware/i2c.h"
+#include "hardware/spi.h"
+#include "cryptoengine.h"
+
+#include "bsp/board.h"
+
+#include "tusb.h"
+#include "usb_descriptors.h"
+#include "ui.h"
+
+static bool has_keyboard_key = false;
+
+/* USB HID: capslock */
+static int capslock_on = 0;
+
+/* USB HID: tx buffer */
+#define TX_BUFFER_SIZE 256
+static char tx_buffer_str[TX_BUFFER_SIZE];
+static volatile int tx_buffer_wr=0, tx_buffer_rd=0;
+
+/* ASCII to HID conversion */
+static const uint8_t const conv_table[128][2] =  { HID_ASCII_TO_KEYCODE };
+
+// Invoked when device is mounted
+void tud_mount_cb(void)
+{
+}
+
+// Invoked when device is unmounted
+void tud_umount_cb(void)
+{
+}
+
+// Invoked when usb bus is suspended
+// remote_wakeup_en : if host allow us  to perform remote wakeup
+// Within 7ms, device must draw an average of current less than 2.5 mA from bus
+void tud_suspend_cb(bool remote_wakeup_en)
+{
+  (void) remote_wakeup_en;
+}
+
+// Invoked when usb bus is resumed
+void tud_resume_cb(void)
+{
+}
+
+/* USB: tud complete cb */
+void tud_hid_report_complete_cb(uint8_t instance, uint8_t const* report, uint8_t len)
+{
+    (void) instance;
+    (void) len;
+    (void) report;
+    if (has_keyboard_key) {
+        tud_hid_keyboard_report(REPORT_ID_KEYBOARD, 0, NULL);
+        has_keyboard_key = false;
+    } else if (tx_buffer_rd > tx_buffer_wr) {
+        uint8_t  modifier = 0;
+        uint8_t keycode[6] = {0};
+        char c = tx_buffer_str[tx_buffer_wr];
+        if (c == '\t')
+            keycode[0] = HID_KEY_TAB;
+        else {
+            modifier = conv_table[c][0];
+            keycode[0] = conv_table[c][1];
+        }
+        if (capslock_on) {
+            if (((c >= 'a') && (c <= 'z')) || ((c >= 'A') && (c <= 'Z'))) {
+                modifier = !modifier;
+            }
+        }
+        if (modifier)
+            modifier = KEYBOARD_MODIFIER_LEFTSHIFT;
+        tud_hid_keyboard_report(REPORT_ID_KEYBOARD, modifier, keycode);
+        has_keyboard_key = true;
+        tx_buffer_wr++;
+    }
+
+}
+
+/* USB HID: get report */
+uint16_t tud_hid_get_report_cb(uint8_t instance, uint8_t report_id, hid_report_type_t report_type, uint8_t* buffer, uint16_t reqlen)
+{
+  // TODO not Implemented
+  (void) instance;
+  (void) report_id;
+  (void) report_type;
+  (void) buffer;
+  (void) reqlen;
+
+  return 0;
+}
+
+/* Invoked when SET_REPORT control request or 
+ * data on OUT endpoint ( Report ID = 0, Type = 0 ) are received
+ */
+void tud_hid_set_report_cb(uint8_t instance, uint8_t report_id, hid_report_type_t report_type, uint8_t const* buffer, uint16_t bufsize)
+{
+  (void) instance;
+
+  if (report_type == HID_REPORT_TYPE_OUTPUT)
+  {
+    // Set keyboard LED e.g Capslock, Numlock etc...
+    if (report_id == REPORT_ID_KEYBOARD)
+    {
+      // bufsize should be (at least) 1
+      if ( bufsize < 1 ) return;
+
+      uint8_t const kbd_leds = buffer[0];
+
+      if (kbd_leds & KEYBOARD_LED_CAPSLOCK)
+      {
+          capslock_on = 1;
+      }else
+      {
+          capslock_on = 0;
+      }
+    }
+  }
+}
+
+
+//--------------------------------------------------------------------+
+// USB HID
+//--------------------------------------------------------------------+
+
+static void send_hid_report(uint8_t report_id, uint32_t unused)
+{
+    (void)unused;
+
+    if ( !tud_hid_ready() )
+        return;
+
+    switch(report_id)
+    {
+        case REPORT_ID_KEYBOARD:
+            {
+                // use to avoid send multiple consecutive zero report for keyboard
+                uint8_t modifier = 0;
+
+                if (tx_buffer_rd > tx_buffer_wr) {
+                    uint8_t keycode[6] = { 0 };
+                    char c = tx_buffer_str[tx_buffer_wr];
+                    if (c == '\t')
+                        keycode[0] = HID_KEY_TAB;
+                    else {
+                        modifier = conv_table[c][0];
+                        keycode[0] = conv_table[c][1];
+                    }
+                    if (capslock_on) {
+                        if (((c >= 'a') && (c <= 'z')) || ((c >= 'A') && (c <= 'Z'))) {
+                            modifier = !modifier;
+                        }
+                    }
+                    if (modifier)
+                        modifier = KEYBOARD_MODIFIER_LEFTSHIFT;
+                    tud_hid_keyboard_report(REPORT_ID_KEYBOARD, modifier, keycode);
+                    has_keyboard_key = true;
+                    tx_buffer_wr++;
+                } else {
+                    if (has_keyboard_key)
+                        tud_hid_keyboard_report(REPORT_ID_KEYBOARD, 0, NULL);
+                    has_keyboard_key = false;
+                }
+            }
+            break;
+
+
+        default: break;
+    }
+}
+
+void hid_keys_string_send(const char *str)
+{
+    int len = strlen(str);
+    int i;
+    if (tx_buffer_rd == tx_buffer_wr) {
+        tx_buffer_rd = 0;
+        ForceZero(tx_buffer_str, TX_BUFFER_SIZE);
+        tx_buffer_wr = 0;
+    }
+    for(i = 0; i < len; i++) {
+        if (tx_buffer_rd >= TX_BUFFER_SIZE)
+            return;
+        tx_buffer_str[tx_buffer_rd++] = str[i];
+    }
+    gpio_put(17, 0);
+}
+
+// Every 10ms, we will sent 1 report for each HID profile (keyboard, mouse etc ..)
+// tud_hid_report_complete_cb() is used to send the next report after previous one is complete
+void hid_task(void)
+{
+  // Poll every 10ms
+  const uint32_t interval_ms = 10;
+  static uint32_t start_ms = 0;
+  if (!tud_inited())
+      return;
+
+  if ( board_millis() - start_ms < interval_ms) return; // not enough time
+  start_ms += interval_ms;
+
+  // Remote wakeup
+  if ( tud_suspended() && (tx_buffer_rd > tx_buffer_wr))
+  {
+    // Wake up host if we are in suspend mode
+    // and REMOTE_WAKEUP feature is enabled by host
+    tud_remote_wakeup();
+  }else
+  {
+    // Send the 1st of report chain, the rest will be sent by tud_hid_report_complete_cb()
+    send_hid_report(REPORT_ID_KEYBOARD, 0);
+    gpio_put(17, 1);
+  }
+}

+ 26 - 0
src/hid.h

@@ -0,0 +1,26 @@
+/* Motenpoche 
+ *
+ * (c) 2023 Daniele Lacamera <root@danielinux.net>
+ *
+ *
+ * Motenpoche is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Motenpoche is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
+ *
+ */
+#ifndef HID_H_INCLUDED
+#define HID_H_INCLUDED
+void hid_task(void);
+void hid_keys_string_send(const char *str);
+
+#endif

+ 265 - 0
src/msc_disk.c

@@ -0,0 +1,265 @@
+/* 
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 Ha Thach (tinyusb.org)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ */
+
+#include "bsp/board.h"
+#include "tusb.h"
+
+#if CFG_TUD_MSC
+
+// whether host does safe-eject
+static bool ejected = false;
+
+// Some MCU doesn't have enough 8KB SRAM to store the whole disk
+// We will use Flash as read-only disk with board that has
+// CFG_EXAMPLE_MSC_READONLY defined
+
+#define README_CONTENTS \
+"This is the password vault utilities directory.\r\n\r\nWork in progress\r\n"
+
+enum
+{
+  DISK_BLOCK_NUM  = 16, // 8KB is the smallest size that windows allow to mount
+  DISK_BLOCK_SIZE = 512
+};
+
+#ifdef CFG_EXAMPLE_MSC_READONLY
+const
+#endif
+uint8_t msc_disk[DISK_BLOCK_NUM][DISK_BLOCK_SIZE] =
+{
+  //------------- Block0: Boot Sector -------------//
+  // byte_per_sector    = DISK_BLOCK_SIZE; fat12_sector_num_16  = DISK_BLOCK_NUM;
+  // sector_per_cluster = 1; reserved_sectors = 1;
+  // fat_num            = 1; fat12_root_entry_num = 16;
+  // sector_per_fat     = 1; sector_per_track = 1; head_num = 1; hidden_sectors = 0;
+  // drive_number       = 0x80; media_type = 0xf8; extended_boot_signature = 0x29;
+  // filesystem_type    = "FAT12   "; volume_serial_number = 0x1234; volume_label = "TinyUSB MSC";
+  // FAT magic code at offset 510-511
+  {
+      0xEB, 0x3C, 0x90, 0x4D, 0x53, 0x44, 0x4F, 0x53, 0x35, 0x2E, 0x30, 0x00, 0x02, 0x01, 0x01, 0x00,
+      0x01, 0x10, 0x00, 0x10, 0x00, 0xF8, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x29, 0x34, 0x12, 0x00, 0x00, 'V' , 'a' , 'u' , 'l' , 't' ,
+      ' ' , 'T' , 'o' , 'o' , 'l' , 's' , 0x46, 0x41, 0x54, 0x31, 0x32, 0x20, 0x20, 0x20, 0x00, 0x00,
+
+      // Zero up to 2 last bytes of FAT magic code
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0xAA
+  },
+
+  //------------- Block1: FAT12 Table -------------//
+  {
+      0xF8, 0xFF, 0xFF, 0xFF, 0x0F // // first 2 entries must be F8FF, third entry is cluster end of readme file
+  },
+
+  //------------- Block2: Root Directory -------------//
+  {
+      // first entry is volume label
+      'V' , 'a' , 'u' , 'l' , 't' , ' ' , 'T' , 'o' , 'o' , 'l' , 's' , 0x08, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4F, 0x6D, 0x65, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      // second entry is readme file
+      'R' , 'E' , 'A' , 'D' , 'M' , 'E' , ' ' , ' ' , 'T' , 'X' , 'T' , 0x20, 0x00, 0xC6, 0x52, 0x6D,
+      0x65, 0x43, 0x65, 0x43, 0x00, 0x00, 0x88, 0x6D, 0x65, 0x43, 0x02, 0x00,
+      sizeof(README_CONTENTS)-1, 0x00, 0x00, 0x00 // readme's files size (4 Bytes)
+  },
+
+  //------------- Block3: Readme Content -------------//
+  README_CONTENTS
+};
+
+// Invoked when received SCSI_CMD_INQUIRY
+// Application fill vendor id, product id and revision with string up to 8, 16, 4 characters respectively
+void tud_msc_inquiry_cb(uint8_t lun, uint8_t vendor_id[8], uint8_t product_id[16], uint8_t product_rev[4])
+{
+  (void) lun;
+
+  const char vid[] = "DLX";
+  const char pid[] = "Vault tools";
+  const char rev[] = "0.1a";
+
+  memcpy(vendor_id  , vid, strlen(vid));
+  memcpy(product_id , pid, strlen(pid));
+  memcpy(product_rev, rev, strlen(rev));
+}
+
+// Invoked when received Test Unit Ready command.
+// return true allowing host to read/write this LUN e.g SD card inserted
+bool tud_msc_test_unit_ready_cb(uint8_t lun)
+{
+  (void) lun;
+
+  // RAM disk is ready until ejected
+  if (ejected) {
+    tud_msc_set_sense(lun, SCSI_SENSE_NOT_READY, 0x3a, 0x00);
+    return false;
+  }
+
+  return true;
+}
+
+// Invoked when received SCSI_CMD_READ_CAPACITY_10 and SCSI_CMD_READ_FORMAT_CAPACITY to determine the disk size
+// Application update block count and block size
+void tud_msc_capacity_cb(uint8_t lun, uint32_t* block_count, uint16_t* block_size)
+{
+  (void) lun;
+
+  *block_count = DISK_BLOCK_NUM;
+  *block_size  = DISK_BLOCK_SIZE;
+}
+
+// Invoked when received Start Stop Unit command
+// - Start = 0 : stopped power mode, if load_eject = 1 : unload disk storage
+// - Start = 1 : active mode, if load_eject = 1 : load disk storage
+bool tud_msc_start_stop_cb(uint8_t lun, uint8_t power_condition, bool start, bool load_eject)
+{
+  (void) lun;
+  (void) power_condition;
+
+  if ( load_eject )
+  {
+    if (start)
+    {
+      // load disk storage
+    }else
+    {
+      // unload disk storage
+      ejected = true;
+    }
+  }
+
+  return true;
+}
+
+// Callback invoked when received READ10 command.
+// Copy disk's data to buffer (up to bufsize) and return number of copied bytes.
+int32_t tud_msc_read10_cb(uint8_t lun, uint32_t lba, uint32_t offset, void* buffer, uint32_t bufsize)
+{
+  (void) lun;
+
+  // out of ramdisk
+  if ( lba >= DISK_BLOCK_NUM ) return -1;
+
+  uint8_t const* addr = msc_disk[lba] + offset;
+  memcpy(buffer, addr, bufsize);
+
+  return bufsize;
+}
+
+bool tud_msc_is_writable_cb (uint8_t lun)
+{
+  (void) lun;
+
+  /* Read only. */
+  return false;
+}
+
+// Callback invoked when received WRITE10 command.
+// Process data in buffer to disk's storage and return number of written bytes
+int32_t tud_msc_write10_cb(uint8_t lun, uint32_t lba, uint32_t offset, uint8_t* buffer, uint32_t bufsize)
+{
+  (void) lun;
+  // out of ramdisk
+  if ( lba >= DISK_BLOCK_NUM )
+      return -1;
+  /* Read only. Silently fail. */
+  (void) lba; (void) offset; (void) buffer;
+  return bufsize;
+}
+
+// Callback invoked when received an SCSI command not in built-in list below
+// - READ_CAPACITY10, READ_FORMAT_CAPACITY, INQUIRY, MODE_SENSE6, REQUEST_SENSE
+// - READ10 and WRITE10 has their own callbacks
+int32_t tud_msc_scsi_cb (uint8_t lun, uint8_t const scsi_cmd[16], void* buffer, uint16_t bufsize)
+{
+  // read10 & write10 has their own callback and MUST not be handled here
+
+  void const* response = NULL;
+  int32_t resplen = 0;
+
+  // most scsi handled is input
+  bool in_xfer = true;
+
+  switch (scsi_cmd[0])
+  {
+    case SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL:
+      // Host is about to read/write etc ... better not to disconnect disk
+      resplen = 0;
+    break;
+
+    default:
+      // Set Sense = Invalid Command Operation
+      tud_msc_set_sense(lun, SCSI_SENSE_ILLEGAL_REQUEST, 0x20, 0x00);
+
+      // negative means error -> tinyusb could stall and/or response with failed status
+      resplen = -1;
+    break;
+  }
+
+  // return resplen must not larger than bufsize
+  if ( resplen > bufsize ) resplen = bufsize;
+
+  if ( response && (resplen > 0) )
+  {
+    if(in_xfer)
+    {
+      memcpy(buffer, response, resplen);
+    }else
+    {
+      // SCSI output
+    }
+  }
+
+  return resplen;
+}
+
+#endif

+ 341 - 0
src/password_safe.c

@@ -0,0 +1,341 @@
+/* Motenpoche 
+ *
+ * (c) 2023 Daniele Lacamera <root@danielinux.net>
+ *
+ *
+ * Motenpoche is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Motenpoche is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
+ *
+ */
+#include <stdio.h>
+#include <stdint.h>
+#include "pico/stdlib.h"
+#include "pico/multicore.h"
+#include "hardware/gpio.h"
+#include "hardware/adc.h"
+#include "hardware/i2c.h"
+#include "hardware/spi.h"
+#include "cryptoengine.h"
+
+#include "bsp/board.h"
+
+#include "tusb.h"
+#include "usb_descriptors.h"
+#include "ui.h"
+
+#include "user_settings.h"
+#include "wolfssl/wolfcrypt/settings.h"
+#include "class/cdc/cdc.h"
+#include "class/cdc/cdc_device.h"
+#include "class/msc/msc.h"
+#include "hardware/gpio.h"
+#include "flash.h"
+#include "display.h"
+#include "hid.h"
+    
+
+void core1_main(void);
+static volatile int main_plug = 1;
+int thread_control_ui = 0;
+
+
+/* DOUT */
+
+#define RED_LED 17
+#define GREEN_LED 16
+#define PICO_LED    PICO_DEFAULT_LED_PIN
+
+static uint Led[] = {
+    RED_LED,
+    GREEN_LED,
+    PICO_LED
+};
+
+
+/* DIN */
+#define ROT_S0       19
+#define ROT_S1       20
+#define ROT_KEY      18
+#define OK_BUTTON    21
+#define BACK_BUTTON  22
+
+/* I2C */
+#define I2C         (&i2c1_inst)
+#define I2C_BAUDRATE 48000
+#define I2C_SCL_PIN 27
+#define I2C_SDA_PIN 26
+
+/* SPI */
+#define SPI              (spi0)
+#define SPI_BAUDRATE     100000
+#define SPI_SCLK_PIN     2
+#define SPI_MOSI_PIN     3
+#define SPI_MISO_PIN     4
+#define SPI_FLASH_CS_PIN 5
+
+
+
+uint16_t flash_info = 0xFFFF;
+
+#define AIRCR *(volatile uint32_t *)(0xE000ED0C)
+#define AIRCR_VKEY (0x05FA << 16)
+#define AIRCR_SYSRESETREQ (1 << 2)
+static void sys_reboot(void)
+{
+    AIRCR = AIRCR_SYSRESETREQ | AIRCR_VKEY;
+    while(1)
+        ;
+}
+
+void system_reboot(void)
+{
+    int i;
+    main_plug = 0;
+    thread_control_ui = 2;
+    for (i = display_getcontrast(); i >= 0; i--) {
+        display_setcontrast(i);
+        sleep_ms(5);
+    }
+    display_clear();
+}
+
+void system_boot(void)
+{
+    int i, ret;
+    set_sys_clock_48mhz();
+    multicore_reset_core1();
+    //stdio_init_all();
+
+    printf("Initializing USB...\r\n");
+    tusb_init();
+    printf("Done.\r\n");
+
+    /* LED and Douts */
+    printf("Setting LEDs\r\n");
+    for (i = 0; i < 3; i++) {
+        gpio_init(Led[i]);
+        gpio_set_dir(Led[i], GPIO_OUT);
+        gpio_put(Led[i], 0);
+    }
+    gpio_put(RED_LED, 1);
+    gpio_put(GREEN_LED, 1);
+    printf("Done.\n");
+
+    /* BTN Dins */
+    printf("Setting buttons and digital inputs...\r\n");
+    gpio_init(ROT_S0);
+    gpio_init(ROT_S1);
+    gpio_init(ROT_KEY);
+    gpio_init(OK_BUTTON);
+    gpio_init(BACK_BUTTON);
+    gpio_set_dir(ROT_S0, GPIO_IN);
+    gpio_set_dir(ROT_S1, GPIO_IN);
+    gpio_set_dir(ROT_KEY, GPIO_IN);
+    gpio_set_dir(OK_BUTTON, GPIO_IN);
+    gpio_set_dir(BACK_BUTTON, GPIO_IN);
+    gpio_pull_down(ROT_S0); 
+    gpio_pull_down(ROT_S1); 
+    gpio_pull_up(ROT_KEY); 
+    gpio_pull_down(OK_BUTTON);
+    gpio_pull_down(BACK_BUTTON);
+    printf("Done.\n");
+
+
+
+    printf("Initializing SPI Flash\r\n");
+    gpio_init(SPI_SCLK_PIN);
+    gpio_init(SPI_MOSI_PIN);
+    gpio_init(SPI_MISO_PIN);
+    gpio_init(SPI_FLASH_CS_PIN);
+    gpio_set_function(SPI_SCLK_PIN, GPIO_FUNC_SPI);
+    gpio_set_function(SPI_MOSI_PIN, GPIO_FUNC_SPI);
+    gpio_set_function(SPI_MISO_PIN, GPIO_FUNC_SPI);
+    gpio_set_dir(SPI_FLASH_CS_PIN, GPIO_OUT);
+    gpio_put(SPI_FLASH_CS_PIN, 1);
+    spi_init(SPI, SPI_BAUDRATE);
+    flash_info = flash_init(SPI);
+    
+    printf("Initializing I2C Display\r\n");
+    gpio_init(I2C_SDA_PIN);
+    gpio_init(I2C_SCL_PIN);
+    gpio_set_function(I2C_SDA_PIN, GPIO_FUNC_I2C);
+    gpio_set_function(I2C_SCL_PIN, GPIO_FUNC_I2C);
+    i2c_init(I2C, I2C_BAUDRATE);
+    ui_init(I2C);
+    printf("Done\r\n");
+    
+    printf("Starting CPU Core 1\r\n");
+    multicore_launch_core1(core1_main);
+    printf("Done\r\n");
+
+    gpio_put(RED_LED, 0);
+    printf("Init complete.\r\n");
+}
+
+#define ROT_UP 1
+#define ROT_DOWN 2
+
+uint32_t rotary_action(void)
+{
+    uint32_t action = 0;
+    if (gpio_get(ROT_S0))
+        action |= 1;
+    if (gpio_get(ROT_S1))
+        action |= 2;
+    return action;
+}
+
+int rot_updown(void)
+{
+    static int rot_up = 0;
+    static int rot_down = 0;
+    static uint32_t rotary_pos = 0;
+    uint32_t rotary_now;
+    rotary_now = rotary_action();
+    if (rotary_now != rotary_pos) {
+        if ((rotary_pos == 0 && rotary_now == 3) ||
+                (rotary_pos == 3 && rotary_now == 2) ||
+                (rotary_pos == 2 && rotary_now == 0) ||
+                (rotary_pos == 1 && rotary_now == 3)) {
+            rot_down++;
+            rot_up = 0;
+        }
+        if ((rotary_pos == 0 && rotary_now == 1) ||
+                (rotary_pos == 3 && rotary_now == 1) ||
+                (rotary_pos == 2 && rotary_now == 3) ||
+                (rotary_pos == 1 && rotary_now == 0)) {
+            rot_up++;
+            rot_down = 0;
+        }
+        rotary_pos = rotary_now;
+    }
+    if (rot_up > 1) {
+        rot_up = 0;
+        return ROT_UP;
+    }
+    if (rot_down > 1) {
+        rot_down = 0;
+        return ROT_DOWN;
+    }
+    return 0;
+}
+
+static uint32_t key_press_counter = 0;
+static uint32_t ok_press_counter = 0;
+static uint32_t back_press_counter = 0;
+
+void clear_input(void)
+{
+    key_press_counter = 0;
+    ok_press_counter = 0;
+    back_press_counter = 0;
+}
+
+void poll_buttons(void)
+{
+    int rot_ud = 0;
+
+    if (gpio_get(ROT_KEY) == 0) {
+        key_press_counter++;
+    } else {
+        key_press_counter = 0;
+    }
+
+    if (gpio_get(OK_BUTTON) != 0) {
+        ok_press_counter++;
+    } else {
+        ok_press_counter = 0;
+    }
+    if (gpio_get(BACK_BUTTON) != 0) {
+        back_press_counter++;
+    } else {
+        back_press_counter = 0;
+    }
+    
+    if (ok_press_counter == 100) {
+        printf("OK: pressed\n");
+        ui_confirm_button();
+        return;
+    }
+    
+    if (key_press_counter == 100) {
+        printf("key: pressed\n");
+        ui_key_button();
+        return;
+    }
+    
+    if (back_press_counter == 100) {
+        printf("back: pressed\n");
+        ui_back_button();
+        return;
+    }
+    if ((fsm_get() == VAULT_BOOTUP) && (back_press_counter == 100000)) {
+        uint32_t i;
+        for (i = 0; i < VAULT_FLASH_SIZE; i+=SPI_FLASH_SECTOR_SIZE)
+            flash_sector_erase(i);
+
+        system_reboot();
+        return;
+    }
+
+    rot_ud = rot_updown();
+
+    if (rot_ud == ROT_UP) {
+        ui_rot_up();
+        sleep_ms(1);
+        return;
+    }
+    if (rot_ud == ROT_DOWN) {
+        ui_rot_down();
+        sleep_ms(1);
+        return;
+    }
+}
+
+uint8_t *fbuf = NULL;
+
+
+static uint8_t flash_buf[4];
+int main(void) {
+    int i;
+    system_boot();
+    printf("Loop started.\n");
+
+
+    while (main_plug) {
+        uint32_t ms_tick = board_millis();
+        if ((ms_tick % 10) == 0) {
+            if (thread_control_ui == 0) {
+                poll_buttons();
+            }
+        }
+        if (thread_control_ui == 0) {
+            if ((ms_tick % 100) == 0) {
+                ui_task();
+            }
+        }
+    }
+    
+    /* End of session. Goodbye. */
+    multicore_reset_core1();
+    sys_reboot();
+}
+
+void core1_main(void)
+{
+    while(1) {
+        hid_task();
+        tud_task();
+    }
+}

+ 114 - 0
src/tusb_config.h

@@ -0,0 +1,114 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 Ha Thach (tinyusb.org)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ */
+
+#ifndef _TUSB_CONFIG_H_
+#define _TUSB_CONFIG_H_
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+//--------------------------------------------------------------------
+// COMMON CONFIGURATION
+//--------------------------------------------------------------------
+
+// defined by board.mk
+#ifndef CFG_TUSB_MCU
+  #error CFG_TUSB_MCU must be defined
+#endif
+
+// RHPort number used for device can be defined by board.mk, default to port 0
+#ifndef BOARD_DEVICE_RHPORT_NUM
+  #define BOARD_DEVICE_RHPORT_NUM     0
+#endif
+
+// RHPort max operational speed can defined by board.mk
+// Default to Highspeed for MCU with internal HighSpeed PHY (can be port specific), otherwise FullSpeed
+#ifndef BOARD_DEVICE_RHPORT_SPEED
+  #if (CFG_TUSB_MCU == OPT_MCU_LPC18XX || CFG_TUSB_MCU == OPT_MCU_LPC43XX || CFG_TUSB_MCU == OPT_MCU_MIMXRT10XX || \
+       CFG_TUSB_MCU == OPT_MCU_NUC505  || CFG_TUSB_MCU == OPT_MCU_CXD56 || CFG_TUSB_MCU == OPT_MCU_SAMX7X)
+    #define BOARD_DEVICE_RHPORT_SPEED   OPT_MODE_HIGH_SPEED
+  #else
+    #define BOARD_DEVICE_RHPORT_SPEED   OPT_MODE_FULL_SPEED
+  #endif
+#endif
+
+// Device mode with rhport and speed defined by board.mk
+#if   BOARD_DEVICE_RHPORT_NUM == 0
+  #define CFG_TUSB_RHPORT0_MODE     (OPT_MODE_DEVICE | BOARD_DEVICE_RHPORT_SPEED)
+#elif BOARD_DEVICE_RHPORT_NUM == 1
+  #define CFG_TUSB_RHPORT1_MODE     (OPT_MODE_DEVICE | BOARD_DEVICE_RHPORT_SPEED)
+#else
+  #error "Incorrect RHPort configuration"
+#endif
+
+#ifndef CFG_TUSB_OS
+#define CFG_TUSB_OS               OPT_OS_NONE
+#endif
+
+// CFG_TUSB_DEBUG is defined by compiler in DEBUG build
+// #define CFG_TUSB_DEBUG           0
+
+/* USB DMA on some MCUs can only access a specific SRAM region with restriction on alignment.
+ * Tinyusb use follows macros to declare transferring memory so that they can be put
+ * into those specific section.
+ * e.g
+ * - CFG_TUSB_MEM SECTION : __attribute__ (( section(".usb_ram") ))
+ * - CFG_TUSB_MEM_ALIGN   : __attribute__ ((aligned(4)))
+ */
+#ifndef CFG_TUSB_MEM_SECTION
+#define CFG_TUSB_MEM_SECTION
+#endif
+
+#ifndef CFG_TUSB_MEM_ALIGN
+#define CFG_TUSB_MEM_ALIGN          __attribute__ ((aligned(4)))
+#endif
+
+//--------------------------------------------------------------------
+// DEVICE CONFIGURATION
+//--------------------------------------------------------------------
+
+#ifndef CFG_TUD_ENDPOINT0_SIZE
+#define CFG_TUD_ENDPOINT0_SIZE    64
+#endif
+
+//------------- CLASS -------------//
+#define CFG_TUD_HID               1
+#define CFG_TUD_CDC               1
+#define CFG_TUD_MSC               1
+#define CFG_TUD_MIDI              0
+#define CFG_TUD_VENDOR            0
+
+// HID buffer size Should be sufficient to hold ID (if any) + Data
+#define CFG_TUD_HID_EP_BUFSIZE    16
+#define CFG_TUD_MSC_EP_BUFSIZE    64
+#define CFG_TUD_CDC_RX_BUFSIZE    64
+#define CFG_TUD_CDC_TX_BUFSIZE    64
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif /* _TUSB_CONFIG_H_ */

+ 583 - 0
src/ui.c

@@ -0,0 +1,583 @@
+/* Motenpoche 
+ *
+ * (c) 2023 Daniele Lacamera <root@danielinux.net>
+ *
+ *
+ * Motenpoche is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Motenpoche is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
+ *
+ */
+#include <stdint.h>
+#include "ui.h"
+#include "display.h"
+#include "bsp/board.h"
+#include "hardware/gpio.h"
+#include "cryptoengine.h"
+#include "wolfssl/wolfcrypt/settings.h"
+#include "wolfssl/wolfcrypt/misc.h"
+#include "fsm.h"
+#include "display.h"
+#include "flash.h"
+#include "hid.h"
+
+
+#define PASSPHRASE_MAX 128
+
+#ifndef GREEN_LED
+#define GREEN_LED 16
+#endif
+
+
+static const char welcome_message0[]= "  There is no  ";
+static const char welcome_message1[]= "knowledge that ";
+static const char welcome_message2[]= " is not power. ";
+
+extern void system_reboot(void);
+static uint16_t service_list_selected = 0;
+static uint16_t service_list_count = 0;
+static void ui_service_list(uint32_t count);
+
+
+
+/* UI current state globals */
+static int current_row = 1;
+static int current_char_pos = 0;
+static char current_char = ' ';
+static char passphrase[PASSPHRASE_MAX];
+static int blinking = 0;
+
+void ui_event_cb(enum vault_state old_st, enum vault_state st)
+{
+    int result = 0;
+    int ret = -1;
+    current_char = ' ';
+    (void)old_st;
+    switch (st) {
+        case VAULT_BOOTUP:
+            display_clear();
+            display_text(0, "Type Passphrase");
+            ForceZero(passphrase, PASSPHRASE_MAX);
+            current_char_pos = 0;
+            break;
+        case VAULT_VERIFY_PASSPHRASE:
+            char msg[17];
+            display_text(0, "Authenticating..");
+            display_text(1, "                ");
+            display_text(2, "                ");
+            display_text(3,"                 ");
+            ret = cryptoengine_verify_passphrase(passphrase, &result);
+            if ((ret != 0) || (result != 1)) {
+                fsm_set(VAULT_VERIFY_FAILED);
+                return;
+            }
+            gpio_put(GREEN_LED, 0);
+            fsm_set(VAULT_MAIN_MENU);
+            return;
+            break;
+        case VAULT_MAIN_MENU:
+            display_text(0,"                 ");
+            display_text(1,"                 ");
+            display_text(2,"                 ");
+            display_text(3,"                 ");
+            display_text_inverse(0, 2, "[Main Menu]");
+            break;
+        case VAULT_SETTINGS_MENU:
+            display_text(0,"                 ");
+            display_text(1,"                 ");
+            display_text(2,"                 ");
+            display_text(3,"                 ");
+            display_text_inverse(0, 3, "[Settings]");
+            break;
+        case VAULT_SERVICE_LIST:
+            uint16_t count, spot;
+            cryptoengine_service_count(&count, &spot);
+            service_list_count = count;
+            display_text(0,"                 ");
+            display_text(1,"                 ");
+            display_text(2,"                 ");
+            display_text(3,"                 ");
+            display_text_inverse(0, 3, "[Services]");
+            break;
+    }
+    ui_task();
+}
+
+
+static const char main_menu_entry[3][17] = {
+    "[~  Services  ~]",
+    "[~  Settings  ~]",
+    "[~  Reboot    ~]"
+};
+
+
+#define MAINMENU_ENTRIES 3
+
+static const char settings_menu_entry[3][17] = {
+    "[~ Keyb map   ~]",
+    "[~ Paste mode ~]",
+    "[~ Forget All ~]"
+};
+#define SETTINGSMENU_ENTRIES 3
+
+static int menu_sel = 0;
+static int old_menu_sel = 0xFF;
+
+static const char Keymaps[][17] = {
+    "      [US]",
+    "      [FR]",
+    "      [DE]",
+    "      [UK]",
+    "      [IT]"
+};
+
+static int cur_keymap = 0;
+
+#define KEYMAPS_ENTRIES 5
+
+
+#define PASTEMODE_PASS_ONLY 0
+#define PASTEMODE_PASS_ENTER 1
+#define PASTEMODE_USER_TAB_PASS_ENTER 2
+#define PASTEMODE_USER_ENTER_PASS_ENTER 3
+
+static const char PasteModes[][17] = {
+    "[Password only ]",
+    "[Password+Enter]",
+    "[UserTabPswdEnt]",
+    "[UserEntPswdEnt]"
+};
+
+static int cur_pastemode = 0;
+
+#define PASTEMODE_ENTRIES 4
+
+static const char Are_you_sure[][17] = {
+    "Sure? NO    ",
+    "Sure? Cancel",
+    "Sure? My mistake",
+    "Sure? Whut?",
+    "Sure? YES DO IT!"
+};
+
+static int cur_wipe_choice = 0;
+#define AREYOUSURE_ENTRIES 5
+
+
+
+static void mainmenu_action(void)
+{
+    switch (menu_sel) {
+        case 0: /* Services */
+            fsm_set(VAULT_SERVICE_LIST);
+            break;
+        case 1: /* Settings */
+            fsm_set(VAULT_SETTINGS_MENU);
+            break;
+        case 2: /* Reboot */
+            system_reboot();
+            break;
+    }
+}
+
+static void settingsmenu_action(void)
+{
+    switch (menu_sel) {
+        case 0: /* Keymap */
+            cur_keymap++;
+            if (cur_keymap == KEYMAPS_ENTRIES)
+                cur_keymap = 0;
+            break;
+        case 1: /* Paste mode */
+            cur_pastemode++;
+            if (cur_pastemode == PASTEMODE_ENTRIES)
+                cur_pastemode = 0;
+            break;
+        case 2: /* Forget */
+            cur_wipe_choice++;
+            if (cur_wipe_choice == AREYOUSURE_ENTRIES)
+                cur_wipe_choice = 0;
+            break;
+    }
+    /* Force redraw */
+    old_menu_sel = 0xFF;
+}
+
+static void settingsmenu_confirm(void)
+{
+    int i;
+    if ((menu_sel == 2) && (cur_wipe_choice == 4)) {
+        for (i = 0; i < VAULT_FLASH_SIZE; i+= SPI_FLASH_SECTOR_SIZE)
+            flash_sector_erase(i);
+        system_reboot();
+    } else
+        settingsmenu_action();
+}
+
+
+static void ui_service_list(uint32_t count)
+{
+    static int old_selected = -1;
+    int i = 0;
+    uint32_t address = SVC_FLASH_OFFSET;
+    uint32_t a_sel, a_prev = 0, a_next = 0;
+    struct vault_service svc;
+
+    if (old_selected == (int)service_list_selected)
+        return;
+    old_selected = service_list_selected;
+
+    if (count == 0)
+        return;
+
+
+    flash_read(address + service_list_selected * SVC_SIZE,
+            (void *)&svc, SVC_SIZE);
+    if (svc.flags != SVC_FLAG_ACTIVE) {
+        i =  0;
+        while (address < VAULT_FLASH_SIZE) {
+            flash_read(address + i * SVC_SIZE, &svc, SVC_SIZE);
+            if (svc.flags == SVC_FLAG_ACTIVE) {
+                service_list_selected = i;
+                break;
+            }
+            i += SVC_SIZE;
+        }
+    }
+    a_sel = SVC_FLASH_OFFSET + service_list_selected * SVC_SIZE;
+    a_next = 0;
+    a_prev = 0;
+
+    /* Find previous entry */
+    if (service_list_selected != 0) {
+        i = 1;
+        address = SVC_FLASH_OFFSET + SVC_SIZE * (service_list_selected - i);
+        while (address >= SVC_FLASH_OFFSET) {
+            flash_read(address, (void *)&svc, SVC_SIZE);
+            if (svc.flags == SVC_FLAG_ACTIVE) {
+                a_prev = address;
+                break;
+            }
+            i++;
+            address = SVC_FLASH_OFFSET + SVC_SIZE * (service_list_selected - i);
+        }
+    }
+    /* Find next entry */
+    i = 1;
+    address = SVC_FLASH_OFFSET + SVC_SIZE * (service_list_selected + i);
+    while (address < VAULT_FLASH_SIZE) {
+        flash_read(address, (void *)&svc, SVC_SIZE);
+        if (svc.flags == SVC_FLAG_ACTIVE) {
+            a_next = address;
+            break;
+        } else if (svc.flags == SVC_FLAG_UNUSED) {
+            break;
+        }
+        i++;
+        address = SVC_FLASH_OFFSET + SVC_SIZE * (service_list_selected + i);
+    }
+
+    display_text(1,"                 ");
+    display_text(2,"                 ");
+    display_text(3,"                 ");
+
+    if (a_prev != 0) {
+        flash_decrypt_read_svc(&svc, a_prev);
+        display_text(1, svc.name);
+    }
+    if (a_next != 0) {
+        flash_decrypt_read_svc(&svc, a_next);
+        display_text(3, svc.name);
+    }
+    flash_decrypt_read_svc(&svc, a_sel);
+    display_text_inverse(2, 0, svc.name);
+}
+
+
+static void paste_password(void)
+{
+    struct vault_service svc;
+    uint32_t address;
+    if (fsm_get() != VAULT_SERVICE_LIST)
+        return;
+    if (flash_decrypt_read_svc(&svc, SVC_FLASH_OFFSET +
+                service_list_selected * SVC_SIZE) < 0)
+        return;
+
+    switch(cur_pastemode) {
+        case PASTEMODE_PASS_ONLY:
+            hid_keys_string_send(svc.pass);
+            break;
+        case PASTEMODE_PASS_ENTER:
+            hid_keys_string_send(svc.pass);
+            hid_keys_string_send("\r");
+            break;
+        case PASTEMODE_USER_TAB_PASS_ENTER:
+            hid_keys_string_send(svc.user);
+            hid_keys_string_send("\t");
+            hid_keys_string_send(svc.pass);
+            hid_keys_string_send("\r");
+            break;
+        case PASTEMODE_USER_ENTER_PASS_ENTER:
+            hid_keys_string_send(svc.user);
+            hid_keys_string_send("\t");
+            hid_keys_string_send(svc.pass);
+            hid_keys_string_send("\r");
+            break;
+    }
+}
+
+void ui_task(void)
+{
+    const uint32_t interval_ms = 500;
+    static uint32_t start_ms = 0;
+
+    if ( board_millis() - start_ms >= interval_ms) {
+        blinking ^= 1;
+        start_ms = board_millis();
+    }
+
+    switch(fsm_get()) {
+        case VAULT_TOFU:
+            gpio_put(17, blinking ^ 1);
+            display_text(0, "    Welcome!");
+            display_text(1, "Run tools on PC ");
+            display_text(2, " to initialize  ");
+            break;
+        case VAULT_BOOTUP:
+            char pass_prompt[16];
+            int i;
+            int sz;
+            gpio_put(17, blinking ^ 1);
+            sz = current_char_pos;
+            if (sz > 15)
+                sz = 15;
+            memset(pass_prompt, 0, 16);
+            for (i = 0; i < sz; i++) {
+               pass_prompt[i] = '*';
+            }
+            if (!blinking)
+                pass_prompt[sz] = current_char; 
+            display_text(1, pass_prompt);
+            if (blinking) {
+                char cursor[2] = {current_char, 0};
+                display_text_inverse(1, sz, cursor);
+            }
+            break;
+        case VAULT_VERIFY_PASSPHRASE:
+            display_text(2, "Verifying...");
+            gpio_put(17, blinking ^ 1);
+            break;
+        case VAULT_VERIFY_FAILED:
+            display_text(0, " Bad Passphrase ");
+            gpio_put(17, 0);
+            if (blinking) {
+                display_text(1,"    ");
+                display_text(2,"   ");
+                display_text_inverse(1, 4, "(x_x)");
+                display_text_inverse(2, 3, "Try again");
+            } else {
+                display_text(1, "    (x_x)   ");
+                display_text(2, "            ");
+            }
+            break;
+        case VAULT_MAIN_MENU:
+            display_text(2,main_menu_entry[menu_sel]);
+            break;
+        case VAULT_SETTINGS_MENU:
+
+            if (old_menu_sel != menu_sel) {
+                old_menu_sel = menu_sel;
+
+                display_text(1, "                ");
+                display_text(2, "                ");
+                display_text(3, "                ");
+                display_text(2,settings_menu_entry[menu_sel]);
+                switch(menu_sel) {
+                    case 0: /* Keymap */
+                        display_text(3, Keymaps[cur_keymap]);
+                        break;
+                    case 1:
+                        display_text(3, PasteModes[cur_pastemode]);
+                        break;
+                    case 2:
+                        display_text(3, Are_you_sure[cur_wipe_choice]);
+                        break;
+                }
+            }
+            break;
+        case VAULT_SERVICE_LIST:
+            if (service_list_count == 0) {
+                display_text(2, "  No Services  "); 
+                break;
+            } else {
+                ui_service_list(service_list_count);
+            }
+            break;
+    }
+}
+
+void ui_key_button(void)
+{
+    static int alter = 0;
+    enum vault_state vs = fsm_get();
+    if (vs == VAULT_BOOTUP) {
+        passphrase[current_char_pos] = current_char;
+        current_char_pos++;
+        if(current_char_pos >= PASSPHRASE_MAX) {
+            fsm_set(VAULT_VERIFY_FAILED);
+            return;
+        }
+        passphrase[current_char_pos] = 0;
+        gpio_put(17, alter);
+        alter ^=1;
+    } else if (vs == VAULT_MAIN_MENU)
+        mainmenu_action();
+    else if (vs == VAULT_SETTINGS_MENU)
+        settingsmenu_action();
+    else if (vs == VAULT_SERVICE_LIST)
+        paste_password();
+}
+
+void ui_back_button(void)
+{
+    enum vault_state vault_state = fsm_get();
+    if (vault_state == VAULT_BOOTUP) {
+        if (current_char_pos > 0) {
+            passphrase[current_char_pos] = '\0';
+            current_char_pos--;
+        }
+        display_text(1, "               ");
+    }
+    else if (vault_state == VAULT_VERIFY_FAILED) {
+        current_char_pos = 0;
+        fsm_set(VAULT_BOOTUP);
+    }
+    else if (vault_state == VAULT_SETTINGS_MENU)
+        fsm_set(VAULT_MAIN_MENU);
+    else if (vault_state == VAULT_SERVICE_LIST)
+        fsm_set(VAULT_MAIN_MENU);
+}
+
+void ui_confirm_button(void)
+{
+    enum vault_state vault_state = fsm_get();
+    if (vault_state == VAULT_BOOTUP) {
+        current_char_pos = 0;
+        fsm_set(VAULT_VERIFY_PASSPHRASE);
+    }
+    else if (vault_state == VAULT_MAIN_MENU)
+        mainmenu_action();
+    else if (vault_state == VAULT_SETTINGS_MENU)
+        settingsmenu_confirm();
+    else if (vault_state == VAULT_SERVICE_LIST)
+        paste_password();
+}
+
+void ui_rot_up(void)
+{
+    enum vault_state vault_state = fsm_get();
+    if (vault_state == VAULT_BOOTUP) {
+        current_char++;
+        if (current_char > 126)
+            current_char = ' ';
+    }
+    else if (vault_state == VAULT_MAIN_MENU) {
+        menu_sel++;
+        if (menu_sel == MAINMENU_ENTRIES)
+            menu_sel = 0;
+    }
+    else if (vault_state == VAULT_SETTINGS_MENU) {
+        menu_sel++;
+        cur_wipe_choice = 0;
+        if (menu_sel == MAINMENU_ENTRIES)
+            menu_sel = 0;
+    }
+    else if (vault_state == VAULT_SERVICE_LIST) {
+        if (service_list_selected > 0)
+            service_list_selected --;
+    }
+}
+
+void ui_rot_down(void)
+{
+    enum vault_state vault_state = fsm_get();
+    if (vault_state == VAULT_BOOTUP) {
+        current_char--;
+        if (current_char < ' ')
+            current_char = 126;
+    }
+    else if (vault_state == VAULT_MAIN_MENU) {
+        menu_sel--;
+        if (menu_sel < 0)
+            menu_sel = MAINMENU_ENTRIES - 1;
+    }
+    else if (vault_state == VAULT_SETTINGS_MENU) {
+        menu_sel--;
+        cur_wipe_choice = 0;
+        if (menu_sel < 0)
+            menu_sel = SETTINGSMENU_ENTRIES - 1;
+    }
+    else if (vault_state == VAULT_SERVICE_LIST) {
+        struct vault_service svc;
+        int next = service_list_selected + 1;
+        while (1) { 
+            flash_read(SVC_FLASH_OFFSET + next * SVC_SIZE, &svc, SVC_SIZE);
+            if (svc.flags == SVC_FLAG_UNUSED)
+                return; /* Keep old value */
+            else if (svc.flags == SVC_FLAG_ERASED) {
+                next++;
+            } else {
+                service_list_selected = next;
+                break;
+            }
+        }
+    }
+}
+
+void ui_init(i2c_inst_t *i2c)
+{
+    int i;
+    display_init(i2c);
+    display_clear();
+#ifdef SHOW_MOTD
+    display_scroll(0x3f);
+    display_text(0, welcome_message0);
+    display_text(1, welcome_message1);
+    display_text(2, welcome_message2);
+    for (i = 0x3f; i >= 0x20; i--) {
+        display_scroll(i);
+        sleep_us(50000);
+    }
+    for (i = display_getcontrast(); i >= 0; i--) {
+        display_setcontrast(i);
+        sleep_us(10000);
+    }
+    display_scroll(0);
+    display_clear();
+#endif
+    display_setcontrast(0xcf);
+    current_char_pos = 0; 
+    sleep_us(50000);
+    display_scroll(0x20);
+
+
+    if (cryptoengine_check_vault() < 0)
+        fsm_set(VAULT_TOFU);
+    else
+        fsm_set(VAULT_BOOTUP);
+}
+
+void ui_event(uint32_t ev)
+{
+}

+ 47 - 0
src/ui.h

@@ -0,0 +1,47 @@
+/* Motenpoche 
+ *
+ * (c) 2023 Daniele Lacamera <root@danielinux.net>
+ *
+ *
+ * Motenpoche is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Motenpoche is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
+ *
+ */
+#ifndef UI_H_INCLUDED
+#define UI_H_INCLUDED
+#include "hardware/i2c.h"
+#include "fsm.h"
+
+#define UI_EV_SCROLL_UP     (1 << 0)
+#define UI_EV_SCROLL_DN     (1 << 1)
+#define UI_EV_KEY_PRESS     (1 << 2)
+#define UI_EV_BUTTON_OK     (1 << 3)
+#define UI_EV_BUTTON_BACK   (1 << 4)
+
+
+void ui_init(i2c_inst_t *i2c);
+void ui_task(void);
+void ui_event_cb(enum vault_state old_st, enum vault_state st);
+void ui_event(uint32_t ev);
+void ui_key_button(void);
+
+void ui_back_button(void);
+
+void ui_confirm_button(void);
+void ui_rot_up(void);
+
+void ui_rot_down(void);
+
+
+#endif

+ 221 - 0
src/usb_descriptors.c

@@ -0,0 +1,221 @@
+/* 
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 Ha Thach (tinyusb.org)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ */
+
+#include "tusb.h"
+#include "usb_descriptors.h"
+#include "class/cdc/cdc.h"
+#include "class/cdc/cdc_device.h"
+#include "class/msc/msc.h"
+
+/* A combination of interfaces must have a unique product id, since PC will save device driver after the first plug.
+ * Same VID/PID with different interface e.g MSC (first), then CDC (later) will possibly cause system error on PC.
+ *
+ * Auto ProductID layout's Bitmap:
+ *   [MSB]         HID | MSC | CDC          [LSB]
+ */
+#define _PID_MAP(itf, n)  ( (CFG_TUD_##itf) << (n) )
+#define USB_PID           (0x4000 | _PID_MAP(CDC, 0) | _PID_MAP(MSC, 1) | _PID_MAP(HID, 2) | \
+                           _PID_MAP(MIDI, 3) | _PID_MAP(VENDOR, 4) )
+
+#define USB_VID   0xCafe
+#define USB_BCD   0x0200
+
+//--------------------------------------------------------------------+
+// Device Descriptors
+//--------------------------------------------------------------------+
+tusb_desc_device_t const desc_device =
+{
+    .bLength            = sizeof(tusb_desc_device_t),
+    .bDescriptorType    = TUSB_DESC_DEVICE,
+    .bcdUSB             = USB_BCD,
+    .bDeviceClass       = 0x00,
+    .bDeviceSubClass    = 0x00,
+    .bDeviceProtocol    = 0x00,
+    .bMaxPacketSize0    = CFG_TUD_ENDPOINT0_SIZE,
+
+  // Use Interface Association Descriptor (IAD) for CDC
+  // As required by USB Specs IAD's subclass must be common class (2) and protocol must be IAD (1)
+  .bDeviceClass       = TUSB_CLASS_MISC,
+  .bDeviceSubClass    = MISC_SUBCLASS_COMMON,
+  .bDeviceProtocol    = MISC_PROTOCOL_IAD,
+
+  .bMaxPacketSize0    = CFG_TUD_ENDPOINT0_SIZE,
+
+  .idVendor           = USB_VID,
+  .idProduct          = USB_PID,
+  .bcdDevice          = 0x0100,
+
+  .iManufacturer      = 0x01,
+  .iProduct           = 0x02,
+  .iSerialNumber      = 0x03,
+
+  .bNumConfigurations = 0x01
+};
+
+// Invoked when received GET DEVICE DESCRIPTOR
+// Application return pointer to descriptor
+uint8_t const * tud_descriptor_device_cb(void)
+{
+  return (uint8_t const *) &desc_device;
+}
+
+//--------------------------------------------------------------------+
+// HID Report Descriptor
+//--------------------------------------------------------------------+
+
+uint8_t const desc_hid_report[] =
+{
+  TUD_HID_REPORT_DESC_KEYBOARD(HID_REPORT_ID(REPORT_ID_KEYBOARD)),
+//  TUD_HID_REPORT_DESC_KEYBOARD(),
+};
+
+// Invoked when received GET HID REPORT DESCRIPTOR
+// Application return pointer to descriptor
+// Descriptor contents must exist long enough for transfer to complete
+uint8_t const * tud_hid_descriptor_report_cb(uint8_t instance)
+{
+  (void) instance;
+  return desc_hid_report;
+}
+
+//--------------------------------------------------------------------+
+// Configuration Descriptor
+//--------------------------------------------------------------------+
+
+enum
+{
+  ITF_NUM_HID = 0,
+  ITF_NUM_CDC,
+  ITF_NUM_CDC_DATA,
+  ITF_NUM_MSC,
+  ITF_NUM_TOTAL
+};
+
+
+#define EPNUM_HID         0x84
+#define EPNUM_CDC_NOTIF   0x81
+#define EPNUM_CDC_OUT     0x02
+#define EPNUM_CDC_IN      0x82
+#define EPNUM_MSC_OUT     0x03
+#define EPNUM_MSC_IN      0x83
+
+#if 1
+#define CONFIG_TOTAL_LEN    (TUD_CONFIG_DESC_LEN + TUD_CDC_DESC_LEN + TUD_MSC_DESC_LEN + TUD_HID_DESC_LEN)
+#else
+#define CONFIG_TOTAL_LEN    (TUD_CONFIG_DESC_LEN + TUD_HID_DESC_LEN + TUD_CDC_DESC_LEN)
+#endif
+
+
+// full speed configuration
+uint8_t const desc_fs_configuration[] =
+{
+    // Config number, interface count, string index, total length, attribute, power in mA
+    TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, 0x00, 100),
+    //TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, 100), 
+    
+    // Interface number, string index, protocol, report descriptor len, EP In address, size & polling interval
+    TUD_HID_DESCRIPTOR(ITF_NUM_HID, 6, HID_ITF_PROTOCOL_NONE, sizeof(desc_hid_report), EPNUM_HID, CFG_TUD_HID_EP_BUFSIZE, 10),
+
+    // Interface number, string index, EP notification address and size, EP data address (out, in) and size.
+    TUD_CDC_DESCRIPTOR(ITF_NUM_CDC, 4, EPNUM_CDC_NOTIF, 8, EPNUM_CDC_OUT, EPNUM_CDC_IN, 64),
+
+    // Interface number, string index, EP Out & EP In address, EP size
+    TUD_MSC_DESCRIPTOR(ITF_NUM_MSC, 5, EPNUM_MSC_OUT, EPNUM_MSC_IN, 64),
+
+
+
+};
+
+
+// Invoked when received GET CONFIGURATION DESCRIPTOR
+// Application return pointer to descriptor
+// Descriptor contents must exist long enough for transfer to complete
+uint8_t const * tud_descriptor_configuration_cb(uint8_t index)
+{
+  (void) index; // for multiple configurations
+
+#if TUD_OPT_HIGH_SPEED
+  // Although we are highspeed, host may be fullspeed.
+  return (tud_speed_get() == TUSB_SPEED_HIGH) ?  desc_hs_configuration : desc_fs_configuration;
+#else
+  return desc_fs_configuration;
+#endif
+}
+
+//--------------------------------------------------------------------+
+// String Descriptors
+//--------------------------------------------------------------------+
+
+// array of pointer to string descriptors
+char const* string_desc_arr [] =
+{
+  (const char[]) { 0x09, 0x04 }, // 0: is supported language is English (0x0409)
+  "Danielinux",                     // 1: Manufacturer
+  "Password Vault",                 // 2: Product
+  "052023",                         // 3: Serials, should use chip ID
+  "Command CDC",                   // 4: CDC Interface
+  "Virtual MSC",                    // 5: MSC Interface
+  "Virtual Keyboard"                // 6: HID (Keyboard)
+};
+
+static uint16_t _desc_str[32];
+
+// Invoked when received GET STRING DESCRIPTOR request
+// Application return pointer to descriptor, whose contents must exist long enough for transfer to complete
+uint16_t const* tud_descriptor_string_cb(uint8_t index, uint16_t langid)
+{
+  (void) langid;
+
+  uint8_t chr_count;
+
+  if ( index == 0)
+  {
+    memcpy(&_desc_str[1], string_desc_arr[0], 2);
+    chr_count = 1;
+  }else
+  {
+    // Note: the 0xEE index string is a Microsoft OS 1.0 Descriptors.
+    // https://docs.microsoft.com/en-us/windows-hardware/drivers/usbcon/microsoft-defined-usb-descriptors
+
+    if ( !(index < sizeof(string_desc_arr)/sizeof(string_desc_arr[0])) ) return NULL;
+
+    const char* str = string_desc_arr[index];
+
+    // Cap at max char
+    chr_count = strlen(str);
+    if ( chr_count > 31 ) chr_count = 31;
+
+    // Convert ASCII string into UTF-16
+    for(uint8_t i=0; i<chr_count; i++)
+    {
+      _desc_str[1+i] = str[i];
+    }
+  }
+
+  // first byte is length (including header), second byte is string type
+  _desc_str[0] = (TUSB_DESC_STRING << 8 ) | (2*chr_count + 2);
+
+  return _desc_str;
+}

+ 37 - 0
src/usb_descriptors.h

@@ -0,0 +1,37 @@
+/* 
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 Ha Thach (tinyusb.org)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef USB_DESCRIPTORS_H_
+#define USB_DESCRIPTORS_H_
+
+enum
+{
+  REPORT_ID_KEYBOARD = 1,
+  REPORT_ID_MOUSE,
+  REPORT_ID_CONSUMER_CONTROL,
+  REPORT_ID_GAMEPAD,
+  REPORT_ID_COUNT
+};
+
+#endif /* USB_DESCRIPTORS_H_ */

+ 108 - 0
src/user_settings.h

@@ -0,0 +1,108 @@
+/* Motenpoche 
+ *
+ * (c) 2023 Daniele Lacamera <root@danielinux.net>
+ *
+ *
+ * Motenpoche is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Motenpoche is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
+ *
+ */
+
+/* user_settings.h for wolfcrypt */
+
+#ifndef H_USER_SETTINGS_
+#define H_USER_SETTINGS_
+
+/* System */
+#define WOLFSSL_GENERAL_ALIGNMENT 4
+#define SINGLE_THREADED
+//#define WOLFSSL_SMALL_STACK
+#define WOLFCRYPT_ONLY
+#define TFM_TIMING_RESISTANT
+#define HAVE_CHACHA
+#define WOLFSSL_CHACHA
+#define HAVE_SHA256
+#define WOLFSSL_SHA512
+#define HAVE_PBKDF2
+#define HAVE_AES
+#define HAVE_AES_CBC
+#define HAVE_AES_DECRYPT
+
+
+#define HAVE_ECC
+#   define ECC_TIMING_RESISTANT
+#   define ECC_USER_CURVES /* enables only 256-bit by default */
+/* ECC options disabled to reduce size */
+#   define NO_ECC_SIGN
+#   define NO_ECC_EXPORT
+#   define NO_ECC_DHE
+#   define NO_ECC_KEY_EXPORT
+#   define HAVE_ECC256
+#   define FP_MAX_BITS (256 + 32)
+#   define SP_WORD_SIZE 32
+#   ifndef ULLONG_MAX
+#       define ULLONG_MAX 18446744073709551615ULL
+#   endif
+#   define WOLFSSL_SP
+#   define WOLFSSL_SP_MATH
+#   define WOLFSSL_HAVE_SP_ECC
+
+#define CUSTOM_RAND_GENERATE random_uint32
+#define CUSTOM_RAND_TYPE uint32_t
+
+#define ED25519_SMALL
+#define WOLFSSL_CURVE25519
+
+#define NO_INLINE
+
+
+#define WOLFSSL_SP
+#define WOLFSSL_SP_SMALL
+#define WOLFSSL_SP_MATH
+//#define WOLFSSL_SP_ARM_ARCH 4
+//#define WOLFSSL_SP_ARM_THUMB_ASM
+#define SP_WORD_SIZE 32
+#define SINGLE_THREADED
+
+/* Disables - For minimum wolfCrypt build */
+#define NO_CMAC
+#define NO_CODING
+#define NO_RSA
+#define NO_BIG_INT
+#define NO_ASN
+#define NO_RC4
+#define NO_SHA
+#define NO_DH
+#define NO_DSA
+#define NO_MD4
+#define NO_RABBIT
+#define NO_MD5
+#define NO_SIG_WRAPPER
+#define NO_CERT
+#define NO_SESSION_CACHE
+#define NO_HC128
+#define NO_DES3
+#define NO_WRITEV
+#define NO_DEV_RANDOM
+#define NO_FILESYSTEM
+#define NO_MAIN_DRIVER
+#define NO_OLD_RNGNAME
+#define NO_WOLFSSL_DIR
+#define WOLFSSL_NO_SOCK
+
+
+#define WOLFSSL_SP_NO_MALLOC
+#define WOLFSSL_SP_NO_DYN_STACK
+
+#endif /* !H_USER_SETTINGS_ */