diff --git a/Ganesha_II_V2/.cproject b/Ganesha_II_V2/.cproject
index 358a67b..bb5d8fb 100644
--- a/Ganesha_II_V2/.cproject
+++ b/Ganesha_II_V2/.cproject
@@ -23,8 +23,8 @@
-
-
+
+
@@ -49,7 +49,10 @@
-
+
+
+
+
@@ -68,7 +71,10 @@
-
+
+
+
+
@@ -92,7 +98,9 @@
+
+
@@ -114,59 +122,65 @@
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
-
+
-
+
-
-
-
+
+
-
-
-
-
+
+
-
-
+
@@ -184,7 +198,9 @@
+
+
diff --git a/Ganesha_II_V2/.metadata/.ide.log b/Ganesha_II_V2/.metadata/.ide.log
new file mode 100644
index 0000000..45bdd0c
--- /dev/null
+++ b/Ganesha_II_V2/.metadata/.ide.log
@@ -0,0 +1,338 @@
+2026-02-06 17:25:11,515 [INFO] Activator:176 -
+
+
+2026-02-06 17:25:11,516 [INFO] Activator:177 - !SESSION log4j initialized
+2026-02-06 17:25:12,965 [ERROR] LogOutputStream:75 - [STDERR_REDIRECT]
+2026-02-06 17:25:15,261 [INFO] LogOutputStream:77 - [STDOUT_REDIRECT]
+2026-02-06 17:25:16,938 [INFO] ApplicationProperties:184 - Using Application install path: /Applications/STM32CubeIDE.app/Contents/Eclipse/plugins/com.st.stm32cube.common.mx_6.15.0.202507011659
+2026-02-06 17:25:16,950 [INFO] DbMcusXml:78 - Set database path to: /Applications/STM32CubeIDE.app/Contents/Eclipse/plugins/com.st.stm32cube.common.mx_6.15.0.202507011659//db//mcu/
+2026-02-06 17:25:16,950 [INFO] ApiDb:274 - Set plugin database path to: /Applications/STM32CubeIDE.app/Contents/Eclipse/plugins/com.st.stm32cube.common.mx_6.15.0.202507011659//db//plugins/boardmanager/
+2026-02-06 17:25:16,950 [WARN] ApiDb:259 - Overriding images path with different value: => /Applications/STM32CubeIDE.app/Contents/Eclipse/plugins/com.st.stm32cube.common.mx_6.15.0.202507011659//db//plugins/mcufinder/images/
+2026-02-06 17:25:16,982 [INFO] ApiDb:250 - Set database path to: /Users/akshitgarg/.stmcufinder/plugins/mcufinder//mcu/
+2026-02-06 17:25:16,983 [INFO] DbMcusAds:125 - Set database path to: /Users/akshitgarg/.stmcufinder/plugins/mcufinder//mcu/
+2026-02-06 17:25:16,985 [INFO] CrossReferenceDbSqlite:203 - Set database path to: /Users/akshitgarg/.stmcufinder/plugins/mcufinder//mcu/cs/
+2026-02-06 17:25:17,171 [INFO] RulesReader:64 - Compatibility file has been processed (317 Rules)
+2026-02-06 17:25:17,236 [INFO] DbMcusXml:78 - Set database path to: /Applications/STM32CubeIDE.app/Contents/Eclipse/plugins/com.st.stm32cube.common.mx_6.15.0.202507011659//db//mcu/
+2026-02-06 17:25:17,236 [INFO] ApiDb:274 - Set plugin database path to: /Applications/STM32CubeIDE.app/Contents/Eclipse/plugins/com.st.stm32cube.common.mx_6.15.0.202507011659//db//plugins/boardmanager/
+2026-02-06 17:25:17,237 [INFO] ApiDb:261 - Set plugin images path to: /Applications/STM32CubeIDE.app/Contents/Eclipse/plugins/com.st.stm32cube.common.mx_6.15.0.202507011659//db//plugins/mcufinder/images/
+2026-02-06 17:25:17,237 [WARN] DbFile:41 - Overriding database path with different value: /Users/akshitgarg/.stmcufinder/plugins/mcufinder/ => /Users/akshitgarg/.stmcufinder/plugins/mcufinder
+2026-02-06 17:25:17,237 [INFO] ApiDb:250 - Set database path to: /Users/akshitgarg/.stmcufinder/plugins/mcufinder//mcu/
+2026-02-06 17:25:17,237 [WARN] DbFile:41 - Overriding database path with different value: /Users/akshitgarg/.stmcufinder/plugins/mcufinder/ => /Users/akshitgarg/.stmcufinder/plugins/mcufinder
+2026-02-06 17:25:17,237 [INFO] DbMcusAds:125 - Set database path to: /Users/akshitgarg/.stmcufinder/plugins/mcufinder//mcu/
+2026-02-06 17:25:17,237 [WARN] DbFile:41 - Overriding database path with different value: /Users/akshitgarg/.stmcufinder/plugins/mcufinder/ => /Users/akshitgarg/.stmcufinder/plugins/mcufinder
+2026-02-06 17:25:17,237 [WARN] DbFile:41 - Overriding database path with different value: /Users/akshitgarg/.stmcufinder/plugins/mcufinder/ => /Users/akshitgarg/.stmcufinder/plugins/mcufinder
+2026-02-06 17:25:17,237 [INFO] CrossReferenceDbSqlite:203 - Set database path to: /Users/akshitgarg/.stmcufinder/plugins/mcufinder//mcu/cs/
+2026-02-06 17:25:17,310 [INFO] MainPanel:274 - HeapMemory: 381681664
+2026-02-06 17:25:17,706 [INFO] DbMcusXml:78 - Set database path to: /Applications/STM32CubeIDE.app/Contents/Eclipse/plugins/com.st.stm32cube.common.mx_6.15.0.202507011659//db//mcu/
+2026-02-06 17:25:17,706 [INFO] ApiDb:274 - Set plugin database path to: /Applications/STM32CubeIDE.app/Contents/Eclipse/plugins/com.st.stm32cube.common.mx_6.15.0.202507011659//db//plugins/boardmanager/
+2026-02-06 17:25:17,706 [INFO] ApiDb:261 - Set plugin images path to: /Applications/STM32CubeIDE.app/Contents/Eclipse/plugins/com.st.stm32cube.common.mx_6.15.0.202507011659//db//plugins/mcufinder/images/
+2026-02-06 17:25:17,706 [WARN] DbFile:41 - Overriding database path with different value: /Users/akshitgarg/.stmcufinder/plugins/mcufinder/ => /Users/akshitgarg/.stmcufinder/plugins/mcufinder
+2026-02-06 17:25:17,706 [INFO] ApiDb:250 - Set database path to: /Users/akshitgarg/.stmcufinder/plugins/mcufinder//mcu/
+2026-02-06 17:25:17,706 [WARN] DbFile:41 - Overriding database path with different value: /Users/akshitgarg/.stmcufinder/plugins/mcufinder/ => /Users/akshitgarg/.stmcufinder/plugins/mcufinder
+2026-02-06 17:25:17,706 [INFO] DbMcusAds:125 - Set database path to: /Users/akshitgarg/.stmcufinder/plugins/mcufinder//mcu/
+2026-02-06 17:25:17,706 [WARN] DbFile:41 - Overriding database path with different value: /Users/akshitgarg/.stmcufinder/plugins/mcufinder/ => /Users/akshitgarg/.stmcufinder/plugins/mcufinder
+2026-02-06 17:25:17,706 [WARN] DbFile:41 - Overriding database path with different value: /Users/akshitgarg/.stmcufinder/plugins/mcufinder/ => /Users/akshitgarg/.stmcufinder/plugins/mcufinder
+2026-02-06 17:25:17,707 [INFO] CrossReferenceDbSqlite:203 - Set database path to: /Users/akshitgarg/.stmcufinder/plugins/mcufinder//mcu/cs/
+2026-02-06 17:25:17,728 [INFO] ApplicationProperties:184 - Using Application install path: /Applications/STM32CubeIDE.app/Contents/Eclipse/plugins/com.st.stm32cube.common.mx_6.15.0.202507011659
+2026-02-06 17:25:17,729 [INFO] PluginManage:196 - Search for loadable plugins [exclusion list=, ]
+2026-02-06 17:25:17,731 [INFO] PluginManage:310 - Check plugin analytics
+2026-02-06 17:25:18,431 [INFO] AnalyticsPlugin:253 - Accepted Software Licenses:
+2026-02-06 17:25:18,453 [INFO] AnalyticsPlugin:255 - Accepted CMSIS Pack Licenses:
+2026-02-06 17:25:18,462 [INFO] AnalyticsPlugin:257 - Accepted Firmware Licenses: FW.H7.1.11.0,FW.H7.1.12.0
+2026-02-06 17:25:18,535 [INFO] PluginManage:359 - Loaded plugin analytics (category:tool,tabindex:-1)
+2026-02-06 17:25:18,543 [INFO] PluginManage:310 - Check plugin cadmodel
+2026-02-06 17:25:18,613 [INFO] CADModel:105 - Init CAD model plugin
+2026-02-06 17:25:18,614 [INFO] PluginManage:359 - Loaded plugin cadmodel (category:power,tabindex:5)
+2026-02-06 17:25:18,616 [INFO] PluginManage:310 - Check plugin clock
+2026-02-06 17:25:18,633 [INFO] PluginManage:359 - Loaded plugin clock (category:base,tabindex:2)
+2026-02-06 17:25:18,635 [INFO] PluginManage:310 - Check plugin ddr
+2026-02-06 17:25:18,638 [INFO] PluginManage:359 - Loaded plugin ddr (category:tool,tabindex:6)
+2026-02-06 17:25:18,639 [INFO] PluginManage:310 - Check plugin filemanager
+2026-02-06 17:25:18,825 [INFO] PluginManage:359 - Loaded plugin filemanager (category:base,tabindex:10)
+2026-02-06 17:25:18,826 [INFO] PluginManage:310 - Check plugin ipmanager
+2026-02-06 17:25:18,838 [INFO] PluginManage:359 - Loaded plugin ipmanager (category:base,tabindex:5)
+2026-02-06 17:25:18,839 [INFO] PluginManage:310 - Check plugin lpbam
+2026-02-06 17:25:18,848 [INFO] PluginManage:359 - Loaded plugin lpbam (category:base,tabindex:0)
+2026-02-06 17:25:18,849 [INFO] PluginManage:310 - Check plugin memorymap
+2026-02-06 17:25:18,858 [INFO] PluginManage:359 - Loaded plugin memorymap (category:base,tabindex:4)
+2026-02-06 17:25:18,859 [INFO] PluginManage:310 - Check plugin pinoutandconfiguration
+2026-02-06 17:25:18,863 [INFO] PluginManage:359 - Loaded plugin pinoutandconfiguration (category:base,tabindex:1)
+2026-02-06 17:25:18,864 [INFO] PluginManage:310 - Check plugin pinoutconfig
+2026-02-06 17:25:18,942 [WARN] SupportedApi:132 - Cannot load RTOS API schema: s4s-elt-must-match.1: The content of 'definitions' must match (annotation?, (simpleType | complexType)?, (unique | key | keyref)*)). A problem was found starting at: attribute.
+2026-02-06 17:25:19,105 [INFO] PluginManage:359 - Loaded plugin pinoutconfig (category:base,tabindex:0)
+2026-02-06 17:25:19,106 [INFO] PluginManage:310 - Check plugin power
+2026-02-06 17:25:19,113 [INFO] PluginManage:359 - Loaded plugin power (category:power,tabindex:4)
+2026-02-06 17:25:19,114 [INFO] PluginManage:310 - Check plugin projectmanager
+2026-02-06 17:25:19,140 [INFO] PluginManage:359 - Loaded plugin projectmanager (category:projectmanager,tabindex:4)
+2026-02-06 17:25:19,140 [INFO] PluginManage:310 - Check plugin rif
+2026-02-06 17:25:19,145 [INFO] PluginManage:359 - Loaded plugin rif (category:base,tabindex:3)
+2026-02-06 17:25:19,145 [INFO] PluginManage:310 - Check plugin thirdparty
+2026-02-06 17:25:19,301 [INFO] PluginManage:359 - Loaded plugin thirdparty (category:base,tabindex:-1)
+2026-02-06 17:25:19,302 [INFO] PluginManage:310 - Check plugin tools
+2026-02-06 17:25:19,301 [WARN] IntegrityCheckThread:84 - waiting for thirdparty lock release [integrity check]
+2026-02-06 17:25:19,303 [INFO] IntegrityCheckThread:86 - entering critical section [integrity check]
+2026-02-06 17:25:19,304 [INFO] ThirdPartyUpdaterWithRetryManager:70 - Updater plugin not ready yet. [1/15]
+2026-02-06 17:25:19,306 [INFO] PluginManage:359 - Loaded plugin tools (category:base,tabindex:7)
+2026-02-06 17:25:19,306 [INFO] PluginManage:310 - Check plugin tutovideos
+2026-02-06 17:25:19,457 [INFO] PluginManage:359 - Loaded plugin tutovideos (category:base,tabindex:-1)
+2026-02-06 17:25:19,457 [INFO] PluginManage:310 - Check plugin updater
+2026-02-06 17:25:19,483 [INFO] PluginManage:359 - Loaded plugin updater (category:base,tabindex:12)
+2026-02-06 17:25:19,483 [INFO] PluginManage:310 - Check plugin userauth
+2026-02-06 17:25:19,486 [INFO] UserAuth:118 - Init User Auth plugin
+2026-02-06 17:25:19,487 [INFO] PluginManage:359 - Loaded plugin userauth (category:base,tabindex:14)
+2026-02-06 17:25:19,488 [INFO] PluginManage:283 - PluginManage : Loaded plugins [18]
+2026-02-06 17:25:19,674 [INFO] PinOutPanel:1589 - setPackage(No Configuration,No Configuration)
+2026-02-06 17:25:19,765 [INFO] CADModel:165 - CPN selected for project level
+2026-02-06 17:25:19,765 [INFO] CADModel:114 - Register for checkConnection events
+2026-02-06 17:25:19,775 [INFO] IPUIPlugin:80 - create IPUIPlugin
+2026-02-06 17:25:19,775 [INFO] PluginManager:220 - loadIPPluginJar : add mdma
+2026-02-06 17:25:19,779 [INFO] IPUIPlugin:80 - create IPUIPlugin
+2026-02-06 17:25:19,779 [INFO] PluginManager:220 - loadIPPluginJar : add freertos
+2026-02-06 17:25:19,781 [INFO] IPUIPlugin:80 - create IPUIPlugin
+2026-02-06 17:25:19,782 [INFO] PluginManager:220 - loadIPPluginJar : add gic
+2026-02-06 17:25:19,787 [INFO] IPUIPlugin:80 - create IPUIPlugin
+2026-02-06 17:25:19,788 [INFO] PluginManager:220 - loadIPPluginJar : add adc
+2026-02-06 17:25:19,789 [INFO] IPUIPlugin:80 - create IPUIPlugin
+2026-02-06 17:25:19,789 [INFO] PluginManager:220 - loadIPPluginJar : add gtzc
+2026-02-06 17:25:19,789 [INFO] IPUIPlugin:80 - create IPUIPlugin
+2026-02-06 17:25:19,789 [INFO] PluginManager:220 - loadIPPluginJar : add quadspi
+2026-02-06 17:25:19,790 [INFO] IPUIPlugin:80 - create IPUIPlugin
+2026-02-06 17:25:19,790 [INFO] PluginManager:220 - loadIPPluginJar : add aes
+2026-02-06 17:25:19,791 [INFO] IPUIPlugin:80 - create IPUIPlugin
+2026-02-06 17:25:19,791 [INFO] PluginManager:220 - loadIPPluginJar : add pdm2pcm
+2026-02-06 17:25:19,792 [INFO] IPUIPlugin:80 - create IPUIPlugin
+2026-02-06 17:25:19,792 [INFO] PluginManager:220 - loadIPPluginJar : add hash
+2026-02-06 17:25:19,793 [INFO] IPUIPlugin:80 - create IPUIPlugin
+2026-02-06 17:25:19,793 [INFO] PluginManager:220 - loadIPPluginJar : add tim
+2026-02-06 17:25:19,794 [INFO] IPUIPlugin:80 - create IPUIPlugin
+2026-02-06 17:25:19,794 [INFO] PluginManager:220 - loadIPPluginJar : add tsc
+2026-02-06 17:25:19,795 [INFO] IPUIPlugin:80 - create IPUIPlugin
+2026-02-06 17:25:19,795 [INFO] PluginManager:220 - loadIPPluginJar : add extmemmanager
+2026-02-06 17:25:19,796 [INFO] IPUIPlugin:80 - create IPUIPlugin
+2026-02-06 17:25:19,796 [INFO] PluginManager:220 - loadIPPluginJar : add ts
+2026-02-06 17:25:19,797 [INFO] IPUIPlugin:80 - create IPUIPlugin
+2026-02-06 17:25:19,797 [INFO] PluginManager:220 - loadIPPluginJar : add radio
+2026-02-06 17:25:19,798 [INFO] IPUIPlugin:80 - create IPUIPlugin
+2026-02-06 17:25:19,798 [INFO] PluginManager:220 - loadIPPluginJar : add can
+2026-02-06 17:25:19,799 [INFO] IPUIPlugin:80 - create IPUIPlugin
+2026-02-06 17:25:19,799 [INFO] PluginManager:220 - loadIPPluginJar : add dma3
+2026-02-06 17:25:19,800 [INFO] IPUIPlugin:80 - create IPUIPlugin
+2026-02-06 17:25:19,800 [INFO] PluginManager:220 - loadIPPluginJar : add dfsdm
+2026-02-06 17:25:19,801 [INFO] IPUIPlugin:80 - create IPUIPlugin
+2026-02-06 17:25:19,801 [INFO] PluginManager:220 - loadIPPluginJar : add spi
+2026-02-06 17:25:19,802 [INFO] IPUIPlugin:80 - create IPUIPlugin
+2026-02-06 17:25:19,802 [INFO] PluginManager:220 - loadIPPluginJar : add gfxmmu
+2026-02-06 17:25:19,803 [INFO] IPUIPlugin:80 - create IPUIPlugin
+2026-02-06 17:25:19,804 [INFO] PluginManager:220 - loadIPPluginJar : add genericplugin
+2026-02-06 17:25:19,805 [INFO] IPUIPlugin:80 - create IPUIPlugin
+2026-02-06 17:25:19,805 [INFO] PluginManager:220 - loadIPPluginJar : add cryp
+2026-02-06 17:25:19,808 [INFO] IPUIPlugin:80 - create IPUIPlugin
+2026-02-06 17:25:19,808 [INFO] PluginManager:220 - loadIPPluginJar : add gpio
+2026-02-06 17:25:19,810 [INFO] IPUIPlugin:80 - create IPUIPlugin
+2026-02-06 17:25:19,810 [INFO] PluginManager:220 - loadIPPluginJar : add ddr_ctrl_phy
+2026-02-06 17:25:19,811 [INFO] IPUIPlugin:80 - create IPUIPlugin
+2026-02-06 17:25:19,811 [INFO] PluginManager:220 - loadIPPluginJar : add comp
+2026-02-06 17:25:19,812 [INFO] IPUIPlugin:80 - create IPUIPlugin
+2026-02-06 17:25:19,813 [INFO] PluginManager:220 - loadIPPluginJar : add tracer_emb
+2026-02-06 17:25:19,815 [INFO] IPUIPlugin:80 - create IPUIPlugin
+2026-02-06 17:25:19,815 [INFO] PluginManager:220 - loadIPPluginJar : add openamp
+2026-02-06 17:25:19,818 [INFO] IPUIPlugin:80 - create IPUIPlugin
+2026-02-06 17:25:19,818 [INFO] PluginManager:220 - loadIPPluginJar : add stm32_wpan
+2026-02-06 17:25:19,821 [INFO] IPUIPlugin:80 - create IPUIPlugin
+2026-02-06 17:25:19,823 [INFO] PluginManager:220 - loadIPPluginJar : add plateformsettings
+2026-02-06 17:25:19,824 [INFO] IPUIPlugin:80 - create IPUIPlugin
+2026-02-06 17:25:19,824 [INFO] PluginManager:220 - loadIPPluginJar : add ipddr
+2026-02-06 17:25:19,825 [INFO] IPUIPlugin:80 - create IPUIPlugin
+2026-02-06 17:25:19,825 [INFO] PluginManager:220 - loadIPPluginJar : add usart
+2026-02-06 17:25:19,826 [INFO] IPUIPlugin:80 - create IPUIPlugin
+2026-02-06 17:25:19,826 [INFO] PluginManager:220 - loadIPPluginJar : add ltdc
+2026-02-06 17:25:19,827 [INFO] IPUIPlugin:80 - create IPUIPlugin
+2026-02-06 17:25:19,827 [INFO] PluginManager:220 - loadIPPluginJar : add nvic
+2026-02-06 17:25:19,828 [INFO] IPUIPlugin:80 - create IPUIPlugin
+2026-02-06 17:25:19,828 [INFO] PluginManager:220 - loadIPPluginJar : add fatfs
+2026-02-06 17:25:19,831 [INFO] IPUIPlugin:80 - create IPUIPlugin
+2026-02-06 17:25:19,832 [INFO] PluginManager:220 - loadIPPluginJar : add linkedlist
+2026-02-06 17:25:19,835 [INFO] IPUIPlugin:80 - create IPUIPlugin
+2026-02-06 17:25:19,835 [INFO] PluginManager:220 - loadIPPluginJar : add dma
+2026-02-06 17:25:19,838 [INFO] IPUIPlugin:80 - create IPUIPlugin
+2026-02-06 17:25:19,838 [INFO] PluginManager:220 - loadIPPluginJar : add fmc
+2026-02-06 17:25:19,840 [INFO] IPUIPlugin:80 - create IPUIPlugin
+2026-02-06 17:25:19,840 [INFO] PluginManager:220 - loadIPPluginJar : add i2s
+2026-02-06 17:25:19,842 [INFO] IPUIPlugin:80 - create IPUIPlugin
+2026-02-06 17:25:19,843 [INFO] PluginManager:220 - loadIPPluginJar : add ucpd
+2026-02-06 17:25:19,844 [INFO] IPUIPlugin:80 - create IPUIPlugin
+2026-02-06 17:25:19,844 [INFO] PluginManager:220 - loadIPPluginJar : add lorawan
+2026-02-06 17:25:19,845 [INFO] IPUIPlugin:80 - create IPUIPlugin
+2026-02-06 17:25:19,846 [INFO] PluginManager:220 - loadIPPluginJar : add opamp
+2026-02-06 17:25:19,847 [INFO] IPUIPlugin:80 - create IPUIPlugin
+2026-02-06 17:25:19,847 [INFO] PluginManager:220 - loadIPPluginJar : add i3c
+2026-02-06 17:25:19,848 [INFO] IPUIPlugin:80 - create IPUIPlugin
+2026-02-06 17:25:19,848 [INFO] PluginManager:220 - loadIPPluginJar : add touchsensing
+2026-02-06 17:25:19,850 [INFO] IPUIPlugin:80 - create IPUIPlugin
+2026-02-06 17:25:19,850 [INFO] PluginManager:220 - loadIPPluginJar : add i2c
+2026-02-06 17:25:19,852 [INFO] IPUIPlugin:80 - create IPUIPlugin
+2026-02-06 17:25:19,852 [INFO] PluginManager:220 - loadIPPluginJar : add resmgrutility
+2026-02-06 17:25:19,853 [INFO] IPUIPlugin:80 - create IPUIPlugin
+2026-02-06 17:25:19,853 [INFO] PluginManager:220 - loadIPPluginJar : add sai
+2026-02-06 17:25:19,854 [INFO] IPUIPlugin:80 - create IPUIPlugin
+2026-02-06 17:25:19,855 [INFO] PluginManager:220 - loadIPPluginJar : add usbx
+2026-02-06 17:25:19,968 [FATAL] Updater:351 - Updater called before beeing initialized
+2026-02-06 17:25:20,022 [INFO] RulesReader:64 - Compatibility file has been processed (317 Rules)
+2026-02-06 17:25:20,036 [INFO] RulesReader:64 - Compatibility file has been processed (317 Rules)
+2026-02-06 17:25:20,043 [INFO] CADModel:165 - CPN selected for project level
+2026-02-06 17:25:20,043 [INFO] CADModel:114 - Register for checkConnection events
+2026-02-06 17:25:20,043 [FATAL] Updater:351 - Updater called before beeing initialized
+2026-02-06 17:25:20,043 [ERROR] CADModel:125 - Updater not yet initialized, retry later
+2026-02-06 17:25:20,390 [FATAL] Updater:351 - Updater called before beeing initialized
+2026-02-06 17:25:20,399 [INFO] CADModel:165 - CPN selected for project level
+2026-02-06 17:25:20,400 [INFO] CADModel:114 - Register for checkConnection events
+2026-02-06 17:25:20,400 [FATAL] Updater:351 - Updater called before beeing initialized
+2026-02-06 17:25:20,400 [ERROR] CADModel:125 - Updater not yet initialized, retry later
+2026-02-06 17:25:20,405 [FATAL] Updater:351 - Updater called before beeing initialized
+2026-02-06 17:25:20,664 [FATAL] Updater:351 - Updater called before beeing initialized
+2026-02-06 17:25:20,675 [INFO] DbMcusAds:53 - JSON generation date=Thu Jan 08 10:57:51 EST 2026 (1767887871456)
+2026-02-06 17:25:20,677 [FATAL] Updater:351 - Updater called before beeing initialized
+2026-02-06 17:25:20,731 [WARN] DetailPanel:346 - Failed to get advertising image, set to default
+2026-02-06 17:25:20,790 [FATAL] Updater:351 - Updater called before beeing initialized
+2026-02-06 17:25:20,793 [FATAL] Updater:351 - Updater called before beeing initialized
+2026-02-06 17:25:20,793 [FATAL] Updater:351 - Updater called before beeing initialized
+2026-02-06 17:25:20,794 [WARN] DetailPanel:346 - Failed to get advertising image, set to default
+2026-02-06 17:25:20,796 [FATAL] Updater:351 - Updater called before beeing initialized
+2026-02-06 17:25:20,865 [ERROR] Updater:1198 - MainUpdater not yet initialized. External WinMGr cannot be set.
+2026-02-06 17:25:20,878 [INFO] Updater:1134 - Updater Version found : 6.15.0
+2026-02-06 17:25:20,890 [INFO] ApplicationProperties:184 - Using Application install path: /Applications/STM32CubeIDE.app/Contents/Eclipse/plugins/com.st.stm32cube.common.mx_6.15.0.202507011659
+2026-02-06 17:25:21,278 [INFO] MainUpdater:2872 - connection check result : 10
+2026-02-06 17:25:21,278 [INFO] MainUpdater:289 - Updater Check For Update Now.
+2026-02-06 17:25:21,278 [INFO] MicroXplorer:498 - Change Database Version : DB.6.0.150
+2026-02-06 17:25:21,284 [INFO] McuFinderGlobals:63 - Set McuFinder mode to 2 (CubeIDE integrated)
+2026-02-06 17:25:21,285 [INFO] UserAuth:487 - Internet connection configuration mode: 1
+2026-02-06 17:25:21,297 [INFO] JxBrowserEngine:152 - Initiate JxBrowser Engine with user profile folder
+2026-02-06 17:25:21,526 [INFO] CheckServerUpdateThread:120 - End of CheckServer Thread
+2026-02-06 17:25:22,517 [WARN] PackLoader:240 - Cannot read IP mode file for STMicroelectronics.FP-SNS-MOTENVWB1.1.4.0
+2026-02-06 17:25:22,537 [WARN] PackLoader:240 - Cannot read IP mode file for STMicroelectronics.FP-ATR-ASTRA1.2.0.2
+2026-02-06 17:25:22,546 [WARN] PackLoader:240 - Cannot read IP mode file for STMicroelectronics.FP-ATR-ASTRA1.2.0.1
+2026-02-06 17:25:22,559 [WARN] PackLoader:240 - Cannot read IP mode file for STMicroelectronics.X-CUBE-SMBUS.2.1.0
+2026-02-06 17:25:22,566 [WARN] PackLoader:240 - Cannot read IP mode file for STMicroelectronics.X-CUBE-WB05N.1.1.0
+2026-02-06 17:25:22,571 [WARN] PackLoader:240 - Cannot read IP mode file for STMicroelectronics.X-CUBE-ST60.1.0.0
+2026-02-06 17:25:22,619 [WARN] PackLoader:240 - Cannot read IP mode file for STMicroelectronics.X-CUBE-AZRTOS-F7.1.1.0
+2026-02-06 17:25:22,662 [WARN] PackLoader:240 - Cannot read IP mode file for STMicroelectronics.FP-SNS-MOTENV1.5.1.0
+2026-02-06 17:25:22,671 [WARN] PackLoader:240 - Cannot read IP mode file for STMicroelectronics.FP-SNS-FLIGHT1.5.0.2
+2026-02-06 17:25:22,705 [WARN] PackLoader:240 - Cannot read IP mode file for Infineon.AIROC-Wi-Fi-Bluetooth-STM32.1.7.0
+2026-02-06 17:25:22,762 [WARN] PackLoader:240 - Cannot read IP mode file for STMicroelectronics.X-CUBE-AZRTOS-H7.3.4.0
+2026-02-06 17:25:22,790 [WARN] PackLoader:240 - Cannot read IP mode file for STMicroelectronics.X-CUBE-DISPLAY.3.0.0
+2026-02-06 17:25:22,808 [WARN] PackLoader:240 - Cannot read IP mode file for STMicroelectronics.X-CUBE-BLE1.7.0.0
+2026-02-06 17:25:22,820 [WARN] PackLoader:240 - Cannot read IP mode file for STMicroelectronics.X-CUBE-NFC10.1.0.0
+2026-02-06 17:25:22,837 [WARN] PackLoader:240 - Cannot read IP mode file for STMicroelectronics.X-CUBE-BLEMGR.4.0.0
+2026-02-06 17:25:22,862 [WARN] PackLoader:240 - Cannot read IP mode file for STMicroelectronics.X-CUBE-ST60.1.1.0
+2026-02-06 17:25:22,871 [WARN] PackLoader:240 - Cannot read IP mode file for emotas.I-CUBE-CANOPEN.1.3.0
+2026-02-06 17:25:22,883 [WARN] PackLoader:240 - Cannot read IP mode file for STMicroelectronics.X-CUBE-GNSS1.7.1.0
+2026-02-06 17:25:22,889 [WARN] PackLoader:240 - Cannot read IP mode file for STMicroelectronics.X-CUBE-AI.10.0.0
+2026-02-06 17:25:22,898 [WARN] PackLoader:240 - Cannot read IP mode file for STMicroelectronics.FP-SNS-STBOX1.2.1.0
+2026-02-06 17:25:22,906 [WARN] PackLoader:240 - Cannot read IP mode file for STMicroelectronics.FP-SNS-SMARTAG2.1.2.0
+2026-02-06 17:25:22,910 [WARN] PackLoader:240 - Cannot read IP mode file for STMicroelectronics.FP-SNS-FLIGHT1.5.1.0
+2026-02-06 17:25:22,989 [WARN] PackLoader:240 - Cannot read IP mode file for STMicroelectronics.X-CUBE-MEMS1.11.1.0
+2026-02-06 17:25:23,098 [INFO] LogOutputStream:77 - [STDOUT_REDIRECT] 1 : Invalid condition id : UX_CORESTACK_Condition cause : null
+2026-02-06 17:25:23,100 [INFO] LogOutputStream:77 - [STDOUT_REDIRECT] 1 : Invalid condition id : UX_CORESTACK_Condition cause : null
+2026-02-06 17:25:23,101 [INFO] LogOutputStream:77 - [STDOUT_REDIRECT] 1 : Invalid condition id : UX_CORESTACK_Condition cause : null
+2026-02-06 17:25:23,101 [INFO] LogOutputStream:77 - [STDOUT_REDIRECT] 1 : Invalid condition id : UX_CORESTACK_Condition cause : null
+2026-02-06 17:25:23,101 [INFO] LogOutputStream:77 - [STDOUT_REDIRECT] 1 : Invalid condition id : UX_CORESTACK_Condition cause : null
+2026-02-06 17:25:23,106 [WARN] PackLoader:240 - Cannot read IP mode file for STMicroelectronics.X-CUBE-AZRTOS-WL.2.0.0
+2026-02-06 17:25:23,112 [WARN] PackLoader:240 - Cannot read IP mode file for STMicroelectronics.FP-SNS-MOTENV1.5.0.0
+2026-02-06 17:25:23,134 [WARN] PackLoader:240 - Cannot read IP mode file for STMicroelectronics.X-CUBE-AZRTOS-H7RS.1.2.0
+2026-02-06 17:25:23,145 [WARN] PackLoader:240 - Cannot read IP mode file for wolfSSL.I-CUBE-wolfMQTT.1.19.0
+2026-02-06 17:25:23,153 [WARN] PackLoader:240 - Cannot read IP mode file for WES.I-CUBE-Cesium.1.3.0
+2026-02-06 17:25:23,161 [WARN] PackLoader:240 - Cannot read IP mode file for STMicroelectronics.X-CUBE-BLE2.3.3.0
+2026-02-06 17:25:23,185 [WARN] PackLoader:240 - Cannot read IP mode file for STMicroelectronics.X-CUBE-NFC9.1.0.0
+2026-02-06 17:25:23,197 [WARN] PackLoader:240 - Cannot read IP mode file for STMicroelectronics.X-CUBE-BLE1.7.1.0
+2026-02-06 17:25:23,204 [WARN] PackLoader:240 - Cannot read IP mode file for STMicroelectronics.X-CUBE-FREERTOS.1.4.0
+2026-02-06 17:25:23,214 [WARN] PackLoader:240 - Cannot read IP mode file for STMicroelectronics.X-CUBE-EEPRMA1.5.2.0
+2026-02-06 17:25:23,224 [WARN] PackLoader:240 - Cannot read IP mode file for STMicroelectronics.X-CUBE-ST67W61.1.1.0
+2026-02-06 17:25:23,311 [WARN] PackLoader:240 - Cannot read IP mode file for STMicroelectronics.X-CUBE-MEMS1.12.0.0
+2026-02-06 17:25:23,439 [WARN] PackLoader:240 - Cannot read IP mode file for STMicroelectronics.X-CUBE-MEMS1.11.2.0
+2026-02-06 17:25:23,522 [WARN] PackLoader:240 - Cannot read IP mode file for STMicroelectronics.X-CUBE-AZRTOS-G0.1.1.0
+2026-02-06 17:25:23,534 [WARN] PackLoader:240 - Cannot read IP mode file for STMicroelectronics.X-CUBE-SAFEA1.1.2.2
+2026-02-06 17:25:23,541 [WARN] PackLoader:240 - Cannot read IP mode file for STMicroelectronics.X-CUBE-NFC4.3.0.0
+2026-02-06 17:25:23,558 [WARN] PackLoader:240 - Cannot read IP mode file for EmbeddedOffice.I-CUBE-FS-RTOS.1.0.1
+2026-02-06 17:25:23,581 [WARN] PackLoader:240 - Cannot read IP mode file for STMicroelectronics.X-CUBE-WB05N.2.0.0
+2026-02-06 17:25:23,606 [WARN] PackLoader:240 - Cannot read IP mode file for STMicroelectronics.X-CUBE-TCPP.4.2.0
+2026-02-06 17:25:23,629 [WARN] PackLoader:240 - Cannot read IP mode file for RealThread.X-CUBE-RT-Thread_Nano.4.1.1
+2026-02-06 17:25:23,642 [WARN] PackLoader:240 - Cannot read IP mode file for STMicroelectronics.FP-ATR-SIGFOX1.3.2.0
+2026-02-06 17:25:23,650 [WARN] ConditionMgr:438 - getConditionDescription Invalid condition id : Cortex-A Device cause : null
+2026-02-06 17:25:23,668 [WARN] ConditionMgr:1044 - genDependencies : Invalid condition id : Cortex-A Device cause : null
+2026-02-06 17:25:23,669 [WARN] ConditionMgr:1044 - genDependencies : Invalid condition id : Cortex-A Device cause : null
+2026-02-06 17:25:23,669 [WARN] ConditionMgr:1044 - genDependencies : Invalid condition id : Cortex-A Device cause : null
+2026-02-06 17:25:23,688 [WARN] PackLoader:240 - Cannot read IP mode file for STMicroelectronics.X-CUBE-EEPRMA1.5.1.0
+2026-02-06 17:25:23,700 [WARN] PackLoader:240 - Cannot read IP mode file for wolfSSL.I-CUBE-wolfSSL.5.7.6
+2026-02-06 17:25:23,715 [WARN] PackLoader:240 - Cannot read IP mode file for ITTIA_DB.I-CUBE-ITTIADB.8.9.0
+2026-02-06 17:25:23,729 [WARN] PackLoader:240 - Cannot read IP mode file for STMicroelectronics.X-CUBE-NFC6.3.2.0
+2026-02-06 17:25:23,741 [WARN] PackLoader:240 - Cannot read IP mode file for STMicroelectronics.X-CUBE-ST67W61.1.0.0
+2026-02-06 17:25:23,757 [WARN] PackLoader:240 - Cannot read IP mode file for STMicroelectronics.X-CUBE-AI.10.2.0
+2026-02-06 17:25:23,915 [WARN] PackLoader:240 - Cannot read IP mode file for SEGGER.I-CUBE-embOS.1.3.1
+2026-02-06 17:25:24,069 [WARN] PackLoader:240 - Cannot read IP mode file for STMicroelectronics.X-CUBE-ALGOBUILD.1.4.0
+2026-02-06 17:25:24,157 [WARN] PackLoader:240 - Cannot read IP mode file for STMicroelectronics.X-CUBE-MEMS1.11.3.0
+2026-02-06 17:25:24,220 [WARN] PackLoader:240 - Cannot read IP mode file for STMicroelectronics.X-CUBE-PM33A1.1.0.0
+2026-02-06 17:25:24,238 [WARN] PackLoader:240 - Cannot read IP mode file for STMicroelectronics.X-CUBE-AZRTOS-F4.1.1.0
+2026-02-06 17:25:24,252 [WARN] PackLoader:240 - Cannot read IP mode file for Avnet-IotConnect.X-CUBE-IoTC-DA16k-PMOD.1.0.0
+2026-02-06 17:25:24,264 [WARN] PackLoader:240 - Cannot read IP mode file for STMicroelectronics.X-CUBE-ISPU.2.1.0
+2026-02-06 17:25:24,277 [WARN] PackLoader:240 - Cannot read IP mode file for STMicroelectronics.X-CUBE-IPS.3.2.0
+2026-02-06 17:25:24,291 [WARN] PackLoader:240 - Cannot read IP mode file for STMicroelectronics.X-CUBE-NFC12.1.0.0
+2026-02-06 17:25:24,318 [WARN] PackLoader:240 - Cannot read IP mode file for STMicroelectronics.X-CUBE-AZRTOS-L5.2.0.0
+2026-02-06 17:25:24,343 [WARN] PackLoader:240 - Cannot read IP mode file for STMicroelectronics.X-CUBE-NFC6.3.1.0
+2026-02-06 17:25:24,352 [WARN] PackLoader:240 - Cannot read IP mode file for STMicroelectronics.X-CUBE-DPower.1.2.0
+2026-02-06 17:25:24,361 [WARN] PackLoader:240 - Cannot read IP mode file for STMicroelectronics.X-CUBE-FREERTOS.1.3.1
+2026-02-06 17:25:24,365 [WARN] PackLoader:240 - Cannot read IP mode file for STMicroelectronics.X-CUBE-FREERTOS.1.3.0
+2026-02-06 17:25:24,368 [WARN] PackLoader:240 - Cannot read IP mode file for STMicroelectronics.X-CUBE-NFC7.1.0.1
+2026-02-06 17:25:24,387 [WARN] PackLoader:240 - Cannot read IP mode file for STMicroelectronics.X-CUBE-TOUCHGFX.4.26.0
+2026-02-06 17:25:24,393 [WARN] PackLoader:240 - Cannot read IP mode file for STMicroelectronics.FP-SNS-STAIOTCFT.1.0.0
+2026-02-06 17:25:24,397 [WARN] PackLoader:240 - Cannot read IP mode file for STMicroelectronics.X-CUBE-DPower.1.3.0
+2026-02-06 17:25:24,415 [WARN] ConditionMgr:438 - getConditionDescription Invalid condition id : LAN8742 Phy interface Condition cause : null
+2026-02-06 17:25:24,416 [WARN] PackLoader:240 - Cannot read IP mode file for STMicroelectronics.X-CUBE-AZRTOS-L4.2.0.0
+2026-02-06 17:25:24,418 [WARN] ConditionMgr:1044 - genDependencies : Invalid condition id : LAN8742 Phy interface Condition cause : null
+2026-02-06 17:25:24,419 [WARN] ConditionMgr:1044 - genDependencies : Invalid condition id : LAN8742 Phy interface Condition cause : null
+2026-02-06 17:25:24,419 [WARN] ConditionMgr:1044 - genDependencies : Invalid condition id : LAN8742 Phy interface Condition cause : null
+2026-02-06 17:25:24,425 [WARN] PackLoader:240 - Cannot read IP mode file for STMicroelectronics.X-CUBE-SFXS2LP1.4.0.0
+2026-02-06 17:25:24,431 [WARN] PackLoader:240 - Cannot read IP mode file for STMicroelectronics.X-CUBE-ST67W61.1.2.0
+2026-02-06 17:25:24,452 [WARN] PackLoader:240 - Cannot read IP mode file for STMicroelectronics.X-CUBE-AZRTOS-H7.3.3.0
+2026-02-06 17:25:24,470 [WARN] PackLoader:240 - Cannot read IP mode file for STMicroelectronics.X-CUBE-BLEMGR.4.1.0
+2026-02-06 17:25:24,485 [WARN] ConditionMgr:438 - getConditionDescription Invalid condition id : UX DEVICE CLASS RTOS Condition cause : null
+2026-02-06 17:25:24,486 [WARN] ConditionMgr:438 - getConditionDescription Invalid condition id : UX DEVICE CLASS RTOS Condition cause : null
+2026-02-06 17:25:24,489 [WARN] PackLoader:240 - Cannot read IP mode file for STMicroelectronics.X-CUBE-AZRTOS-WB.2.0.0
+2026-02-06 17:25:24,490 [WARN] ConditionMgr:1044 - genDependencies : Invalid condition id : UX DEVICE CLASS RTOS Condition cause : null
+2026-02-06 17:25:24,490 [WARN] ConditionMgr:1044 - genDependencies : Invalid condition id : UX DEVICE CLASS RTOS Condition cause : null
+2026-02-06 17:25:24,490 [WARN] ConditionMgr:1044 - genDependencies : Invalid condition id : UX DEVICE CLASS RTOS Condition cause : null
+2026-02-06 17:25:24,491 [WARN] ConditionMgr:1044 - genDependencies : Invalid condition id : UX DEVICE CLASS RTOS Condition cause : null
+2026-02-06 17:25:24,491 [WARN] ConditionMgr:1044 - genDependencies : Invalid condition id : UX DEVICE CLASS RTOS Condition cause : null
+2026-02-06 17:25:24,496 [WARN] PackLoader:240 - Cannot read IP mode file for STMicroelectronics.X-CUBE-GNSS1.7.0.1
+2026-02-06 17:25:24,518 [WARN] PackLoader:240 - Cannot read IP mode file for STMicroelectronics.X-CUBE-TOUCHGFX.4.25.0
+2026-02-06 17:25:24,524 [WARN] PackLoader:240 - Cannot read IP mode file for STMicroelectronics.FP-SNS-STBOX1.2.0.0
+2026-02-06 17:25:24,532 [WARN] PackLoader:240 - Cannot read IP mode file for STMicroelectronics.X-CUBE-STSE01.2.0.0
+2026-02-06 17:25:24,553 [WARN] PackLoader:240 - Cannot read IP mode file for STMicroelectronics.X-CUBE-SUBG2.5.0.0
+2026-02-06 17:25:24,592 [WARN] PackLoader:240 - Cannot read IP mode file for STMicroelectronics.X-CUBE-AZRTOS-H7RS.1.1.0
+2026-02-06 17:25:24,601 [WARN] PackLoader:240 - Cannot read IP mode file for Cesanta.I-CUBE-Mongoose.7.13.0
+2026-02-06 17:25:24,616 [WARN] PackLoader:240 - Cannot read IP mode file for STMicroelectronics.X-CUBE-AZRTOS-G4.2.0.0
+2026-02-06 17:25:24,633 [WARN] PackLoader:240 - Cannot read IP mode file for STMicroelectronics.X-CUBE-NFC7.2.0.0
+2026-02-06 17:25:24,644 [WARN] PackLoader:240 - Cannot read IP mode file for STMicroelectronics.X-CUBE-IPS.3.1.0
+2026-02-06 17:25:24,658 [WARN] PackLoader:240 - Cannot read IP mode file for STMicroelectronics.X-CUBE-ALS.1.0.2
+2026-02-06 17:25:24,662 [WARN] PackLoader:240 - Cannot read IP mode file for STMicroelectronics.X-CUBE-TOUCHGFX.4.24.2
+2026-02-06 17:25:24,669 [WARN] PackLoader:240 - Cannot read IP mode file for STMicroelectronics.X-CUBE-STSE01.1.0.0
+2026-02-06 17:25:24,673 [WARN] PackLoader:240 - Cannot read IP mode file for wolfSSL.I-CUBE-wolfTPM.3.4.0
+2026-02-06 17:25:24,678 [WARN] PackLoader:240 - Cannot read IP mode file for portGmbH.I-Cube-SoM-uGOAL.1.1.0
+2026-02-06 17:25:24,703 [WARN] PackLoader:240 - Cannot read IP mode file for STMicroelectronics.X-CUBE-AZRTOS-H7RS.1.0.0
+2026-02-06 17:25:24,717 [WARN] PackLoader:240 - Cannot read IP mode file for STMicroelectronics.X-CUBE-TOF1.3.4.2
+2026-02-06 17:25:24,734 [WARN] PackLoader:240 - Cannot read IP mode file for STMicroelectronics.X-CUBE-TOF1.3.4.3
+2026-02-06 17:25:24,742 [WARN] PackLoader:240 - Cannot read IP mode file for wolfSSL.I-CUBE-wolfSSH.1.4.17
+2026-02-06 17:25:24,756 [INFO] ThirdParty:978 - Integrity check success = true
+2026-02-06 17:25:24,756 [INFO] IntegrityCheckThread:100 - exiting critical section [integrity check]
+2026-02-06 17:25:24,756 [INFO] IntegrityCheckThread:103 - End integrity checks thread
+2026-02-06 17:25:25,691 [INFO] WebApp:169 - Instantiating new browser for Auth
+2026-02-06 17:25:27,099 [INFO] WebApp:463 - Apply proxy settings
+2026-02-06 17:25:27,122 [INFO] WebApp:508 - Chromium authenticates against Manually configured proxy
+2026-02-06 17:25:27,134 [INFO] WebApp:516 - Username used for proxy authentication:
+2026-02-06 17:25:27,173 [INFO] WebApp:900 - Register for checkConnection events
+2026-02-06 17:25:27,174 [INFO] WebApp:463 - Apply proxy settings
+2026-02-06 17:25:27,179 [INFO] WebApp:508 - Chromium authenticates against Manually configured proxy
+2026-02-06 17:25:27,179 [INFO] WebApp:516 - Username used for proxy authentication:
+2026-02-06 17:25:27,331 [INFO] WebApp:225 - Starting web application
+2026-02-06 17:25:27,332 [INFO] WebApp:593 - Web application path used /Applications/STM32CubeIDE.app/Contents/Eclipse/plugins/com.st.stm32cube.common.mx_6.15.0.202507011659/db/plugins/mcufinder/reactClient1/index.html
+2026-02-06 17:25:27,699 [INFO] WebApp:191 - Connection restablished
+2026-02-06 17:25:28,031 [INFO] UserAuth:487 - Internet connection configuration mode: 1
diff --git a/Ganesha_II_V2/.metadata/.lock b/Ganesha_II_V2/.metadata/.lock
new file mode 100644
index 0000000..e69de29
diff --git a/Ganesha_II_V2/.metadata/.log b/Ganesha_II_V2/.metadata/.log
new file mode 100644
index 0000000..fcc5b6d
--- /dev/null
+++ b/Ganesha_II_V2/.metadata/.log
@@ -0,0 +1,61 @@
+!SESSION 2026-02-06 17:24:47.422 -----------------------------------------------
+eclipse.buildId=Version 1.19.0
+java.version=21.0.3
+java.vendor=Eclipse Adoptium
+BootLoader constants: OS=macosx, ARCH=x86_64, WS=cocoa, NL=en_US
+Framework arguments: -keyring /Users/akshitgarg/.eclipse_keyring
+Command-line arguments: -os macosx -ws cocoa -arch x86_64 -keyring /Users/akshitgarg/.eclipse_keyring
+
+!ENTRY org.eclipse.egit.core 1 0 2026-02-06 17:25:07.486
+!MESSAGE Using Apache MINA sshd as ssh client.
+
+!ENTRY com.st.stm32cube.ide.mcu.informationcenter 4 4 2026-02-06 17:25:11.357
+!MESSAGE CubeMX plugin appears to be active, Log4j initialization might be too late.
+
+!ENTRY com.st.stm32cube.ide.mcu.informationcenter 1 1 2026-02-06 17:25:11.357
+!MESSAGE Log4j2 initialized with config file /Users/akshitgarg/code/RRPL/Ganesha/Ganesha_vII/Ganesha_II_V2/.metadata/.log4j2.xml
+
+!ENTRY com.st.stm32cube.ide.mcu.ide 1 1 2026-02-06 17:25:15.751
+!MESSAGE Started RMI Server, listening on port 41337
+
+!ENTRY org.eclipse.equinox.p2.metadata.repository 4 0 2026-02-06 17:25:51.350
+!MESSAGE Unexpected error loading extension: org.eclipse.equinox.p2.metadata.repository.compositeRepository
+!STACK 0
+java.lang.IllegalStateException: bundle org.eclipse.equinox.p2.repository is not started
+ at org.eclipse.equinox.internal.p2.repository.Activator.getContext(Activator.java:65)
+ at org.eclipse.equinox.internal.p2.repository.helpers.AbstractRepositoryManager.restoreFromSystemProperty(AbstractRepositoryManager.java:1031)
+ at org.eclipse.equinox.internal.p2.repository.helpers.AbstractRepositoryManager.restoreRepositories(AbstractRepositoryManager.java:1051)
+ at org.eclipse.equinox.internal.p2.repository.helpers.AbstractRepositoryManager.getRepositoryProperty(AbstractRepositoryManager.java:583)
+ at org.eclipse.equinox.internal.p2.repository.helpers.AbstractRepositoryManager.loadRepository(AbstractRepositoryManager.java:715)
+ at org.eclipse.equinox.internal.p2.metadata.repository.MetadataRepositoryManager.loadRepository(MetadataRepositoryManager.java:110)
+ at org.eclipse.equinox.internal.p2.metadata.repository.MetadataRepositoryManager.loadRepository(MetadataRepositoryManager.java:105)
+ at org.eclipse.equinox.internal.p2.metadata.repository.CompositeMetadataRepository.addChild(CompositeMetadataRepository.java:161)
+ at org.eclipse.equinox.internal.p2.metadata.repository.CompositeMetadataRepository.(CompositeMetadataRepository.java:93)
+ at org.eclipse.equinox.internal.p2.metadata.repository.CompositeMetadataRepositoryFactory.load(CompositeMetadataRepositoryFactory.java:124)
+ at org.eclipse.equinox.internal.p2.metadata.repository.MetadataRepositoryManager.factoryLoad(MetadataRepositoryManager.java:63)
+ at org.eclipse.equinox.internal.p2.repository.helpers.AbstractRepositoryManager.loadRepository(AbstractRepositoryManager.java:799)
+ at org.eclipse.equinox.internal.p2.repository.helpers.AbstractRepositoryManager.loadRepository(AbstractRepositoryManager.java:697)
+ at org.eclipse.equinox.internal.p2.metadata.repository.MetadataRepositoryManager.loadRepository(MetadataRepositoryManager.java:110)
+ at org.eclipse.equinox.internal.p2.metadata.repository.MetadataRepositoryManager.loadRepository(MetadataRepositoryManager.java:105)
+ at org.eclipse.equinox.internal.p2.updatechecker.UpdateChecker.getAvailableRepositories(UpdateChecker.java:164)
+ at org.eclipse.equinox.internal.p2.updatechecker.UpdateChecker.checkForUpdates(UpdateChecker.java:144)
+ at org.eclipse.equinox.internal.p2.updatechecker.UpdateChecker$UpdateCheckThread.run(UpdateChecker.java:83)
+
+!ENTRY org.eclipse.equinox.p2.metadata.repository 4 1000 2026-02-06 17:25:51.352
+!MESSAGE No repository found at https://sw-center.st.com/stm32cubeide/openstlinux/updatesite1.
+
+!ENTRY org.eclipse.equinox.p2.updatechecker 4 0 2026-02-06 17:25:51.352
+!MESSAGE Exception in update check thread
+!STACK 0
+java.lang.IllegalStateException: bundle org.eclipse.equinox.p2.repository is not started
+ at org.eclipse.equinox.internal.p2.repository.Activator.getContext(Activator.java:65)
+ at org.eclipse.equinox.internal.p2.repository.helpers.AbstractRepositoryManager.getPreferences(AbstractRepositoryManager.java:518)
+ at org.eclipse.equinox.internal.p2.repository.helpers.AbstractRepositoryManager.remember(AbstractRepositoryManager.java:914)
+ at org.eclipse.equinox.internal.p2.repository.helpers.AbstractRepositoryManager.addRepository(AbstractRepositoryManager.java:178)
+ at org.eclipse.equinox.internal.p2.repository.helpers.AbstractRepositoryManager.addRepository(AbstractRepositoryManager.java:163)
+ at org.eclipse.equinox.internal.p2.repository.helpers.AbstractRepositoryManager.loadRepository(AbstractRepositoryManager.java:684)
+ at org.eclipse.equinox.internal.p2.metadata.repository.MetadataRepositoryManager.loadRepository(MetadataRepositoryManager.java:110)
+ at org.eclipse.equinox.internal.p2.metadata.repository.MetadataRepositoryManager.loadRepository(MetadataRepositoryManager.java:105)
+ at org.eclipse.equinox.internal.p2.updatechecker.UpdateChecker.getAvailableRepositories(UpdateChecker.java:164)
+ at org.eclipse.equinox.internal.p2.updatechecker.UpdateChecker.checkForUpdates(UpdateChecker.java:144)
+ at org.eclipse.equinox.internal.p2.updatechecker.UpdateChecker$UpdateCheckThread.run(UpdateChecker.java:83)
diff --git a/Ganesha_II_V2/.metadata/.log4j2.xml b/Ganesha_II_V2/.metadata/.log4j2.xml
new file mode 100644
index 0000000..b4d4768
--- /dev/null
+++ b/Ganesha_II_V2/.metadata/.log4j2.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Ganesha_II_V2/.metadata/.plugins/com.st.stm32cube.ide.mcu.informationcenter/2.3.200.202507011752 b/Ganesha_II_V2/.metadata/.plugins/com.st.stm32cube.ide.mcu.informationcenter/2.3.200.202507011752
new file mode 100644
index 0000000..e69de29
diff --git a/Ganesha_II_V2/.metadata/.plugins/org.eclipse.cdt.core/.log b/Ganesha_II_V2/.metadata/.plugins/org.eclipse.cdt.core/.log
new file mode 100644
index 0000000..37fa472
--- /dev/null
+++ b/Ganesha_II_V2/.metadata/.plugins/org.eclipse.cdt.core/.log
@@ -0,0 +1 @@
+*** SESSION Feb 06, 2026 17:25:09.473 ------------------------------------------
diff --git a/Ganesha_II_V2/.metadata/.plugins/org.eclipse.cdt.make.core/specs.c b/Ganesha_II_V2/.metadata/.plugins/org.eclipse.cdt.make.core/specs.c
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/Ganesha_II_V2/.metadata/.plugins/org.eclipse.cdt.make.core/specs.c
@@ -0,0 +1 @@
+
diff --git a/Ganesha_II_V2/.metadata/.plugins/org.eclipse.cdt.make.core/specs.cpp b/Ganesha_II_V2/.metadata/.plugins/org.eclipse.cdt.make.core/specs.cpp
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/Ganesha_II_V2/.metadata/.plugins/org.eclipse.cdt.make.core/specs.cpp
@@ -0,0 +1 @@
+
diff --git a/Ganesha_II_V2/.metadata/.plugins/org.eclipse.cdt.make.ui/dialog_settings.xml b/Ganesha_II_V2/.metadata/.plugins/org.eclipse.cdt.make.ui/dialog_settings.xml
new file mode 100644
index 0000000..1cb58a4
--- /dev/null
+++ b/Ganesha_II_V2/.metadata/.plugins/org.eclipse.cdt.make.ui/dialog_settings.xml
@@ -0,0 +1,5 @@
+
+
diff --git a/Ganesha_II_V2/.metadata/.plugins/org.eclipse.core.resources/.root/.indexes/history.version b/Ganesha_II_V2/.metadata/.plugins/org.eclipse.core.resources/.root/.indexes/history.version
new file mode 100644
index 0000000..25cb955
--- /dev/null
+++ b/Ganesha_II_V2/.metadata/.plugins/org.eclipse.core.resources/.root/.indexes/history.version
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/Ganesha_II_V2/.metadata/.plugins/org.eclipse.core.resources/.root/.indexes/properties.version b/Ganesha_II_V2/.metadata/.plugins/org.eclipse.core.resources/.root/.indexes/properties.version
new file mode 100644
index 0000000..6b2aaa7
--- /dev/null
+++ b/Ganesha_II_V2/.metadata/.plugins/org.eclipse.core.resources/.root/.indexes/properties.version
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/Ganesha_II_V2/.metadata/.plugins/org.eclipse.core.resources/.root/1.tree b/Ganesha_II_V2/.metadata/.plugins/org.eclipse.core.resources/.root/1.tree
new file mode 100644
index 0000000..14482a9
Binary files /dev/null and b/Ganesha_II_V2/.metadata/.plugins/org.eclipse.core.resources/.root/1.tree differ
diff --git a/Ganesha_II_V2/.metadata/.plugins/org.eclipse.core.resources/.safetable/org.eclipse.core.resources b/Ganesha_II_V2/.metadata/.plugins/org.eclipse.core.resources/.safetable/org.eclipse.core.resources
new file mode 100644
index 0000000..90bc78b
Binary files /dev/null and b/Ganesha_II_V2/.metadata/.plugins/org.eclipse.core.resources/.safetable/org.eclipse.core.resources differ
diff --git a/Ganesha_II_V2/.metadata/.plugins/org.eclipse.core.runtime/.settings/com.st.stm32cube.ide.mcu.ide.oss.prefs b/Ganesha_II_V2/.metadata/.plugins/org.eclipse.core.runtime/.settings/com.st.stm32cube.ide.mcu.ide.oss.prefs
new file mode 100644
index 0000000..3a4957f
--- /dev/null
+++ b/Ganesha_II_V2/.metadata/.plugins/org.eclipse.core.runtime/.settings/com.st.stm32cube.ide.mcu.ide.oss.prefs
@@ -0,0 +1,2 @@
+eclipse.preferences.version=1
+project_presentation/setHierarchicalMode=false
diff --git a/Ganesha_II_V2/.metadata/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.cdt.debug.core.prefs b/Ganesha_II_V2/.metadata/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.cdt.debug.core.prefs
new file mode 100644
index 0000000..2762d40
--- /dev/null
+++ b/Ganesha_II_V2/.metadata/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.cdt.debug.core.prefs
@@ -0,0 +1,2 @@
+eclipse.preferences.version=1
+org.eclipse.cdt.debug.core.cDebug.default_source_containers=\n\n \n \n \n \n \n\n
diff --git a/Ganesha_II_V2/.metadata/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.cdt.ui.prefs b/Ganesha_II_V2/.metadata/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.cdt.ui.prefs
new file mode 100644
index 0000000..5e2da66
--- /dev/null
+++ b/Ganesha_II_V2/.metadata/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.cdt.ui.prefs
@@ -0,0 +1,4 @@
+eclipse.preferences.version=1
+spelling_locale_initialized=true
+useAnnotationsPrefPage=true
+useQuickDiffPrefPage=true
diff --git a/Ganesha_II_V2/.metadata/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.core.resources.prefs b/Ganesha_II_V2/.metadata/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.core.resources.prefs
new file mode 100644
index 0000000..dffc6b5
--- /dev/null
+++ b/Ganesha_II_V2/.metadata/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.core.resources.prefs
@@ -0,0 +1,2 @@
+eclipse.preferences.version=1
+version=1
diff --git a/Ganesha_II_V2/.metadata/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.debug.core.prefs b/Ganesha_II_V2/.metadata/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.debug.core.prefs
new file mode 100644
index 0000000..dd78b8d
--- /dev/null
+++ b/Ganesha_II_V2/.metadata/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.debug.core.prefs
@@ -0,0 +1,5 @@
+//org.eclipse.debug.core.PREFERRED_DELEGATES/org.eclipse.cdt.launch.applicationLaunchType=org.eclipse.cdt.dsf.gdb.launch.localCLaunch,debug,;org.eclipse.cdt.cdi.launch.localCLaunch,run,;
+//org.eclipse.debug.core.PREFERRED_DELEGATES/org.eclipse.cdt.launch.attachLaunchType=org.eclipse.cdt.dsf.gdb.launch.attachCLaunch,debug,;
+//org.eclipse.debug.core.PREFERRED_DELEGATES/org.eclipse.cdt.launch.postmortemLaunchType=org.eclipse.cdt.dsf.gdb.launch.coreCLaunch,debug,;
+//org.eclipse.debug.core.PREFERRED_DELEGATES/org.eclipse.cdt.launch.remoteApplicationLaunchType=org.eclipse.rse.remotecdt.dsf.debug,debug,;
+eclipse.preferences.version=1
diff --git a/Ganesha_II_V2/.metadata/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.debug.ui.prefs b/Ganesha_II_V2/.metadata/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.debug.ui.prefs
new file mode 100644
index 0000000..6e6c73f
--- /dev/null
+++ b/Ganesha_II_V2/.metadata/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.debug.ui.prefs
@@ -0,0 +1,2 @@
+eclipse.preferences.version=1
+org.eclipse.debug.ui.PREF_LAUNCH_PERSPECTIVES=\n\n
diff --git a/Ganesha_II_V2/.metadata/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.ui.ide.prefs b/Ganesha_II_V2/.metadata/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.ui.ide.prefs
new file mode 100644
index 0000000..e4533b1
--- /dev/null
+++ b/Ganesha_II_V2/.metadata/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.ui.ide.prefs
@@ -0,0 +1,4 @@
+eclipse.preferences.version=1
+platformState=786064110972819
+quickStart=false
+tipsAndTricks=true
diff --git a/Ganesha_II_V2/.metadata/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.ui.navigator.prefs b/Ganesha_II_V2/.metadata/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.ui.navigator.prefs
new file mode 100644
index 0000000..af564f1
--- /dev/null
+++ b/Ganesha_II_V2/.metadata/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.ui.navigator.prefs
@@ -0,0 +1,2 @@
+eclipse.preferences.version=1
+org.eclipse.ui.navigator.ProjectExplorer.filterActivation=\:org.eclipse.ui.navigator.resources.filters.startsWithDot\:org.eclipse.cdt.ui.navigator.filters.AnonymousStructFilter\:org.eclipse.cdt.ui.navigator.filters.AbsentTranslationUnitFilter\:org.eclipse.ui.navigator.resources.nested.HideTopLevelProjectIfNested\:org.eclipse.ui.navigator.resources.nested.HideFolderWhenProjectIsShownAsNested\:org.eclipse.cdt.ui.navigator.filters.ForwardDeclarationFilter\:
diff --git a/Ganesha_II_V2/.metadata/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.ui.prefs b/Ganesha_II_V2/.metadata/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.ui.prefs
new file mode 100644
index 0000000..08076f2
--- /dev/null
+++ b/Ganesha_II_V2/.metadata/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.ui.prefs
@@ -0,0 +1,2 @@
+eclipse.preferences.version=1
+showIntro=false
diff --git a/Ganesha_II_V2/.metadata/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.ui.workbench.prefs b/Ganesha_II_V2/.metadata/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.ui.workbench.prefs
new file mode 100644
index 0000000..f633373
--- /dev/null
+++ b/Ganesha_II_V2/.metadata/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.ui.workbench.prefs
@@ -0,0 +1,12 @@
+//org.eclipse.ui.commands/state/com.st.stm32cube.ide.mcu.buildanalyzer.showstate/org.eclipse.ui.commands.radioState=human
+//org.eclipse.ui.commands/state/org.eclipse.ui.navigator.resources.nested.changeProjectPresentation/org.eclipse.ui.commands.radioState=false
+eclipse.preferences.version=1
+org.eclipse.ui.workbench.ACTIVE_NOFOCUS_TAB_BG_END=41,41,41
+org.eclipse.ui.workbench.ACTIVE_NOFOCUS_TAB_BG_START=43,44,45
+org.eclipse.ui.workbench.ACTIVE_NOFOCUS_TAB_TEXT_COLOR=204,204,204
+org.eclipse.ui.workbench.ACTIVE_TAB_BG_END=41,41,41
+org.eclipse.ui.workbench.ACTIVE_TAB_BG_START=43,44,45
+org.eclipse.ui.workbench.ACTIVE_TAB_TEXT_COLOR=221,221,221
+org.eclipse.ui.workbench.INACTIVE_TAB_BG_END=49,53,56
+org.eclipse.ui.workbench.INACTIVE_TAB_BG_START=59,64,66
+org.eclipse.ui.workbench.INACTIVE_TAB_TEXT_COLOR=187,187,187
diff --git a/Ganesha_II_V2/.metadata/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.urischeme.prefs b/Ganesha_II_V2/.metadata/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.urischeme.prefs
new file mode 100644
index 0000000..855d634
--- /dev/null
+++ b/Ganesha_II_V2/.metadata/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.urischeme.prefs
@@ -0,0 +1,2 @@
+eclipse.preferences.version=1
+processedSchemes=,eclipse+command,eclipse+mpc
diff --git a/Ganesha_II_V2/.metadata/.plugins/org.eclipse.e4.workbench/workbench.xmi b/Ganesha_II_V2/.metadata/.plugins/org.eclipse.e4.workbench/workbench.xmi
new file mode 100644
index 0000000..eafe549
--- /dev/null
+++ b/Ganesha_II_V2/.metadata/.plugins/org.eclipse.e4.workbench/workbench.xmi
@@ -0,0 +1,2256 @@
+
+
+
+ activeSchemeId:org.eclipse.ui.defaultAcceleratorConfiguration
+
+
+
+
+
+
+
+ topLevel
+ shellMaximized
+
+
+
+
+ persp.actionSet:com.st.stm32cube.ide.mcu.informationcenter.actionSet3
+ persp.actionSet:org.eclipse.ui.cheatsheets.actionSet
+ persp.actionSet:org.eclipse.search.searchActionSet
+ persp.actionSet:org.eclipse.text.quicksearch.actionSet
+ persp.actionSet:org.eclipse.ui.edit.text.actionSet.annotationNavigation
+ persp.actionSet:org.eclipse.ui.edit.text.actionSet.navigation
+ persp.actionSet:org.eclipse.ui.edit.text.actionSet.convertLineDelimitersTo
+ persp.actionSet:org.eclipse.ui.externaltools.ExternalToolsSet
+ persp.actionSet:org.eclipse.ui.actionSet.keyBindings
+ persp.actionSet:org.eclipse.ui.actionSet.openFiles
+ persp.actionSet:org.eclipse.cdt.ui.SearchActionSet
+ persp.actionSet:org.eclipse.cdt.ui.CElementCreationActionSet
+ persp.actionSet:org.eclipse.ui.NavigateActionSet
+ persp.viewSC:org.eclipse.ui.console.ConsoleView
+ persp.viewSC:org.eclipse.search.ui.views.SearchView
+ persp.viewSC:org.eclipse.ui.views.ContentOutline
+ persp.viewSC:org.eclipse.ui.views.ProblemView
+ persp.viewSC:org.eclipse.cdt.ui.CView
+ persp.viewSC:org.eclipse.ui.views.PropertySheet
+ persp.viewSC:org.eclipse.ui.views.TaskList
+ persp.newWizSC:org.eclipse.cdt.ui.wizards.ConvertToMakeWizard
+ persp.newWizSC:org.eclipse.cdt.ui.wizards.NewMakeFromExisting
+ persp.newWizSC:org.eclipse.cdt.ui.wizard.project
+ persp.newWizSC:org.eclipse.cdt.ui.wizards.NewSourceFolderCreationWizard
+ persp.newWizSC:org.eclipse.cdt.ui.wizards.NewFolderCreationWizard
+ persp.newWizSC:org.eclipse.cdt.ui.wizards.NewSourceFileCreationWizard
+ persp.newWizSC:org.eclipse.cdt.ui.wizards.NewHeaderFileCreationWizard
+ persp.newWizSC:org.eclipse.cdt.ui.wizards.NewFileCreationWizard
+ persp.newWizSC:org.eclipse.cdt.ui.wizards.NewClassCreationWizard
+ persp.perspSC:org.eclipse.debug.ui.DebugPerspective
+ persp.perspSC:org.eclipse.team.ui.TeamSynchronizingPerspective
+ persp.actionSet:org.eclipse.debug.ui.launchActionSet
+ persp.actionSet:org.eclipse.cdt.ui.buildConfigActionSet
+ persp.actionSet:org.eclipse.cdt.ui.NavigationActionSet
+ persp.actionSet:org.eclipse.cdt.ui.OpenActionSet
+ persp.actionSet:org.eclipse.cdt.ui.CodingActionSet
+ persp.actionSet:org.eclipse.ui.edit.text.actionSet.presentation
+ persp.showIn:org.eclipse.cdt.ui.includeBrowser
+ persp.showIn:org.eclipse.cdt.ui.CView
+ persp.showIn:org.eclipse.ui.navigator.ProjectExplorer
+ persp.viewSC:org.eclipse.ui.navigator.ProjectExplorer
+ persp.viewSC:org.eclipse.cdt.ui.includeBrowser
+ persp.actionSet:org.eclipse.debug.ui.breakpointActionSet
+ persp.newWizSC:com.st.stm32cube.common.projectcreation.ui.stm32projectwizard
+ persp.newWizSC:com.st.stm32cube.common.projectcreation.ui.stm32projectfromiocwizard
+ persp.viewSC:org.eclipse.cdt.make.ui.views.MakeView
+ persp.actionSet:org.eclipse.cdt.make.ui.makeTargetActionSet
+ persp.showIn:org.eclipse.cdt.codan.internal.ui.views.ProblemDetails
+ persp.viewSC:org.eclipse.cdt.codan.internal.ui.views.ProblemDetails
+ persp.viewSC:com.st.stm32cube.ide.mcu.buildanalyzer.view
+ persp.viewSC:com.st.stm32cube.ide.mcu.stackanalyzer.stackanalyzer.view
+ persp.newWizSC:com.st.stm32cube.ide.cmake.newwizard
+ persp.viewSC:com.st.stm32cube.ide.mcu.cyclomaticcomplexity.view
+ persp.viewSC:com.st.stm32cube.ide.mcu.sfrview
+
+
+
+ View
+ categoryTag:General
+
+
+ View
+ categoryTag:C/C++
+
+
+ View
+ categoryTag:General
+
+
+
+
+
+
+
+ View
+ categoryTag:General
+
+
+ View
+ categoryTag:General
+
+
+ View
+ categoryTag:Make
+
+
+
+
+
+ active
+
+ View
+ categoryTag:General
+
+
+ View
+ categoryTag:General
+
+
+ View
+ categoryTag:General
+
+
+ View
+ categoryTag:General
+
+
+
+
+ View
+ categoryTag:C/C++
+
+
+ View
+ categoryTag:C/C++
+
+
+ View
+ categoryTag:C/C++
+
+
+
+
+
+
+
+
+
+ View
+ categoryTag:Help
+
+
+ View
+ categoryTag:General
+
+
+ View
+ categoryTag:Help
+
+
+
+
+
+
+ View
+ categoryTag:Help
+
+
+
+
+
+ View
+ categoryTag:General
+
+ ViewMenu
+ menuContribution:menu
+
+
+
+
+
+
+ View
+ categoryTag:Help
+
+
+
+ EditorStack
+ org.eclipse.e4.primaryDataStack
+
+
+
+
+
+
+ View
+ categoryTag:General
+
+ ViewMenu
+ menuContribution:menu
+
+
+
+
+
+
+ View
+ categoryTag:C/C++
+
+
+
+
+ View
+ categoryTag:General
+
+
+
+
+
+ View
+ categoryTag:General
+ active
+ activeOnClose
+
+ ViewMenu
+ menuContribution:menu
+
+
+
+
+
+
+
+ View
+ categoryTag:General
+
+ ViewMenu
+ menuContribution:menu
+
+
+
+
+
+
+
+ View
+ categoryTag:General
+
+ ViewMenu
+ menuContribution:menu
+
+
+
+
+
+
+
+ View
+ categoryTag:General
+
+ ViewMenu
+ menuContribution:menu
+
+
+
+
+
+
+
+ View
+ categoryTag:General
+
+ ViewMenu
+ menuContribution:menu
+
+
+
+
+
+
+ View
+ categoryTag:General
+
+
+
+
+
+ View
+ categoryTag:Make
+
+ ViewMenu
+ menuContribution:menu
+
+
+
+
+
+
+
+ View
+ categoryTag:C/C++
+
+ ViewMenu
+ menuContribution:menu
+
+
+
+
+
+
+
+ View
+ categoryTag:C/C++
+
+ ViewMenu
+ menuContribution:menu
+
+
+
+
+
+
+
+ View
+ categoryTag:C/C++
+
+ ViewMenu
+ menuContribution:menu
+
+
+
+
+
+ toolbarSeparator
+
+
+
+ Draggable
+
+
+
+ toolbarSeparator
+
+
+
+ Draggable
+
+
+
+
+ toolbarSeparator
+
+
+
+ Draggable
+
+
+ Draggable
+
+
+ Draggable
+
+
+ Draggable
+
+
+ toolbarSeparator
+
+
+
+ Draggable
+
+
+
+ toolbarSeparator
+
+
+
+ toolbarSeparator
+
+
+
+ Draggable
+
+
+ stretch
+ SHOW_RESTORE_MENU
+
+
+ Draggable
+ HIDEABLE
+ SHOW_RESTORE_MENU
+
+
+
+
+ stretch
+
+
+ Draggable
+
+
+ Draggable
+
+
+
+
+ TrimStack
+ Draggable
+
+
+
+
+
+
+
+
+
+
+
+
+ platform:cocoa
+
+
+ platform:cocoa
+
+
+
+
+
+ platform:cocoa
+
+
+ platform:cocoa
+
+
+
+
+
+ platform:cocoa
+
+
+
+
+
+
+
+
+
+ platform:cocoa
+
+
+
+ platform:cocoa
+
+
+
+ platform:cocoa
+
+
+
+ platform:cocoa
+
+
+ platform:cocoa
+
+
+
+ platform:cocoa
+
+
+
+ platform:cocoa
+
+
+
+ platform:cocoa
+
+
+
+ platform:cocoa
+
+
+
+ platform:cocoa
+
+
+
+ platform:cocoa
+
+
+
+
+
+
+ platform:cocoa
+
+
+
+
+
+
+
+
+ platform:cocoa
+
+
+ platform:cocoa
+
+
+ platform:cocoa
+
+
+ platform:cocoa
+
+
+
+
+
+
+
+
+ platform:cocoa
+
+
+ platform:cocoa
+
+
+
+
+
+
+
+
+ platform:cocoa
+
+
+ platform:cocoa
+
+
+ platform:cocoa
+
+
+
+
+
+
+
+
+
+
+
+
+
+ platform:cocoa
+
+
+ platform:cocoa
+
+
+
+
+
+ platform:cocoa
+
+
+
+ platform:cocoa
+
+
+
+
+ platform:cocoa
+
+
+
+ platform:cocoa
+
+
+
+
+
+
+
+ platform:cocoa
+
+
+ platform:cocoa
+
+
+
+ platform:cocoa
+
+
+
+
+
+ platform:cocoa
+
+
+ platform:cocoa
+
+
+ platform:cocoa
+
+
+ platform:cocoa
+
+
+ platform:cocoa
+
+
+ platform:cocoa
+
+
+ platform:cocoa
+
+
+
+
+
+
+
+
+
+
+
+
+ platform:cocoa
+
+
+
+
+ platform:cocoa
+
+
+ platform:cocoa
+
+
+
+
+
+ platform:cocoa
+
+
+ platform:cocoa
+
+
+ platform:cocoa
+
+
+
+
+
+
+
+
+
+
+
+
+
+ platform:cocoa
+
+
+
+
+
+
+
+
+
+
+
+
+ platform:cocoa
+
+
+ platform:cocoa
+
+
+ platform:cocoa
+
+
+
+ platform:cocoa
+
+
+ platform:cocoa
+
+
+ platform:cocoa
+
+
+
+
+ platform:cocoa
+
+
+
+
+ platform:cocoa
+
+
+ platform:cocoa
+
+
+
+ platform:cocoa
+
+
+ platform:cocoa
+
+
+ platform:cocoa
+
+
+ platform:cocoa
+
+
+
+ platform:cocoa
+
+
+
+
+ platform:cocoa
+
+
+
+
+
+
+
+
+
+
+
+ platform:cocoa
+
+
+
+
+ platform:cocoa
+
+
+
+
+
+
+ platform:cocoa
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ platform:cocoa
+
+
+ platform:cocoa
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Editor
+ removeOnHide
+
+
+
+
+ View
+ categoryTag:Device Configuration Tool
+
+
+
+
+ View
+ categoryTag:C/C++
+
+
+
+
+ View
+ categoryTag:C/C++
+
+
+
+
+ View
+ categoryTag:SWV
+
+
+
+
+ View
+ categoryTag:SWV
+
+
+
+
+ View
+ categoryTag:SWV
+
+
+
+
+ View
+ categoryTag:SWV
+
+
+
+
+ View
+ categoryTag:SWV
+
+
+
+
+ View
+ categoryTag:SWV
+
+
+
+
+ View
+ categoryTag:Debug
+
+
+
+
+ View
+ categoryTag:FreeRTOS
+
+
+
+
+ View
+ categoryTag:FreeRTOS
+
+
+
+
+ View
+ categoryTag:FreeRTOS
+
+
+
+
+ View
+ categoryTag:FreeRTOS
+
+
+
+
+ View
+ categoryTag:Debug
+
+
+
+
+ View
+ categoryTag:Debug
+
+
+
+
+ View
+ categoryTag:C/C++
+
+
+
+
+ View
+ categoryTag:Other
+
+
+
+
+ View
+ categoryTag:ThreadX
+
+
+
+
+ View
+ categoryTag:ThreadX
+
+
+
+
+ View
+ categoryTag:ThreadX
+
+
+
+
+ View
+ categoryTag:ThreadX
+
+
+
+
+ View
+ categoryTag:ThreadX
+
+
+
+
+ View
+ categoryTag:ThreadX
+
+
+
+
+ View
+ categoryTag:ThreadX
+
+
+
+
+ View
+ categoryTag:ThreadX
+
+
+
+
+ View
+ categoryTag:C/C++
+
+
+
+
+ View
+ categoryTag:Debug
+
+
+
+
+ View
+ categoryTag:Debug
+
+
+
+
+ View
+ categoryTag:Debug
+
+
+
+
+ View
+ categoryTag:Debug
+
+
+
+
+ View
+ categoryTag:Debug
+
+
+
+
+ View
+ categoryTag:Debug
+
+
+
+
+ View
+ categoryTag:Debug
+
+
+
+
+ View
+ categoryTag:Debug
+
+
+
+
+ View
+ categoryTag:Make
+
+
+
+
+ View
+ categoryTag:C/C++
+
+
+
+
+ View
+ categoryTag:C/C++
+
+
+
+
+ View
+ categoryTag:C/C++
+
+
+
+
+ View
+ categoryTag:C/C++
+
+
+
+
+ View
+ categoryTag:C/C++
+
+
+
+
+ View
+ categoryTag:General
+
+
+
+
+ View
+ categoryTag:Debug
+
+
+
+
+ View
+ categoryTag:Debug
+
+
+
+
+ View
+ categoryTag:Debug
+
+
+
+
+ View
+ categoryTag:Debug
+
+
+
+
+ View
+ categoryTag:Debug
+
+
+
+
+ View
+ categoryTag:Debug
+
+
+
+
+ View
+ categoryTag:Debug
+
+
+ View
+ categoryTag:Debug
+
+
+
+
+ View
+ categoryTag:Help
+
+
+
+
+ View
+ categoryTag:Connections
+
+
+
+
+ View
+ categoryTag:General
+
+
+
+
+ View
+ categoryTag:Version Control (Team)
+
+
+
+
+ View
+ categoryTag:Version Control (Team)
+
+
+
+
+ View
+ categoryTag:General
+
+
+
+
+ View
+ categoryTag:General
+
+
+
+
+ View
+ categoryTag:Help
+
+
+
+
+ View
+ categoryTag:General
+
+
+
+
+ View
+ categoryTag:General
+
+
+
+
+ View
+ categoryTag:General
+
+
+
+
+ View
+ categoryTag:General
+
+
+
+
+ View
+ categoryTag:General
+
+
+
+
+ View
+ categoryTag:General
+
+
+
+
+ View
+ categoryTag:General
+
+
+
+
+ View
+ categoryTag:General
+
+
+
+
+ View
+ categoryTag:General
+
+
+
+
+ View
+ categoryTag:General
+
+
+
+
+ View
+ categoryTag:General
+
+
+
+
+ View
+ categoryTag:Git
+
+
+
+
+ View
+ categoryTag:Git
+
+
+
+
+ View
+ categoryTag:Git
+
+
+
+
+ View
+ categoryTag:Git
+ NoRestore
+
+
+
+
+ View
+ categoryTag:Git
+
+
+
+ glue
+ move_after:PerspectiveSpacer
+ SHOW_RESTORE_MENU
+
+
+ move_after:Spacer Glue
+ HIDEABLE
+ SHOW_RESTORE_MENU
+
+
+ glue
+ move_after:SearchField
+ SHOW_RESTORE_MENU
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Ganesha_II_V2/.metadata/.plugins/org.eclipse.ui.ide/dialog_settings.xml b/Ganesha_II_V2/.metadata/.plugins/org.eclipse.ui.ide/dialog_settings.xml
new file mode 100644
index 0000000..e62602e
--- /dev/null
+++ b/Ganesha_II_V2/.metadata/.plugins/org.eclipse.ui.ide/dialog_settings.xml
@@ -0,0 +1,19 @@
+
+
diff --git a/Ganesha_II_V2/.metadata/.plugins/org.eclipse.ui.workbench/dialog_settings.xml b/Ganesha_II_V2/.metadata/.plugins/org.eclipse.ui.workbench/dialog_settings.xml
new file mode 100644
index 0000000..5ca0b77
--- /dev/null
+++ b/Ganesha_II_V2/.metadata/.plugins/org.eclipse.ui.workbench/dialog_settings.xml
@@ -0,0 +1,3 @@
+
+
diff --git a/Ganesha_II_V2/.metadata/.plugins/org.eclipse.ui.workbench/workingsets.xml b/Ganesha_II_V2/.metadata/.plugins/org.eclipse.ui.workbench/workingsets.xml
new file mode 100644
index 0000000..874df77
--- /dev/null
+++ b/Ganesha_II_V2/.metadata/.plugins/org.eclipse.ui.workbench/workingsets.xml
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/Ganesha_II_V2/.metadata/version.ini b/Ganesha_II_V2/.metadata/version.ini
new file mode 100644
index 0000000..16e06ee
--- /dev/null
+++ b/Ganesha_II_V2/.metadata/version.ini
@@ -0,0 +1,3 @@
+#Fri Feb 06 17:25:06 EST 2026
+org.eclipse.core.runtime=2
+org.eclipse.platform=4.33.0.v20240903-0240
diff --git a/Ganesha_II_V2/.mxproject b/Ganesha_II_V2/.mxproject
index 3f4d623..dabe201 100644
--- a/Ganesha_II_V2/.mxproject
+++ b/Ganesha_II_V2/.mxproject
@@ -1,25 +1,42 @@
[PreviousLibFiles]
-LibFiles=Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_cortex.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_ll_cortex.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_crc.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_crc_ex.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_ll_crc.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_rcc.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_rcc_ex.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_ll_bus.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_ll_rcc.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_ll_crs.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_ll_system.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_ll_utils.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_flash.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_flash_ex.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_gpio.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_gpio_ex.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_ll_gpio.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_hsem.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_ll_hsem.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_dma.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_dma_ex.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_ll_dma.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_ll_dmamux.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_mdma.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_pwr.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_pwr_ex.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_ll_pwr.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_def.h;Drivers\STM32H7xx_HAL_Driver\Inc\Legacy\stm32_hal_legacy.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_i2c.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_i2c_ex.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_exti.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_ll_exti.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_ll_i2c.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_spi.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_ll_spi.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_spi_ex.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_tim.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_tim_ex.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_ll_tim.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_uart.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_ll_usart.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_ll_lpuart.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_uart_ex.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_pcd.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_pcd_ex.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_ll_usb.h;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_cortex.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_crc.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_crc_ex.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_rcc.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_rcc_ex.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_flash.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_flash_ex.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_gpio.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_hsem.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_dma.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_dma_ex.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_mdma.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_pwr.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_pwr_ex.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_i2c.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_i2c_ex.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_exti.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_spi.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_spi_ex.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_tim.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_tim_ex.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_uart.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_uart_ex.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_pcd.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_pcd_ex.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_ll_usb.c;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_cortex.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_ll_cortex.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_crc.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_crc_ex.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_ll_crc.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_rcc.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_rcc_ex.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_ll_bus.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_ll_rcc.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_ll_crs.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_ll_system.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_ll_utils.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_flash.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_flash_ex.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_gpio.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_gpio_ex.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_ll_gpio.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_hsem.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_ll_hsem.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_dma.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_dma_ex.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_ll_dma.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_ll_dmamux.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_mdma.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_pwr.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_pwr_ex.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_ll_pwr.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_def.h;Drivers\STM32H7xx_HAL_Driver\Inc\Legacy\stm32_hal_legacy.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_i2c.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_i2c_ex.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_exti.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_ll_exti.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_ll_i2c.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_spi.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_ll_spi.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_spi_ex.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_tim.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_tim_ex.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_ll_tim.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_uart.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_ll_usart.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_ll_lpuart.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_uart_ex.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_pcd.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_pcd_ex.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_ll_usb.h;Drivers\CMSIS\Device\ST\STM32H7xx\Include\stm32h743xx.h;Drivers\CMSIS\Device\ST\STM32H7xx\Include\stm32h7xx.h;Drivers\CMSIS\Device\ST\STM32H7xx\Include\system_stm32h7xx.h;Drivers\CMSIS\Device\ST\STM32H7xx\Include\system_stm32h7xx.h;Drivers\CMSIS\Device\ST\STM32H7xx\Source\Templates\system_stm32h7xx.c;Drivers\CMSIS\Include\cmsis_armcc.h;Drivers\CMSIS\Include\cmsis_armclang.h;Drivers\CMSIS\Include\cmsis_armclang_ltm.h;Drivers\CMSIS\Include\cmsis_compiler.h;Drivers\CMSIS\Include\cmsis_gcc.h;Drivers\CMSIS\Include\cmsis_iccarm.h;Drivers\CMSIS\Include\cmsis_version.h;Drivers\CMSIS\Include\core_armv81mml.h;Drivers\CMSIS\Include\core_armv8mbl.h;Drivers\CMSIS\Include\core_armv8mml.h;Drivers\CMSIS\Include\core_cm0.h;Drivers\CMSIS\Include\core_cm0plus.h;Drivers\CMSIS\Include\core_cm1.h;Drivers\CMSIS\Include\core_cm23.h;Drivers\CMSIS\Include\core_cm3.h;Drivers\CMSIS\Include\core_cm33.h;Drivers\CMSIS\Include\core_cm35p.h;Drivers\CMSIS\Include\core_cm4.h;Drivers\CMSIS\Include\core_cm7.h;Drivers\CMSIS\Include\core_sc000.h;Drivers\CMSIS\Include\core_sc300.h;Drivers\CMSIS\Include\mpu_armv7.h;Drivers\CMSIS\Include\mpu_armv8.h;Drivers\CMSIS\Include\tz_context.h;
+LibFiles=Drivers/STM32H7xx_HAL_Driver/Inc/stm32h7xx_hal_pcd.h;Drivers/STM32H7xx_HAL_Driver/Inc/stm32h7xx_hal_pcd_ex.h;Drivers/STM32H7xx_HAL_Driver/Inc/stm32h7xx_ll_usb.h;Drivers/STM32H7xx_HAL_Driver/Inc/stm32h7xx_hal_rcc.h;Drivers/STM32H7xx_HAL_Driver/Inc/stm32h7xx_hal_rcc_ex.h;Drivers/STM32H7xx_HAL_Driver/Inc/stm32h7xx_ll_bus.h;Drivers/STM32H7xx_HAL_Driver/Inc/stm32h7xx_ll_rcc.h;Drivers/STM32H7xx_HAL_Driver/Inc/stm32h7xx_ll_crs.h;Drivers/STM32H7xx_HAL_Driver/Inc/stm32h7xx_ll_system.h;Drivers/STM32H7xx_HAL_Driver/Inc/stm32h7xx_ll_utils.h;Drivers/STM32H7xx_HAL_Driver/Inc/stm32h7xx_hal_flash.h;Drivers/STM32H7xx_HAL_Driver/Inc/stm32h7xx_hal_flash_ex.h;Drivers/STM32H7xx_HAL_Driver/Inc/stm32h7xx_hal_gpio.h;Drivers/STM32H7xx_HAL_Driver/Inc/stm32h7xx_hal_gpio_ex.h;Drivers/STM32H7xx_HAL_Driver/Inc/stm32h7xx_ll_gpio.h;Drivers/STM32H7xx_HAL_Driver/Inc/stm32h7xx_hal_hsem.h;Drivers/STM32H7xx_HAL_Driver/Inc/stm32h7xx_ll_hsem.h;Drivers/STM32H7xx_HAL_Driver/Inc/stm32h7xx_hal_dma.h;Drivers/STM32H7xx_HAL_Driver/Inc/stm32h7xx_hal_dma_ex.h;Drivers/STM32H7xx_HAL_Driver/Inc/stm32h7xx_ll_dma.h;Drivers/STM32H7xx_HAL_Driver/Inc/stm32h7xx_ll_dmamux.h;Drivers/STM32H7xx_HAL_Driver/Inc/stm32h7xx_hal_mdma.h;Drivers/STM32H7xx_HAL_Driver/Inc/stm32h7xx_hal_pwr.h;Drivers/STM32H7xx_HAL_Driver/Inc/stm32h7xx_hal_pwr_ex.h;Drivers/STM32H7xx_HAL_Driver/Inc/stm32h7xx_ll_pwr.h;Drivers/STM32H7xx_HAL_Driver/Inc/stm32h7xx_hal_cortex.h;Drivers/STM32H7xx_HAL_Driver/Inc/stm32h7xx_ll_cortex.h;Drivers/STM32H7xx_HAL_Driver/Inc/stm32h7xx_hal.h;Drivers/STM32H7xx_HAL_Driver/Inc/stm32h7xx_hal_def.h;Drivers/STM32H7xx_HAL_Driver/Inc/Legacy/stm32_hal_legacy.h;Drivers/STM32H7xx_HAL_Driver/Inc/stm32h7xx_hal_i2c.h;Drivers/STM32H7xx_HAL_Driver/Inc/stm32h7xx_hal_i2c_ex.h;Drivers/STM32H7xx_HAL_Driver/Inc/stm32h7xx_hal_exti.h;Drivers/STM32H7xx_HAL_Driver/Inc/stm32h7xx_ll_exti.h;Drivers/STM32H7xx_HAL_Driver/Inc/stm32h7xx_hal_crc.h;Drivers/STM32H7xx_HAL_Driver/Inc/stm32h7xx_hal_crc_ex.h;Drivers/STM32H7xx_HAL_Driver/Inc/stm32h7xx_ll_crc.h;Drivers/STM32H7xx_HAL_Driver/Inc/stm32h7xx_ll_i2c.h;Drivers/STM32H7xx_HAL_Driver/Inc/stm32h7xx_hal_spi.h;Drivers/STM32H7xx_HAL_Driver/Inc/stm32h7xx_ll_spi.h;Drivers/STM32H7xx_HAL_Driver/Inc/stm32h7xx_hal_spi_ex.h;Drivers/STM32H7xx_HAL_Driver/Inc/stm32h7xx_hal_tim.h;Drivers/STM32H7xx_HAL_Driver/Inc/stm32h7xx_hal_tim_ex.h;Drivers/STM32H7xx_HAL_Driver/Inc/stm32h7xx_ll_tim.h;Drivers/STM32H7xx_HAL_Driver/Inc/stm32h7xx_hal_uart.h;Drivers/STM32H7xx_HAL_Driver/Inc/stm32h7xx_ll_usart.h;Drivers/STM32H7xx_HAL_Driver/Inc/stm32h7xx_ll_lpuart.h;Drivers/STM32H7xx_HAL_Driver/Inc/stm32h7xx_hal_uart_ex.h;Middlewares/ST/STM32_USB_Device_Library/Core/Inc/usbd_core.h;Middlewares/ST/STM32_USB_Device_Library/Core/Inc/usbd_ctlreq.h;Middlewares/ST/STM32_USB_Device_Library/Core/Inc/usbd_def.h;Middlewares/ST/STM32_USB_Device_Library/Core/Inc/usbd_ioreq.h;Middlewares/ST/STM32_USB_Device_Library/Class/CDC/Inc/usbd_cdc.h;Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_pcd.c;Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_pcd_ex.c;Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_ll_usb.c;Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_rcc.c;Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_rcc_ex.c;Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_flash.c;Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_flash_ex.c;Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_gpio.c;Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_hsem.c;Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_dma.c;Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_dma_ex.c;Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_mdma.c;Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_pwr.c;Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_pwr_ex.c;Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_cortex.c;Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal.c;Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_i2c.c;Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_i2c_ex.c;Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_exti.c;Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_crc.c;Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_crc_ex.c;Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_spi.c;Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_spi_ex.c;Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_tim.c;Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_tim_ex.c;Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_uart.c;Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_uart_ex.c;Middlewares/ST/STM32_USB_Device_Library/Core/Src/usbd_core.c;Middlewares/ST/STM32_USB_Device_Library/Core/Src/usbd_ctlreq.c;Middlewares/ST/STM32_USB_Device_Library/Core/Src/usbd_ioreq.c;Middlewares/ST/STM32_USB_Device_Library/Class/CDC/Src/usbd_cdc.c;Drivers/STM32H7xx_HAL_Driver/Inc/stm32h7xx_hal_pcd.h;Drivers/STM32H7xx_HAL_Driver/Inc/stm32h7xx_hal_pcd_ex.h;Drivers/STM32H7xx_HAL_Driver/Inc/stm32h7xx_ll_usb.h;Drivers/STM32H7xx_HAL_Driver/Inc/stm32h7xx_hal_rcc.h;Drivers/STM32H7xx_HAL_Driver/Inc/stm32h7xx_hal_rcc_ex.h;Drivers/STM32H7xx_HAL_Driver/Inc/stm32h7xx_ll_bus.h;Drivers/STM32H7xx_HAL_Driver/Inc/stm32h7xx_ll_rcc.h;Drivers/STM32H7xx_HAL_Driver/Inc/stm32h7xx_ll_crs.h;Drivers/STM32H7xx_HAL_Driver/Inc/stm32h7xx_ll_system.h;Drivers/STM32H7xx_HAL_Driver/Inc/stm32h7xx_ll_utils.h;Drivers/STM32H7xx_HAL_Driver/Inc/stm32h7xx_hal_flash.h;Drivers/STM32H7xx_HAL_Driver/Inc/stm32h7xx_hal_flash_ex.h;Drivers/STM32H7xx_HAL_Driver/Inc/stm32h7xx_hal_gpio.h;Drivers/STM32H7xx_HAL_Driver/Inc/stm32h7xx_hal_gpio_ex.h;Drivers/STM32H7xx_HAL_Driver/Inc/stm32h7xx_ll_gpio.h;Drivers/STM32H7xx_HAL_Driver/Inc/stm32h7xx_hal_hsem.h;Drivers/STM32H7xx_HAL_Driver/Inc/stm32h7xx_ll_hsem.h;Drivers/STM32H7xx_HAL_Driver/Inc/stm32h7xx_hal_dma.h;Drivers/STM32H7xx_HAL_Driver/Inc/stm32h7xx_hal_dma_ex.h;Drivers/STM32H7xx_HAL_Driver/Inc/stm32h7xx_ll_dma.h;Drivers/STM32H7xx_HAL_Driver/Inc/stm32h7xx_ll_dmamux.h;Drivers/STM32H7xx_HAL_Driver/Inc/stm32h7xx_hal_mdma.h;Drivers/STM32H7xx_HAL_Driver/Inc/stm32h7xx_hal_pwr.h;Drivers/STM32H7xx_HAL_Driver/Inc/stm32h7xx_hal_pwr_ex.h;Drivers/STM32H7xx_HAL_Driver/Inc/stm32h7xx_ll_pwr.h;Drivers/STM32H7xx_HAL_Driver/Inc/stm32h7xx_hal_cortex.h;Drivers/STM32H7xx_HAL_Driver/Inc/stm32h7xx_ll_cortex.h;Drivers/STM32H7xx_HAL_Driver/Inc/stm32h7xx_hal.h;Drivers/STM32H7xx_HAL_Driver/Inc/stm32h7xx_hal_def.h;Drivers/STM32H7xx_HAL_Driver/Inc/Legacy/stm32_hal_legacy.h;Drivers/STM32H7xx_HAL_Driver/Inc/stm32h7xx_hal_i2c.h;Drivers/STM32H7xx_HAL_Driver/Inc/stm32h7xx_hal_i2c_ex.h;Drivers/STM32H7xx_HAL_Driver/Inc/stm32h7xx_hal_exti.h;Drivers/STM32H7xx_HAL_Driver/Inc/stm32h7xx_ll_exti.h;Drivers/STM32H7xx_HAL_Driver/Inc/stm32h7xx_hal_crc.h;Drivers/STM32H7xx_HAL_Driver/Inc/stm32h7xx_hal_crc_ex.h;Drivers/STM32H7xx_HAL_Driver/Inc/stm32h7xx_ll_crc.h;Drivers/STM32H7xx_HAL_Driver/Inc/stm32h7xx_ll_i2c.h;Drivers/STM32H7xx_HAL_Driver/Inc/stm32h7xx_hal_spi.h;Drivers/STM32H7xx_HAL_Driver/Inc/stm32h7xx_ll_spi.h;Drivers/STM32H7xx_HAL_Driver/Inc/stm32h7xx_hal_spi_ex.h;Drivers/STM32H7xx_HAL_Driver/Inc/stm32h7xx_hal_tim.h;Drivers/STM32H7xx_HAL_Driver/Inc/stm32h7xx_hal_tim_ex.h;Drivers/STM32H7xx_HAL_Driver/Inc/stm32h7xx_ll_tim.h;Drivers/STM32H7xx_HAL_Driver/Inc/stm32h7xx_hal_uart.h;Drivers/STM32H7xx_HAL_Driver/Inc/stm32h7xx_ll_usart.h;Drivers/STM32H7xx_HAL_Driver/Inc/stm32h7xx_ll_lpuart.h;Drivers/STM32H7xx_HAL_Driver/Inc/stm32h7xx_hal_uart_ex.h;Middlewares/ST/STM32_USB_Device_Library/Core/Inc/usbd_core.h;Middlewares/ST/STM32_USB_Device_Library/Core/Inc/usbd_ctlreq.h;Middlewares/ST/STM32_USB_Device_Library/Core/Inc/usbd_def.h;Middlewares/ST/STM32_USB_Device_Library/Core/Inc/usbd_ioreq.h;Middlewares/ST/STM32_USB_Device_Library/Class/CDC/Inc/usbd_cdc.h;Drivers/CMSIS/Device/ST/STM32H7xx/Include/stm32h743xx.h;Drivers/CMSIS/Device/ST/STM32H7xx/Include/stm32h7xx.h;Drivers/CMSIS/Device/ST/STM32H7xx/Include/system_stm32h7xx.h;Drivers/CMSIS/Device/ST/STM32H7xx/Include/system_stm32h7xx.h;Drivers/CMSIS/Device/ST/STM32H7xx/Source/Templates/system_stm32h7xx.c;Drivers/CMSIS/Include/core_armv81mml.h;Drivers/CMSIS/Include/mpu_armv8.h;Drivers/CMSIS/Include/core_cm23.h;Drivers/CMSIS/Include/core_cm1.h;Drivers/CMSIS/Include/core_cm0.h;Drivers/CMSIS/Include/core_cm33.h;Drivers/CMSIS/Include/cmsis_gcc.h;Drivers/CMSIS/Include/cmsis_armclang.h;Drivers/CMSIS/Include/core_armv8mbl.h;Drivers/CMSIS/Include/cmsis_compiler.h;Drivers/CMSIS/Include/core_cm4.h;Drivers/CMSIS/Include/cmsis_iccarm.h;Drivers/CMSIS/Include/core_cm7.h;Drivers/CMSIS/Include/core_sc300.h;Drivers/CMSIS/Include/core_armv8mml.h;Drivers/CMSIS/Include/core_cm35p.h;Drivers/CMSIS/Include/cmsis_armclang_ltm.h;Drivers/CMSIS/Include/core_sc000.h;Drivers/CMSIS/Include/core_cm3.h;Drivers/CMSIS/Include/cmsis_armcc.h;Drivers/CMSIS/Include/core_cm0plus.h;Drivers/CMSIS/Include/tz_context.h;Drivers/CMSIS/Include/mpu_armv7.h;Drivers/CMSIS/Include/cmsis_version.h;
[PreviousUsedCubeIDEFiles]
-SourceFiles=Core\Src\main.c;Core\Src\stm32h7xx_it.c;Core\Src\stm32h7xx_hal_msp.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_cortex.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_crc.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_crc_ex.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_rcc.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_rcc_ex.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_flash.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_flash_ex.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_gpio.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_hsem.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_dma.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_dma_ex.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_mdma.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_pwr.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_pwr_ex.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_i2c.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_i2c_ex.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_exti.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_spi.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_spi_ex.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_tim.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_tim_ex.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_uart.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_uart_ex.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_pcd.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_pcd_ex.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_ll_usb.c;Drivers\CMSIS\Device\ST\STM32H7xx\Source\Templates\system_stm32h7xx.c;Core\Src\system_stm32h7xx.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_cortex.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_crc.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_crc_ex.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_rcc.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_rcc_ex.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_flash.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_flash_ex.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_gpio.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_hsem.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_dma.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_dma_ex.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_mdma.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_pwr.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_pwr_ex.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_i2c.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_i2c_ex.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_exti.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_spi.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_spi_ex.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_tim.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_tim_ex.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_uart.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_uart_ex.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_pcd.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_pcd_ex.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_ll_usb.c;Drivers\CMSIS\Device\ST\STM32H7xx\Source\Templates\system_stm32h7xx.c;Core\Src\system_stm32h7xx.c;;;
-HeaderPath=Drivers\STM32H7xx_HAL_Driver\Inc;Drivers\STM32H7xx_HAL_Driver\Inc\Legacy;Drivers\CMSIS\Device\ST\STM32H7xx\Include;Drivers\CMSIS\Include;Core\Inc;
+SourceFiles=Core/Src/main.c;USB_DEVICE/App/usb_device.c;USB_DEVICE/Target/usbd_conf.c;USB_DEVICE/App/usbd_desc.c;USB_DEVICE/App/usbd_cdc_if.c;Core/Src/stm32h7xx_it.c;Core/Src/stm32h7xx_hal_msp.c;Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_pcd.c;Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_pcd_ex.c;Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_ll_usb.c;Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_rcc.c;Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_rcc_ex.c;Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_flash.c;Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_flash_ex.c;Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_gpio.c;Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_hsem.c;Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_dma.c;Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_dma_ex.c;Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_mdma.c;Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_pwr.c;Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_pwr_ex.c;Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_cortex.c;Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal.c;Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_i2c.c;Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_i2c_ex.c;Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_exti.c;Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_crc.c;Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_crc_ex.c;Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_spi.c;Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_spi_ex.c;Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_tim.c;Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_tim_ex.c;Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_uart.c;Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_uart_ex.c;Middlewares/ST/STM32_USB_Device_Library/Core/Src/usbd_core.c;Middlewares/ST/STM32_USB_Device_Library/Core/Src/usbd_ctlreq.c;Middlewares/ST/STM32_USB_Device_Library/Core/Src/usbd_ioreq.c;Middlewares/ST/STM32_USB_Device_Library/Class/CDC/Src/usbd_cdc.c;Drivers/CMSIS/Device/ST/STM32H7xx/Source/Templates/system_stm32h7xx.c;Core/Src/system_stm32h7xx.c;Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_pcd.c;Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_pcd_ex.c;Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_ll_usb.c;Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_rcc.c;Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_rcc_ex.c;Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_flash.c;Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_flash_ex.c;Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_gpio.c;Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_hsem.c;Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_dma.c;Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_dma_ex.c;Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_mdma.c;Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_pwr.c;Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_pwr_ex.c;Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_cortex.c;Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal.c;Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_i2c.c;Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_i2c_ex.c;Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_exti.c;Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_crc.c;Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_crc_ex.c;Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_spi.c;Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_spi_ex.c;Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_tim.c;Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_tim_ex.c;Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_uart.c;Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_uart_ex.c;Middlewares/ST/STM32_USB_Device_Library/Core/Src/usbd_core.c;Middlewares/ST/STM32_USB_Device_Library/Core/Src/usbd_ctlreq.c;Middlewares/ST/STM32_USB_Device_Library/Core/Src/usbd_ioreq.c;Middlewares/ST/STM32_USB_Device_Library/Class/CDC/Src/usbd_cdc.c;Drivers/CMSIS/Device/ST/STM32H7xx/Source/Templates/system_stm32h7xx.c;Core/Src/system_stm32h7xx.c;;;Middlewares/ST/STM32_USB_Device_Library/Core/Src/usbd_core.c;Middlewares/ST/STM32_USB_Device_Library/Core/Src/usbd_ctlreq.c;Middlewares/ST/STM32_USB_Device_Library/Core/Src/usbd_ioreq.c;Middlewares/ST/STM32_USB_Device_Library/Class/CDC/Src/usbd_cdc.c;
+HeaderPath=Drivers/STM32H7xx_HAL_Driver/Inc;Drivers/STM32H7xx_HAL_Driver/Inc/Legacy;Middlewares/ST/STM32_USB_Device_Library/Core/Inc;Middlewares/ST/STM32_USB_Device_Library/Class/CDC/Inc;Drivers/CMSIS/Device/ST/STM32H7xx/Include;Drivers/CMSIS/Include;USB_DEVICE/App;USB_DEVICE/Target;Core/Inc;
+CDefines=USE_PWR_LDO_SUPPLY;USE_PWR_LDO_SUPPLY;USE_HAL_DRIVER;STM32H743xx;USE_HAL_DRIVER;USE_HAL_DRIVER;
+
+[PreviousUsedMakefileFiles]
+SourceFiles=Core/Src/main.c;USB_DEVICE/App/usb_device.c;USB_DEVICE/Target/usbd_conf.c;USB_DEVICE/App/usbd_desc.c;USB_DEVICE/App/usbd_cdc_if.c;Core/Src/stm32h7xx_it.c;Core/Src/stm32h7xx_hal_msp.c;Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_pcd.c;Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_pcd_ex.c;Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_ll_usb.c;Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_rcc.c;Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_rcc_ex.c;Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_flash.c;Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_flash_ex.c;Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_gpio.c;Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_hsem.c;Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_dma.c;Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_dma_ex.c;Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_mdma.c;Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_pwr.c;Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_pwr_ex.c;Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_cortex.c;Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal.c;Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_i2c.c;Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_i2c_ex.c;Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_exti.c;Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_crc.c;Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_crc_ex.c;Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_spi.c;Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_spi_ex.c;Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_tim.c;Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_tim_ex.c;Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_uart.c;Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_uart_ex.c;Middlewares/ST/STM32_USB_Device_Library/Core/Src/usbd_core.c;Middlewares/ST/STM32_USB_Device_Library/Core/Src/usbd_ctlreq.c;Middlewares/ST/STM32_USB_Device_Library/Core/Src/usbd_ioreq.c;Middlewares/ST/STM32_USB_Device_Library/Class/CDC/Src/usbd_cdc.c;Drivers/CMSIS/Device/ST/STM32H7xx/Source/Templates/system_stm32h7xx.c;Core/Src/system_stm32h7xx.c;Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_pcd.c;Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_pcd_ex.c;Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_ll_usb.c;Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_rcc.c;Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_rcc_ex.c;Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_flash.c;Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_flash_ex.c;Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_gpio.c;Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_hsem.c;Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_dma.c;Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_dma_ex.c;Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_mdma.c;Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_pwr.c;Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_pwr_ex.c;Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_cortex.c;Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal.c;Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_i2c.c;Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_i2c_ex.c;Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_exti.c;Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_crc.c;Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_crc_ex.c;Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_spi.c;Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_spi_ex.c;Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_tim.c;Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_tim_ex.c;Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_uart.c;Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_uart_ex.c;Middlewares/ST/STM32_USB_Device_Library/Core/Src/usbd_core.c;Middlewares/ST/STM32_USB_Device_Library/Core/Src/usbd_ctlreq.c;Middlewares/ST/STM32_USB_Device_Library/Core/Src/usbd_ioreq.c;Middlewares/ST/STM32_USB_Device_Library/Class/CDC/Src/usbd_cdc.c;Drivers/CMSIS/Device/ST/STM32H7xx/Source/Templates/system_stm32h7xx.c;Core/Src/system_stm32h7xx.c;;;Middlewares/ST/STM32_USB_Device_Library/Core/Src/usbd_core.c;Middlewares/ST/STM32_USB_Device_Library/Core/Src/usbd_ctlreq.c;Middlewares/ST/STM32_USB_Device_Library/Core/Src/usbd_ioreq.c;Middlewares/ST/STM32_USB_Device_Library/Class/CDC/Src/usbd_cdc.c;
+HeaderPath=Drivers/STM32H7xx_HAL_Driver/Inc;Drivers/STM32H7xx_HAL_Driver/Inc/Legacy;Middlewares/ST/STM32_USB_Device_Library/Core/Inc;Middlewares/ST/STM32_USB_Device_Library/Class/CDC/Inc;Drivers/CMSIS/Device/ST/STM32H7xx/Include;Drivers/CMSIS/Include;USB_DEVICE/App;USB_DEVICE/Target;Core/Inc;
CDefines=USE_PWR_LDO_SUPPLY;USE_PWR_LDO_SUPPLY;USE_HAL_DRIVER;STM32H743xx;USE_HAL_DRIVER;USE_HAL_DRIVER;
[PreviousGenFiles]
AdvancedFolderStructure=true
-HeaderFileListSize=3
-HeaderFiles#0=..\Core\Inc\stm32h7xx_it.h
-HeaderFiles#1=..\Core\Inc\stm32h7xx_hal_conf.h
-HeaderFiles#2=..\Core\Inc\main.h
-HeaderFolderListSize=1
-HeaderPath#0=..\Core\Inc
+HeaderFileListSize=7
+HeaderFiles#0=../USB_DEVICE/App/usb_device.h
+HeaderFiles#1=../USB_DEVICE/Target/usbd_conf.h
+HeaderFiles#2=../USB_DEVICE/App/usbd_desc.h
+HeaderFiles#3=../USB_DEVICE/App/usbd_cdc_if.h
+HeaderFiles#4=../Core/Inc/stm32h7xx_it.h
+HeaderFiles#5=../Core/Inc/stm32h7xx_hal_conf.h
+HeaderFiles#6=../Core/Inc/main.h
+HeaderFolderListSize=3
+HeaderPath#0=../USB_DEVICE/App
+HeaderPath#1=../USB_DEVICE/Target
+HeaderPath#2=../Core/Inc
HeaderFiles=;
-SourceFileListSize=3
-SourceFiles#0=..\Core\Src\stm32h7xx_it.c
-SourceFiles#1=..\Core\Src\stm32h7xx_hal_msp.c
-SourceFiles#2=..\Core\Src\main.c
-SourceFolderListSize=1
-SourcePath#0=..\Core\Src
+SourceFileListSize=7
+SourceFiles#0=../USB_DEVICE/App/usb_device.c
+SourceFiles#1=../USB_DEVICE/Target/usbd_conf.c
+SourceFiles#2=../USB_DEVICE/App/usbd_desc.c
+SourceFiles#3=../USB_DEVICE/App/usbd_cdc_if.c
+SourceFiles#4=../Core/Src/stm32h7xx_it.c
+SourceFiles#5=../Core/Src/stm32h7xx_hal_msp.c
+SourceFiles#6=../Core/Src/main.c
+SourceFolderListSize=3
+SourcePath#0=../USB_DEVICE/App
+SourcePath#1=../USB_DEVICE/Target
+SourcePath#2=../Core/Src
SourceFiles=;
diff --git a/Ganesha_II_V2/.settings/language.settings.xml b/Ganesha_II_V2/.settings/language.settings.xml
index 32a63b1..7ee61d0 100644
--- a/Ganesha_II_V2/.settings/language.settings.xml
+++ b/Ganesha_II_V2/.settings/language.settings.xml
@@ -5,7 +5,7 @@
-
+
@@ -16,7 +16,7 @@
-
+
@@ -27,7 +27,7 @@
-
+
@@ -38,7 +38,7 @@
-
+
diff --git a/Ganesha_II_V2/Core/Inc/flash/flash.h b/Ganesha_II_V2/Core/Inc/flash/flash.h
new file mode 100644
index 0000000..6109dde
--- /dev/null
+++ b/Ganesha_II_V2/Core/Inc/flash/flash.h
@@ -0,0 +1,27 @@
+#ifndef FLASH_H
+#define FLASH_H
+
+#include "lfs.h"
+
+#include
+
+enum flash_name {
+ W25N01KV,
+ GD5F1GQ5XE
+};
+
+struct flash_dev {
+ enum flash_name name;
+ /* struct lfs_config config; */
+ lfs_t lfs;
+};
+
+void flash_init(struct flash_dev *dev, enum flash_name name);
+lfs_ssize_t flash_mount(struct flash_dev *flash, const struct lfs_config *config);
+int flash_unmount(struct flash_dev *flash);
+uint32_t flash_boot_count(struct flash_dev *flash, bool update);
+uint32_t flash_open(struct flash_dev *flash, lfs_file_t *file, const char *filename);
+bool flash_append(struct flash_dev *flash, lfs_file_t *file, const uint8_t *bytes, uint32_t size);
+int flash_close(struct flash_dev *flash, lfs_file_t *file);
+
+#endif
diff --git a/Ganesha_II_V2/Core/Inc/flash/gd5f1gq5xe.h b/Ganesha_II_V2/Core/Inc/flash/gd5f1gq5xe.h
new file mode 100644
index 0000000..19238a8
--- /dev/null
+++ b/Ganesha_II_V2/Core/Inc/flash/gd5f1gq5xe.h
@@ -0,0 +1,18 @@
+#ifndef GD5F1GQ5XE_H
+#define GD5F1GQ5XE_H
+
+#include
+#include
+
+// Flash Sizes
+#define GD5F_BLOCK_COUNT 1024
+#define GD5F_PAGES_PER_BLOCK 64
+#define GD5F_PAGE_SIZE 2048
+#define GD5F_BLOCK_SIZE GD5F_PAGES_PER_BLOCK * GD5F_PAGE_SIZE
+
+bool gd5f1gq5xe_read(uint32_t block, uint32_t offset, void *buffer, uint32_t size);
+bool gd5f1gq5xe_write(uint32_t block, uint32_t offset, void *buffer, uint32_t size);
+bool gd5f1gq5xe_erase(uint32_t block);
+bool gd5f1gq5xe_unlock();
+
+#endif
diff --git a/Ganesha_II_V2/Core/Inc/flash/w25n01kv.h b/Ganesha_II_V2/Core/Inc/flash/w25n01kv.h
new file mode 100644
index 0000000..7476a4b
--- /dev/null
+++ b/Ganesha_II_V2/Core/Inc/flash/w25n01kv.h
@@ -0,0 +1,28 @@
+#ifndef W25N01KV_H
+#define W25N01KV_H
+
+#include
+#include
+
+#define W25N_CMD_READ_JEDEC_ID 0x9F
+#define W25N_CMD_READ_STATUS_REGISTER 0x0F // Checks if Page Data Read is done (BUSY = 1) (not sure if needed for now)
+#define W25N_CMD_PAGE_DATA_READ 0x13 // Reads data from a flash page into the data buffer | Resets WEL bit
+#define W25N_CMD_READ_FROM_BUFFER 0x03 // Reads from the data buffer
+#define W25N_CMD_WRITE_ENABLE 0x06 // Required for Load Program Data | Sets WEL bit to 1
+#define W25N_CMD_WRITE_DISABLE 0x04 // Resets WEL bit to 0
+#define W25N_CMD_LOAD_PROGRAM_DATA 0x02 // Loads data into the data buffer (Max 1 page)
+#define W25N_CMD_PROGRAM_EXECUTE 0x10 // Programs the data in the data buffer to the specified page in flash (Also resets WEL bit to 0 when finished)
+#define W25N_CMD_BLOCK_ERASE 0xD8
+
+// General Specs (Page 5 of Datasheet)
+#define W25N_PAGE_SIZE 2048
+#define W25N_PAGES_PER_BLOCK 64
+#define W25N_BLOCK_SIZE (W25N_PAGE_SIZE * W25N_PAGES_PER_BLOCK)
+#define W25N_BLOCK_COUNT 1024
+
+int w25n01kv_read(const uint32_t page, const uint16_t col, void *buffer, const size_t size);
+int w25n01kv_write(const uint32_t page, const uint16_t col, const void *buffer, const size_t size);
+int w25n01kv_erase(const uint32_t page);
+int w25n01kv_unlock();
+
+#endif
diff --git a/Ganesha_II_V2/Core/Inc/littlefs/lfs.h b/Ganesha_II_V2/Core/Inc/littlefs/lfs.h
new file mode 100644
index 0000000..4531560
--- /dev/null
+++ b/Ganesha_II_V2/Core/Inc/littlefs/lfs.h
@@ -0,0 +1,797 @@
+/*
+ * The little filesystem
+ *
+ * Copyright (c) 2022, The littlefs authors.
+ * Copyright (c) 2017, Arm Limited. All rights reserved.
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef LFS_H
+#define LFS_H
+
+#include "lfs_util.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+
+/// Version info ///
+
+// Software library version
+// Major (top-nibble), incremented on backwards incompatible changes
+// Minor (bottom-nibble), incremented on feature additions
+#define LFS_VERSION 0x0002000a
+#define LFS_VERSION_MAJOR (0xffff & (LFS_VERSION >> 16))
+#define LFS_VERSION_MINOR (0xffff & (LFS_VERSION >> 0))
+
+// Version of On-disk data structures
+// Major (top-nibble), incremented on backwards incompatible changes
+// Minor (bottom-nibble), incremented on feature additions
+#define LFS_DISK_VERSION 0x00020001
+#define LFS_DISK_VERSION_MAJOR (0xffff & (LFS_DISK_VERSION >> 16))
+#define LFS_DISK_VERSION_MINOR (0xffff & (LFS_DISK_VERSION >> 0))
+
+
+/// Definitions ///
+
+// Type definitions
+typedef uint32_t lfs_size_t;
+typedef uint32_t lfs_off_t;
+
+typedef int32_t lfs_ssize_t;
+typedef int32_t lfs_soff_t;
+
+typedef uint32_t lfs_block_t;
+
+// Maximum name size in bytes, may be redefined to reduce the size of the
+// info struct. Limited to <= 1022. Stored in superblock and must be
+// respected by other littlefs drivers.
+#ifndef LFS_NAME_MAX
+#define LFS_NAME_MAX 255
+#endif
+
+// Maximum size of a file in bytes, may be redefined to limit to support other
+// drivers. Limited on disk to <= 2147483647. Stored in superblock and must be
+// respected by other littlefs drivers.
+#ifndef LFS_FILE_MAX
+#define LFS_FILE_MAX 2147483647
+#endif
+
+// Maximum size of custom attributes in bytes, may be redefined, but there is
+// no real benefit to using a smaller LFS_ATTR_MAX. Limited to <= 1022. Stored
+// in superblock and must be respected by other littlefs drivers.
+#ifndef LFS_ATTR_MAX
+#define LFS_ATTR_MAX 1022
+#endif
+
+// Possible error codes, these are negative to allow
+// valid positive return values
+enum lfs_error {
+ LFS_ERR_OK = 0, // No error
+ LFS_ERR_IO = -5, // Error during device operation
+ LFS_ERR_CORRUPT = -84, // Corrupted
+ LFS_ERR_NOENT = -2, // No directory entry
+ LFS_ERR_EXIST = -17, // Entry already exists
+ LFS_ERR_NOTDIR = -20, // Entry is not a dir
+ LFS_ERR_ISDIR = -21, // Entry is a dir
+ LFS_ERR_NOTEMPTY = -39, // Dir is not empty
+ LFS_ERR_BADF = -9, // Bad file number
+ LFS_ERR_FBIG = -27, // File too large
+ LFS_ERR_INVAL = -22, // Invalid parameter
+ LFS_ERR_NOSPC = -28, // No space left on device
+ LFS_ERR_NOMEM = -12, // No more memory available
+ LFS_ERR_NOATTR = -61, // No data/attr available
+ LFS_ERR_NAMETOOLONG = -36, // File name too long
+};
+
+// File types
+enum lfs_type {
+ // file types
+ LFS_TYPE_REG = 0x001,
+ LFS_TYPE_DIR = 0x002,
+
+ // internally used types
+ LFS_TYPE_SPLICE = 0x400,
+ LFS_TYPE_NAME = 0x000,
+ LFS_TYPE_STRUCT = 0x200,
+ LFS_TYPE_USERATTR = 0x300,
+ LFS_TYPE_FROM = 0x100,
+ LFS_TYPE_TAIL = 0x600,
+ LFS_TYPE_GLOBALS = 0x700,
+ LFS_TYPE_CRC = 0x500,
+
+ // internally used type specializations
+ LFS_TYPE_CREATE = 0x401,
+ LFS_TYPE_DELETE = 0x4ff,
+ LFS_TYPE_SUPERBLOCK = 0x0ff,
+ LFS_TYPE_DIRSTRUCT = 0x200,
+ LFS_TYPE_CTZSTRUCT = 0x202,
+ LFS_TYPE_INLINESTRUCT = 0x201,
+ LFS_TYPE_SOFTTAIL = 0x600,
+ LFS_TYPE_HARDTAIL = 0x601,
+ LFS_TYPE_MOVESTATE = 0x7ff,
+ LFS_TYPE_CCRC = 0x500,
+ LFS_TYPE_FCRC = 0x5ff,
+
+ // internal chip sources
+ LFS_FROM_NOOP = 0x000,
+ LFS_FROM_MOVE = 0x101,
+ LFS_FROM_USERATTRS = 0x102,
+};
+
+// File open flags
+enum lfs_open_flags {
+ // open flags
+ LFS_O_RDONLY = 1, // Open a file as read only
+#ifndef LFS_READONLY
+ LFS_O_WRONLY = 2, // Open a file as write only
+ LFS_O_RDWR = 3, // Open a file as read and write
+ LFS_O_CREAT = 0x0100, // Create a file if it does not exist
+ LFS_O_EXCL = 0x0200, // Fail if a file already exists
+ LFS_O_TRUNC = 0x0400, // Truncate the existing file to zero size
+ LFS_O_APPEND = 0x0800, // Move to end of file on every write
+#endif
+
+ // internally used flags
+#ifndef LFS_READONLY
+ LFS_F_DIRTY = 0x010000, // File does not match storage
+ LFS_F_WRITING = 0x020000, // File has been written since last flush
+#endif
+ LFS_F_READING = 0x040000, // File has been read since last flush
+#ifndef LFS_READONLY
+ LFS_F_ERRED = 0x080000, // An error occurred during write
+#endif
+ LFS_F_INLINE = 0x100000, // Currently inlined in directory entry
+};
+
+// File seek flags
+enum lfs_whence_flags {
+ LFS_SEEK_SET = 0, // Seek relative to an absolute position
+ LFS_SEEK_CUR = 1, // Seek relative to the current file position
+ LFS_SEEK_END = 2, // Seek relative to the end of the file
+};
+
+
+// Configuration provided during initialization of the littlefs
+struct lfs_config {
+ // Opaque user provided context that can be used to pass
+ // information to the block device operations
+ void *context;
+
+ // Read a region in a block. Negative error codes are propagated
+ // to the user.
+ int (*read)(const struct lfs_config *c, lfs_block_t block,
+ lfs_off_t off, void *buffer, lfs_size_t size);
+
+ // Program a region in a block. The block must have previously
+ // been erased. Negative error codes are propagated to the user.
+ // May return LFS_ERR_CORRUPT if the block should be considered bad.
+ int (*prog)(const struct lfs_config *c, lfs_block_t block,
+ lfs_off_t off, const void *buffer, lfs_size_t size);
+
+ // Erase a block. A block must be erased before being programmed.
+ // The state of an erased block is undefined. Negative error codes
+ // are propagated to the user.
+ // May return LFS_ERR_CORRUPT if the block should be considered bad.
+ int (*erase)(const struct lfs_config *c, lfs_block_t block);
+
+ // Sync the state of the underlying block device. Negative error codes
+ // are propagated to the user.
+ int (*sync)(const struct lfs_config *c);
+
+#ifdef LFS_THREADSAFE
+ // Lock the underlying block device. Negative error codes
+ // are propagated to the user.
+ int (*lock)(const struct lfs_config *c);
+
+ // Unlock the underlying block device. Negative error codes
+ // are propagated to the user.
+ int (*unlock)(const struct lfs_config *c);
+#endif
+
+ // Minimum size of a block read in bytes. All read operations will be a
+ // multiple of this value.
+ lfs_size_t read_size;
+
+ // Minimum size of a block program in bytes. All program operations will be
+ // a multiple of this value.
+ lfs_size_t prog_size;
+
+ // Size of an erasable block in bytes. This does not impact ram consumption
+ // and may be larger than the physical erase size. However, non-inlined
+ // files take up at minimum one block. Must be a multiple of the read and
+ // program sizes.
+ lfs_size_t block_size;
+
+ // Number of erasable blocks on the device. Defaults to block_count stored
+ // on disk when zero.
+ lfs_size_t block_count;
+
+ // Number of erase cycles before littlefs evicts metadata logs and moves
+ // the metadata to another block. Suggested values are in the
+ // range 100-1000, with large values having better performance at the cost
+ // of less consistent wear distribution.
+ //
+ // Set to -1 to disable block-level wear-leveling.
+ int32_t block_cycles;
+
+ // Size of block caches in bytes. Each cache buffers a portion of a block in
+ // RAM. The littlefs needs a read cache, a program cache, and one additional
+ // cache per file. Larger caches can improve performance by storing more
+ // data and reducing the number of disk accesses. Must be a multiple of the
+ // read and program sizes, and a factor of the block size.
+ lfs_size_t cache_size;
+
+ // Size of the lookahead buffer in bytes. A larger lookahead buffer
+ // increases the number of blocks found during an allocation pass. The
+ // lookahead buffer is stored as a compact bitmap, so each byte of RAM
+ // can track 8 blocks.
+ lfs_size_t lookahead_size;
+
+ // Threshold for metadata compaction during lfs_fs_gc in bytes. Metadata
+ // pairs that exceed this threshold will be compacted during lfs_fs_gc.
+ // Defaults to ~88% block_size when zero, though the default may change
+ // in the future.
+ //
+ // Note this only affects lfs_fs_gc. Normal compactions still only occur
+ // when full.
+ //
+ // Set to -1 to disable metadata compaction during lfs_fs_gc.
+ lfs_size_t compact_thresh;
+
+ // Optional statically allocated read buffer. Must be cache_size.
+ // By default lfs_malloc is used to allocate this buffer.
+ void *read_buffer;
+
+ // Optional statically allocated program buffer. Must be cache_size.
+ // By default lfs_malloc is used to allocate this buffer.
+ void *prog_buffer;
+
+ // Optional statically allocated lookahead buffer. Must be lookahead_size.
+ // By default lfs_malloc is used to allocate this buffer.
+ void *lookahead_buffer;
+
+ // Optional upper limit on length of file names in bytes. No downside for
+ // larger names except the size of the info struct which is controlled by
+ // the LFS_NAME_MAX define. Defaults to LFS_NAME_MAX or name_max stored on
+ // disk when zero.
+ lfs_size_t name_max;
+
+ // Optional upper limit on files in bytes. No downside for larger files
+ // but must be <= LFS_FILE_MAX. Defaults to LFS_FILE_MAX or file_max stored
+ // on disk when zero.
+ lfs_size_t file_max;
+
+ // Optional upper limit on custom attributes in bytes. No downside for
+ // larger attributes size but must be <= LFS_ATTR_MAX. Defaults to
+ // LFS_ATTR_MAX or attr_max stored on disk when zero.
+ lfs_size_t attr_max;
+
+ // Optional upper limit on total space given to metadata pairs in bytes. On
+ // devices with large blocks (e.g. 128kB) setting this to a low size (2-8kB)
+ // can help bound the metadata compaction time. Must be <= block_size.
+ // Defaults to block_size when zero.
+ lfs_size_t metadata_max;
+
+ // Optional upper limit on inlined files in bytes. Inlined files live in
+ // metadata and decrease storage requirements, but may be limited to
+ // improve metadata-related performance. Must be <= cache_size, <=
+ // attr_max, and <= block_size/8. Defaults to the largest possible
+ // inline_max when zero.
+ //
+ // Set to -1 to disable inlined files.
+ lfs_size_t inline_max;
+
+#ifdef LFS_MULTIVERSION
+ // On-disk version to use when writing in the form of 16-bit major version
+ // + 16-bit minor version. This limiting metadata to what is supported by
+ // older minor versions. Note that some features will be lost. Defaults to
+ // to the most recent minor version when zero.
+ uint32_t disk_version;
+#endif
+};
+
+// File info structure
+struct lfs_info {
+ // Type of the file, either LFS_TYPE_REG or LFS_TYPE_DIR
+ uint8_t type;
+
+ // Size of the file, only valid for REG files. Limited to 32-bits.
+ lfs_size_t size;
+
+ // Name of the file stored as a null-terminated string. Limited to
+ // LFS_NAME_MAX+1, which can be changed by redefining LFS_NAME_MAX to
+ // reduce RAM. LFS_NAME_MAX is stored in superblock and must be
+ // respected by other littlefs drivers.
+ char name[LFS_NAME_MAX+1];
+};
+
+// Filesystem info structure
+struct lfs_fsinfo {
+ // On-disk version.
+ uint32_t disk_version;
+
+ // Size of a logical block in bytes.
+ lfs_size_t block_size;
+
+ // Number of logical blocks in filesystem.
+ lfs_size_t block_count;
+
+ // Upper limit on the length of file names in bytes.
+ lfs_size_t name_max;
+
+ // Upper limit on the size of files in bytes.
+ lfs_size_t file_max;
+
+ // Upper limit on the size of custom attributes in bytes.
+ lfs_size_t attr_max;
+};
+
+// Custom attribute structure, used to describe custom attributes
+// committed atomically during file writes.
+struct lfs_attr {
+ // 8-bit type of attribute, provided by user and used to
+ // identify the attribute
+ uint8_t type;
+
+ // Pointer to buffer containing the attribute
+ void *buffer;
+
+ // Size of attribute in bytes, limited to LFS_ATTR_MAX
+ lfs_size_t size;
+};
+
+// Optional configuration provided during lfs_file_opencfg
+struct lfs_file_config {
+ // Optional statically allocated file buffer. Must be cache_size.
+ // By default lfs_malloc is used to allocate this buffer.
+ void *buffer;
+
+ // Optional list of custom attributes related to the file. If the file
+ // is opened with read access, these attributes will be read from disk
+ // during the open call. If the file is opened with write access, the
+ // attributes will be written to disk every file sync or close. This
+ // write occurs atomically with update to the file's contents.
+ //
+ // Custom attributes are uniquely identified by an 8-bit type and limited
+ // to LFS_ATTR_MAX bytes. When read, if the stored attribute is smaller
+ // than the buffer, it will be padded with zeros. If the stored attribute
+ // is larger, then it will be silently truncated. If the attribute is not
+ // found, it will be created implicitly.
+ struct lfs_attr *attrs;
+
+ // Number of custom attributes in the list
+ lfs_size_t attr_count;
+};
+
+
+/// internal littlefs data structures ///
+typedef struct lfs_cache {
+ lfs_block_t block;
+ lfs_off_t off;
+ lfs_size_t size;
+ uint8_t *buffer;
+} lfs_cache_t;
+
+typedef struct lfs_mdir {
+ lfs_block_t pair[2];
+ uint32_t rev;
+ lfs_off_t off;
+ uint32_t etag;
+ uint16_t count;
+ bool erased;
+ bool split;
+ lfs_block_t tail[2];
+} lfs_mdir_t;
+
+// littlefs directory type
+typedef struct lfs_dir {
+ struct lfs_dir *next;
+ uint16_t id;
+ uint8_t type;
+ lfs_mdir_t m;
+
+ lfs_off_t pos;
+ lfs_block_t head[2];
+} lfs_dir_t;
+
+// littlefs file type
+typedef struct lfs_file {
+ struct lfs_file *next;
+ uint16_t id;
+ uint8_t type;
+ lfs_mdir_t m;
+
+ struct lfs_ctz {
+ lfs_block_t head;
+ lfs_size_t size;
+ } ctz;
+
+ uint32_t flags;
+ lfs_off_t pos;
+ lfs_block_t block;
+ lfs_off_t off;
+ lfs_cache_t cache;
+
+ const struct lfs_file_config *cfg;
+} lfs_file_t;
+
+typedef struct lfs_superblock {
+ uint32_t version;
+ lfs_size_t block_size;
+ lfs_size_t block_count;
+ lfs_size_t name_max;
+ lfs_size_t file_max;
+ lfs_size_t attr_max;
+} lfs_superblock_t;
+
+typedef struct lfs_gstate {
+ uint32_t tag;
+ lfs_block_t pair[2];
+} lfs_gstate_t;
+
+// The littlefs filesystem type
+typedef struct lfs {
+ lfs_cache_t rcache;
+ lfs_cache_t pcache;
+
+ lfs_block_t root[2];
+ struct lfs_mlist {
+ struct lfs_mlist *next;
+ uint16_t id;
+ uint8_t type;
+ lfs_mdir_t m;
+ } *mlist;
+ uint32_t seed;
+
+ lfs_gstate_t gstate;
+ lfs_gstate_t gdisk;
+ lfs_gstate_t gdelta;
+
+ struct lfs_lookahead {
+ lfs_block_t start;
+ lfs_block_t size;
+ lfs_block_t next;
+ lfs_block_t ckpoint;
+ uint8_t *buffer;
+ } lookahead;
+
+ const struct lfs_config *cfg;
+ lfs_size_t block_count;
+ lfs_size_t name_max;
+ lfs_size_t file_max;
+ lfs_size_t attr_max;
+ lfs_size_t inline_max;
+
+#ifdef LFS_MIGRATE
+ struct lfs1 *lfs1;
+#endif
+} lfs_t;
+
+
+/// Filesystem functions ///
+
+#ifndef LFS_READONLY
+// Format a block device with the littlefs
+//
+// Requires a littlefs object and config struct. This clobbers the littlefs
+// object, and does not leave the filesystem mounted. The config struct must
+// be zeroed for defaults and backwards compatibility.
+//
+// Returns a negative error code on failure.
+int lfs_format(lfs_t *lfs, const struct lfs_config *config);
+#endif
+
+// Mounts a littlefs
+//
+// Requires a littlefs object and config struct. Multiple filesystems
+// may be mounted simultaneously with multiple littlefs objects. Both
+// lfs and config must be allocated while mounted. The config struct must
+// be zeroed for defaults and backwards compatibility.
+//
+// Returns a negative error code on failure.
+int lfs_mount(lfs_t *lfs, const struct lfs_config *config);
+
+// Unmounts a littlefs
+//
+// Does nothing besides releasing any allocated resources.
+// Returns a negative error code on failure.
+int lfs_unmount(lfs_t *lfs);
+
+/// General operations ///
+
+#ifndef LFS_READONLY
+// Removes a file or directory
+//
+// If removing a directory, the directory must be empty.
+// Returns a negative error code on failure.
+int lfs_remove(lfs_t *lfs, const char *path);
+#endif
+
+#ifndef LFS_READONLY
+// Rename or move a file or directory
+//
+// If the destination exists, it must match the source in type.
+// If the destination is a directory, the directory must be empty.
+//
+// Returns a negative error code on failure.
+int lfs_rename(lfs_t *lfs, const char *oldpath, const char *newpath);
+#endif
+
+// Find info about a file or directory
+//
+// Fills out the info structure, based on the specified file or directory.
+// Returns a negative error code on failure.
+int lfs_stat(lfs_t *lfs, const char *path, struct lfs_info *info);
+
+// Get a custom attribute
+//
+// Custom attributes are uniquely identified by an 8-bit type and limited
+// to LFS_ATTR_MAX bytes. When read, if the stored attribute is smaller than
+// the buffer, it will be padded with zeros. If the stored attribute is larger,
+// then it will be silently truncated. If no attribute is found, the error
+// LFS_ERR_NOATTR is returned and the buffer is filled with zeros.
+//
+// Returns the size of the attribute, or a negative error code on failure.
+// Note, the returned size is the size of the attribute on disk, irrespective
+// of the size of the buffer. This can be used to dynamically allocate a buffer
+// or check for existence.
+lfs_ssize_t lfs_getattr(lfs_t *lfs, const char *path,
+ uint8_t type, void *buffer, lfs_size_t size);
+
+#ifndef LFS_READONLY
+// Set custom attributes
+//
+// Custom attributes are uniquely identified by an 8-bit type and limited
+// to LFS_ATTR_MAX bytes. If an attribute is not found, it will be
+// implicitly created.
+//
+// Returns a negative error code on failure.
+int lfs_setattr(lfs_t *lfs, const char *path,
+ uint8_t type, const void *buffer, lfs_size_t size);
+#endif
+
+#ifndef LFS_READONLY
+// Removes a custom attribute
+//
+// If an attribute is not found, nothing happens.
+//
+// Returns a negative error code on failure.
+int lfs_removeattr(lfs_t *lfs, const char *path, uint8_t type);
+#endif
+
+
+/// File operations ///
+
+#ifndef LFS_NO_MALLOC
+// Open a file
+//
+// The mode that the file is opened in is determined by the flags, which
+// are values from the enum lfs_open_flags that are bitwise-ored together.
+//
+// Returns a negative error code on failure.
+int lfs_file_open(lfs_t *lfs, lfs_file_t *file,
+ const char *path, int flags);
+
+// if LFS_NO_MALLOC is defined, lfs_file_open() will fail with LFS_ERR_NOMEM
+// thus use lfs_file_opencfg() with config.buffer set.
+#endif
+
+// Open a file with extra configuration
+//
+// The mode that the file is opened in is determined by the flags, which
+// are values from the enum lfs_open_flags that are bitwise-ored together.
+//
+// The config struct provides additional config options per file as described
+// above. The config struct must remain allocated while the file is open, and
+// the config struct must be zeroed for defaults and backwards compatibility.
+//
+// Returns a negative error code on failure.
+int lfs_file_opencfg(lfs_t *lfs, lfs_file_t *file,
+ const char *path, int flags,
+ const struct lfs_file_config *config);
+
+// Close a file
+//
+// Any pending writes are written out to storage as though
+// sync had been called and releases any allocated resources.
+//
+// Returns a negative error code on failure.
+int lfs_file_close(lfs_t *lfs, lfs_file_t *file);
+
+// Synchronize a file on storage
+//
+// Any pending writes are written out to storage.
+// Returns a negative error code on failure.
+int lfs_file_sync(lfs_t *lfs, lfs_file_t *file);
+
+// Read data from file
+//
+// Takes a buffer and size indicating where to store the read data.
+// Returns the number of bytes read, or a negative error code on failure.
+lfs_ssize_t lfs_file_read(lfs_t *lfs, lfs_file_t *file,
+ void *buffer, lfs_size_t size);
+
+#ifndef LFS_READONLY
+// Write data to file
+//
+// Takes a buffer and size indicating the data to write. The file will not
+// actually be updated on the storage until either sync or close is called.
+//
+// Returns the number of bytes written, or a negative error code on failure.
+lfs_ssize_t lfs_file_write(lfs_t *lfs, lfs_file_t *file,
+ const void *buffer, lfs_size_t size);
+#endif
+
+// Change the position of the file
+//
+// The change in position is determined by the offset and whence flag.
+// Returns the new position of the file, or a negative error code on failure.
+lfs_soff_t lfs_file_seek(lfs_t *lfs, lfs_file_t *file,
+ lfs_soff_t off, int whence);
+
+#ifndef LFS_READONLY
+// Truncates the size of the file to the specified size
+//
+// Returns a negative error code on failure.
+int lfs_file_truncate(lfs_t *lfs, lfs_file_t *file, lfs_off_t size);
+#endif
+
+// Return the position of the file
+//
+// Equivalent to lfs_file_seek(lfs, file, 0, LFS_SEEK_CUR)
+// Returns the position of the file, or a negative error code on failure.
+lfs_soff_t lfs_file_tell(lfs_t *lfs, lfs_file_t *file);
+
+// Change the position of the file to the beginning of the file
+//
+// Equivalent to lfs_file_seek(lfs, file, 0, LFS_SEEK_SET)
+// Returns a negative error code on failure.
+int lfs_file_rewind(lfs_t *lfs, lfs_file_t *file);
+
+// Return the size of the file
+//
+// Similar to lfs_file_seek(lfs, file, 0, LFS_SEEK_END)
+// Returns the size of the file, or a negative error code on failure.
+lfs_soff_t lfs_file_size(lfs_t *lfs, lfs_file_t *file);
+
+
+/// Directory operations ///
+
+#ifndef LFS_READONLY
+// Create a directory
+//
+// Returns a negative error code on failure.
+int lfs_mkdir(lfs_t *lfs, const char *path);
+#endif
+
+// Open a directory
+//
+// Once open a directory can be used with read to iterate over files.
+// Returns a negative error code on failure.
+int lfs_dir_open(lfs_t *lfs, lfs_dir_t *dir, const char *path);
+
+// Close a directory
+//
+// Releases any allocated resources.
+// Returns a negative error code on failure.
+int lfs_dir_close(lfs_t *lfs, lfs_dir_t *dir);
+
+// Read an entry in the directory
+//
+// Fills out the info structure, based on the specified file or directory.
+// Returns a positive value on success, 0 at the end of directory,
+// or a negative error code on failure.
+int lfs_dir_read(lfs_t *lfs, lfs_dir_t *dir, struct lfs_info *info);
+
+// Change the position of the directory
+//
+// The new off must be a value previous returned from tell and specifies
+// an absolute offset in the directory seek.
+//
+// Returns a negative error code on failure.
+int lfs_dir_seek(lfs_t *lfs, lfs_dir_t *dir, lfs_off_t off);
+
+// Return the position of the directory
+//
+// The returned offset is only meant to be consumed by seek and may not make
+// sense, but does indicate the current position in the directory iteration.
+//
+// Returns the position of the directory, or a negative error code on failure.
+lfs_soff_t lfs_dir_tell(lfs_t *lfs, lfs_dir_t *dir);
+
+// Change the position of the directory to the beginning of the directory
+//
+// Returns a negative error code on failure.
+int lfs_dir_rewind(lfs_t *lfs, lfs_dir_t *dir);
+
+
+/// Filesystem-level filesystem operations
+
+// Find on-disk info about the filesystem
+//
+// Fills out the fsinfo structure based on the filesystem found on-disk.
+// Returns a negative error code on failure.
+int lfs_fs_stat(lfs_t *lfs, struct lfs_fsinfo *fsinfo);
+
+// Finds the current size of the filesystem
+//
+// Note: Result is best effort. If files share COW structures, the returned
+// size may be larger than the filesystem actually is.
+//
+// Returns the number of allocated blocks, or a negative error code on failure.
+lfs_ssize_t lfs_fs_size(lfs_t *lfs);
+
+// Traverse through all blocks in use by the filesystem
+//
+// The provided callback will be called with each block address that is
+// currently in use by the filesystem. This can be used to determine which
+// blocks are in use or how much of the storage is available.
+//
+// Returns a negative error code on failure.
+int lfs_fs_traverse(lfs_t *lfs, int (*cb)(void*, lfs_block_t), void *data);
+
+#ifndef LFS_READONLY
+// Attempt to make the filesystem consistent and ready for writing
+//
+// Calling this function is not required, consistency will be implicitly
+// enforced on the first operation that writes to the filesystem, but this
+// function allows the work to be performed earlier and without other
+// filesystem changes.
+//
+// Returns a negative error code on failure.
+int lfs_fs_mkconsistent(lfs_t *lfs);
+#endif
+
+#ifndef LFS_READONLY
+// Attempt any janitorial work
+//
+// This currently:
+// 1. Calls mkconsistent if not already consistent
+// 2. Compacts metadata > compact_thresh
+// 3. Populates the block allocator
+//
+// Though additional janitorial work may be added in the future.
+//
+// Calling this function is not required, but may allow the offloading of
+// expensive janitorial work to a less time-critical code path.
+//
+// Returns a negative error code on failure. Accomplishing nothing is not
+// an error.
+int lfs_fs_gc(lfs_t *lfs);
+#endif
+
+#ifndef LFS_READONLY
+// Grows the filesystem to a new size, updating the superblock with the new
+// block count.
+//
+// Note: This is irreversible.
+//
+// Returns a negative error code on failure.
+int lfs_fs_grow(lfs_t *lfs, lfs_size_t block_count);
+#endif
+
+#ifndef LFS_READONLY
+#ifdef LFS_MIGRATE
+// Attempts to migrate a previous version of littlefs
+//
+// Behaves similarly to the lfs_format function. Attempts to mount
+// the previous version of littlefs and update the filesystem so it can be
+// mounted with the current version of littlefs.
+//
+// Requires a littlefs object and config struct. This clobbers the littlefs
+// object, and does not leave the filesystem mounted. The config struct must
+// be zeroed for defaults and backwards compatibility.
+//
+// Returns a negative error code on failure.
+int lfs_migrate(lfs_t *lfs, const struct lfs_config *cfg);
+#endif
+#endif
+
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif
diff --git a/Ganesha_II_V2/Core/Inc/littlefs/lfs_util.h b/Ganesha_II_V2/Core/Inc/littlefs/lfs_util.h
new file mode 100644
index 0000000..0aec488
--- /dev/null
+++ b/Ganesha_II_V2/Core/Inc/littlefs/lfs_util.h
@@ -0,0 +1,273 @@
+/*
+ * lfs utility functions
+ *
+ * Copyright (c) 2022, The littlefs authors.
+ * Copyright (c) 2017, Arm Limited. All rights reserved.
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef LFS_UTIL_H
+#define LFS_UTIL_H
+
+#define LFS_STRINGIZE(x) LFS_STRINGIZE2(x)
+#define LFS_STRINGIZE2(x) #x
+
+// Users can override lfs_util.h with their own configuration by defining
+// LFS_CONFIG as a header file to include (-DLFS_CONFIG=lfs_config.h).
+//
+// If LFS_CONFIG is used, none of the default utils will be emitted and must be
+// provided by the config file. To start, I would suggest copying lfs_util.h
+// and modifying as needed.
+#ifdef LFS_CONFIG
+#include LFS_STRINGIZE(LFS_CONFIG)
+#else
+
+// Alternatively, users can provide a header file which defines
+// macros and other things consumed by littlefs.
+//
+// For example, provide my_defines.h, which contains
+// something like:
+//
+// #include
+// extern void *my_malloc(size_t sz);
+// #define LFS_MALLOC(sz) my_malloc(sz)
+//
+// And build littlefs with the header by defining LFS_DEFINES.
+// (-DLFS_DEFINES=my_defines.h)
+
+#ifdef LFS_DEFINES
+#include LFS_STRINGIZE(LFS_DEFINES)
+#endif
+
+// System includes
+#include
+#include
+#include
+#include
+
+#ifndef LFS_NO_MALLOC
+#include
+#endif
+#ifndef LFS_NO_ASSERT
+#include
+#endif
+#if !defined(LFS_NO_DEBUG) || \
+ !defined(LFS_NO_WARN) || \
+ !defined(LFS_NO_ERROR) || \
+ defined(LFS_YES_TRACE)
+#include
+#endif
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+
+// Macros, may be replaced by system specific wrappers. Arguments to these
+// macros must not have side-effects as the macros can be removed for a smaller
+// code footprint
+
+// Logging functions
+#ifndef LFS_TRACE
+#ifdef LFS_YES_TRACE
+#define LFS_TRACE_(fmt, ...) \
+ printf("%s:%d:trace: " fmt "%s\n", __FILE__, __LINE__, __VA_ARGS__)
+#define LFS_TRACE(...) LFS_TRACE_(__VA_ARGS__, "")
+#else
+#define LFS_TRACE(...)
+#endif
+#endif
+
+#ifndef LFS_DEBUG
+#ifndef LFS_NO_DEBUG
+#define LFS_DEBUG_(fmt, ...) \
+ printf("%s:%d:debug: " fmt "%s\n", __FILE__, __LINE__, __VA_ARGS__)
+#define LFS_DEBUG(...) LFS_DEBUG_(__VA_ARGS__, "")
+#else
+#define LFS_DEBUG(...)
+#endif
+#endif
+
+#ifndef LFS_WARN
+#ifndef LFS_NO_WARN
+#define LFS_WARN_(fmt, ...) \
+ printf("%s:%d:warn: " fmt "%s\n", __FILE__, __LINE__, __VA_ARGS__)
+#define LFS_WARN(...) LFS_WARN_(__VA_ARGS__, "")
+#else
+#define LFS_WARN(...)
+#endif
+#endif
+
+#ifndef LFS_ERROR
+#ifndef LFS_NO_ERROR
+#define LFS_ERROR_(fmt, ...) \
+ printf("%s:%d:error: " fmt "%s\n", __FILE__, __LINE__, __VA_ARGS__)
+#define LFS_ERROR(...) LFS_ERROR_(__VA_ARGS__, "")
+#else
+#define LFS_ERROR(...)
+#endif
+#endif
+
+// Runtime assertions
+#ifndef LFS_ASSERT
+#ifndef LFS_NO_ASSERT
+#define LFS_ASSERT(test) assert(test)
+#else
+#define LFS_ASSERT(test)
+#endif
+#endif
+
+
+// Builtin functions, these may be replaced by more efficient
+// toolchain-specific implementations. LFS_NO_INTRINSICS falls back to a more
+// expensive basic C implementation for debugging purposes
+
+// Min/max functions for unsigned 32-bit numbers
+static inline uint32_t lfs_max(uint32_t a, uint32_t b) {
+ return (a > b) ? a : b;
+}
+
+static inline uint32_t lfs_min(uint32_t a, uint32_t b) {
+ return (a < b) ? a : b;
+}
+
+// Align to nearest multiple of a size
+static inline uint32_t lfs_aligndown(uint32_t a, uint32_t alignment) {
+ return a - (a % alignment);
+}
+
+static inline uint32_t lfs_alignup(uint32_t a, uint32_t alignment) {
+ return lfs_aligndown(a + alignment-1, alignment);
+}
+
+// Find the smallest power of 2 greater than or equal to a
+static inline uint32_t lfs_npw2(uint32_t a) {
+#if !defined(LFS_NO_INTRINSICS) && (defined(__GNUC__) || defined(__CC_ARM))
+ return 32 - __builtin_clz(a-1);
+#else
+ uint32_t r = 0;
+ uint32_t s;
+ a -= 1;
+ s = (a > 0xffff) << 4; a >>= s; r |= s;
+ s = (a > 0xff ) << 3; a >>= s; r |= s;
+ s = (a > 0xf ) << 2; a >>= s; r |= s;
+ s = (a > 0x3 ) << 1; a >>= s; r |= s;
+ return (r | (a >> 1)) + 1;
+#endif
+}
+
+// Count the number of trailing binary zeros in a
+// lfs_ctz(0) may be undefined
+static inline uint32_t lfs_ctz(uint32_t a) {
+#if !defined(LFS_NO_INTRINSICS) && defined(__GNUC__)
+ return __builtin_ctz(a);
+#else
+ return lfs_npw2((a & -a) + 1) - 1;
+#endif
+}
+
+// Count the number of binary ones in a
+static inline uint32_t lfs_popc(uint32_t a) {
+#if !defined(LFS_NO_INTRINSICS) && (defined(__GNUC__) || defined(__CC_ARM))
+ return __builtin_popcount(a);
+#else
+ a = a - ((a >> 1) & 0x55555555);
+ a = (a & 0x33333333) + ((a >> 2) & 0x33333333);
+ return (((a + (a >> 4)) & 0xf0f0f0f) * 0x1010101) >> 24;
+#endif
+}
+
+// Find the sequence comparison of a and b, this is the distance
+// between a and b ignoring overflow
+static inline int lfs_scmp(uint32_t a, uint32_t b) {
+ return (int)(unsigned)(a - b);
+}
+
+// Convert between 32-bit little-endian and native order
+static inline uint32_t lfs_fromle32(uint32_t a) {
+#if (defined( BYTE_ORDER ) && defined( ORDER_LITTLE_ENDIAN ) && BYTE_ORDER == ORDER_LITTLE_ENDIAN ) || \
+ (defined(__BYTE_ORDER ) && defined(__ORDER_LITTLE_ENDIAN ) && __BYTE_ORDER == __ORDER_LITTLE_ENDIAN ) || \
+ (defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
+ return a;
+#elif !defined(LFS_NO_INTRINSICS) && ( \
+ (defined( BYTE_ORDER ) && defined( ORDER_BIG_ENDIAN ) && BYTE_ORDER == ORDER_BIG_ENDIAN ) || \
+ (defined(__BYTE_ORDER ) && defined(__ORDER_BIG_ENDIAN ) && __BYTE_ORDER == __ORDER_BIG_ENDIAN ) || \
+ (defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__))
+ return __builtin_bswap32(a);
+#else
+ return (((uint8_t*)&a)[0] << 0) |
+ (((uint8_t*)&a)[1] << 8) |
+ (((uint8_t*)&a)[2] << 16) |
+ (((uint8_t*)&a)[3] << 24);
+#endif
+}
+
+static inline uint32_t lfs_tole32(uint32_t a) {
+ return lfs_fromle32(a);
+}
+
+// Convert between 32-bit big-endian and native order
+static inline uint32_t lfs_frombe32(uint32_t a) {
+#if !defined(LFS_NO_INTRINSICS) && ( \
+ (defined( BYTE_ORDER ) && defined( ORDER_LITTLE_ENDIAN ) && BYTE_ORDER == ORDER_LITTLE_ENDIAN ) || \
+ (defined(__BYTE_ORDER ) && defined(__ORDER_LITTLE_ENDIAN ) && __BYTE_ORDER == __ORDER_LITTLE_ENDIAN ) || \
+ (defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__))
+ return __builtin_bswap32(a);
+#elif (defined( BYTE_ORDER ) && defined( ORDER_BIG_ENDIAN ) && BYTE_ORDER == ORDER_BIG_ENDIAN ) || \
+ (defined(__BYTE_ORDER ) && defined(__ORDER_BIG_ENDIAN ) && __BYTE_ORDER == __ORDER_BIG_ENDIAN ) || \
+ (defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
+ return a;
+#else
+ return (((uint8_t*)&a)[0] << 24) |
+ (((uint8_t*)&a)[1] << 16) |
+ (((uint8_t*)&a)[2] << 8) |
+ (((uint8_t*)&a)[3] << 0);
+#endif
+}
+
+static inline uint32_t lfs_tobe32(uint32_t a) {
+ return lfs_frombe32(a);
+}
+
+// Calculate CRC-32 with polynomial = 0x04c11db7
+#ifdef LFS_CRC
+uint32_t lfs_crc(uint32_t crc, const void *buffer, size_t size) {
+ return LFS_CRC(crc, buffer, size)
+}
+#else
+uint32_t lfs_crc(uint32_t crc, const void *buffer, size_t size);
+#endif
+
+// Allocate memory, only used if buffers are not provided to littlefs
+//
+// littlefs current has no alignment requirements, as it only allocates
+// byte-level buffers.
+static inline void *lfs_malloc(size_t size) {
+#if defined(LFS_MALLOC)
+ return LFS_MALLOC(size);
+#elif !defined(LFS_NO_MALLOC)
+ return malloc(size);
+#else
+ (void)size;
+ return NULL;
+#endif
+}
+
+// Deallocate memory, only used if buffers are not provided to littlefs
+static inline void lfs_free(void *p) {
+#if defined(LFS_FREE)
+ LFS_FREE(p);
+#elif !defined(LFS_NO_MALLOC)
+ free(p);
+#else
+ (void)p;
+#endif
+}
+
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif
+#endif
diff --git a/Ganesha_II_V2/Core/Inc/main.h b/Ganesha_II_V2/Core/Inc/main.h
index e0cd6e4..33312c8 100644
--- a/Ganesha_II_V2/Core/Inc/main.h
+++ b/Ganesha_II_V2/Core/Inc/main.h
@@ -53,6 +53,7 @@ extern TIM_HandleTypeDef htim2;
void Error_Handler(void);
/* USER CODE BEGIN EFP */
+void handle_usb_cdc(uint8_t* buf, uint32_t len);
/* USER CODE END EFP */
diff --git a/Ganesha_II_V2/Core/Inc/stm32h7xx_it.h b/Ganesha_II_V2/Core/Inc/stm32h7xx_it.h
index 3ad2e86..49bef0a 100644
--- a/Ganesha_II_V2/Core/Inc/stm32h7xx_it.h
+++ b/Ganesha_II_V2/Core/Inc/stm32h7xx_it.h
@@ -61,6 +61,7 @@ void DMA1_Stream0_IRQHandler(void);
void TIM1_UP_IRQHandler(void);
void EXTI15_10_IRQHandler(void);
void UART5_IRQHandler(void);
+void OTG_FS_IRQHandler(void);
/* USER CODE BEGIN EFP */
/* USER CODE END EFP */
diff --git a/Ganesha_II_V2/Core/Src/flash/flash.c b/Ganesha_II_V2/Core/Src/flash/flash.c
new file mode 100644
index 0000000..ae961e5
--- /dev/null
+++ b/Ganesha_II_V2/Core/Src/flash/flash.c
@@ -0,0 +1,109 @@
+#include "flash.h"
+
+#include "w25n01kv.h"
+#include "gd5f1gq5xe.h"
+#include "lfs.h"
+
+#include "STRUCTS.h"
+
+#include
+
+// See: https://github.com/littlefs-project/littlefs/issues/564#issuecomment-2363032827
+// This gives how many bytes are needed before we need to do a fsync. Since we
+// want to sync at the end of a block, this just gives offset from the end.
+//
+// We don't want to sync too often, especially for NAND flashes which have
+// larger block sizes because littlefs does a whole scan and write of the
+// partial block, which is very time-consuming.
+static inline uint32_t offset(uint32_t filesize, uint32_t blocksize)
+{
+ // Edge case for the first block
+ if (filesize < blocksize) {
+ return blocksize - filesize;
+ }
+
+ const uint32_t w = sizeof(uint32_t);
+ uint32_t pop = __builtin_popcount((filesize / (blocksize - (2*w))) - 1);
+ uint32_t n = (filesize - (w * (pop + 2))) / (blocksize - 2*w);
+ uint32_t offset = filesize - (blocksize - 2*w)*n - w*__builtin_popcount(n);
+ return blocksize - offset;
+}
+
+void flash_init(struct flash_dev *dev, enum flash_name name)
+{
+ dev->name = name;
+}
+
+lfs_ssize_t flash_mount(struct flash_dev *flash, const struct lfs_config *config)
+{
+ if (!gd5f1gq5xe_unlock()) return -1;
+ int err = lfs_mount(&(flash->lfs), config);
+ if (err) {
+ lfs_format(&(flash->lfs), config);
+ int res = lfs_mount(&(flash->lfs), config);
+ if (res < 0) return -1;
+ }
+ flash_boot_count(flash, true);
+ return lfs_fs_size(&(flash->lfs));
+}
+
+int flash_unmount(struct flash_dev *flash)
+{
+ return lfs_unmount(&(flash->lfs));
+}
+
+uint32_t flash_boot_count(struct flash_dev *flash, bool update)
+{
+ lfs_file_t file;
+ uint32_t boot_count = 0;
+
+ lfs_file_open(&(flash->lfs), &file, "boot_count", LFS_O_RDWR | LFS_O_CREAT);
+ lfs_file_read(&(flash->lfs), &file, &boot_count, sizeof(boot_count));
+
+ if (update) {
+ ++boot_count;
+ lfs_file_rewind(&(flash->lfs), &file);
+ lfs_file_write(&(flash->lfs), &file, &boot_count, sizeof(boot_count));
+ }
+
+ lfs_file_close(&(flash->lfs), &file);
+ return boot_count;
+}
+
+uint32_t flash_open(struct flash_dev *flash, lfs_file_t *file, const char *filename)
+{
+ lfs_file_open(&(flash->lfs), file, filename, LFS_O_RDWR | LFS_O_CREAT | LFS_O_APPEND);
+ return lfs_file_size(&(flash->lfs), file);
+}
+
+bool flash_append(struct flash_dev *flash, lfs_file_t *file, const uint8_t *bytes, uint32_t size)
+{
+ uint8_t *buf = (uint8_t *) bytes;
+ uint32_t filesize = lfs_file_size(&(flash->lfs), file);
+ uint32_t off = offset(filesize, flash->lfs.cfg->block_size);
+
+ while (size > 0) {
+ uint32_t write_size = size < off ? size : off;
+ if (off == 0) {
+ // Time for a new block, sync and just write whatever
+ lfs_file_sync(&(flash->lfs), file);
+ // Due to constraints, the size is guaranteed to be less
+ // than a block size, so we can just safely do this
+ write_size = size;
+ }
+
+ uint32_t res = lfs_file_write(&(flash->lfs), file, buf, write_size);
+ if (res != write_size) return false;
+
+ size -= res;
+ filesize += res;
+ buf += res;
+ off = offset(filesize, flash->lfs.cfg->block_size);
+ }
+ return true;
+}
+
+int flash_close(struct flash_dev *flash, lfs_file_t *file)
+{
+ return lfs_file_close(&(flash->lfs), file);
+}
diff --git a/Ganesha_II_V2/Core/Src/flash/gd5f1gq5xe.c b/Ganesha_II_V2/Core/Src/flash/gd5f1gq5xe.c
new file mode 100644
index 0000000..316105b
--- /dev/null
+++ b/Ganesha_II_V2/Core/Src/flash/gd5f1gq5xe.c
@@ -0,0 +1,275 @@
+#include "gd5f1gq5xe.h"
+
+#include "main.h"
+
+#include
+
+// Flash Commands
+#define GD5F_SET_FEATURE 0x1F
+#define GD5F_WRITE_ENABLE 0x06
+#define GD5F_WRITE_DISABLE 0x04
+#define GD5F_READ_TO_CACHE 0x13
+#define GD5F_READ_FROM_CACHE 0x03
+#define GD5F_PROGRAM_LOAD 0x02
+#define GD5F_PROGRAM_EXECUTE 0x10
+#define GD5F_ERASE 0xD8
+#define GD5F_READ_ID 0x9F
+
+// This is a NAND flash which uses 3-byte addressing, this means we have
+//
+// | block address | page address |
+// | bytes <15-6> | bytes <5-0> |
+//
+// NAND flashes employ a two step read and progamming process. For reading we
+// first fetch the page using the 3-byte addressing to the cache, and then use a
+// second command to read from the cache, here we can index the bytes using a
+// column address 12 bytes.
+//
+// For writing, we do the inverse. We populate the cache with bytes using the index.
+// After it is filled, we can then write the page to the flash using the 3-byte addressing
+//
+// Note that this flash has a page size of 2048, so we actually only need 11 bytes for
+// the column address.
+
+// TODO: this should be abstracted away into littlefs's context object
+extern SPI_HandleTypeDef hspi4;
+
+static void chip_select()
+{
+ HAL_GPIO_WritePin(FLASH_CS_GPIO_Port, FLASH_CS_Pin, GPIO_PIN_RESET);
+}
+
+static void chip_deselect()
+{
+ HAL_GPIO_WritePin(FLASH_CS_GPIO_Port, FLASH_CS_Pin, GPIO_PIN_SET);
+}
+
+static bool spi_transmit(void *buffer, const size_t size)
+{
+ return HAL_SPI_Transmit(&hspi4, (uint8_t*) buffer, size, HAL_MAX_DELAY);
+}
+
+static bool spi_receive(void *buffer, const size_t size)
+{
+ return HAL_SPI_Receive(&hspi4, (uint8_t*) buffer, size, HAL_MAX_DELAY);
+}
+
+static int write_enable()
+{
+ uint8_t tx = GD5F_WRITE_ENABLE;
+ chip_select();
+ if (spi_transmit(&tx, sizeof(tx)) != 0) {
+ chip_deselect();
+ return 1;
+ }
+ chip_deselect();
+ return 0;
+}
+
+static bool check_id()
+{
+ chip_select();
+ uint8_t cmd[] = { GD5F_READ_ID, 0x00 };
+ uint8_t data[] = { 0, 0 };
+ if (spi_transmit(cmd, sizeof(cmd)) != 0) {
+ chip_deselect();
+ }
+ spi_receive(data, sizeof(data));
+ chip_deselect();
+ // Sometimes the check is not consistent
+ // Investigate for now
+ return data[0] == 0xC8 && data[1] == 0x31;
+ /* assert(data[0] == 0xC8); */
+ /* assert(data[1] == 0x31); */
+}
+
+/// Read a page from the flash into the `buffer`.
+///
+/// `block` must be less than the block-count
+/// `offset` must be less than than the block-size
+/// `size` can be larger than the page-size, but this function will only
+/// read up to the page-size boundary
+///
+/// Returns the number of bytes read.
+static uint32_t gd5f1gq5xe_read_page(const uint32_t block, const uint32_t offset,
+ void *buffer, uint32_t size)
+{
+ assert(block < GD5F_BLOCK_COUNT);
+ assert(offset < GD5F_BLOCK_SIZE);
+
+ // This combines the block and offset to create our 3-byte address
+ // Notice that `block * GD5F_PAGES_PER_BLOCK` is equivalent to
+ // `block << 6`, which is why this code here works.
+ uint32_t addr = block * GD5F_PAGES_PER_BLOCK + (offset / GD5F_PAGE_SIZE);
+ // We can then use the column addreess to read offsets into the page
+ uint16_t col = offset % GD5F_PAGE_SIZE;
+
+ uint8_t tx1[] = {
+ GD5F_READ_TO_CACHE,
+ (addr & 0xFF0000) >> 16,
+ (addr & 0x00FF00) >> 8,
+ (addr & 0x0000FF)
+ };
+ chip_select();
+ if (spi_transmit(tx1, sizeof(tx1)) != 0) {
+ chip_deselect();
+ return 0;
+ }
+ chip_deselect();
+ HAL_Delay(2); // Required delay for cache read
+
+ uint8_t tx2[] = {
+ GD5F_READ_FROM_CACHE,
+ (col & 0x0F00) >> 8, // first 4 bytes are not needed,
+ (col & 0x00FF), // remember that we only need 12 bytes
+ 0x00 // we need a dummy byte (from datasheet)
+ };
+ chip_select();
+ if (spi_transmit(tx2, sizeof(tx2)) != 0) {
+ chip_deselect();
+ return 0;
+ };
+ uint32_t read_size = size <= GD5F_PAGE_SIZE - col ? size : GD5F_PAGE_SIZE - col;
+ if (spi_receive(buffer, read_size) != 0) {
+ chip_deselect();
+ return 0;
+ }
+ chip_deselect();
+ return read_size;
+}
+
+/// Write a page from the `buffer` into the flash
+///
+/// `block` must be less than the block-count
+/// `offset` must be less than than the block-size
+/// `size` can be larger than the page-size, but this function will only
+/// write up to the page-size boundary
+///
+/// Returns the number of bytes written.
+static uint32_t gd5f1gq5xe_write_page(const uint32_t block, const uint32_t offset,
+ const void *buffer, const uint32_t size)
+{
+ assert(block < GD5F_BLOCK_COUNT);
+ assert(offset < GD5F_BLOCK_SIZE);
+
+ uint32_t addr = block * GD5F_PAGES_PER_BLOCK + (offset / GD5F_PAGE_SIZE);
+ uint16_t col = offset % GD5F_PAGE_SIZE;
+
+ uint8_t tx1[] = {
+ GD5F_PROGRAM_LOAD,
+ (col & 0x0F00) >> 8, // similar to before, the first 4 bytes
+ (col & 0x00FF) // are not needed, hence the 0x0F00
+ };
+ chip_select();
+ if (spi_transmit(tx1, sizeof(tx1)) != 0) {
+ chip_deselect();
+ return 0;
+ }
+ uint32_t write_size = size <= GD5F_PAGE_SIZE - col ? size : GD5F_PAGE_SIZE - col;
+ if (spi_transmit(buffer, write_size) != 0) {
+ chip_deselect();
+ return 0;
+ };
+ chip_deselect();
+
+ if (write_enable() != 0) {
+ chip_deselect();
+ return 0;
+ }
+
+ uint8_t tx2[] = {
+ GD5F_PROGRAM_EXECUTE,
+ (addr & 0xFF0000) >> 16,
+ (addr & 0x00FF00) >> 8,
+ (addr & 0x0000FF)
+ };
+ chip_select();
+ if (spi_transmit(tx2, sizeof(tx2)) != 0) {
+ chip_deselect();
+ return 0;
+ }
+ chip_deselect();
+
+ HAL_Delay(1);
+ return write_size;
+}
+
+bool gd5f1gq5xe_read(uint32_t block, uint32_t offset, void *buffer, uint32_t size)
+{
+ uint8_t *buf = (uint8_t *) buffer;
+ while (size > 0) {
+ uint32_t s = gd5f1gq5xe_read_page(block, offset, buf, size);
+ if (s == 0) return false;
+ size -= s;
+ offset += s;
+ buf += s;
+ }
+ return true;
+}
+
+bool gd5f1gq5xe_write(uint32_t block, uint32_t offset, void *buffer, uint32_t size)
+{
+ uint8_t *buf = (uint8_t *) buffer;
+ while (size > 0) {
+ uint32_t s = gd5f1gq5xe_write_page(block, offset, buf, size);
+ if (s == 0) return false;
+ size -= s;
+ offset += s;
+ buf += s;
+ }
+ return true;
+}
+
+bool gd5f1gq5xe_erase(uint32_t block)
+{
+ // Erase acts on blocks and not pages, so we should only have the block
+ // section of the address set and not the page section.
+ uint32_t addr = block * GD5F_PAGES_PER_BLOCK;
+
+ if (write_enable() != 0) {
+ chip_deselect();
+ return false;
+ }
+
+ uint8_t tx[] = {
+ GD5F_ERASE,
+ (addr & 0xFF0000) >> 16,
+ (addr & 0x00FF00) >> 8,
+ (addr & 0x0000FF)
+ };
+ chip_select();
+ if (spi_transmit(tx, sizeof(tx)) != 0) {
+ chip_deselect();
+ return false;
+ }
+ chip_deselect();
+
+ HAL_Delay(12);
+ return true;
+}
+
+bool gd5f1gq5xe_unlock()
+{
+ // Needed for some reason, I don't know why
+ HAL_Delay(5000);
+ if (!check_id()) return false;
+ if (write_enable() != 0) {
+ chip_deselect();
+ return false;
+ }
+
+ uint8_t tx[] = {
+ GD5F_SET_FEATURE,
+ 0xA0,
+ 0x00,
+ };
+ chip_select();
+ if (spi_transmit(tx, sizeof(tx)) != 0) {
+ chip_deselect();
+ return false;
+ }
+ chip_deselect();
+
+ HAL_Delay(5000);
+ return true;
+}
diff --git a/Ganesha_II_V2/Core/Src/flash/w25n01kv.c b/Ganesha_II_V2/Core/Src/flash/w25n01kv.c
new file mode 100644
index 0000000..d63cba8
--- /dev/null
+++ b/Ganesha_II_V2/Core/Src/flash/w25n01kv.c
@@ -0,0 +1,189 @@
+#include "w25n01kv.h"
+
+#include "main.h"
+
+#include
+#include
+
+extern SPI_HandleTypeDef hspi4;
+
+static void chip_select()
+{
+ HAL_GPIO_WritePin(FLASH_CS_GPIO_Port, FLASH_CS_Pin, GPIO_PIN_RESET);
+}
+
+static void chip_deselect()
+{
+ HAL_GPIO_WritePin(FLASH_CS_GPIO_Port, FLASH_CS_Pin, GPIO_PIN_SET);
+}
+
+static int spi_transmit(void *buffer, const size_t size)
+{
+ return HAL_SPI_Transmit(&hspi4, (uint8_t*) buffer, size, HAL_MAX_DELAY);
+}
+
+static int spi_receive(void *buffer, const size_t size)
+{
+ return HAL_SPI_Receive(&hspi4, (uint8_t*) buffer, size, HAL_MAX_DELAY);
+}
+
+static int w25n01kv_write_enable()
+{
+ uint8_t tx = W25N_CMD_WRITE_ENABLE;
+ chip_select();
+ if (spi_transmit(&tx, sizeof(tx)) != 0) {
+ chip_deselect();
+ return 1;
+ }
+ chip_deselect();
+ return 0;
+}
+
+static int w25n01kv_write_disable()
+{
+ uint8_t tx = W25N_CMD_WRITE_DISABLE;
+ chip_select();
+ if (spi_transmit(&tx, sizeof(tx)) != 0) {
+ chip_deselect();
+ return 1;
+ }
+ chip_deselect();
+ return 0;
+}
+
+int w25n01kv_read(const uint32_t page, const uint16_t col, void *buffer, const size_t size)
+{
+ // Read Page Command requires read op code followed by 24-bit address
+ uint8_t tx1[] = {
+ W25N_CMD_PAGE_DATA_READ,
+ (page & 0xFF0000) >> 16,
+ (page & 0x00FF00) >> 8,
+ (page & 0x0000FF)
+ };
+ chip_select();
+ if (spi_transmit(tx1, sizeof(tx1)) != 0) {
+ chip_deselect();
+ return 1;
+ }
+ chip_deselect();
+ HAL_Delay(1);
+
+ // Read Data Command requires read op code followed by 16-bit address
+ // and a 8-bit dummy clock, called after read page in order to actually
+ // get the data. The 16-bit address refers to the column
+ uint8_t tx2[] = {
+ W25N_CMD_READ_FROM_BUFFER,
+ (col & 0xFF00) >> 8,
+ (col & 0x00FF),
+ 0xFF
+ };
+ chip_select();
+ if (!spi_transmit(tx2, sizeof(tx2))) {
+ chip_deselect();
+ return 1;
+ };
+ if (!spi_receive(buffer, size)) {
+ chip_deselect();
+ return 1;
+ }
+ chip_deselect();
+ return 0;
+}
+
+
+int w25n01kv_write(const uint32_t page, const uint16_t col, const void *buffer, const size_t size)
+{
+ if (!w25n01kv_write_enable()) {
+ chip_deselect();
+ return 1;
+ }
+ chip_select();
+
+ uint8_t tx1[] = {
+ W25N_CMD_LOAD_PROGRAM_DATA,
+ (col & 0xFF00) >> 8,
+ (col & 0x00FF)
+ };
+ chip_select();
+ if (!spi_transmit(tx1, sizeof(tx1))) {
+ chip_deselect();
+ return 1;
+ }
+ if (!spi_transmit(buffer, size)) {
+ chip_deselect();
+ return 1;
+ };
+ chip_deselect();
+
+ uint8_t tx2[] = {
+ W25N_CMD_PROGRAM_EXECUTE,
+ (page & 0xFF0000) >> 16,
+ (page & 0x00FF00) >> 8,
+ (page & 0x0000FF)
+ };
+ chip_select();
+ if (!spi_transmit(tx2, sizeof(tx2))) {
+ chip_deselect();
+ return 1;
+ }
+ chip_deselect();
+
+ HAL_Delay(3);
+ return 0;
+}
+
+int w25n01kv_erase(const uint32_t page)
+{
+ if (!w25n01kv_write_enable()) {
+ chip_deselect();
+ return 1;
+ }
+
+ uint8_t tx[] = {
+ W25N_CMD_BLOCK_ERASE,
+ (page & 0xFF0000) >> 16,
+ (page & 0x00FF00) >> 8,
+ (page & 0x0000FF)
+ };
+ chip_select();
+ if (!spi_transmit(tx, sizeof(tx))) {
+ chip_deselect();
+ return 1;
+ }
+ chip_deselect();
+
+ HAL_Delay(10);
+ return 0;
+}
+
+
+int w25n01kv_unlock()
+{
+ chip_select();
+ chip_deselect();
+ uint8_t tx0[] = { 0xFF };
+ // for debugging
+ while (1) {
+ chip_select();
+ if (spi_transmit(tx0, sizeof(tx0)) != 0) {
+ chip_deselect();
+ return 1;
+ }
+ chip_deselect();
+ HAL_Delay(50);
+ }
+
+ uint8_t tx[] = { 0x9F, 0x00 };
+ uint8_t rx[3] = {0};
+ chip_select();
+ if (spi_transmit(tx, sizeof(tx)) != 0) {
+ chip_deselect();
+ return 1;
+ }
+ if (spi_receive(rx, sizeof(rx)) != 0) {
+ chip_deselect();
+ return 1;
+ }
+ chip_deselect();
+ return 0;
+}
diff --git a/Ganesha_II_V2/Core/Src/littlefs/lfs.c b/Ganesha_II_V2/Core/Src/littlefs/lfs.c
new file mode 100644
index 0000000..28a632b
--- /dev/null
+++ b/Ganesha_II_V2/Core/Src/littlefs/lfs.c
@@ -0,0 +1,6518 @@
+/*
+ * The little filesystem
+ *
+ * Copyright (c) 2022, The littlefs authors.
+ * Copyright (c) 2017, Arm Limited. All rights reserved.
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include "lfs.h"
+#include "lfs_util.h"
+
+
+// some constants used throughout the code
+#define LFS_BLOCK_NULL ((lfs_block_t)-1)
+#define LFS_BLOCK_INLINE ((lfs_block_t)-2)
+
+enum {
+ LFS_OK_RELOCATED = 1,
+ LFS_OK_DROPPED = 2,
+ LFS_OK_ORPHANED = 3,
+};
+
+enum {
+ LFS_CMP_EQ = 0,
+ LFS_CMP_LT = 1,
+ LFS_CMP_GT = 2,
+};
+
+
+/// Caching block device operations ///
+
+static inline void lfs_cache_drop(lfs_t *lfs, lfs_cache_t *rcache) {
+ // do not zero, cheaper if cache is readonly or only going to be
+ // written with identical data (during relocates)
+ (void)lfs;
+ rcache->block = LFS_BLOCK_NULL;
+}
+
+static inline void lfs_cache_zero(lfs_t *lfs, lfs_cache_t *pcache) {
+ // zero to avoid information leak
+ memset(pcache->buffer, 0xff, lfs->cfg->cache_size);
+ pcache->block = LFS_BLOCK_NULL;
+}
+
+static int lfs_bd_read(lfs_t *lfs,
+ const lfs_cache_t *pcache, lfs_cache_t *rcache, lfs_size_t hint,
+ lfs_block_t block, lfs_off_t off,
+ void *buffer, lfs_size_t size) {
+ uint8_t *data = buffer;
+ if (off+size > lfs->cfg->block_size
+ || (lfs->block_count && block >= lfs->block_count)) {
+ return LFS_ERR_CORRUPT;
+ }
+
+ while (size > 0) {
+ lfs_size_t diff = size;
+
+ if (pcache && block == pcache->block &&
+ off < pcache->off + pcache->size) {
+ if (off >= pcache->off) {
+ // is already in pcache?
+ diff = lfs_min(diff, pcache->size - (off-pcache->off));
+ memcpy(data, &pcache->buffer[off-pcache->off], diff);
+
+ data += diff;
+ off += diff;
+ size -= diff;
+ continue;
+ }
+
+ // pcache takes priority
+ diff = lfs_min(diff, pcache->off-off);
+ }
+
+ if (block == rcache->block &&
+ off < rcache->off + rcache->size) {
+ if (off >= rcache->off) {
+ // is already in rcache?
+ diff = lfs_min(diff, rcache->size - (off-rcache->off));
+ memcpy(data, &rcache->buffer[off-rcache->off], diff);
+
+ data += diff;
+ off += diff;
+ size -= diff;
+ continue;
+ }
+
+ // rcache takes priority
+ diff = lfs_min(diff, rcache->off-off);
+ }
+
+ if (size >= hint && off % lfs->cfg->read_size == 0 &&
+ size >= lfs->cfg->read_size) {
+ // bypass cache?
+ diff = lfs_aligndown(diff, lfs->cfg->read_size);
+ int err = lfs->cfg->read(lfs->cfg, block, off, data, diff);
+ if (err) {
+ return err;
+ }
+
+ data += diff;
+ off += diff;
+ size -= diff;
+ continue;
+ }
+
+ // load to cache, first condition can no longer fail
+ LFS_ASSERT(!lfs->block_count || block < lfs->block_count);
+ rcache->block = block;
+ rcache->off = lfs_aligndown(off, lfs->cfg->read_size);
+ rcache->size = lfs_min(
+ lfs_min(
+ lfs_alignup(off+hint, lfs->cfg->read_size),
+ lfs->cfg->block_size)
+ - rcache->off,
+ lfs->cfg->cache_size);
+ int err = lfs->cfg->read(lfs->cfg, rcache->block,
+ rcache->off, rcache->buffer, rcache->size);
+ LFS_ASSERT(err <= 0);
+ if (err) {
+ return err;
+ }
+ }
+
+ return 0;
+}
+
+static int lfs_bd_cmp(lfs_t *lfs,
+ const lfs_cache_t *pcache, lfs_cache_t *rcache, lfs_size_t hint,
+ lfs_block_t block, lfs_off_t off,
+ const void *buffer, lfs_size_t size) {
+ const uint8_t *data = buffer;
+ lfs_size_t diff = 0;
+
+ for (lfs_off_t i = 0; i < size; i += diff) {
+ uint8_t dat[8];
+
+ diff = lfs_min(size-i, sizeof(dat));
+ int err = lfs_bd_read(lfs,
+ pcache, rcache, hint-i,
+ block, off+i, &dat, diff);
+ if (err) {
+ return err;
+ }
+
+ int res = memcmp(dat, data + i, diff);
+ if (res) {
+ return res < 0 ? LFS_CMP_LT : LFS_CMP_GT;
+ }
+ }
+
+ return LFS_CMP_EQ;
+}
+
+static int lfs_bd_crc(lfs_t *lfs,
+ const lfs_cache_t *pcache, lfs_cache_t *rcache, lfs_size_t hint,
+ lfs_block_t block, lfs_off_t off, lfs_size_t size, uint32_t *crc) {
+ lfs_size_t diff = 0;
+
+ for (lfs_off_t i = 0; i < size; i += diff) {
+ uint8_t dat[8];
+ diff = lfs_min(size-i, sizeof(dat));
+ int err = lfs_bd_read(lfs,
+ pcache, rcache, hint-i,
+ block, off+i, &dat, diff);
+ if (err) {
+ return err;
+ }
+
+ *crc = lfs_crc(*crc, &dat, diff);
+ }
+
+ return 0;
+}
+
+#ifndef LFS_READONLY
+static int lfs_bd_flush(lfs_t *lfs,
+ lfs_cache_t *pcache, lfs_cache_t *rcache, bool validate) {
+ if (pcache->block != LFS_BLOCK_NULL && pcache->block != LFS_BLOCK_INLINE) {
+ LFS_ASSERT(pcache->block < lfs->block_count);
+ lfs_size_t diff = lfs_alignup(pcache->size, lfs->cfg->prog_size);
+ int err = lfs->cfg->prog(lfs->cfg, pcache->block,
+ pcache->off, pcache->buffer, diff);
+ LFS_ASSERT(err <= 0);
+ if (err) {
+ return err;
+ }
+
+ if (validate) {
+ // check data on disk
+ lfs_cache_drop(lfs, rcache);
+ int res = lfs_bd_cmp(lfs,
+ NULL, rcache, diff,
+ pcache->block, pcache->off, pcache->buffer, diff);
+ if (res < 0) {
+ return res;
+ }
+
+ if (res != LFS_CMP_EQ) {
+ return LFS_ERR_CORRUPT;
+ }
+ }
+
+ lfs_cache_zero(lfs, pcache);
+ }
+
+ return 0;
+}
+#endif
+
+#ifndef LFS_READONLY
+static int lfs_bd_sync(lfs_t *lfs,
+ lfs_cache_t *pcache, lfs_cache_t *rcache, bool validate) {
+ lfs_cache_drop(lfs, rcache);
+
+ int err = lfs_bd_flush(lfs, pcache, rcache, validate);
+ if (err) {
+ return err;
+ }
+
+ err = lfs->cfg->sync(lfs->cfg);
+ LFS_ASSERT(err <= 0);
+ return err;
+}
+#endif
+
+#ifndef LFS_READONLY
+static int lfs_bd_prog(lfs_t *lfs,
+ lfs_cache_t *pcache, lfs_cache_t *rcache, bool validate,
+ lfs_block_t block, lfs_off_t off,
+ const void *buffer, lfs_size_t size) {
+ const uint8_t *data = buffer;
+ LFS_ASSERT(block == LFS_BLOCK_INLINE || block < lfs->block_count);
+ LFS_ASSERT(off + size <= lfs->cfg->block_size);
+
+ while (size > 0) {
+ if (block == pcache->block &&
+ off >= pcache->off &&
+ off < pcache->off + lfs->cfg->cache_size) {
+ // already fits in pcache?
+ lfs_size_t diff = lfs_min(size,
+ lfs->cfg->cache_size - (off-pcache->off));
+ memcpy(&pcache->buffer[off-pcache->off], data, diff);
+
+ data += diff;
+ off += diff;
+ size -= diff;
+
+ pcache->size = lfs_max(pcache->size, off - pcache->off);
+ if (pcache->size == lfs->cfg->cache_size) {
+ // eagerly flush out pcache if we fill up
+ int err = lfs_bd_flush(lfs, pcache, rcache, validate);
+ if (err) {
+ return err;
+ }
+ }
+
+ continue;
+ }
+
+ // pcache must have been flushed, either by programming and
+ // entire block or manually flushing the pcache
+ LFS_ASSERT(pcache->block == LFS_BLOCK_NULL);
+
+ // prepare pcache, first condition can no longer fail
+ pcache->block = block;
+ pcache->off = lfs_aligndown(off, lfs->cfg->prog_size);
+ pcache->size = 0;
+ }
+
+ return 0;
+}
+#endif
+
+#ifndef LFS_READONLY
+static int lfs_bd_erase(lfs_t *lfs, lfs_block_t block) {
+ LFS_ASSERT(block < lfs->block_count);
+ int err = lfs->cfg->erase(lfs->cfg, block);
+ LFS_ASSERT(err <= 0);
+ return err;
+}
+#endif
+
+
+/// Small type-level utilities ///
+
+// some operations on paths
+static inline lfs_size_t lfs_path_namelen(const char *path) {
+ return strcspn(path, "/");
+}
+
+static inline bool lfs_path_islast(const char *path) {
+ lfs_size_t namelen = lfs_path_namelen(path);
+ return path[namelen + strspn(path + namelen, "/")] == '\0';
+}
+
+static inline bool lfs_path_isdir(const char *path) {
+ return path[lfs_path_namelen(path)] != '\0';
+}
+
+// operations on block pairs
+static inline void lfs_pair_swap(lfs_block_t pair[2]) {
+ lfs_block_t t = pair[0];
+ pair[0] = pair[1];
+ pair[1] = t;
+}
+
+static inline bool lfs_pair_isnull(const lfs_block_t pair[2]) {
+ return pair[0] == LFS_BLOCK_NULL || pair[1] == LFS_BLOCK_NULL;
+}
+
+static inline int lfs_pair_cmp(
+ const lfs_block_t paira[2],
+ const lfs_block_t pairb[2]) {
+ return !(paira[0] == pairb[0] || paira[1] == pairb[1] ||
+ paira[0] == pairb[1] || paira[1] == pairb[0]);
+}
+
+static inline bool lfs_pair_issync(
+ const lfs_block_t paira[2],
+ const lfs_block_t pairb[2]) {
+ return (paira[0] == pairb[0] && paira[1] == pairb[1]) ||
+ (paira[0] == pairb[1] && paira[1] == pairb[0]);
+}
+
+static inline void lfs_pair_fromle32(lfs_block_t pair[2]) {
+ pair[0] = lfs_fromle32(pair[0]);
+ pair[1] = lfs_fromle32(pair[1]);
+}
+
+#ifndef LFS_READONLY
+static inline void lfs_pair_tole32(lfs_block_t pair[2]) {
+ pair[0] = lfs_tole32(pair[0]);
+ pair[1] = lfs_tole32(pair[1]);
+}
+#endif
+
+// operations on 32-bit entry tags
+typedef uint32_t lfs_tag_t;
+typedef int32_t lfs_stag_t;
+
+#define LFS_MKTAG(type, id, size) \
+ (((lfs_tag_t)(type) << 20) | ((lfs_tag_t)(id) << 10) | (lfs_tag_t)(size))
+
+#define LFS_MKTAG_IF(cond, type, id, size) \
+ ((cond) ? LFS_MKTAG(type, id, size) : LFS_MKTAG(LFS_FROM_NOOP, 0, 0))
+
+#define LFS_MKTAG_IF_ELSE(cond, type1, id1, size1, type2, id2, size2) \
+ ((cond) ? LFS_MKTAG(type1, id1, size1) : LFS_MKTAG(type2, id2, size2))
+
+static inline bool lfs_tag_isvalid(lfs_tag_t tag) {
+ return !(tag & 0x80000000);
+}
+
+static inline bool lfs_tag_isdelete(lfs_tag_t tag) {
+ return ((int32_t)(tag << 22) >> 22) == -1;
+}
+
+static inline uint16_t lfs_tag_type1(lfs_tag_t tag) {
+ return (tag & 0x70000000) >> 20;
+}
+
+static inline uint16_t lfs_tag_type2(lfs_tag_t tag) {
+ return (tag & 0x78000000) >> 20;
+}
+
+static inline uint16_t lfs_tag_type3(lfs_tag_t tag) {
+ return (tag & 0x7ff00000) >> 20;
+}
+
+static inline uint8_t lfs_tag_chunk(lfs_tag_t tag) {
+ return (tag & 0x0ff00000) >> 20;
+}
+
+static inline int8_t lfs_tag_splice(lfs_tag_t tag) {
+ return (int8_t)lfs_tag_chunk(tag);
+}
+
+static inline uint16_t lfs_tag_id(lfs_tag_t tag) {
+ return (tag & 0x000ffc00) >> 10;
+}
+
+static inline lfs_size_t lfs_tag_size(lfs_tag_t tag) {
+ return tag & 0x000003ff;
+}
+
+static inline lfs_size_t lfs_tag_dsize(lfs_tag_t tag) {
+ return sizeof(tag) + lfs_tag_size(tag + lfs_tag_isdelete(tag));
+}
+
+// operations on attributes in attribute lists
+struct lfs_mattr {
+ lfs_tag_t tag;
+ const void *buffer;
+};
+
+struct lfs_diskoff {
+ lfs_block_t block;
+ lfs_off_t off;
+};
+
+#define LFS_MKATTRS(...) \
+ (struct lfs_mattr[]){__VA_ARGS__}, \
+ sizeof((struct lfs_mattr[]){__VA_ARGS__}) / sizeof(struct lfs_mattr)
+
+// operations on global state
+static inline void lfs_gstate_xor(lfs_gstate_t *a, const lfs_gstate_t *b) {
+ a->tag ^= b->tag;
+ a->pair[0] ^= b->pair[0];
+ a->pair[1] ^= b->pair[1];
+}
+
+static inline bool lfs_gstate_iszero(const lfs_gstate_t *a) {
+ return a->tag == 0
+ && a->pair[0] == 0
+ && a->pair[1] == 0;
+}
+
+#ifndef LFS_READONLY
+static inline bool lfs_gstate_hasorphans(const lfs_gstate_t *a) {
+ return lfs_tag_size(a->tag);
+}
+
+static inline uint8_t lfs_gstate_getorphans(const lfs_gstate_t *a) {
+ return lfs_tag_size(a->tag) & 0x1ff;
+}
+
+static inline bool lfs_gstate_hasmove(const lfs_gstate_t *a) {
+ return lfs_tag_type1(a->tag);
+}
+#endif
+
+static inline bool lfs_gstate_needssuperblock(const lfs_gstate_t *a) {
+ return lfs_tag_size(a->tag) >> 9;
+}
+
+static inline bool lfs_gstate_hasmovehere(const lfs_gstate_t *a,
+ const lfs_block_t *pair) {
+ return lfs_tag_type1(a->tag) && lfs_pair_cmp(a->pair, pair) == 0;
+}
+
+static inline void lfs_gstate_fromle32(lfs_gstate_t *a) {
+ a->tag = lfs_fromle32(a->tag);
+ a->pair[0] = lfs_fromle32(a->pair[0]);
+ a->pair[1] = lfs_fromle32(a->pair[1]);
+}
+
+#ifndef LFS_READONLY
+static inline void lfs_gstate_tole32(lfs_gstate_t *a) {
+ a->tag = lfs_tole32(a->tag);
+ a->pair[0] = lfs_tole32(a->pair[0]);
+ a->pair[1] = lfs_tole32(a->pair[1]);
+}
+#endif
+
+// operations on forward-CRCs used to track erased state
+struct lfs_fcrc {
+ lfs_size_t size;
+ uint32_t crc;
+};
+
+static void lfs_fcrc_fromle32(struct lfs_fcrc *fcrc) {
+ fcrc->size = lfs_fromle32(fcrc->size);
+ fcrc->crc = lfs_fromle32(fcrc->crc);
+}
+
+#ifndef LFS_READONLY
+static void lfs_fcrc_tole32(struct lfs_fcrc *fcrc) {
+ fcrc->size = lfs_tole32(fcrc->size);
+ fcrc->crc = lfs_tole32(fcrc->crc);
+}
+#endif
+
+// other endianness operations
+static void lfs_ctz_fromle32(struct lfs_ctz *ctz) {
+ ctz->head = lfs_fromle32(ctz->head);
+ ctz->size = lfs_fromle32(ctz->size);
+}
+
+#ifndef LFS_READONLY
+static void lfs_ctz_tole32(struct lfs_ctz *ctz) {
+ ctz->head = lfs_tole32(ctz->head);
+ ctz->size = lfs_tole32(ctz->size);
+}
+#endif
+
+static inline void lfs_superblock_fromle32(lfs_superblock_t *superblock) {
+ superblock->version = lfs_fromle32(superblock->version);
+ superblock->block_size = lfs_fromle32(superblock->block_size);
+ superblock->block_count = lfs_fromle32(superblock->block_count);
+ superblock->name_max = lfs_fromle32(superblock->name_max);
+ superblock->file_max = lfs_fromle32(superblock->file_max);
+ superblock->attr_max = lfs_fromle32(superblock->attr_max);
+}
+
+#ifndef LFS_READONLY
+static inline void lfs_superblock_tole32(lfs_superblock_t *superblock) {
+ superblock->version = lfs_tole32(superblock->version);
+ superblock->block_size = lfs_tole32(superblock->block_size);
+ superblock->block_count = lfs_tole32(superblock->block_count);
+ superblock->name_max = lfs_tole32(superblock->name_max);
+ superblock->file_max = lfs_tole32(superblock->file_max);
+ superblock->attr_max = lfs_tole32(superblock->attr_max);
+}
+#endif
+
+#ifndef LFS_NO_ASSERT
+static bool lfs_mlist_isopen(struct lfs_mlist *head,
+ struct lfs_mlist *node) {
+ for (struct lfs_mlist **p = &head; *p; p = &(*p)->next) {
+ if (*p == (struct lfs_mlist*)node) {
+ return true;
+ }
+ }
+
+ return false;
+}
+#endif
+
+static void lfs_mlist_remove(lfs_t *lfs, struct lfs_mlist *mlist) {
+ for (struct lfs_mlist **p = &lfs->mlist; *p; p = &(*p)->next) {
+ if (*p == mlist) {
+ *p = (*p)->next;
+ break;
+ }
+ }
+}
+
+static void lfs_mlist_append(lfs_t *lfs, struct lfs_mlist *mlist) {
+ mlist->next = lfs->mlist;
+ lfs->mlist = mlist;
+}
+
+// some other filesystem operations
+static uint32_t lfs_fs_disk_version(lfs_t *lfs) {
+ (void)lfs;
+#ifdef LFS_MULTIVERSION
+ if (lfs->cfg->disk_version) {
+ return lfs->cfg->disk_version;
+ } else
+#endif
+ {
+ return LFS_DISK_VERSION;
+ }
+}
+
+static uint16_t lfs_fs_disk_version_major(lfs_t *lfs) {
+ return 0xffff & (lfs_fs_disk_version(lfs) >> 16);
+
+}
+
+static uint16_t lfs_fs_disk_version_minor(lfs_t *lfs) {
+ return 0xffff & (lfs_fs_disk_version(lfs) >> 0);
+}
+
+
+/// Internal operations predeclared here ///
+#ifndef LFS_READONLY
+static int lfs_dir_commit(lfs_t *lfs, lfs_mdir_t *dir,
+ const struct lfs_mattr *attrs, int attrcount);
+static int lfs_dir_compact(lfs_t *lfs,
+ lfs_mdir_t *dir, const struct lfs_mattr *attrs, int attrcount,
+ lfs_mdir_t *source, uint16_t begin, uint16_t end);
+static lfs_ssize_t lfs_file_flushedwrite(lfs_t *lfs, lfs_file_t *file,
+ const void *buffer, lfs_size_t size);
+static lfs_ssize_t lfs_file_write_(lfs_t *lfs, lfs_file_t *file,
+ const void *buffer, lfs_size_t size);
+static int lfs_file_sync_(lfs_t *lfs, lfs_file_t *file);
+static int lfs_file_outline(lfs_t *lfs, lfs_file_t *file);
+static int lfs_file_flush(lfs_t *lfs, lfs_file_t *file);
+
+static int lfs_fs_deorphan(lfs_t *lfs, bool powerloss);
+static int lfs_fs_preporphans(lfs_t *lfs, int8_t orphans);
+static void lfs_fs_prepmove(lfs_t *lfs,
+ uint16_t id, const lfs_block_t pair[2]);
+static int lfs_fs_pred(lfs_t *lfs, const lfs_block_t dir[2],
+ lfs_mdir_t *pdir);
+static lfs_stag_t lfs_fs_parent(lfs_t *lfs, const lfs_block_t dir[2],
+ lfs_mdir_t *parent);
+static int lfs_fs_forceconsistency(lfs_t *lfs);
+#endif
+
+static void lfs_fs_prepsuperblock(lfs_t *lfs, bool needssuperblock);
+
+#ifdef LFS_MIGRATE
+static int lfs1_traverse(lfs_t *lfs,
+ int (*cb)(void*, lfs_block_t), void *data);
+#endif
+
+static int lfs_dir_rewind_(lfs_t *lfs, lfs_dir_t *dir);
+
+static lfs_ssize_t lfs_file_flushedread(lfs_t *lfs, lfs_file_t *file,
+ void *buffer, lfs_size_t size);
+static lfs_ssize_t lfs_file_read_(lfs_t *lfs, lfs_file_t *file,
+ void *buffer, lfs_size_t size);
+static int lfs_file_close_(lfs_t *lfs, lfs_file_t *file);
+static lfs_soff_t lfs_file_size_(lfs_t *lfs, lfs_file_t *file);
+
+static lfs_ssize_t lfs_fs_size_(lfs_t *lfs);
+static int lfs_fs_traverse_(lfs_t *lfs,
+ int (*cb)(void *data, lfs_block_t block), void *data,
+ bool includeorphans);
+
+static int lfs_deinit(lfs_t *lfs);
+static int lfs_unmount_(lfs_t *lfs);
+
+
+/// Block allocator ///
+
+// allocations should call this when all allocated blocks are committed to
+// the filesystem
+//
+// after a checkpoint, the block allocator may realloc any untracked blocks
+static void lfs_alloc_ckpoint(lfs_t *lfs) {
+ lfs->lookahead.ckpoint = lfs->block_count;
+}
+
+// drop the lookahead buffer, this is done during mounting and failed
+// traversals in order to avoid invalid lookahead state
+static void lfs_alloc_drop(lfs_t *lfs) {
+ lfs->lookahead.size = 0;
+ lfs->lookahead.next = 0;
+ lfs_alloc_ckpoint(lfs);
+}
+
+#ifndef LFS_READONLY
+static int lfs_alloc_lookahead(void *p, lfs_block_t block) {
+ lfs_t *lfs = (lfs_t*)p;
+ lfs_block_t off = ((block - lfs->lookahead.start)
+ + lfs->block_count) % lfs->block_count;
+
+ if (off < lfs->lookahead.size) {
+ lfs->lookahead.buffer[off / 8] |= 1U << (off % 8);
+ }
+
+ return 0;
+}
+#endif
+
+#ifndef LFS_READONLY
+static int lfs_alloc_scan(lfs_t *lfs) {
+ // move lookahead buffer to the first unused block
+ //
+ // note we limit the lookahead buffer to at most the amount of blocks
+ // checkpointed, this prevents the math in lfs_alloc from underflowing
+ lfs->lookahead.start = (lfs->lookahead.start + lfs->lookahead.next)
+ % lfs->block_count;
+ lfs->lookahead.next = 0;
+ lfs->lookahead.size = lfs_min(
+ 8*lfs->cfg->lookahead_size,
+ lfs->lookahead.ckpoint);
+
+ // find mask of free blocks from tree
+ memset(lfs->lookahead.buffer, 0, lfs->cfg->lookahead_size);
+ int err = lfs_fs_traverse_(lfs, lfs_alloc_lookahead, lfs, true);
+ if (err) {
+ lfs_alloc_drop(lfs);
+ return err;
+ }
+
+ return 0;
+}
+#endif
+
+#ifndef LFS_READONLY
+static int lfs_alloc(lfs_t *lfs, lfs_block_t *block) {
+ while (true) {
+ // scan our lookahead buffer for free blocks
+ while (lfs->lookahead.next < lfs->lookahead.size) {
+ if (!(lfs->lookahead.buffer[lfs->lookahead.next / 8]
+ & (1U << (lfs->lookahead.next % 8)))) {
+ // found a free block
+ *block = (lfs->lookahead.start + lfs->lookahead.next)
+ % lfs->block_count;
+
+ // eagerly find next free block to maximize how many blocks
+ // lfs_alloc_ckpoint makes available for scanning
+ while (true) {
+ lfs->lookahead.next += 1;
+ lfs->lookahead.ckpoint -= 1;
+
+ if (lfs->lookahead.next >= lfs->lookahead.size
+ || !(lfs->lookahead.buffer[lfs->lookahead.next / 8]
+ & (1U << (lfs->lookahead.next % 8)))) {
+ return 0;
+ }
+ }
+ }
+
+ lfs->lookahead.next += 1;
+ lfs->lookahead.ckpoint -= 1;
+ }
+
+ // In order to keep our block allocator from spinning forever when our
+ // filesystem is full, we mark points where there are no in-flight
+ // allocations with a checkpoint before starting a set of allocations.
+ //
+ // If we've looked at all blocks since the last checkpoint, we report
+ // the filesystem as out of storage.
+ //
+ if (lfs->lookahead.ckpoint <= 0) {
+ LFS_ERROR("No more free space 0x%"PRIx32,
+ (lfs->lookahead.start + lfs->lookahead.next)
+ % lfs->block_count);
+ return LFS_ERR_NOSPC;
+ }
+
+ // No blocks in our lookahead buffer, we need to scan the filesystem for
+ // unused blocks in the next lookahead window.
+ int err = lfs_alloc_scan(lfs);
+ if(err) {
+ return err;
+ }
+ }
+}
+#endif
+
+/// Metadata pair and directory operations ///
+static lfs_stag_t lfs_dir_getslice(lfs_t *lfs, const lfs_mdir_t *dir,
+ lfs_tag_t gmask, lfs_tag_t gtag,
+ lfs_off_t goff, void *gbuffer, lfs_size_t gsize) {
+ lfs_off_t off = dir->off;
+ lfs_tag_t ntag = dir->etag;
+ lfs_stag_t gdiff = 0;
+
+ // synthetic moves
+ if (lfs_gstate_hasmovehere(&lfs->gdisk, dir->pair) &&
+ lfs_tag_id(gmask) != 0) {
+ if (lfs_tag_id(lfs->gdisk.tag) == lfs_tag_id(gtag)) {
+ return LFS_ERR_NOENT;
+ } else if (lfs_tag_id(lfs->gdisk.tag) < lfs_tag_id(gtag)) {
+ gdiff -= LFS_MKTAG(0, 1, 0);
+ }
+ }
+
+ // iterate over dir block backwards (for faster lookups)
+ while (off >= sizeof(lfs_tag_t) + lfs_tag_dsize(ntag)) {
+ off -= lfs_tag_dsize(ntag);
+ lfs_tag_t tag = ntag;
+ int err = lfs_bd_read(lfs,
+ NULL, &lfs->rcache, sizeof(ntag),
+ dir->pair[0], off, &ntag, sizeof(ntag));
+ if (err) {
+ return err;
+ }
+
+ ntag = (lfs_frombe32(ntag) ^ tag) & 0x7fffffff;
+
+ if (lfs_tag_id(gmask) != 0 &&
+ lfs_tag_type1(tag) == LFS_TYPE_SPLICE &&
+ lfs_tag_id(tag) <= lfs_tag_id(gtag - gdiff)) {
+ if (tag == (LFS_MKTAG(LFS_TYPE_CREATE, 0, 0) |
+ (LFS_MKTAG(0, 0x3ff, 0) & (gtag - gdiff)))) {
+ // found where we were created
+ return LFS_ERR_NOENT;
+ }
+
+ // move around splices
+ gdiff += LFS_MKTAG(0, lfs_tag_splice(tag), 0);
+ }
+
+ if ((gmask & tag) == (gmask & (gtag - gdiff))) {
+ if (lfs_tag_isdelete(tag)) {
+ return LFS_ERR_NOENT;
+ }
+
+ lfs_size_t diff = lfs_min(lfs_tag_size(tag), gsize);
+ err = lfs_bd_read(lfs,
+ NULL, &lfs->rcache, diff,
+ dir->pair[0], off+sizeof(tag)+goff, gbuffer, diff);
+ if (err) {
+ return err;
+ }
+
+ memset((uint8_t*)gbuffer + diff, 0, gsize - diff);
+
+ return tag + gdiff;
+ }
+ }
+
+ return LFS_ERR_NOENT;
+}
+
+static lfs_stag_t lfs_dir_get(lfs_t *lfs, const lfs_mdir_t *dir,
+ lfs_tag_t gmask, lfs_tag_t gtag, void *buffer) {
+ return lfs_dir_getslice(lfs, dir,
+ gmask, gtag,
+ 0, buffer, lfs_tag_size(gtag));
+}
+
+static int lfs_dir_getread(lfs_t *lfs, const lfs_mdir_t *dir,
+ const lfs_cache_t *pcache, lfs_cache_t *rcache, lfs_size_t hint,
+ lfs_tag_t gmask, lfs_tag_t gtag,
+ lfs_off_t off, void *buffer, lfs_size_t size) {
+ uint8_t *data = buffer;
+ if (off+size > lfs->cfg->block_size) {
+ return LFS_ERR_CORRUPT;
+ }
+
+ while (size > 0) {
+ lfs_size_t diff = size;
+
+ if (pcache && pcache->block == LFS_BLOCK_INLINE &&
+ off < pcache->off + pcache->size) {
+ if (off >= pcache->off) {
+ // is already in pcache?
+ diff = lfs_min(diff, pcache->size - (off-pcache->off));
+ memcpy(data, &pcache->buffer[off-pcache->off], diff);
+
+ data += diff;
+ off += diff;
+ size -= diff;
+ continue;
+ }
+
+ // pcache takes priority
+ diff = lfs_min(diff, pcache->off-off);
+ }
+
+ if (rcache->block == LFS_BLOCK_INLINE &&
+ off < rcache->off + rcache->size) {
+ if (off >= rcache->off) {
+ // is already in rcache?
+ diff = lfs_min(diff, rcache->size - (off-rcache->off));
+ memcpy(data, &rcache->buffer[off-rcache->off], diff);
+
+ data += diff;
+ off += diff;
+ size -= diff;
+ continue;
+ }
+
+ // rcache takes priority
+ diff = lfs_min(diff, rcache->off-off);
+ }
+
+ // load to cache, first condition can no longer fail
+ rcache->block = LFS_BLOCK_INLINE;
+ rcache->off = lfs_aligndown(off, lfs->cfg->read_size);
+ rcache->size = lfs_min(lfs_alignup(off+hint, lfs->cfg->read_size),
+ lfs->cfg->cache_size);
+ int err = lfs_dir_getslice(lfs, dir, gmask, gtag,
+ rcache->off, rcache->buffer, rcache->size);
+ if (err < 0) {
+ return err;
+ }
+ }
+
+ return 0;
+}
+
+#ifndef LFS_READONLY
+static int lfs_dir_traverse_filter(void *p,
+ lfs_tag_t tag, const void *buffer) {
+ lfs_tag_t *filtertag = p;
+ (void)buffer;
+
+ // which mask depends on unique bit in tag structure
+ uint32_t mask = (tag & LFS_MKTAG(0x100, 0, 0))
+ ? LFS_MKTAG(0x7ff, 0x3ff, 0)
+ : LFS_MKTAG(0x700, 0x3ff, 0);
+
+ // check for redundancy
+ if ((mask & tag) == (mask & *filtertag) ||
+ lfs_tag_isdelete(*filtertag) ||
+ (LFS_MKTAG(0x7ff, 0x3ff, 0) & tag) == (
+ LFS_MKTAG(LFS_TYPE_DELETE, 0, 0) |
+ (LFS_MKTAG(0, 0x3ff, 0) & *filtertag))) {
+ *filtertag = LFS_MKTAG(LFS_FROM_NOOP, 0, 0);
+ return true;
+ }
+
+ // check if we need to adjust for created/deleted tags
+ if (lfs_tag_type1(tag) == LFS_TYPE_SPLICE &&
+ lfs_tag_id(tag) <= lfs_tag_id(*filtertag)) {
+ *filtertag += LFS_MKTAG(0, lfs_tag_splice(tag), 0);
+ }
+
+ return false;
+}
+#endif
+
+#ifndef LFS_READONLY
+// maximum recursive depth of lfs_dir_traverse, the deepest call:
+//
+// traverse with commit
+// '-> traverse with move
+// '-> traverse with filter
+//
+#define LFS_DIR_TRAVERSE_DEPTH 3
+
+struct lfs_dir_traverse {
+ const lfs_mdir_t *dir;
+ lfs_off_t off;
+ lfs_tag_t ptag;
+ const struct lfs_mattr *attrs;
+ int attrcount;
+
+ lfs_tag_t tmask;
+ lfs_tag_t ttag;
+ uint16_t begin;
+ uint16_t end;
+ int16_t diff;
+
+ int (*cb)(void *data, lfs_tag_t tag, const void *buffer);
+ void *data;
+
+ lfs_tag_t tag;
+ const void *buffer;
+ struct lfs_diskoff disk;
+};
+
+static int lfs_dir_traverse(lfs_t *lfs,
+ const lfs_mdir_t *dir, lfs_off_t off, lfs_tag_t ptag,
+ const struct lfs_mattr *attrs, int attrcount,
+ lfs_tag_t tmask, lfs_tag_t ttag,
+ uint16_t begin, uint16_t end, int16_t diff,
+ int (*cb)(void *data, lfs_tag_t tag, const void *buffer), void *data) {
+ // This function in inherently recursive, but bounded. To allow tool-based
+ // analysis without unnecessary code-cost we use an explicit stack
+ struct lfs_dir_traverse stack[LFS_DIR_TRAVERSE_DEPTH-1];
+ unsigned sp = 0;
+ int res;
+
+ // iterate over directory and attrs
+ lfs_tag_t tag;
+ const void *buffer;
+ struct lfs_diskoff disk = {0};
+ while (true) {
+ {
+ if (off+lfs_tag_dsize(ptag) < dir->off) {
+ off += lfs_tag_dsize(ptag);
+ int err = lfs_bd_read(lfs,
+ NULL, &lfs->rcache, sizeof(tag),
+ dir->pair[0], off, &tag, sizeof(tag));
+ if (err) {
+ return err;
+ }
+
+ tag = (lfs_frombe32(tag) ^ ptag) | 0x80000000;
+ disk.block = dir->pair[0];
+ disk.off = off+sizeof(lfs_tag_t);
+ buffer = &disk;
+ ptag = tag;
+ } else if (attrcount > 0) {
+ tag = attrs[0].tag;
+ buffer = attrs[0].buffer;
+ attrs += 1;
+ attrcount -= 1;
+ } else {
+ // finished traversal, pop from stack?
+ res = 0;
+ break;
+ }
+
+ // do we need to filter?
+ lfs_tag_t mask = LFS_MKTAG(0x7ff, 0, 0);
+ if ((mask & tmask & tag) != (mask & tmask & ttag)) {
+ continue;
+ }
+
+ if (lfs_tag_id(tmask) != 0) {
+ LFS_ASSERT(sp < LFS_DIR_TRAVERSE_DEPTH);
+ // recurse, scan for duplicates, and update tag based on
+ // creates/deletes
+ stack[sp] = (struct lfs_dir_traverse){
+ .dir = dir,
+ .off = off,
+ .ptag = ptag,
+ .attrs = attrs,
+ .attrcount = attrcount,
+ .tmask = tmask,
+ .ttag = ttag,
+ .begin = begin,
+ .end = end,
+ .diff = diff,
+ .cb = cb,
+ .data = data,
+ .tag = tag,
+ .buffer = buffer,
+ .disk = disk,
+ };
+ sp += 1;
+
+ tmask = 0;
+ ttag = 0;
+ begin = 0;
+ end = 0;
+ diff = 0;
+ cb = lfs_dir_traverse_filter;
+ data = &stack[sp-1].tag;
+ continue;
+ }
+ }
+
+popped:
+ // in filter range?
+ if (lfs_tag_id(tmask) != 0 &&
+ !(lfs_tag_id(tag) >= begin && lfs_tag_id(tag) < end)) {
+ continue;
+ }
+
+ // handle special cases for mcu-side operations
+ if (lfs_tag_type3(tag) == LFS_FROM_NOOP) {
+ // do nothing
+ } else if (lfs_tag_type3(tag) == LFS_FROM_MOVE) {
+ // Without this condition, lfs_dir_traverse can exhibit an
+ // extremely expensive O(n^3) of nested loops when renaming.
+ // This happens because lfs_dir_traverse tries to filter tags by
+ // the tags in the source directory, triggering a second
+ // lfs_dir_traverse with its own filter operation.
+ //
+ // traverse with commit
+ // '-> traverse with filter
+ // '-> traverse with move
+ // '-> traverse with filter
+ //
+ // However we don't actually care about filtering the second set of
+ // tags, since duplicate tags have no effect when filtering.
+ //
+ // This check skips this unnecessary recursive filtering explicitly,
+ // reducing this runtime from O(n^3) to O(n^2).
+ if (cb == lfs_dir_traverse_filter) {
+ continue;
+ }
+
+ // recurse into move
+ stack[sp] = (struct lfs_dir_traverse){
+ .dir = dir,
+ .off = off,
+ .ptag = ptag,
+ .attrs = attrs,
+ .attrcount = attrcount,
+ .tmask = tmask,
+ .ttag = ttag,
+ .begin = begin,
+ .end = end,
+ .diff = diff,
+ .cb = cb,
+ .data = data,
+ .tag = LFS_MKTAG(LFS_FROM_NOOP, 0, 0),
+ };
+ sp += 1;
+
+ uint16_t fromid = lfs_tag_size(tag);
+ uint16_t toid = lfs_tag_id(tag);
+ dir = buffer;
+ off = 0;
+ ptag = 0xffffffff;
+ attrs = NULL;
+ attrcount = 0;
+ tmask = LFS_MKTAG(0x600, 0x3ff, 0);
+ ttag = LFS_MKTAG(LFS_TYPE_STRUCT, 0, 0);
+ begin = fromid;
+ end = fromid+1;
+ diff = toid-fromid+diff;
+ } else if (lfs_tag_type3(tag) == LFS_FROM_USERATTRS) {
+ for (unsigned i = 0; i < lfs_tag_size(tag); i++) {
+ const struct lfs_attr *a = buffer;
+ res = cb(data, LFS_MKTAG(LFS_TYPE_USERATTR + a[i].type,
+ lfs_tag_id(tag) + diff, a[i].size), a[i].buffer);
+ if (res < 0) {
+ return res;
+ }
+
+ if (res) {
+ break;
+ }
+ }
+ } else {
+ res = cb(data, tag + LFS_MKTAG(0, diff, 0), buffer);
+ if (res < 0) {
+ return res;
+ }
+
+ if (res) {
+ break;
+ }
+ }
+ }
+
+ if (sp > 0) {
+ // pop from the stack and return, fortunately all pops share
+ // a destination
+ dir = stack[sp-1].dir;
+ off = stack[sp-1].off;
+ ptag = stack[sp-1].ptag;
+ attrs = stack[sp-1].attrs;
+ attrcount = stack[sp-1].attrcount;
+ tmask = stack[sp-1].tmask;
+ ttag = stack[sp-1].ttag;
+ begin = stack[sp-1].begin;
+ end = stack[sp-1].end;
+ diff = stack[sp-1].diff;
+ cb = stack[sp-1].cb;
+ data = stack[sp-1].data;
+ tag = stack[sp-1].tag;
+ buffer = stack[sp-1].buffer;
+ disk = stack[sp-1].disk;
+ sp -= 1;
+ goto popped;
+ } else {
+ return res;
+ }
+}
+#endif
+
+static lfs_stag_t lfs_dir_fetchmatch(lfs_t *lfs,
+ lfs_mdir_t *dir, const lfs_block_t pair[2],
+ lfs_tag_t fmask, lfs_tag_t ftag, uint16_t *id,
+ int (*cb)(void *data, lfs_tag_t tag, const void *buffer), void *data) {
+ // we can find tag very efficiently during a fetch, since we're already
+ // scanning the entire directory
+ lfs_stag_t besttag = -1;
+
+ // if either block address is invalid we return LFS_ERR_CORRUPT here,
+ // otherwise later writes to the pair could fail
+ if (lfs->block_count
+ && (pair[0] >= lfs->block_count || pair[1] >= lfs->block_count)) {
+ return LFS_ERR_CORRUPT;
+ }
+
+ // find the block with the most recent revision
+ uint32_t revs[2] = {0, 0};
+ int r = 0;
+ for (int i = 0; i < 2; i++) {
+ int err = lfs_bd_read(lfs,
+ NULL, &lfs->rcache, sizeof(revs[i]),
+ pair[i], 0, &revs[i], sizeof(revs[i]));
+ revs[i] = lfs_fromle32(revs[i]);
+ if (err && err != LFS_ERR_CORRUPT) {
+ return err;
+ }
+
+ if (err != LFS_ERR_CORRUPT &&
+ lfs_scmp(revs[i], revs[(i+1)%2]) > 0) {
+ r = i;
+ }
+ }
+
+ dir->pair[0] = pair[(r+0)%2];
+ dir->pair[1] = pair[(r+1)%2];
+ dir->rev = revs[(r+0)%2];
+ dir->off = 0; // nonzero = found some commits
+
+ // now scan tags to fetch the actual dir and find possible match
+ for (int i = 0; i < 2; i++) {
+ lfs_off_t off = 0;
+ lfs_tag_t ptag = 0xffffffff;
+
+ uint16_t tempcount = 0;
+ lfs_block_t temptail[2] = {LFS_BLOCK_NULL, LFS_BLOCK_NULL};
+ bool tempsplit = false;
+ lfs_stag_t tempbesttag = besttag;
+
+ // assume not erased until proven otherwise
+ bool maybeerased = false;
+ bool hasfcrc = false;
+ struct lfs_fcrc fcrc;
+
+ dir->rev = lfs_tole32(dir->rev);
+ uint32_t crc = lfs_crc(0xffffffff, &dir->rev, sizeof(dir->rev));
+ dir->rev = lfs_fromle32(dir->rev);
+
+ while (true) {
+ // extract next tag
+ lfs_tag_t tag;
+ off += lfs_tag_dsize(ptag);
+ int err = lfs_bd_read(lfs,
+ NULL, &lfs->rcache, lfs->cfg->block_size,
+ dir->pair[0], off, &tag, sizeof(tag));
+ if (err) {
+ if (err == LFS_ERR_CORRUPT) {
+ // can't continue?
+ break;
+ }
+ return err;
+ }
+
+ crc = lfs_crc(crc, &tag, sizeof(tag));
+ tag = lfs_frombe32(tag) ^ ptag;
+
+ // next commit not yet programmed?
+ if (!lfs_tag_isvalid(tag)) {
+ // we only might be erased if the last tag was a crc
+ maybeerased = (lfs_tag_type2(ptag) == LFS_TYPE_CCRC);
+ break;
+ // out of range?
+ } else if (off + lfs_tag_dsize(tag) > lfs->cfg->block_size) {
+ break;
+ }
+
+ ptag = tag;
+
+ if (lfs_tag_type2(tag) == LFS_TYPE_CCRC) {
+ // check the crc attr
+ uint32_t dcrc;
+ err = lfs_bd_read(lfs,
+ NULL, &lfs->rcache, lfs->cfg->block_size,
+ dir->pair[0], off+sizeof(tag), &dcrc, sizeof(dcrc));
+ if (err) {
+ if (err == LFS_ERR_CORRUPT) {
+ break;
+ }
+ return err;
+ }
+ dcrc = lfs_fromle32(dcrc);
+
+ if (crc != dcrc) {
+ break;
+ }
+
+ // reset the next bit if we need to
+ ptag ^= (lfs_tag_t)(lfs_tag_chunk(tag) & 1U) << 31;
+
+ // toss our crc into the filesystem seed for
+ // pseudorandom numbers, note we use another crc here
+ // as a collection function because it is sufficiently
+ // random and convenient
+ lfs->seed = lfs_crc(lfs->seed, &crc, sizeof(crc));
+
+ // update with what's found so far
+ besttag = tempbesttag;
+ dir->off = off + lfs_tag_dsize(tag);
+ dir->etag = ptag;
+ dir->count = tempcount;
+ dir->tail[0] = temptail[0];
+ dir->tail[1] = temptail[1];
+ dir->split = tempsplit;
+
+ // reset crc, hasfcrc
+ crc = 0xffffffff;
+ continue;
+ }
+
+ // crc the entry first, hopefully leaving it in the cache
+ err = lfs_bd_crc(lfs,
+ NULL, &lfs->rcache, lfs->cfg->block_size,
+ dir->pair[0], off+sizeof(tag),
+ lfs_tag_dsize(tag)-sizeof(tag), &crc);
+ if (err) {
+ if (err == LFS_ERR_CORRUPT) {
+ break;
+ }
+ return err;
+ }
+
+ // directory modification tags?
+ if (lfs_tag_type1(tag) == LFS_TYPE_NAME) {
+ // increase count of files if necessary
+ if (lfs_tag_id(tag) >= tempcount) {
+ tempcount = lfs_tag_id(tag) + 1;
+ }
+ } else if (lfs_tag_type1(tag) == LFS_TYPE_SPLICE) {
+ tempcount += lfs_tag_splice(tag);
+
+ if (tag == (LFS_MKTAG(LFS_TYPE_DELETE, 0, 0) |
+ (LFS_MKTAG(0, 0x3ff, 0) & tempbesttag))) {
+ tempbesttag |= 0x80000000;
+ } else if (tempbesttag != -1 &&
+ lfs_tag_id(tag) <= lfs_tag_id(tempbesttag)) {
+ tempbesttag += LFS_MKTAG(0, lfs_tag_splice(tag), 0);
+ }
+ } else if (lfs_tag_type1(tag) == LFS_TYPE_TAIL) {
+ tempsplit = (lfs_tag_chunk(tag) & 1);
+
+ err = lfs_bd_read(lfs,
+ NULL, &lfs->rcache, lfs->cfg->block_size,
+ dir->pair[0], off+sizeof(tag), &temptail, 8);
+ if (err) {
+ if (err == LFS_ERR_CORRUPT) {
+ break;
+ }
+ return err;
+ }
+ lfs_pair_fromle32(temptail);
+ } else if (lfs_tag_type3(tag) == LFS_TYPE_FCRC) {
+ err = lfs_bd_read(lfs,
+ NULL, &lfs->rcache, lfs->cfg->block_size,
+ dir->pair[0], off+sizeof(tag),
+ &fcrc, sizeof(fcrc));
+ if (err) {
+ if (err == LFS_ERR_CORRUPT) {
+ break;
+ }
+ }
+
+ lfs_fcrc_fromle32(&fcrc);
+ hasfcrc = true;
+ }
+
+ // found a match for our fetcher?
+ if ((fmask & tag) == (fmask & ftag)) {
+ int res = cb(data, tag, &(struct lfs_diskoff){
+ dir->pair[0], off+sizeof(tag)});
+ if (res < 0) {
+ if (res == LFS_ERR_CORRUPT) {
+ break;
+ }
+ return res;
+ }
+
+ if (res == LFS_CMP_EQ) {
+ // found a match
+ tempbesttag = tag;
+ } else if ((LFS_MKTAG(0x7ff, 0x3ff, 0) & tag) ==
+ (LFS_MKTAG(0x7ff, 0x3ff, 0) & tempbesttag)) {
+ // found an identical tag, but contents didn't match
+ // this must mean that our besttag has been overwritten
+ tempbesttag = -1;
+ } else if (res == LFS_CMP_GT &&
+ lfs_tag_id(tag) <= lfs_tag_id(tempbesttag)) {
+ // found a greater match, keep track to keep things sorted
+ tempbesttag = tag | 0x80000000;
+ }
+ }
+ }
+
+ // found no valid commits?
+ if (dir->off == 0) {
+ // try the other block?
+ lfs_pair_swap(dir->pair);
+ dir->rev = revs[(r+1)%2];
+ continue;
+ }
+
+ // did we end on a valid commit? we may have an erased block
+ dir->erased = false;
+ if (maybeerased && dir->off % lfs->cfg->prog_size == 0) {
+ #ifdef LFS_MULTIVERSION
+ // note versions < lfs2.1 did not have fcrc tags, if
+ // we're < lfs2.1 treat missing fcrc as erased data
+ //
+ // we don't strictly need to do this, but otherwise writing
+ // to lfs2.0 disks becomes very inefficient
+ if (lfs_fs_disk_version(lfs) < 0x00020001) {
+ dir->erased = true;
+
+ } else
+ #endif
+ if (hasfcrc) {
+ // check for an fcrc matching the next prog's erased state, if
+ // this failed most likely a previous prog was interrupted, we
+ // need a new erase
+ uint32_t fcrc_ = 0xffffffff;
+ int err = lfs_bd_crc(lfs,
+ NULL, &lfs->rcache, lfs->cfg->block_size,
+ dir->pair[0], dir->off, fcrc.size, &fcrc_);
+ if (err && err != LFS_ERR_CORRUPT) {
+ return err;
+ }
+
+ // found beginning of erased part?
+ dir->erased = (fcrc_ == fcrc.crc);
+ }
+ }
+
+ // synthetic move
+ if (lfs_gstate_hasmovehere(&lfs->gdisk, dir->pair)) {
+ if (lfs_tag_id(lfs->gdisk.tag) == lfs_tag_id(besttag)) {
+ besttag |= 0x80000000;
+ } else if (besttag != -1 &&
+ lfs_tag_id(lfs->gdisk.tag) < lfs_tag_id(besttag)) {
+ besttag -= LFS_MKTAG(0, 1, 0);
+ }
+ }
+
+ // found tag? or found best id?
+ if (id) {
+ *id = lfs_min(lfs_tag_id(besttag), dir->count);
+ }
+
+ if (lfs_tag_isvalid(besttag)) {
+ return besttag;
+ } else if (lfs_tag_id(besttag) < dir->count) {
+ return LFS_ERR_NOENT;
+ } else {
+ return 0;
+ }
+ }
+
+ LFS_ERROR("Corrupted dir pair at {0x%"PRIx32", 0x%"PRIx32"}",
+ dir->pair[0], dir->pair[1]);
+ return LFS_ERR_CORRUPT;
+}
+
+static int lfs_dir_fetch(lfs_t *lfs,
+ lfs_mdir_t *dir, const lfs_block_t pair[2]) {
+ // note, mask=-1, tag=-1 can never match a tag since this
+ // pattern has the invalid bit set
+ return (int)lfs_dir_fetchmatch(lfs, dir, pair,
+ (lfs_tag_t)-1, (lfs_tag_t)-1, NULL, NULL, NULL);
+}
+
+static int lfs_dir_getgstate(lfs_t *lfs, const lfs_mdir_t *dir,
+ lfs_gstate_t *gstate) {
+ lfs_gstate_t temp;
+ lfs_stag_t res = lfs_dir_get(lfs, dir, LFS_MKTAG(0x7ff, 0, 0),
+ LFS_MKTAG(LFS_TYPE_MOVESTATE, 0, sizeof(temp)), &temp);
+ if (res < 0 && res != LFS_ERR_NOENT) {
+ return res;
+ }
+
+ if (res != LFS_ERR_NOENT) {
+ // xor together to find resulting gstate
+ lfs_gstate_fromle32(&temp);
+ lfs_gstate_xor(gstate, &temp);
+ }
+
+ return 0;
+}
+
+static int lfs_dir_getinfo(lfs_t *lfs, lfs_mdir_t *dir,
+ uint16_t id, struct lfs_info *info) {
+ if (id == 0x3ff) {
+ // special case for root
+ strcpy(info->name, "/");
+ info->type = LFS_TYPE_DIR;
+ return 0;
+ }
+
+ lfs_stag_t tag = lfs_dir_get(lfs, dir, LFS_MKTAG(0x780, 0x3ff, 0),
+ LFS_MKTAG(LFS_TYPE_NAME, id, lfs->name_max+1), info->name);
+ if (tag < 0) {
+ return (int)tag;
+ }
+
+ info->type = lfs_tag_type3(tag);
+
+ struct lfs_ctz ctz;
+ tag = lfs_dir_get(lfs, dir, LFS_MKTAG(0x700, 0x3ff, 0),
+ LFS_MKTAG(LFS_TYPE_STRUCT, id, sizeof(ctz)), &ctz);
+ if (tag < 0) {
+ return (int)tag;
+ }
+ lfs_ctz_fromle32(&ctz);
+
+ if (lfs_tag_type3(tag) == LFS_TYPE_CTZSTRUCT) {
+ info->size = ctz.size;
+ } else if (lfs_tag_type3(tag) == LFS_TYPE_INLINESTRUCT) {
+ info->size = lfs_tag_size(tag);
+ }
+
+ return 0;
+}
+
+struct lfs_dir_find_match {
+ lfs_t *lfs;
+ const void *name;
+ lfs_size_t size;
+};
+
+static int lfs_dir_find_match(void *data,
+ lfs_tag_t tag, const void *buffer) {
+ struct lfs_dir_find_match *name = data;
+ lfs_t *lfs = name->lfs;
+ const struct lfs_diskoff *disk = buffer;
+
+ // compare with disk
+ lfs_size_t diff = lfs_min(name->size, lfs_tag_size(tag));
+ int res = lfs_bd_cmp(lfs,
+ NULL, &lfs->rcache, diff,
+ disk->block, disk->off, name->name, diff);
+ if (res != LFS_CMP_EQ) {
+ return res;
+ }
+
+ // only equal if our size is still the same
+ if (name->size != lfs_tag_size(tag)) {
+ return (name->size < lfs_tag_size(tag)) ? LFS_CMP_LT : LFS_CMP_GT;
+ }
+
+ // found a match!
+ return LFS_CMP_EQ;
+}
+
+// lfs_dir_find tries to set path and id even if file is not found
+//
+// returns:
+// - 0 if file is found
+// - LFS_ERR_NOENT if file or parent is not found
+// - LFS_ERR_NOTDIR if parent is not a dir
+static lfs_stag_t lfs_dir_find(lfs_t *lfs, lfs_mdir_t *dir,
+ const char **path, uint16_t *id) {
+ // we reduce path to a single name if we can find it
+ const char *name = *path;
+
+ // default to root dir
+ lfs_stag_t tag = LFS_MKTAG(LFS_TYPE_DIR, 0x3ff, 0);
+ dir->tail[0] = lfs->root[0];
+ dir->tail[1] = lfs->root[1];
+
+ // empty paths are not allowed
+ if (*name == '\0') {
+ return LFS_ERR_INVAL;
+ }
+
+ while (true) {
+nextname:
+ // skip slashes if we're a directory
+ if (lfs_tag_type3(tag) == LFS_TYPE_DIR) {
+ name += strspn(name, "/");
+ }
+ lfs_size_t namelen = strcspn(name, "/");
+
+ // skip '.'
+ if (namelen == 1 && memcmp(name, ".", 1) == 0) {
+ name += namelen;
+ goto nextname;
+ }
+
+ // error on unmatched '..', trying to go above root?
+ if (namelen == 2 && memcmp(name, "..", 2) == 0) {
+ return LFS_ERR_INVAL;
+ }
+
+ // skip if matched by '..' in name
+ const char *suffix = name + namelen;
+ lfs_size_t sufflen;
+ int depth = 1;
+ while (true) {
+ suffix += strspn(suffix, "/");
+ sufflen = strcspn(suffix, "/");
+ if (sufflen == 0) {
+ break;
+ }
+
+ if (sufflen == 1 && memcmp(suffix, ".", 1) == 0) {
+ // noop
+ } else if (sufflen == 2 && memcmp(suffix, "..", 2) == 0) {
+ depth -= 1;
+ if (depth == 0) {
+ name = suffix + sufflen;
+ goto nextname;
+ }
+ } else {
+ depth += 1;
+ }
+
+ suffix += sufflen;
+ }
+
+ // found path
+ if (*name == '\0') {
+ return tag;
+ }
+
+ // update what we've found so far
+ *path = name;
+
+ // only continue if we're a directory
+ if (lfs_tag_type3(tag) != LFS_TYPE_DIR) {
+ return LFS_ERR_NOTDIR;
+ }
+
+ // grab the entry data
+ if (lfs_tag_id(tag) != 0x3ff) {
+ lfs_stag_t res = lfs_dir_get(lfs, dir, LFS_MKTAG(0x700, 0x3ff, 0),
+ LFS_MKTAG(LFS_TYPE_STRUCT, lfs_tag_id(tag), 8), dir->tail);
+ if (res < 0) {
+ return res;
+ }
+ lfs_pair_fromle32(dir->tail);
+ }
+
+ // find entry matching name
+ while (true) {
+ tag = lfs_dir_fetchmatch(lfs, dir, dir->tail,
+ LFS_MKTAG(0x780, 0, 0),
+ LFS_MKTAG(LFS_TYPE_NAME, 0, namelen),
+ id,
+ lfs_dir_find_match, &(struct lfs_dir_find_match){
+ lfs, name, namelen});
+ if (tag < 0) {
+ return tag;
+ }
+
+ if (tag) {
+ break;
+ }
+
+ if (!dir->split) {
+ return LFS_ERR_NOENT;
+ }
+ }
+
+ // to next name
+ name += namelen;
+ }
+}
+
+// commit logic
+struct lfs_commit {
+ lfs_block_t block;
+ lfs_off_t off;
+ lfs_tag_t ptag;
+ uint32_t crc;
+
+ lfs_off_t begin;
+ lfs_off_t end;
+};
+
+#ifndef LFS_READONLY
+static int lfs_dir_commitprog(lfs_t *lfs, struct lfs_commit *commit,
+ const void *buffer, lfs_size_t size) {
+ int err = lfs_bd_prog(lfs,
+ &lfs->pcache, &lfs->rcache, false,
+ commit->block, commit->off ,
+ (const uint8_t*)buffer, size);
+ if (err) {
+ return err;
+ }
+
+ commit->crc = lfs_crc(commit->crc, buffer, size);
+ commit->off += size;
+ return 0;
+}
+#endif
+
+#ifndef LFS_READONLY
+static int lfs_dir_commitattr(lfs_t *lfs, struct lfs_commit *commit,
+ lfs_tag_t tag, const void *buffer) {
+ // check if we fit
+ lfs_size_t dsize = lfs_tag_dsize(tag);
+ if (commit->off + dsize > commit->end) {
+ return LFS_ERR_NOSPC;
+ }
+
+ // write out tag
+ lfs_tag_t ntag = lfs_tobe32((tag & 0x7fffffff) ^ commit->ptag);
+ int err = lfs_dir_commitprog(lfs, commit, &ntag, sizeof(ntag));
+ if (err) {
+ return err;
+ }
+
+ if (!(tag & 0x80000000)) {
+ // from memory
+ err = lfs_dir_commitprog(lfs, commit, buffer, dsize-sizeof(tag));
+ if (err) {
+ return err;
+ }
+ } else {
+ // from disk
+ const struct lfs_diskoff *disk = buffer;
+ for (lfs_off_t i = 0; i < dsize-sizeof(tag); i++) {
+ // rely on caching to make this efficient
+ uint8_t dat;
+ err = lfs_bd_read(lfs,
+ NULL, &lfs->rcache, dsize-sizeof(tag)-i,
+ disk->block, disk->off+i, &dat, 1);
+ if (err) {
+ return err;
+ }
+
+ err = lfs_dir_commitprog(lfs, commit, &dat, 1);
+ if (err) {
+ return err;
+ }
+ }
+ }
+
+ commit->ptag = tag & 0x7fffffff;
+ return 0;
+}
+#endif
+
+#ifndef LFS_READONLY
+
+static int lfs_dir_commitcrc(lfs_t *lfs, struct lfs_commit *commit) {
+ // align to program units
+ //
+ // this gets a bit complex as we have two types of crcs:
+ // - 5-word crc with fcrc to check following prog (middle of block)
+ // - 2-word crc with no following prog (end of block)
+ const lfs_off_t end = lfs_alignup(
+ lfs_min(commit->off + 5*sizeof(uint32_t), lfs->cfg->block_size),
+ lfs->cfg->prog_size);
+
+ lfs_off_t off1 = 0;
+ uint32_t crc1 = 0;
+
+ // create crc tags to fill up remainder of commit, note that
+ // padding is not crced, which lets fetches skip padding but
+ // makes committing a bit more complicated
+ while (commit->off < end) {
+ lfs_off_t noff = (
+ lfs_min(end - (commit->off+sizeof(lfs_tag_t)), 0x3fe)
+ + (commit->off+sizeof(lfs_tag_t)));
+ // too large for crc tag? need padding commits
+ if (noff < end) {
+ noff = lfs_min(noff, end - 5*sizeof(uint32_t));
+ }
+
+ // space for fcrc?
+ uint8_t eperturb = (uint8_t)-1;
+ if (noff >= end && noff <= lfs->cfg->block_size - lfs->cfg->prog_size) {
+ // first read the leading byte, this always contains a bit
+ // we can perturb to avoid writes that don't change the fcrc
+ int err = lfs_bd_read(lfs,
+ NULL, &lfs->rcache, lfs->cfg->prog_size,
+ commit->block, noff, &eperturb, 1);
+ if (err && err != LFS_ERR_CORRUPT) {
+ return err;
+ }
+
+ #ifdef LFS_MULTIVERSION
+ // unfortunately fcrcs break mdir fetching < lfs2.1, so only write
+ // these if we're a >= lfs2.1 filesystem
+ if (lfs_fs_disk_version(lfs) <= 0x00020000) {
+ // don't write fcrc
+ } else
+ #endif
+ {
+ // find the expected fcrc, don't bother avoiding a reread
+ // of the eperturb, it should still be in our cache
+ struct lfs_fcrc fcrc = {
+ .size = lfs->cfg->prog_size,
+ .crc = 0xffffffff
+ };
+ err = lfs_bd_crc(lfs,
+ NULL, &lfs->rcache, lfs->cfg->prog_size,
+ commit->block, noff, fcrc.size, &fcrc.crc);
+ if (err && err != LFS_ERR_CORRUPT) {
+ return err;
+ }
+
+ lfs_fcrc_tole32(&fcrc);
+ err = lfs_dir_commitattr(lfs, commit,
+ LFS_MKTAG(LFS_TYPE_FCRC, 0x3ff, sizeof(struct lfs_fcrc)),
+ &fcrc);
+ if (err) {
+ return err;
+ }
+ }
+ }
+
+ // build commit crc
+ struct {
+ lfs_tag_t tag;
+ uint32_t crc;
+ } ccrc;
+ lfs_tag_t ntag = LFS_MKTAG(
+ LFS_TYPE_CCRC + (((uint8_t)~eperturb) >> 7), 0x3ff,
+ noff - (commit->off+sizeof(lfs_tag_t)));
+ ccrc.tag = lfs_tobe32(ntag ^ commit->ptag);
+ commit->crc = lfs_crc(commit->crc, &ccrc.tag, sizeof(lfs_tag_t));
+ ccrc.crc = lfs_tole32(commit->crc);
+
+ int err = lfs_bd_prog(lfs,
+ &lfs->pcache, &lfs->rcache, false,
+ commit->block, commit->off, &ccrc, sizeof(ccrc));
+ if (err) {
+ return err;
+ }
+
+ // keep track of non-padding checksum to verify
+ if (off1 == 0) {
+ off1 = commit->off + sizeof(lfs_tag_t);
+ crc1 = commit->crc;
+ }
+
+ commit->off = noff;
+ // perturb valid bit?
+ commit->ptag = ntag ^ ((0x80UL & ~eperturb) << 24);
+ // reset crc for next commit
+ commit->crc = 0xffffffff;
+
+ // manually flush here since we don't prog the padding, this confuses
+ // the caching layer
+ if (noff >= end || noff >= lfs->pcache.off + lfs->cfg->cache_size) {
+ // flush buffers
+ int err = lfs_bd_sync(lfs, &lfs->pcache, &lfs->rcache, false);
+ if (err) {
+ return err;
+ }
+ }
+ }
+
+ // successful commit, check checksums to make sure
+ //
+ // note that we don't need to check padding commits, worst
+ // case if they are corrupted we would have had to compact anyways
+ lfs_off_t off = commit->begin;
+ uint32_t crc = 0xffffffff;
+ int err = lfs_bd_crc(lfs,
+ NULL, &lfs->rcache, off1+sizeof(uint32_t),
+ commit->block, off, off1-off, &crc);
+ if (err) {
+ return err;
+ }
+
+ // check non-padding commits against known crc
+ if (crc != crc1) {
+ return LFS_ERR_CORRUPT;
+ }
+
+ // make sure to check crc in case we happen to pick
+ // up an unrelated crc (frozen block?)
+ err = lfs_bd_crc(lfs,
+ NULL, &lfs->rcache, sizeof(uint32_t),
+ commit->block, off1, sizeof(uint32_t), &crc);
+ if (err) {
+ return err;
+ }
+
+ if (crc != 0) {
+ return LFS_ERR_CORRUPT;
+ }
+
+ return 0;
+}
+#endif
+
+#ifndef LFS_READONLY
+static int lfs_dir_alloc(lfs_t *lfs, lfs_mdir_t *dir) {
+ // allocate pair of dir blocks (backwards, so we write block 1 first)
+ for (int i = 0; i < 2; i++) {
+ int err = lfs_alloc(lfs, &dir->pair[(i+1)%2]);
+ if (err) {
+ return err;
+ }
+ }
+
+ // zero for reproducibility in case initial block is unreadable
+ dir->rev = 0;
+
+ // rather than clobbering one of the blocks we just pretend
+ // the revision may be valid
+ int err = lfs_bd_read(lfs,
+ NULL, &lfs->rcache, sizeof(dir->rev),
+ dir->pair[0], 0, &dir->rev, sizeof(dir->rev));
+ dir->rev = lfs_fromle32(dir->rev);
+ if (err && err != LFS_ERR_CORRUPT) {
+ return err;
+ }
+
+ // to make sure we don't immediately evict, align the new revision count
+ // to our block_cycles modulus, see lfs_dir_compact for why our modulus
+ // is tweaked this way
+ if (lfs->cfg->block_cycles > 0) {
+ dir->rev = lfs_alignup(dir->rev, ((lfs->cfg->block_cycles+1)|1));
+ }
+
+ // set defaults
+ dir->off = sizeof(dir->rev);
+ dir->etag = 0xffffffff;
+ dir->count = 0;
+ dir->tail[0] = LFS_BLOCK_NULL;
+ dir->tail[1] = LFS_BLOCK_NULL;
+ dir->erased = false;
+ dir->split = false;
+
+ // don't write out yet, let caller take care of that
+ return 0;
+}
+#endif
+
+#ifndef LFS_READONLY
+static int lfs_dir_drop(lfs_t *lfs, lfs_mdir_t *dir, lfs_mdir_t *tail) {
+ // steal state
+ int err = lfs_dir_getgstate(lfs, tail, &lfs->gdelta);
+ if (err) {
+ return err;
+ }
+
+ // steal tail
+ lfs_pair_tole32(tail->tail);
+ err = lfs_dir_commit(lfs, dir, LFS_MKATTRS(
+ {LFS_MKTAG(LFS_TYPE_TAIL + tail->split, 0x3ff, 8), tail->tail}));
+ lfs_pair_fromle32(tail->tail);
+ if (err) {
+ return err;
+ }
+
+ return 0;
+}
+#endif
+
+#ifndef LFS_READONLY
+static int lfs_dir_split(lfs_t *lfs,
+ lfs_mdir_t *dir, const struct lfs_mattr *attrs, int attrcount,
+ lfs_mdir_t *source, uint16_t split, uint16_t end) {
+ // create tail metadata pair
+ lfs_mdir_t tail;
+ int err = lfs_dir_alloc(lfs, &tail);
+ if (err) {
+ return err;
+ }
+
+ tail.split = dir->split;
+ tail.tail[0] = dir->tail[0];
+ tail.tail[1] = dir->tail[1];
+
+ // note we don't care about LFS_OK_RELOCATED
+ int res = lfs_dir_compact(lfs, &tail, attrs, attrcount, source, split, end);
+ if (res < 0) {
+ return res;
+ }
+
+ dir->tail[0] = tail.pair[0];
+ dir->tail[1] = tail.pair[1];
+ dir->split = true;
+
+ // update root if needed
+ if (lfs_pair_cmp(dir->pair, lfs->root) == 0 && split == 0) {
+ lfs->root[0] = tail.pair[0];
+ lfs->root[1] = tail.pair[1];
+ }
+
+ return 0;
+}
+#endif
+
+#ifndef LFS_READONLY
+static int lfs_dir_commit_size(void *p, lfs_tag_t tag, const void *buffer) {
+ lfs_size_t *size = p;
+ (void)buffer;
+
+ *size += lfs_tag_dsize(tag);
+ return 0;
+}
+#endif
+
+#ifndef LFS_READONLY
+struct lfs_dir_commit_commit {
+ lfs_t *lfs;
+ struct lfs_commit *commit;
+};
+#endif
+
+#ifndef LFS_READONLY
+static int lfs_dir_commit_commit(void *p, lfs_tag_t tag, const void *buffer) {
+ struct lfs_dir_commit_commit *commit = p;
+ return lfs_dir_commitattr(commit->lfs, commit->commit, tag, buffer);
+}
+#endif
+
+#ifndef LFS_READONLY
+static bool lfs_dir_needsrelocation(lfs_t *lfs, lfs_mdir_t *dir) {
+ // If our revision count == n * block_cycles, we should force a relocation,
+ // this is how littlefs wear-levels at the metadata-pair level. Note that we
+ // actually use (block_cycles+1)|1, this is to avoid two corner cases:
+ // 1. block_cycles = 1, which would prevent relocations from terminating
+ // 2. block_cycles = 2n, which, due to aliasing, would only ever relocate
+ // one metadata block in the pair, effectively making this useless
+ return (lfs->cfg->block_cycles > 0
+ && ((dir->rev + 1) % ((lfs->cfg->block_cycles+1)|1) == 0));
+}
+#endif
+
+#ifndef LFS_READONLY
+static int lfs_dir_compact(lfs_t *lfs,
+ lfs_mdir_t *dir, const struct lfs_mattr *attrs, int attrcount,
+ lfs_mdir_t *source, uint16_t begin, uint16_t end) {
+ // save some state in case block is bad
+ bool relocated = false;
+ bool tired = lfs_dir_needsrelocation(lfs, dir);
+
+ // increment revision count
+ dir->rev += 1;
+
+ // do not proactively relocate blocks during migrations, this
+ // can cause a number of failure states such: clobbering the
+ // v1 superblock if we relocate root, and invalidating directory
+ // pointers if we relocate the head of a directory. On top of
+ // this, relocations increase the overall complexity of
+ // lfs_migration, which is already a delicate operation.
+#ifdef LFS_MIGRATE
+ if (lfs->lfs1) {
+ tired = false;
+ }
+#endif
+
+ if (tired && lfs_pair_cmp(dir->pair, (const lfs_block_t[2]){0, 1}) != 0) {
+ // we're writing too much, time to relocate
+ goto relocate;
+ }
+
+ // begin loop to commit compaction to blocks until a compact sticks
+ while (true) {
+ {
+ // setup commit state
+ struct lfs_commit commit = {
+ .block = dir->pair[1],
+ .off = 0,
+ .ptag = 0xffffffff,
+ .crc = 0xffffffff,
+
+ .begin = 0,
+ .end = (lfs->cfg->metadata_max ?
+ lfs->cfg->metadata_max : lfs->cfg->block_size) - 8,
+ };
+
+ // erase block to write to
+ int err = lfs_bd_erase(lfs, dir->pair[1]);
+ if (err) {
+ if (err == LFS_ERR_CORRUPT) {
+ goto relocate;
+ }
+ return err;
+ }
+
+ // write out header
+ dir->rev = lfs_tole32(dir->rev);
+ err = lfs_dir_commitprog(lfs, &commit,
+ &dir->rev, sizeof(dir->rev));
+ dir->rev = lfs_fromle32(dir->rev);
+ if (err) {
+ if (err == LFS_ERR_CORRUPT) {
+ goto relocate;
+ }
+ return err;
+ }
+
+ // traverse the directory, this time writing out all unique tags
+ err = lfs_dir_traverse(lfs,
+ source, 0, 0xffffffff, attrs, attrcount,
+ LFS_MKTAG(0x400, 0x3ff, 0),
+ LFS_MKTAG(LFS_TYPE_NAME, 0, 0),
+ begin, end, -begin,
+ lfs_dir_commit_commit, &(struct lfs_dir_commit_commit){
+ lfs, &commit});
+ if (err) {
+ if (err == LFS_ERR_CORRUPT) {
+ goto relocate;
+ }
+ return err;
+ }
+
+ // commit tail, which may be new after last size check
+ if (!lfs_pair_isnull(dir->tail)) {
+ lfs_pair_tole32(dir->tail);
+ err = lfs_dir_commitattr(lfs, &commit,
+ LFS_MKTAG(LFS_TYPE_TAIL + dir->split, 0x3ff, 8),
+ dir->tail);
+ lfs_pair_fromle32(dir->tail);
+ if (err) {
+ if (err == LFS_ERR_CORRUPT) {
+ goto relocate;
+ }
+ return err;
+ }
+ }
+
+ // bring over gstate?
+ lfs_gstate_t delta = {0};
+ if (!relocated) {
+ lfs_gstate_xor(&delta, &lfs->gdisk);
+ lfs_gstate_xor(&delta, &lfs->gstate);
+ }
+ lfs_gstate_xor(&delta, &lfs->gdelta);
+ delta.tag &= ~LFS_MKTAG(0, 0, 0x3ff);
+
+ err = lfs_dir_getgstate(lfs, dir, &delta);
+ if (err) {
+ return err;
+ }
+
+ if (!lfs_gstate_iszero(&delta)) {
+ lfs_gstate_tole32(&delta);
+ err = lfs_dir_commitattr(lfs, &commit,
+ LFS_MKTAG(LFS_TYPE_MOVESTATE, 0x3ff,
+ sizeof(delta)), &delta);
+ if (err) {
+ if (err == LFS_ERR_CORRUPT) {
+ goto relocate;
+ }
+ return err;
+ }
+ }
+
+ // complete commit with crc
+ err = lfs_dir_commitcrc(lfs, &commit);
+ if (err) {
+ if (err == LFS_ERR_CORRUPT) {
+ goto relocate;
+ }
+ return err;
+ }
+
+ // successful compaction, swap dir pair to indicate most recent
+ LFS_ASSERT(commit.off % lfs->cfg->prog_size == 0);
+ lfs_pair_swap(dir->pair);
+ dir->count = end - begin;
+ dir->off = commit.off;
+ dir->etag = commit.ptag;
+ // update gstate
+ lfs->gdelta = (lfs_gstate_t){0};
+ if (!relocated) {
+ lfs->gdisk = lfs->gstate;
+ }
+ }
+ break;
+
+relocate:
+ // commit was corrupted, drop caches and prepare to relocate block
+ relocated = true;
+ lfs_cache_drop(lfs, &lfs->pcache);
+ if (!tired) {
+ LFS_DEBUG("Bad block at 0x%"PRIx32, dir->pair[1]);
+ }
+
+ // can't relocate superblock, filesystem is now frozen
+ if (lfs_pair_cmp(dir->pair, (const lfs_block_t[2]){0, 1}) == 0) {
+ LFS_WARN("Superblock 0x%"PRIx32" has become unwritable",
+ dir->pair[1]);
+ return LFS_ERR_NOSPC;
+ }
+
+ // relocate half of pair
+ int err = lfs_alloc(lfs, &dir->pair[1]);
+ if (err && (err != LFS_ERR_NOSPC || !tired)) {
+ return err;
+ }
+
+ tired = false;
+ continue;
+ }
+
+ return relocated ? LFS_OK_RELOCATED : 0;
+}
+#endif
+
+#ifndef LFS_READONLY
+static int lfs_dir_splittingcompact(lfs_t *lfs, lfs_mdir_t *dir,
+ const struct lfs_mattr *attrs, int attrcount,
+ lfs_mdir_t *source, uint16_t begin, uint16_t end) {
+ while (true) {
+ // find size of first split, we do this by halving the split until
+ // the metadata is guaranteed to fit
+ //
+ // Note that this isn't a true binary search, we never increase the
+ // split size. This may result in poorly distributed metadata but isn't
+ // worth the extra code size or performance hit to fix.
+ lfs_size_t split = begin;
+ while (end - split > 1) {
+ lfs_size_t size = 0;
+ int err = lfs_dir_traverse(lfs,
+ source, 0, 0xffffffff, attrs, attrcount,
+ LFS_MKTAG(0x400, 0x3ff, 0),
+ LFS_MKTAG(LFS_TYPE_NAME, 0, 0),
+ split, end, -split,
+ lfs_dir_commit_size, &size);
+ if (err) {
+ return err;
+ }
+
+ // space is complicated, we need room for:
+ //
+ // - tail: 4+2*4 = 12 bytes
+ // - gstate: 4+3*4 = 16 bytes
+ // - move delete: 4 = 4 bytes
+ // - crc: 4+4 = 8 bytes
+ // total = 40 bytes
+ //
+ // And we cap at half a block to avoid degenerate cases with
+ // nearly-full metadata blocks.
+ //
+ lfs_size_t metadata_max = (lfs->cfg->metadata_max)
+ ? lfs->cfg->metadata_max
+ : lfs->cfg->block_size;
+ if (end - split < 0xff
+ && size <= lfs_min(
+ metadata_max - 40,
+ lfs_alignup(
+ metadata_max/2,
+ lfs->cfg->prog_size))) {
+ break;
+ }
+
+ split = split + ((end - split) / 2);
+ }
+
+ if (split == begin) {
+ // no split needed
+ break;
+ }
+
+ // split into two metadata pairs and continue
+ int err = lfs_dir_split(lfs, dir, attrs, attrcount,
+ source, split, end);
+ if (err && err != LFS_ERR_NOSPC) {
+ return err;
+ }
+
+ if (err) {
+ // we can't allocate a new block, try to compact with degraded
+ // performance
+ LFS_WARN("Unable to split {0x%"PRIx32", 0x%"PRIx32"}",
+ dir->pair[0], dir->pair[1]);
+ break;
+ } else {
+ end = split;
+ }
+ }
+
+ if (lfs_dir_needsrelocation(lfs, dir)
+ && lfs_pair_cmp(dir->pair, (const lfs_block_t[2]){0, 1}) == 0) {
+ // oh no! we're writing too much to the superblock,
+ // should we expand?
+ lfs_ssize_t size = lfs_fs_size_(lfs);
+ if (size < 0) {
+ return size;
+ }
+
+ // littlefs cannot reclaim expanded superblocks, so expand cautiously
+ //
+ // if our filesystem is more than ~88% full, don't expand, this is
+ // somewhat arbitrary
+ if (lfs->block_count - size > lfs->block_count/8) {
+ LFS_DEBUG("Expanding superblock at rev %"PRIu32, dir->rev);
+ int err = lfs_dir_split(lfs, dir, attrs, attrcount,
+ source, begin, end);
+ if (err && err != LFS_ERR_NOSPC) {
+ return err;
+ }
+
+ if (err) {
+ // welp, we tried, if we ran out of space there's not much
+ // we can do, we'll error later if we've become frozen
+ LFS_WARN("Unable to expand superblock");
+ } else {
+ // duplicate the superblock entry into the new superblock
+ end = 1;
+ }
+ }
+ }
+
+ return lfs_dir_compact(lfs, dir, attrs, attrcount, source, begin, end);
+}
+#endif
+
+#ifndef LFS_READONLY
+static int lfs_dir_relocatingcommit(lfs_t *lfs, lfs_mdir_t *dir,
+ const lfs_block_t pair[2],
+ const struct lfs_mattr *attrs, int attrcount,
+ lfs_mdir_t *pdir) {
+ int state = 0;
+
+ // calculate changes to the directory
+ bool hasdelete = false;
+ for (int i = 0; i < attrcount; i++) {
+ if (lfs_tag_type3(attrs[i].tag) == LFS_TYPE_CREATE) {
+ dir->count += 1;
+ } else if (lfs_tag_type3(attrs[i].tag) == LFS_TYPE_DELETE) {
+ LFS_ASSERT(dir->count > 0);
+ dir->count -= 1;
+ hasdelete = true;
+ } else if (lfs_tag_type1(attrs[i].tag) == LFS_TYPE_TAIL) {
+ dir->tail[0] = ((lfs_block_t*)attrs[i].buffer)[0];
+ dir->tail[1] = ((lfs_block_t*)attrs[i].buffer)[1];
+ dir->split = (lfs_tag_chunk(attrs[i].tag) & 1);
+ lfs_pair_fromle32(dir->tail);
+ }
+ }
+
+ // should we actually drop the directory block?
+ if (hasdelete && dir->count == 0) {
+ LFS_ASSERT(pdir);
+ int err = lfs_fs_pred(lfs, dir->pair, pdir);
+ if (err && err != LFS_ERR_NOENT) {
+ return err;
+ }
+
+ if (err != LFS_ERR_NOENT && pdir->split) {
+ state = LFS_OK_DROPPED;
+ goto fixmlist;
+ }
+ }
+
+ if (dir->erased) {
+ // try to commit
+ struct lfs_commit commit = {
+ .block = dir->pair[0],
+ .off = dir->off,
+ .ptag = dir->etag,
+ .crc = 0xffffffff,
+
+ .begin = dir->off,
+ .end = (lfs->cfg->metadata_max ?
+ lfs->cfg->metadata_max : lfs->cfg->block_size) - 8,
+ };
+
+ // traverse attrs that need to be written out
+ lfs_pair_tole32(dir->tail);
+ int err = lfs_dir_traverse(lfs,
+ dir, dir->off, dir->etag, attrs, attrcount,
+ 0, 0, 0, 0, 0,
+ lfs_dir_commit_commit, &(struct lfs_dir_commit_commit){
+ lfs, &commit});
+ lfs_pair_fromle32(dir->tail);
+ if (err) {
+ if (err == LFS_ERR_NOSPC || err == LFS_ERR_CORRUPT) {
+ goto compact;
+ }
+ return err;
+ }
+
+ // commit any global diffs if we have any
+ lfs_gstate_t delta = {0};
+ lfs_gstate_xor(&delta, &lfs->gstate);
+ lfs_gstate_xor(&delta, &lfs->gdisk);
+ lfs_gstate_xor(&delta, &lfs->gdelta);
+ delta.tag &= ~LFS_MKTAG(0, 0, 0x3ff);
+ if (!lfs_gstate_iszero(&delta)) {
+ err = lfs_dir_getgstate(lfs, dir, &delta);
+ if (err) {
+ return err;
+ }
+
+ lfs_gstate_tole32(&delta);
+ err = lfs_dir_commitattr(lfs, &commit,
+ LFS_MKTAG(LFS_TYPE_MOVESTATE, 0x3ff,
+ sizeof(delta)), &delta);
+ if (err) {
+ if (err == LFS_ERR_NOSPC || err == LFS_ERR_CORRUPT) {
+ goto compact;
+ }
+ return err;
+ }
+ }
+
+ // finalize commit with the crc
+ err = lfs_dir_commitcrc(lfs, &commit);
+ if (err) {
+ if (err == LFS_ERR_NOSPC || err == LFS_ERR_CORRUPT) {
+ goto compact;
+ }
+ return err;
+ }
+
+ // successful commit, update dir
+ LFS_ASSERT(commit.off % lfs->cfg->prog_size == 0);
+ dir->off = commit.off;
+ dir->etag = commit.ptag;
+ // and update gstate
+ lfs->gdisk = lfs->gstate;
+ lfs->gdelta = (lfs_gstate_t){0};
+
+ goto fixmlist;
+ }
+
+compact:
+ // fall back to compaction
+ lfs_cache_drop(lfs, &lfs->pcache);
+
+ state = lfs_dir_splittingcompact(lfs, dir, attrs, attrcount,
+ dir, 0, dir->count);
+ if (state < 0) {
+ return state;
+ }
+
+ goto fixmlist;
+
+fixmlist:;
+ // this complicated bit of logic is for fixing up any active
+ // metadata-pairs that we may have affected
+ //
+ // note we have to make two passes since the mdir passed to
+ // lfs_dir_commit could also be in this list, and even then
+ // we need to copy the pair so they don't get clobbered if we refetch
+ // our mdir.
+ lfs_block_t oldpair[2] = {pair[0], pair[1]};
+ for (struct lfs_mlist *d = lfs->mlist; d; d = d->next) {
+ if (lfs_pair_cmp(d->m.pair, oldpair) == 0) {
+ d->m = *dir;
+ if (d->m.pair != pair) {
+ for (int i = 0; i < attrcount; i++) {
+ if (lfs_tag_type3(attrs[i].tag) == LFS_TYPE_DELETE &&
+ d->id == lfs_tag_id(attrs[i].tag) &&
+ d->type != LFS_TYPE_DIR) {
+ d->m.pair[0] = LFS_BLOCK_NULL;
+ d->m.pair[1] = LFS_BLOCK_NULL;
+ } else if (lfs_tag_type3(attrs[i].tag) == LFS_TYPE_DELETE &&
+ d->id > lfs_tag_id(attrs[i].tag)) {
+ d->id -= 1;
+ if (d->type == LFS_TYPE_DIR) {
+ ((lfs_dir_t*)d)->pos -= 1;
+ }
+ } else if (lfs_tag_type3(attrs[i].tag) == LFS_TYPE_CREATE &&
+ d->id >= lfs_tag_id(attrs[i].tag)) {
+ d->id += 1;
+ if (d->type == LFS_TYPE_DIR) {
+ ((lfs_dir_t*)d)->pos += 1;
+ }
+ }
+ }
+ }
+
+ while (d->id >= d->m.count && d->m.split) {
+ // we split and id is on tail now
+ if (lfs_pair_cmp(d->m.tail, lfs->root) != 0) {
+ d->id -= d->m.count;
+ }
+ int err = lfs_dir_fetch(lfs, &d->m, d->m.tail);
+ if (err) {
+ return err;
+ }
+ }
+ }
+ }
+
+ return state;
+}
+#endif
+
+#ifndef LFS_READONLY
+static int lfs_dir_orphaningcommit(lfs_t *lfs, lfs_mdir_t *dir,
+ const struct lfs_mattr *attrs, int attrcount) {
+ // check for any inline files that aren't RAM backed and
+ // forcefully evict them, needed for filesystem consistency
+ for (lfs_file_t *f = (lfs_file_t*)lfs->mlist; f; f = f->next) {
+ if (dir != &f->m && lfs_pair_cmp(f->m.pair, dir->pair) == 0 &&
+ f->type == LFS_TYPE_REG && (f->flags & LFS_F_INLINE) &&
+ f->ctz.size > lfs->cfg->cache_size) {
+ int err = lfs_file_outline(lfs, f);
+ if (err) {
+ return err;
+ }
+
+ err = lfs_file_flush(lfs, f);
+ if (err) {
+ return err;
+ }
+ }
+ }
+
+ lfs_block_t lpair[2] = {dir->pair[0], dir->pair[1]};
+ lfs_mdir_t ldir = *dir;
+ lfs_mdir_t pdir;
+ int state = lfs_dir_relocatingcommit(lfs, &ldir, dir->pair,
+ attrs, attrcount, &pdir);
+ if (state < 0) {
+ return state;
+ }
+
+ // update if we're not in mlist, note we may have already been
+ // updated if we are in mlist
+ if (lfs_pair_cmp(dir->pair, lpair) == 0) {
+ *dir = ldir;
+ }
+
+ // commit was successful, but may require other changes in the
+ // filesystem, these would normally be tail recursive, but we have
+ // flattened them here avoid unbounded stack usage
+
+ // need to drop?
+ if (state == LFS_OK_DROPPED) {
+ // steal state
+ int err = lfs_dir_getgstate(lfs, dir, &lfs->gdelta);
+ if (err) {
+ return err;
+ }
+
+ // steal tail, note that this can't create a recursive drop
+ lpair[0] = pdir.pair[0];
+ lpair[1] = pdir.pair[1];
+ lfs_pair_tole32(dir->tail);
+ state = lfs_dir_relocatingcommit(lfs, &pdir, lpair, LFS_MKATTRS(
+ {LFS_MKTAG(LFS_TYPE_TAIL + dir->split, 0x3ff, 8),
+ dir->tail}),
+ NULL);
+ lfs_pair_fromle32(dir->tail);
+ if (state < 0) {
+ return state;
+ }
+
+ ldir = pdir;
+ }
+
+ // need to relocate?
+ bool orphans = false;
+ while (state == LFS_OK_RELOCATED) {
+ LFS_DEBUG("Relocating {0x%"PRIx32", 0x%"PRIx32"} "
+ "-> {0x%"PRIx32", 0x%"PRIx32"}",
+ lpair[0], lpair[1], ldir.pair[0], ldir.pair[1]);
+ state = 0;
+
+ // update internal root
+ if (lfs_pair_cmp(lpair, lfs->root) == 0) {
+ lfs->root[0] = ldir.pair[0];
+ lfs->root[1] = ldir.pair[1];
+ }
+
+ // update internally tracked dirs
+ for (struct lfs_mlist *d = lfs->mlist; d; d = d->next) {
+ if (lfs_pair_cmp(lpair, d->m.pair) == 0) {
+ d->m.pair[0] = ldir.pair[0];
+ d->m.pair[1] = ldir.pair[1];
+ }
+
+ if (d->type == LFS_TYPE_DIR &&
+ lfs_pair_cmp(lpair, ((lfs_dir_t*)d)->head) == 0) {
+ ((lfs_dir_t*)d)->head[0] = ldir.pair[0];
+ ((lfs_dir_t*)d)->head[1] = ldir.pair[1];
+ }
+ }
+
+ // find parent
+ lfs_stag_t tag = lfs_fs_parent(lfs, lpair, &pdir);
+ if (tag < 0 && tag != LFS_ERR_NOENT) {
+ return tag;
+ }
+
+ bool hasparent = (tag != LFS_ERR_NOENT);
+ if (tag != LFS_ERR_NOENT) {
+ // note that if we have a parent, we must have a pred, so this will
+ // always create an orphan
+ int err = lfs_fs_preporphans(lfs, +1);
+ if (err) {
+ return err;
+ }
+
+ // fix pending move in this pair? this looks like an optimization but
+ // is in fact _required_ since relocating may outdate the move.
+ uint16_t moveid = 0x3ff;
+ if (lfs_gstate_hasmovehere(&lfs->gstate, pdir.pair)) {
+ moveid = lfs_tag_id(lfs->gstate.tag);
+ LFS_DEBUG("Fixing move while relocating "
+ "{0x%"PRIx32", 0x%"PRIx32"} 0x%"PRIx16"\n",
+ pdir.pair[0], pdir.pair[1], moveid);
+ lfs_fs_prepmove(lfs, 0x3ff, NULL);
+ if (moveid < lfs_tag_id(tag)) {
+ tag -= LFS_MKTAG(0, 1, 0);
+ }
+ }
+
+ lfs_block_t ppair[2] = {pdir.pair[0], pdir.pair[1]};
+ lfs_pair_tole32(ldir.pair);
+ state = lfs_dir_relocatingcommit(lfs, &pdir, ppair, LFS_MKATTRS(
+ {LFS_MKTAG_IF(moveid != 0x3ff,
+ LFS_TYPE_DELETE, moveid, 0), NULL},
+ {tag, ldir.pair}),
+ NULL);
+ lfs_pair_fromle32(ldir.pair);
+ if (state < 0) {
+ return state;
+ }
+
+ if (state == LFS_OK_RELOCATED) {
+ lpair[0] = ppair[0];
+ lpair[1] = ppair[1];
+ ldir = pdir;
+ orphans = true;
+ continue;
+ }
+ }
+
+ // find pred
+ int err = lfs_fs_pred(lfs, lpair, &pdir);
+ if (err && err != LFS_ERR_NOENT) {
+ return err;
+ }
+ LFS_ASSERT(!(hasparent && err == LFS_ERR_NOENT));
+
+ // if we can't find dir, it must be new
+ if (err != LFS_ERR_NOENT) {
+ if (lfs_gstate_hasorphans(&lfs->gstate)) {
+ // next step, clean up orphans
+ err = lfs_fs_preporphans(lfs, -(int8_t)hasparent);
+ if (err) {
+ return err;
+ }
+ }
+
+ // fix pending move in this pair? this looks like an optimization
+ // but is in fact _required_ since relocating may outdate the move.
+ uint16_t moveid = 0x3ff;
+ if (lfs_gstate_hasmovehere(&lfs->gstate, pdir.pair)) {
+ moveid = lfs_tag_id(lfs->gstate.tag);
+ LFS_DEBUG("Fixing move while relocating "
+ "{0x%"PRIx32", 0x%"PRIx32"} 0x%"PRIx16"\n",
+ pdir.pair[0], pdir.pair[1], moveid);
+ lfs_fs_prepmove(lfs, 0x3ff, NULL);
+ }
+
+ // replace bad pair, either we clean up desync, or no desync occured
+ lpair[0] = pdir.pair[0];
+ lpair[1] = pdir.pair[1];
+ lfs_pair_tole32(ldir.pair);
+ state = lfs_dir_relocatingcommit(lfs, &pdir, lpair, LFS_MKATTRS(
+ {LFS_MKTAG_IF(moveid != 0x3ff,
+ LFS_TYPE_DELETE, moveid, 0), NULL},
+ {LFS_MKTAG(LFS_TYPE_TAIL + pdir.split, 0x3ff, 8),
+ ldir.pair}),
+ NULL);
+ lfs_pair_fromle32(ldir.pair);
+ if (state < 0) {
+ return state;
+ }
+
+ ldir = pdir;
+ }
+ }
+
+ return orphans ? LFS_OK_ORPHANED : 0;
+}
+#endif
+
+#ifndef LFS_READONLY
+static int lfs_dir_commit(lfs_t *lfs, lfs_mdir_t *dir,
+ const struct lfs_mattr *attrs, int attrcount) {
+ int orphans = lfs_dir_orphaningcommit(lfs, dir, attrs, attrcount);
+ if (orphans < 0) {
+ return orphans;
+ }
+
+ if (orphans) {
+ // make sure we've removed all orphans, this is a noop if there
+ // are none, but if we had nested blocks failures we may have
+ // created some
+ int err = lfs_fs_deorphan(lfs, false);
+ if (err) {
+ return err;
+ }
+ }
+
+ return 0;
+}
+#endif
+
+
+/// Top level directory operations ///
+#ifndef LFS_READONLY
+static int lfs_mkdir_(lfs_t *lfs, const char *path) {
+ // deorphan if we haven't yet, needed at most once after poweron
+ int err = lfs_fs_forceconsistency(lfs);
+ if (err) {
+ return err;
+ }
+
+ struct lfs_mlist cwd;
+ cwd.next = lfs->mlist;
+ uint16_t id;
+ err = lfs_dir_find(lfs, &cwd.m, &path, &id);
+ if (!(err == LFS_ERR_NOENT && lfs_path_islast(path))) {
+ return (err < 0) ? err : LFS_ERR_EXIST;
+ }
+
+ // check that name fits
+ lfs_size_t nlen = lfs_path_namelen(path);
+ if (nlen > lfs->name_max) {
+ return LFS_ERR_NAMETOOLONG;
+ }
+
+ // build up new directory
+ lfs_alloc_ckpoint(lfs);
+ lfs_mdir_t dir;
+ err = lfs_dir_alloc(lfs, &dir);
+ if (err) {
+ return err;
+ }
+
+ // find end of list
+ lfs_mdir_t pred = cwd.m;
+ while (pred.split) {
+ err = lfs_dir_fetch(lfs, &pred, pred.tail);
+ if (err) {
+ return err;
+ }
+ }
+
+ // setup dir
+ lfs_pair_tole32(pred.tail);
+ err = lfs_dir_commit(lfs, &dir, LFS_MKATTRS(
+ {LFS_MKTAG(LFS_TYPE_SOFTTAIL, 0x3ff, 8), pred.tail}));
+ lfs_pair_fromle32(pred.tail);
+ if (err) {
+ return err;
+ }
+
+ // current block not end of list?
+ if (cwd.m.split) {
+ // update tails, this creates a desync
+ err = lfs_fs_preporphans(lfs, +1);
+ if (err) {
+ return err;
+ }
+
+ // it's possible our predecessor has to be relocated, and if
+ // our parent is our predecessor's predecessor, this could have
+ // caused our parent to go out of date, fortunately we can hook
+ // ourselves into littlefs to catch this
+ cwd.type = 0;
+ cwd.id = 0;
+ lfs->mlist = &cwd;
+
+ lfs_pair_tole32(dir.pair);
+ err = lfs_dir_commit(lfs, &pred, LFS_MKATTRS(
+ {LFS_MKTAG(LFS_TYPE_SOFTTAIL, 0x3ff, 8), dir.pair}));
+ lfs_pair_fromle32(dir.pair);
+ if (err) {
+ lfs->mlist = cwd.next;
+ return err;
+ }
+
+ lfs->mlist = cwd.next;
+ err = lfs_fs_preporphans(lfs, -1);
+ if (err) {
+ return err;
+ }
+ }
+
+ // now insert into our parent block
+ lfs_pair_tole32(dir.pair);
+ err = lfs_dir_commit(lfs, &cwd.m, LFS_MKATTRS(
+ {LFS_MKTAG(LFS_TYPE_CREATE, id, 0), NULL},
+ {LFS_MKTAG(LFS_TYPE_DIR, id, nlen), path},
+ {LFS_MKTAG(LFS_TYPE_DIRSTRUCT, id, 8), dir.pair},
+ {LFS_MKTAG_IF(!cwd.m.split,
+ LFS_TYPE_SOFTTAIL, 0x3ff, 8), dir.pair}));
+ lfs_pair_fromle32(dir.pair);
+ if (err) {
+ return err;
+ }
+
+ return 0;
+}
+#endif
+
+static int lfs_dir_open_(lfs_t *lfs, lfs_dir_t *dir, const char *path) {
+ lfs_stag_t tag = lfs_dir_find(lfs, &dir->m, &path, NULL);
+ if (tag < 0) {
+ return tag;
+ }
+
+ if (lfs_tag_type3(tag) != LFS_TYPE_DIR) {
+ return LFS_ERR_NOTDIR;
+ }
+
+ lfs_block_t pair[2];
+ if (lfs_tag_id(tag) == 0x3ff) {
+ // handle root dir separately
+ pair[0] = lfs->root[0];
+ pair[1] = lfs->root[1];
+ } else {
+ // get dir pair from parent
+ lfs_stag_t res = lfs_dir_get(lfs, &dir->m, LFS_MKTAG(0x700, 0x3ff, 0),
+ LFS_MKTAG(LFS_TYPE_STRUCT, lfs_tag_id(tag), 8), pair);
+ if (res < 0) {
+ return res;
+ }
+ lfs_pair_fromle32(pair);
+ }
+
+ // fetch first pair
+ int err = lfs_dir_fetch(lfs, &dir->m, pair);
+ if (err) {
+ return err;
+ }
+
+ // setup entry
+ dir->head[0] = dir->m.pair[0];
+ dir->head[1] = dir->m.pair[1];
+ dir->id = 0;
+ dir->pos = 0;
+
+ // add to list of mdirs
+ dir->type = LFS_TYPE_DIR;
+ lfs_mlist_append(lfs, (struct lfs_mlist *)dir);
+
+ return 0;
+}
+
+static int lfs_dir_close_(lfs_t *lfs, lfs_dir_t *dir) {
+ // remove from list of mdirs
+ lfs_mlist_remove(lfs, (struct lfs_mlist *)dir);
+
+ return 0;
+}
+
+static int lfs_dir_read_(lfs_t *lfs, lfs_dir_t *dir, struct lfs_info *info) {
+ memset(info, 0, sizeof(*info));
+
+ // special offset for '.' and '..'
+ if (dir->pos == 0) {
+ info->type = LFS_TYPE_DIR;
+ strcpy(info->name, ".");
+ dir->pos += 1;
+ return true;
+ } else if (dir->pos == 1) {
+ info->type = LFS_TYPE_DIR;
+ strcpy(info->name, "..");
+ dir->pos += 1;
+ return true;
+ }
+
+ while (true) {
+ if (dir->id == dir->m.count) {
+ if (!dir->m.split) {
+ return false;
+ }
+
+ int err = lfs_dir_fetch(lfs, &dir->m, dir->m.tail);
+ if (err) {
+ return err;
+ }
+
+ dir->id = 0;
+ }
+
+ int err = lfs_dir_getinfo(lfs, &dir->m, dir->id, info);
+ if (err && err != LFS_ERR_NOENT) {
+ return err;
+ }
+
+ dir->id += 1;
+ if (err != LFS_ERR_NOENT) {
+ break;
+ }
+ }
+
+ dir->pos += 1;
+ return true;
+}
+
+static int lfs_dir_seek_(lfs_t *lfs, lfs_dir_t *dir, lfs_off_t off) {
+ // simply walk from head dir
+ int err = lfs_dir_rewind_(lfs, dir);
+ if (err) {
+ return err;
+ }
+
+ // first two for ./..
+ dir->pos = lfs_min(2, off);
+ off -= dir->pos;
+
+ // skip superblock entry
+ dir->id = (off > 0 && lfs_pair_cmp(dir->head, lfs->root) == 0);
+
+ while (off > 0) {
+ if (dir->id == dir->m.count) {
+ if (!dir->m.split) {
+ return LFS_ERR_INVAL;
+ }
+
+ err = lfs_dir_fetch(lfs, &dir->m, dir->m.tail);
+ if (err) {
+ return err;
+ }
+
+ dir->id = 0;
+ }
+
+ int diff = lfs_min(dir->m.count - dir->id, off);
+ dir->id += diff;
+ dir->pos += diff;
+ off -= diff;
+ }
+
+ return 0;
+}
+
+static lfs_soff_t lfs_dir_tell_(lfs_t *lfs, lfs_dir_t *dir) {
+ (void)lfs;
+ return dir->pos;
+}
+
+static int lfs_dir_rewind_(lfs_t *lfs, lfs_dir_t *dir) {
+ // reload the head dir
+ int err = lfs_dir_fetch(lfs, &dir->m, dir->head);
+ if (err) {
+ return err;
+ }
+
+ dir->id = 0;
+ dir->pos = 0;
+ return 0;
+}
+
+
+/// File index list operations ///
+static int lfs_ctz_index(lfs_t *lfs, lfs_off_t *off) {
+ lfs_off_t size = *off;
+ lfs_off_t b = lfs->cfg->block_size - 2*4;
+ lfs_off_t i = size / b;
+ if (i == 0) {
+ return 0;
+ }
+
+ i = (size - 4*(lfs_popc(i-1)+2)) / b;
+ *off = size - b*i - 4*lfs_popc(i);
+ return i;
+}
+
+static int lfs_ctz_find(lfs_t *lfs,
+ const lfs_cache_t *pcache, lfs_cache_t *rcache,
+ lfs_block_t head, lfs_size_t size,
+ lfs_size_t pos, lfs_block_t *block, lfs_off_t *off) {
+ if (size == 0) {
+ *block = LFS_BLOCK_NULL;
+ *off = 0;
+ return 0;
+ }
+
+ lfs_off_t current = lfs_ctz_index(lfs, &(lfs_off_t){size-1});
+ lfs_off_t target = lfs_ctz_index(lfs, &pos);
+
+ while (current > target) {
+ lfs_size_t skip = lfs_min(
+ lfs_npw2(current-target+1) - 1,
+ lfs_ctz(current));
+
+ int err = lfs_bd_read(lfs,
+ pcache, rcache, sizeof(head),
+ head, 4*skip, &head, sizeof(head));
+ head = lfs_fromle32(head);
+ if (err) {
+ return err;
+ }
+
+ current -= 1 << skip;
+ }
+
+ *block = head;
+ *off = pos;
+ return 0;
+}
+
+#ifndef LFS_READONLY
+static int lfs_ctz_extend(lfs_t *lfs,
+ lfs_cache_t *pcache, lfs_cache_t *rcache,
+ lfs_block_t head, lfs_size_t size,
+ lfs_block_t *block, lfs_off_t *off) {
+ while (true) {
+ // go ahead and grab a block
+ lfs_block_t nblock;
+ int err = lfs_alloc(lfs, &nblock);
+ if (err) {
+ return err;
+ }
+
+ {
+ err = lfs_bd_erase(lfs, nblock);
+ if (err) {
+ if (err == LFS_ERR_CORRUPT) {
+ goto relocate;
+ }
+ return err;
+ }
+
+ if (size == 0) {
+ *block = nblock;
+ *off = 0;
+ return 0;
+ }
+
+ lfs_size_t noff = size - 1;
+ lfs_off_t index = lfs_ctz_index(lfs, &noff);
+ noff = noff + 1;
+
+ // just copy out the last block if it is incomplete
+ if (noff != lfs->cfg->block_size) {
+ for (lfs_off_t i = 0; i < noff; i++) {
+ uint8_t data;
+ err = lfs_bd_read(lfs,
+ NULL, rcache, noff-i,
+ head, i, &data, 1);
+ if (err) {
+ return err;
+ }
+
+ err = lfs_bd_prog(lfs,
+ pcache, rcache, true,
+ nblock, i, &data, 1);
+ if (err) {
+ if (err == LFS_ERR_CORRUPT) {
+ goto relocate;
+ }
+ return err;
+ }
+ }
+
+ *block = nblock;
+ *off = noff;
+ return 0;
+ }
+
+ // append block
+ index += 1;
+ lfs_size_t skips = lfs_ctz(index) + 1;
+ lfs_block_t nhead = head;
+ for (lfs_off_t i = 0; i < skips; i++) {
+ nhead = lfs_tole32(nhead);
+ err = lfs_bd_prog(lfs, pcache, rcache, true,
+ nblock, 4*i, &nhead, 4);
+ nhead = lfs_fromle32(nhead);
+ if (err) {
+ if (err == LFS_ERR_CORRUPT) {
+ goto relocate;
+ }
+ return err;
+ }
+
+ if (i != skips-1) {
+ err = lfs_bd_read(lfs,
+ NULL, rcache, sizeof(nhead),
+ nhead, 4*i, &nhead, sizeof(nhead));
+ nhead = lfs_fromle32(nhead);
+ if (err) {
+ return err;
+ }
+ }
+ }
+
+ *block = nblock;
+ *off = 4*skips;
+ return 0;
+ }
+
+relocate:
+ LFS_DEBUG("Bad block at 0x%"PRIx32, nblock);
+
+ // just clear cache and try a new block
+ lfs_cache_drop(lfs, pcache);
+ }
+}
+#endif
+
+static int lfs_ctz_traverse(lfs_t *lfs,
+ const lfs_cache_t *pcache, lfs_cache_t *rcache,
+ lfs_block_t head, lfs_size_t size,
+ int (*cb)(void*, lfs_block_t), void *data) {
+ if (size == 0) {
+ return 0;
+ }
+
+ lfs_off_t index = lfs_ctz_index(lfs, &(lfs_off_t){size-1});
+
+ while (true) {
+ int err = cb(data, head);
+ if (err) {
+ return err;
+ }
+
+ if (index == 0) {
+ return 0;
+ }
+
+ lfs_block_t heads[2];
+ int count = 2 - (index & 1);
+ err = lfs_bd_read(lfs,
+ pcache, rcache, count*sizeof(head),
+ head, 0, &heads, count*sizeof(head));
+ heads[0] = lfs_fromle32(heads[0]);
+ heads[1] = lfs_fromle32(heads[1]);
+ if (err) {
+ return err;
+ }
+
+ for (int i = 0; i < count-1; i++) {
+ err = cb(data, heads[i]);
+ if (err) {
+ return err;
+ }
+ }
+
+ head = heads[count-1];
+ index -= count;
+ }
+}
+
+
+/// Top level file operations ///
+static int lfs_file_opencfg_(lfs_t *lfs, lfs_file_t *file,
+ const char *path, int flags,
+ const struct lfs_file_config *cfg) {
+#ifndef LFS_READONLY
+ // deorphan if we haven't yet, needed at most once after poweron
+ if ((flags & LFS_O_WRONLY) == LFS_O_WRONLY) {
+ int err = lfs_fs_forceconsistency(lfs);
+ if (err) {
+ return err;
+ }
+ }
+#else
+ LFS_ASSERT((flags & LFS_O_RDONLY) == LFS_O_RDONLY);
+#endif
+
+ // setup simple file details
+ int err;
+ file->cfg = cfg;
+ file->flags = flags;
+ file->pos = 0;
+ file->off = 0;
+ file->cache.buffer = NULL;
+
+ // allocate entry for file if it doesn't exist
+ lfs_stag_t tag = lfs_dir_find(lfs, &file->m, &path, &file->id);
+ if (tag < 0 && !(tag == LFS_ERR_NOENT && lfs_path_islast(path))) {
+ err = tag;
+ goto cleanup;
+ }
+
+ // get id, add to list of mdirs to catch update changes
+ file->type = LFS_TYPE_REG;
+ lfs_mlist_append(lfs, (struct lfs_mlist *)file);
+
+#ifdef LFS_READONLY
+ if (tag == LFS_ERR_NOENT) {
+ err = LFS_ERR_NOENT;
+ goto cleanup;
+#else
+ if (tag == LFS_ERR_NOENT) {
+ if (!(flags & LFS_O_CREAT)) {
+ err = LFS_ERR_NOENT;
+ goto cleanup;
+ }
+
+ // don't allow trailing slashes
+ if (lfs_path_isdir(path)) {
+ err = LFS_ERR_NOTDIR;
+ goto cleanup;
+ }
+
+ // check that name fits
+ lfs_size_t nlen = lfs_path_namelen(path);
+ if (nlen > lfs->name_max) {
+ err = LFS_ERR_NAMETOOLONG;
+ goto cleanup;
+ }
+
+ // get next slot and create entry to remember name
+ err = lfs_dir_commit(lfs, &file->m, LFS_MKATTRS(
+ {LFS_MKTAG(LFS_TYPE_CREATE, file->id, 0), NULL},
+ {LFS_MKTAG(LFS_TYPE_REG, file->id, nlen), path},
+ {LFS_MKTAG(LFS_TYPE_INLINESTRUCT, file->id, 0), NULL}));
+
+ // it may happen that the file name doesn't fit in the metadata blocks, e.g., a 256 byte file name will
+ // not fit in a 128 byte block.
+ err = (err == LFS_ERR_NOSPC) ? LFS_ERR_NAMETOOLONG : err;
+ if (err) {
+ goto cleanup;
+ }
+
+ tag = LFS_MKTAG(LFS_TYPE_INLINESTRUCT, 0, 0);
+ } else if (flags & LFS_O_EXCL) {
+ err = LFS_ERR_EXIST;
+ goto cleanup;
+#endif
+ } else if (lfs_tag_type3(tag) != LFS_TYPE_REG) {
+ err = LFS_ERR_ISDIR;
+ goto cleanup;
+#ifndef LFS_READONLY
+ } else if (flags & LFS_O_TRUNC) {
+ // truncate if requested
+ tag = LFS_MKTAG(LFS_TYPE_INLINESTRUCT, file->id, 0);
+ file->flags |= LFS_F_DIRTY;
+#endif
+ } else {
+ // try to load what's on disk, if it's inlined we'll fix it later
+ tag = lfs_dir_get(lfs, &file->m, LFS_MKTAG(0x700, 0x3ff, 0),
+ LFS_MKTAG(LFS_TYPE_STRUCT, file->id, 8), &file->ctz);
+ if (tag < 0) {
+ err = tag;
+ goto cleanup;
+ }
+ lfs_ctz_fromle32(&file->ctz);
+ }
+
+ // fetch attrs
+ for (unsigned i = 0; i < file->cfg->attr_count; i++) {
+ // if opened for read / read-write operations
+ if ((file->flags & LFS_O_RDONLY) == LFS_O_RDONLY) {
+ lfs_stag_t res = lfs_dir_get(lfs, &file->m,
+ LFS_MKTAG(0x7ff, 0x3ff, 0),
+ LFS_MKTAG(LFS_TYPE_USERATTR + file->cfg->attrs[i].type,
+ file->id, file->cfg->attrs[i].size),
+ file->cfg->attrs[i].buffer);
+ if (res < 0 && res != LFS_ERR_NOENT) {
+ err = res;
+ goto cleanup;
+ }
+ }
+
+#ifndef LFS_READONLY
+ // if opened for write / read-write operations
+ if ((file->flags & LFS_O_WRONLY) == LFS_O_WRONLY) {
+ if (file->cfg->attrs[i].size > lfs->attr_max) {
+ err = LFS_ERR_NOSPC;
+ goto cleanup;
+ }
+
+ file->flags |= LFS_F_DIRTY;
+ }
+#endif
+ }
+
+ // allocate buffer if needed
+ if (file->cfg->buffer) {
+ file->cache.buffer = file->cfg->buffer;
+ } else {
+ file->cache.buffer = lfs_malloc(lfs->cfg->cache_size);
+ if (!file->cache.buffer) {
+ err = LFS_ERR_NOMEM;
+ goto cleanup;
+ }
+ }
+
+ // zero to avoid information leak
+ lfs_cache_zero(lfs, &file->cache);
+
+ if (lfs_tag_type3(tag) == LFS_TYPE_INLINESTRUCT) {
+ // load inline files
+ file->ctz.head = LFS_BLOCK_INLINE;
+ file->ctz.size = lfs_tag_size(tag);
+ file->flags |= LFS_F_INLINE;
+ file->cache.block = file->ctz.head;
+ file->cache.off = 0;
+ file->cache.size = lfs->cfg->cache_size;
+
+ // don't always read (may be new/trunc file)
+ if (file->ctz.size > 0) {
+ lfs_stag_t res = lfs_dir_get(lfs, &file->m,
+ LFS_MKTAG(0x700, 0x3ff, 0),
+ LFS_MKTAG(LFS_TYPE_STRUCT, file->id,
+ lfs_min(file->cache.size, 0x3fe)),
+ file->cache.buffer);
+ if (res < 0) {
+ err = res;
+ goto cleanup;
+ }
+ }
+ }
+
+ return 0;
+
+cleanup:
+ // clean up lingering resources
+#ifndef LFS_READONLY
+ file->flags |= LFS_F_ERRED;
+#endif
+ lfs_file_close_(lfs, file);
+ return err;
+}
+
+#ifndef LFS_NO_MALLOC
+static int lfs_file_open_(lfs_t *lfs, lfs_file_t *file,
+ const char *path, int flags) {
+ static const struct lfs_file_config defaults = {0};
+ int err = lfs_file_opencfg_(lfs, file, path, flags, &defaults);
+ return err;
+}
+#endif
+
+static int lfs_file_close_(lfs_t *lfs, lfs_file_t *file) {
+#ifndef LFS_READONLY
+ int err = lfs_file_sync_(lfs, file);
+#else
+ int err = 0;
+#endif
+
+ // remove from list of mdirs
+ lfs_mlist_remove(lfs, (struct lfs_mlist*)file);
+
+ // clean up memory
+ if (!file->cfg->buffer) {
+ lfs_free(file->cache.buffer);
+ }
+
+ return err;
+}
+
+
+#ifndef LFS_READONLY
+static int lfs_file_relocate(lfs_t *lfs, lfs_file_t *file) {
+ while (true) {
+ // just relocate what exists into new block
+ lfs_block_t nblock;
+ int err = lfs_alloc(lfs, &nblock);
+ if (err) {
+ return err;
+ }
+
+ err = lfs_bd_erase(lfs, nblock);
+ if (err) {
+ if (err == LFS_ERR_CORRUPT) {
+ goto relocate;
+ }
+ return err;
+ }
+
+ // either read from dirty cache or disk
+ for (lfs_off_t i = 0; i < file->off; i++) {
+ uint8_t data;
+ if (file->flags & LFS_F_INLINE) {
+ err = lfs_dir_getread(lfs, &file->m,
+ // note we evict inline files before they can be dirty
+ NULL, &file->cache, file->off-i,
+ LFS_MKTAG(0xfff, 0x1ff, 0),
+ LFS_MKTAG(LFS_TYPE_INLINESTRUCT, file->id, 0),
+ i, &data, 1);
+ if (err) {
+ return err;
+ }
+ } else {
+ err = lfs_bd_read(lfs,
+ &file->cache, &lfs->rcache, file->off-i,
+ file->block, i, &data, 1);
+ if (err) {
+ return err;
+ }
+ }
+
+ err = lfs_bd_prog(lfs,
+ &lfs->pcache, &lfs->rcache, true,
+ nblock, i, &data, 1);
+ if (err) {
+ if (err == LFS_ERR_CORRUPT) {
+ goto relocate;
+ }
+ return err;
+ }
+ }
+
+ // copy over new state of file
+ memcpy(file->cache.buffer, lfs->pcache.buffer, lfs->cfg->cache_size);
+ file->cache.block = lfs->pcache.block;
+ file->cache.off = lfs->pcache.off;
+ file->cache.size = lfs->pcache.size;
+ lfs_cache_zero(lfs, &lfs->pcache);
+
+ file->block = nblock;
+ file->flags |= LFS_F_WRITING;
+ return 0;
+
+relocate:
+ LFS_DEBUG("Bad block at 0x%"PRIx32, nblock);
+
+ // just clear cache and try a new block
+ lfs_cache_drop(lfs, &lfs->pcache);
+ }
+}
+#endif
+
+#ifndef LFS_READONLY
+static int lfs_file_outline(lfs_t *lfs, lfs_file_t *file) {
+ file->off = file->pos;
+ lfs_alloc_ckpoint(lfs);
+ int err = lfs_file_relocate(lfs, file);
+ if (err) {
+ return err;
+ }
+
+ file->flags &= ~LFS_F_INLINE;
+ return 0;
+}
+#endif
+
+static int lfs_file_flush(lfs_t *lfs, lfs_file_t *file) {
+ if (file->flags & LFS_F_READING) {
+ if (!(file->flags & LFS_F_INLINE)) {
+ lfs_cache_drop(lfs, &file->cache);
+ }
+ file->flags &= ~LFS_F_READING;
+ }
+
+#ifndef LFS_READONLY
+ if (file->flags & LFS_F_WRITING) {
+ lfs_off_t pos = file->pos;
+
+ if (!(file->flags & LFS_F_INLINE)) {
+ // copy over anything after current branch
+ lfs_file_t orig = {
+ .ctz.head = file->ctz.head,
+ .ctz.size = file->ctz.size,
+ .flags = LFS_O_RDONLY,
+ .pos = file->pos,
+ .cache = lfs->rcache,
+ };
+ lfs_cache_drop(lfs, &lfs->rcache);
+
+ while (file->pos < file->ctz.size) {
+ // copy over a byte at a time, leave it up to caching
+ // to make this efficient
+ uint8_t data;
+ lfs_ssize_t res = lfs_file_flushedread(lfs, &orig, &data, 1);
+ if (res < 0) {
+ return res;
+ }
+
+ res = lfs_file_flushedwrite(lfs, file, &data, 1);
+ if (res < 0) {
+ return res;
+ }
+
+ // keep our reference to the rcache in sync
+ if (lfs->rcache.block != LFS_BLOCK_NULL) {
+ lfs_cache_drop(lfs, &orig.cache);
+ lfs_cache_drop(lfs, &lfs->rcache);
+ }
+ }
+
+ // write out what we have
+ while (true) {
+ int err = lfs_bd_flush(lfs, &file->cache, &lfs->rcache, true);
+ if (err) {
+ if (err == LFS_ERR_CORRUPT) {
+ goto relocate;
+ }
+ return err;
+ }
+
+ break;
+
+relocate:
+ LFS_DEBUG("Bad block at 0x%"PRIx32, file->block);
+ err = lfs_file_relocate(lfs, file);
+ if (err) {
+ return err;
+ }
+ }
+ } else {
+ file->pos = lfs_max(file->pos, file->ctz.size);
+ }
+
+ // actual file updates
+ file->ctz.head = file->block;
+ file->ctz.size = file->pos;
+ file->flags &= ~LFS_F_WRITING;
+ file->flags |= LFS_F_DIRTY;
+
+ file->pos = pos;
+ }
+#endif
+
+ return 0;
+}
+
+#ifndef LFS_READONLY
+static int lfs_file_sync_(lfs_t *lfs, lfs_file_t *file) {
+ if (file->flags & LFS_F_ERRED) {
+ // it's not safe to do anything if our file errored
+ return 0;
+ }
+
+ int err = lfs_file_flush(lfs, file);
+ if (err) {
+ file->flags |= LFS_F_ERRED;
+ return err;
+ }
+
+
+ if ((file->flags & LFS_F_DIRTY) &&
+ !lfs_pair_isnull(file->m.pair)) {
+ // before we commit metadata, we need sync the disk to make sure
+ // data writes don't complete after metadata writes
+ if (!(file->flags & LFS_F_INLINE)) {
+ err = lfs_bd_sync(lfs, &lfs->pcache, &lfs->rcache, false);
+ if (err) {
+ return err;
+ }
+ }
+
+ // update dir entry
+ uint16_t type;
+ const void *buffer;
+ lfs_size_t size;
+ struct lfs_ctz ctz;
+ if (file->flags & LFS_F_INLINE) {
+ // inline the whole file
+ type = LFS_TYPE_INLINESTRUCT;
+ buffer = file->cache.buffer;
+ size = file->ctz.size;
+ } else {
+ // update the ctz reference
+ type = LFS_TYPE_CTZSTRUCT;
+ // copy ctz so alloc will work during a relocate
+ ctz = file->ctz;
+ lfs_ctz_tole32(&ctz);
+ buffer = &ctz;
+ size = sizeof(ctz);
+ }
+
+ // commit file data and attributes
+ err = lfs_dir_commit(lfs, &file->m, LFS_MKATTRS(
+ {LFS_MKTAG(type, file->id, size), buffer},
+ {LFS_MKTAG(LFS_FROM_USERATTRS, file->id,
+ file->cfg->attr_count), file->cfg->attrs}));
+ if (err) {
+ file->flags |= LFS_F_ERRED;
+ return err;
+ }
+
+ file->flags &= ~LFS_F_DIRTY;
+ }
+
+ return 0;
+}
+#endif
+
+static lfs_ssize_t lfs_file_flushedread(lfs_t *lfs, lfs_file_t *file,
+ void *buffer, lfs_size_t size) {
+ uint8_t *data = buffer;
+ lfs_size_t nsize = size;
+
+ if (file->pos >= file->ctz.size) {
+ // eof if past end
+ return 0;
+ }
+
+ size = lfs_min(size, file->ctz.size - file->pos);
+ nsize = size;
+
+ while (nsize > 0) {
+ // check if we need a new block
+ if (!(file->flags & LFS_F_READING) ||
+ file->off == lfs->cfg->block_size) {
+ if (!(file->flags & LFS_F_INLINE)) {
+ int err = lfs_ctz_find(lfs, NULL, &file->cache,
+ file->ctz.head, file->ctz.size,
+ file->pos, &file->block, &file->off);
+ if (err) {
+ return err;
+ }
+ } else {
+ file->block = LFS_BLOCK_INLINE;
+ file->off = file->pos;
+ }
+
+ file->flags |= LFS_F_READING;
+ }
+
+ // read as much as we can in current block
+ lfs_size_t diff = lfs_min(nsize, lfs->cfg->block_size - file->off);
+ if (file->flags & LFS_F_INLINE) {
+ int err = lfs_dir_getread(lfs, &file->m,
+ NULL, &file->cache, lfs->cfg->block_size,
+ LFS_MKTAG(0xfff, 0x1ff, 0),
+ LFS_MKTAG(LFS_TYPE_INLINESTRUCT, file->id, 0),
+ file->off, data, diff);
+ if (err) {
+ return err;
+ }
+ } else {
+ int err = lfs_bd_read(lfs,
+ NULL, &file->cache, lfs->cfg->block_size,
+ file->block, file->off, data, diff);
+ if (err) {
+ return err;
+ }
+ }
+
+ file->pos += diff;
+ file->off += diff;
+ data += diff;
+ nsize -= diff;
+ }
+
+ return size;
+}
+
+static lfs_ssize_t lfs_file_read_(lfs_t *lfs, lfs_file_t *file,
+ void *buffer, lfs_size_t size) {
+ LFS_ASSERT((file->flags & LFS_O_RDONLY) == LFS_O_RDONLY);
+
+#ifndef LFS_READONLY
+ if (file->flags & LFS_F_WRITING) {
+ // flush out any writes
+ int err = lfs_file_flush(lfs, file);
+ if (err) {
+ return err;
+ }
+ }
+#endif
+
+ return lfs_file_flushedread(lfs, file, buffer, size);
+}
+
+
+#ifndef LFS_READONLY
+static lfs_ssize_t lfs_file_flushedwrite(lfs_t *lfs, lfs_file_t *file,
+ const void *buffer, lfs_size_t size) {
+ const uint8_t *data = buffer;
+ lfs_size_t nsize = size;
+
+ if ((file->flags & LFS_F_INLINE) &&
+ lfs_max(file->pos+nsize, file->ctz.size) > lfs->inline_max) {
+ // inline file doesn't fit anymore
+ int err = lfs_file_outline(lfs, file);
+ if (err) {
+ file->flags |= LFS_F_ERRED;
+ return err;
+ }
+ }
+
+ while (nsize > 0) {
+ // check if we need a new block
+ if (!(file->flags & LFS_F_WRITING) ||
+ file->off == lfs->cfg->block_size) {
+ if (!(file->flags & LFS_F_INLINE)) {
+ if (!(file->flags & LFS_F_WRITING) && file->pos > 0) {
+ // find out which block we're extending from
+ int err = lfs_ctz_find(lfs, NULL, &file->cache,
+ file->ctz.head, file->ctz.size,
+ file->pos-1, &file->block, &(lfs_off_t){0});
+ if (err) {
+ file->flags |= LFS_F_ERRED;
+ return err;
+ }
+
+ // mark cache as dirty since we may have read data into it
+ lfs_cache_zero(lfs, &file->cache);
+ }
+
+ // extend file with new blocks
+ lfs_alloc_ckpoint(lfs);
+ int err = lfs_ctz_extend(lfs, &file->cache, &lfs->rcache,
+ file->block, file->pos,
+ &file->block, &file->off);
+ if (err) {
+ file->flags |= LFS_F_ERRED;
+ return err;
+ }
+ } else {
+ file->block = LFS_BLOCK_INLINE;
+ file->off = file->pos;
+ }
+
+ file->flags |= LFS_F_WRITING;
+ }
+
+ // program as much as we can in current block
+ lfs_size_t diff = lfs_min(nsize, lfs->cfg->block_size - file->off);
+ while (true) {
+ int err = lfs_bd_prog(lfs, &file->cache, &lfs->rcache, true,
+ file->block, file->off, data, diff);
+ if (err) {
+ if (err == LFS_ERR_CORRUPT) {
+ goto relocate;
+ }
+ file->flags |= LFS_F_ERRED;
+ return err;
+ }
+
+ break;
+relocate:
+ err = lfs_file_relocate(lfs, file);
+ if (err) {
+ file->flags |= LFS_F_ERRED;
+ return err;
+ }
+ }
+
+ file->pos += diff;
+ file->off += diff;
+ data += diff;
+ nsize -= diff;
+
+ lfs_alloc_ckpoint(lfs);
+ }
+
+ return size;
+}
+
+static lfs_ssize_t lfs_file_write_(lfs_t *lfs, lfs_file_t *file,
+ const void *buffer, lfs_size_t size) {
+ LFS_ASSERT((file->flags & LFS_O_WRONLY) == LFS_O_WRONLY);
+
+ if (file->flags & LFS_F_READING) {
+ // drop any reads
+ int err = lfs_file_flush(lfs, file);
+ if (err) {
+ return err;
+ }
+ }
+
+ if ((file->flags & LFS_O_APPEND) && file->pos < file->ctz.size) {
+ file->pos = file->ctz.size;
+ }
+
+ if (file->pos + size > lfs->file_max) {
+ // Larger than file limit?
+ return LFS_ERR_FBIG;
+ }
+
+ if (!(file->flags & LFS_F_WRITING) && file->pos > file->ctz.size) {
+ // fill with zeros
+ lfs_off_t pos = file->pos;
+ file->pos = file->ctz.size;
+
+ while (file->pos < pos) {
+ lfs_ssize_t res = lfs_file_flushedwrite(lfs, file, &(uint8_t){0}, 1);
+ if (res < 0) {
+ return res;
+ }
+ }
+ }
+
+ lfs_ssize_t nsize = lfs_file_flushedwrite(lfs, file, buffer, size);
+ if (nsize < 0) {
+ return nsize;
+ }
+
+ file->flags &= ~LFS_F_ERRED;
+ return nsize;
+}
+#endif
+
+static lfs_soff_t lfs_file_seek_(lfs_t *lfs, lfs_file_t *file,
+ lfs_soff_t off, int whence) {
+ // find new pos
+ //
+ // fortunately for us, littlefs is limited to 31-bit file sizes, so we
+ // don't have to worry too much about integer overflow
+ lfs_off_t npos = file->pos;
+ if (whence == LFS_SEEK_SET) {
+ npos = off;
+ } else if (whence == LFS_SEEK_CUR) {
+ npos = file->pos + (lfs_off_t)off;
+ } else if (whence == LFS_SEEK_END) {
+ npos = (lfs_off_t)lfs_file_size_(lfs, file) + (lfs_off_t)off;
+ }
+
+ if (npos > lfs->file_max) {
+ // file position out of range
+ return LFS_ERR_INVAL;
+ }
+
+ if (file->pos == npos) {
+ // noop - position has not changed
+ return npos;
+ }
+
+ // if we're only reading and our new offset is still in the file's cache
+ // we can avoid flushing and needing to reread the data
+ if ((file->flags & LFS_F_READING)
+ && file->off != lfs->cfg->block_size) {
+ int oindex = lfs_ctz_index(lfs, &(lfs_off_t){file->pos});
+ lfs_off_t noff = npos;
+ int nindex = lfs_ctz_index(lfs, &noff);
+ if (oindex == nindex
+ && noff >= file->cache.off
+ && noff < file->cache.off + file->cache.size) {
+ file->pos = npos;
+ file->off = noff;
+ return npos;
+ }
+ }
+
+ // write out everything beforehand, may be noop if rdonly
+ int err = lfs_file_flush(lfs, file);
+ if (err) {
+ return err;
+ }
+
+ // update pos
+ file->pos = npos;
+ return npos;
+}
+
+#ifndef LFS_READONLY
+static int lfs_file_truncate_(lfs_t *lfs, lfs_file_t *file, lfs_off_t size) {
+ LFS_ASSERT((file->flags & LFS_O_WRONLY) == LFS_O_WRONLY);
+
+ if (size > LFS_FILE_MAX) {
+ return LFS_ERR_INVAL;
+ }
+
+ lfs_off_t pos = file->pos;
+ lfs_off_t oldsize = lfs_file_size_(lfs, file);
+ if (size < oldsize) {
+ // revert to inline file?
+ if (size <= lfs->inline_max) {
+ // flush+seek to head
+ lfs_soff_t res = lfs_file_seek_(lfs, file, 0, LFS_SEEK_SET);
+ if (res < 0) {
+ return (int)res;
+ }
+
+ // read our data into rcache temporarily
+ lfs_cache_drop(lfs, &lfs->rcache);
+ res = lfs_file_flushedread(lfs, file,
+ lfs->rcache.buffer, size);
+ if (res < 0) {
+ return (int)res;
+ }
+
+ file->ctz.head = LFS_BLOCK_INLINE;
+ file->ctz.size = size;
+ file->flags |= LFS_F_DIRTY | LFS_F_READING | LFS_F_INLINE;
+ file->cache.block = file->ctz.head;
+ file->cache.off = 0;
+ file->cache.size = lfs->cfg->cache_size;
+ memcpy(file->cache.buffer, lfs->rcache.buffer, size);
+
+ } else {
+ // need to flush since directly changing metadata
+ int err = lfs_file_flush(lfs, file);
+ if (err) {
+ return err;
+ }
+
+ // lookup new head in ctz skip list
+ err = lfs_ctz_find(lfs, NULL, &file->cache,
+ file->ctz.head, file->ctz.size,
+ size-1, &file->block, &(lfs_off_t){0});
+ if (err) {
+ return err;
+ }
+
+ // need to set pos/block/off consistently so seeking back to
+ // the old position does not get confused
+ file->pos = size;
+ file->ctz.head = file->block;
+ file->ctz.size = size;
+ file->flags |= LFS_F_DIRTY | LFS_F_READING;
+ }
+ } else if (size > oldsize) {
+ // flush+seek if not already at end
+ lfs_soff_t res = lfs_file_seek_(lfs, file, 0, LFS_SEEK_END);
+ if (res < 0) {
+ return (int)res;
+ }
+
+ // fill with zeros
+ while (file->pos < size) {
+ res = lfs_file_write_(lfs, file, &(uint8_t){0}, 1);
+ if (res < 0) {
+ return (int)res;
+ }
+ }
+ }
+
+ // restore pos
+ lfs_soff_t res = lfs_file_seek_(lfs, file, pos, LFS_SEEK_SET);
+ if (res < 0) {
+ return (int)res;
+ }
+
+ return 0;
+}
+#endif
+
+static lfs_soff_t lfs_file_tell_(lfs_t *lfs, lfs_file_t *file) {
+ (void)lfs;
+ return file->pos;
+}
+
+static int lfs_file_rewind_(lfs_t *lfs, lfs_file_t *file) {
+ lfs_soff_t res = lfs_file_seek_(lfs, file, 0, LFS_SEEK_SET);
+ if (res < 0) {
+ return (int)res;
+ }
+
+ return 0;
+}
+
+static lfs_soff_t lfs_file_size_(lfs_t *lfs, lfs_file_t *file) {
+ (void)lfs;
+
+#ifndef LFS_READONLY
+ if (file->flags & LFS_F_WRITING) {
+ return lfs_max(file->pos, file->ctz.size);
+ }
+#endif
+
+ return file->ctz.size;
+}
+
+
+/// General fs operations ///
+static int lfs_stat_(lfs_t *lfs, const char *path, struct lfs_info *info) {
+ lfs_mdir_t cwd;
+ lfs_stag_t tag = lfs_dir_find(lfs, &cwd, &path, NULL);
+ if (tag < 0) {
+ return (int)tag;
+ }
+
+ // only allow trailing slashes on dirs
+ if (strchr(path, '/') != NULL
+ && lfs_tag_type3(tag) != LFS_TYPE_DIR) {
+ return LFS_ERR_NOTDIR;
+ }
+
+ return lfs_dir_getinfo(lfs, &cwd, lfs_tag_id(tag), info);
+}
+
+#ifndef LFS_READONLY
+static int lfs_remove_(lfs_t *lfs, const char *path) {
+ // deorphan if we haven't yet, needed at most once after poweron
+ int err = lfs_fs_forceconsistency(lfs);
+ if (err) {
+ return err;
+ }
+
+ lfs_mdir_t cwd;
+ lfs_stag_t tag = lfs_dir_find(lfs, &cwd, &path, NULL);
+ if (tag < 0 || lfs_tag_id(tag) == 0x3ff) {
+ return (tag < 0) ? (int)tag : LFS_ERR_INVAL;
+ }
+
+ struct lfs_mlist dir;
+ dir.next = lfs->mlist;
+ if (lfs_tag_type3(tag) == LFS_TYPE_DIR) {
+ // must be empty before removal
+ lfs_block_t pair[2];
+ lfs_stag_t res = lfs_dir_get(lfs, &cwd, LFS_MKTAG(0x700, 0x3ff, 0),
+ LFS_MKTAG(LFS_TYPE_STRUCT, lfs_tag_id(tag), 8), pair);
+ if (res < 0) {
+ return (int)res;
+ }
+ lfs_pair_fromle32(pair);
+
+ err = lfs_dir_fetch(lfs, &dir.m, pair);
+ if (err) {
+ return err;
+ }
+
+ if (dir.m.count > 0 || dir.m.split) {
+ return LFS_ERR_NOTEMPTY;
+ }
+
+ // mark fs as orphaned
+ err = lfs_fs_preporphans(lfs, +1);
+ if (err) {
+ return err;
+ }
+
+ // I know it's crazy but yes, dir can be changed by our parent's
+ // commit (if predecessor is child)
+ dir.type = 0;
+ dir.id = 0;
+ lfs->mlist = &dir;
+ }
+
+ // delete the entry
+ err = lfs_dir_commit(lfs, &cwd, LFS_MKATTRS(
+ {LFS_MKTAG(LFS_TYPE_DELETE, lfs_tag_id(tag), 0), NULL}));
+ if (err) {
+ lfs->mlist = dir.next;
+ return err;
+ }
+
+ lfs->mlist = dir.next;
+ if (lfs_tag_type3(tag) == LFS_TYPE_DIR) {
+ // fix orphan
+ err = lfs_fs_preporphans(lfs, -1);
+ if (err) {
+ return err;
+ }
+
+ err = lfs_fs_pred(lfs, dir.m.pair, &cwd);
+ if (err) {
+ return err;
+ }
+
+ err = lfs_dir_drop(lfs, &cwd, &dir.m);
+ if (err) {
+ return err;
+ }
+ }
+
+ return 0;
+}
+#endif
+
+#ifndef LFS_READONLY
+static int lfs_rename_(lfs_t *lfs, const char *oldpath, const char *newpath) {
+ // deorphan if we haven't yet, needed at most once after poweron
+ int err = lfs_fs_forceconsistency(lfs);
+ if (err) {
+ return err;
+ }
+
+ // find old entry
+ lfs_mdir_t oldcwd;
+ lfs_stag_t oldtag = lfs_dir_find(lfs, &oldcwd, &oldpath, NULL);
+ if (oldtag < 0 || lfs_tag_id(oldtag) == 0x3ff) {
+ return (oldtag < 0) ? (int)oldtag : LFS_ERR_INVAL;
+ }
+
+ // find new entry
+ lfs_mdir_t newcwd;
+ uint16_t newid;
+ lfs_stag_t prevtag = lfs_dir_find(lfs, &newcwd, &newpath, &newid);
+ if ((prevtag < 0 || lfs_tag_id(prevtag) == 0x3ff) &&
+ !(prevtag == LFS_ERR_NOENT && lfs_path_islast(newpath))) {
+ return (prevtag < 0) ? (int)prevtag : LFS_ERR_INVAL;
+ }
+
+ // if we're in the same pair there's a few special cases...
+ bool samepair = (lfs_pair_cmp(oldcwd.pair, newcwd.pair) == 0);
+ uint16_t newoldid = lfs_tag_id(oldtag);
+
+ struct lfs_mlist prevdir;
+ prevdir.next = lfs->mlist;
+ if (prevtag == LFS_ERR_NOENT) {
+ // if we're a file, don't allow trailing slashes
+ if (lfs_path_isdir(newpath)
+ && lfs_tag_type3(oldtag) != LFS_TYPE_DIR) {
+ return LFS_ERR_NOTDIR;
+ }
+
+ // check that name fits
+ lfs_size_t nlen = lfs_path_namelen(newpath);
+ if (nlen > lfs->name_max) {
+ return LFS_ERR_NAMETOOLONG;
+ }
+
+ // there is a small chance we are being renamed in the same
+ // directory/ to an id less than our old id, the global update
+ // to handle this is a bit messy
+ if (samepair && newid <= newoldid) {
+ newoldid += 1;
+ }
+ } else if (lfs_tag_type3(prevtag) != lfs_tag_type3(oldtag)) {
+ return (lfs_tag_type3(prevtag) == LFS_TYPE_DIR)
+ ? LFS_ERR_ISDIR
+ : LFS_ERR_NOTDIR;
+ } else if (samepair && newid == newoldid) {
+ // we're renaming to ourselves??
+ return 0;
+ } else if (lfs_tag_type3(prevtag) == LFS_TYPE_DIR) {
+ // must be empty before removal
+ lfs_block_t prevpair[2];
+ lfs_stag_t res = lfs_dir_get(lfs, &newcwd, LFS_MKTAG(0x700, 0x3ff, 0),
+ LFS_MKTAG(LFS_TYPE_STRUCT, newid, 8), prevpair);
+ if (res < 0) {
+ return (int)res;
+ }
+ lfs_pair_fromle32(prevpair);
+
+ // must be empty before removal
+ err = lfs_dir_fetch(lfs, &prevdir.m, prevpair);
+ if (err) {
+ return err;
+ }
+
+ if (prevdir.m.count > 0 || prevdir.m.split) {
+ return LFS_ERR_NOTEMPTY;
+ }
+
+ // mark fs as orphaned
+ err = lfs_fs_preporphans(lfs, +1);
+ if (err) {
+ return err;
+ }
+
+ // I know it's crazy but yes, dir can be changed by our parent's
+ // commit (if predecessor is child)
+ prevdir.type = 0;
+ prevdir.id = 0;
+ lfs->mlist = &prevdir;
+ }
+
+ if (!samepair) {
+ lfs_fs_prepmove(lfs, newoldid, oldcwd.pair);
+ }
+
+ // move over all attributes
+ err = lfs_dir_commit(lfs, &newcwd, LFS_MKATTRS(
+ {LFS_MKTAG_IF(prevtag != LFS_ERR_NOENT,
+ LFS_TYPE_DELETE, newid, 0), NULL},
+ {LFS_MKTAG(LFS_TYPE_CREATE, newid, 0), NULL},
+ {LFS_MKTAG(lfs_tag_type3(oldtag),
+ newid, lfs_path_namelen(newpath)), newpath},
+ {LFS_MKTAG(LFS_FROM_MOVE, newid, lfs_tag_id(oldtag)), &oldcwd},
+ {LFS_MKTAG_IF(samepair,
+ LFS_TYPE_DELETE, newoldid, 0), NULL}));
+ if (err) {
+ lfs->mlist = prevdir.next;
+ return err;
+ }
+
+ // let commit clean up after move (if we're different! otherwise move
+ // logic already fixed it for us)
+ if (!samepair && lfs_gstate_hasmove(&lfs->gstate)) {
+ // prep gstate and delete move id
+ lfs_fs_prepmove(lfs, 0x3ff, NULL);
+ err = lfs_dir_commit(lfs, &oldcwd, LFS_MKATTRS(
+ {LFS_MKTAG(LFS_TYPE_DELETE, lfs_tag_id(oldtag), 0), NULL}));
+ if (err) {
+ lfs->mlist = prevdir.next;
+ return err;
+ }
+ }
+
+ lfs->mlist = prevdir.next;
+ if (prevtag != LFS_ERR_NOENT
+ && lfs_tag_type3(prevtag) == LFS_TYPE_DIR) {
+ // fix orphan
+ err = lfs_fs_preporphans(lfs, -1);
+ if (err) {
+ return err;
+ }
+
+ err = lfs_fs_pred(lfs, prevdir.m.pair, &newcwd);
+ if (err) {
+ return err;
+ }
+
+ err = lfs_dir_drop(lfs, &newcwd, &prevdir.m);
+ if (err) {
+ return err;
+ }
+ }
+
+ return 0;
+}
+#endif
+
+static lfs_ssize_t lfs_getattr_(lfs_t *lfs, const char *path,
+ uint8_t type, void *buffer, lfs_size_t size) {
+ lfs_mdir_t cwd;
+ lfs_stag_t tag = lfs_dir_find(lfs, &cwd, &path, NULL);
+ if (tag < 0) {
+ return tag;
+ }
+
+ uint16_t id = lfs_tag_id(tag);
+ if (id == 0x3ff) {
+ // special case for root
+ id = 0;
+ int err = lfs_dir_fetch(lfs, &cwd, lfs->root);
+ if (err) {
+ return err;
+ }
+ }
+
+ tag = lfs_dir_get(lfs, &cwd, LFS_MKTAG(0x7ff, 0x3ff, 0),
+ LFS_MKTAG(LFS_TYPE_USERATTR + type,
+ id, lfs_min(size, lfs->attr_max)),
+ buffer);
+ if (tag < 0) {
+ if (tag == LFS_ERR_NOENT) {
+ return LFS_ERR_NOATTR;
+ }
+
+ return tag;
+ }
+
+ return lfs_tag_size(tag);
+}
+
+#ifndef LFS_READONLY
+static int lfs_commitattr(lfs_t *lfs, const char *path,
+ uint8_t type, const void *buffer, lfs_size_t size) {
+ lfs_mdir_t cwd;
+ lfs_stag_t tag = lfs_dir_find(lfs, &cwd, &path, NULL);
+ if (tag < 0) {
+ return tag;
+ }
+
+ uint16_t id = lfs_tag_id(tag);
+ if (id == 0x3ff) {
+ // special case for root
+ id = 0;
+ int err = lfs_dir_fetch(lfs, &cwd, lfs->root);
+ if (err) {
+ return err;
+ }
+ }
+
+ return lfs_dir_commit(lfs, &cwd, LFS_MKATTRS(
+ {LFS_MKTAG(LFS_TYPE_USERATTR + type, id, size), buffer}));
+}
+#endif
+
+#ifndef LFS_READONLY
+static int lfs_setattr_(lfs_t *lfs, const char *path,
+ uint8_t type, const void *buffer, lfs_size_t size) {
+ if (size > lfs->attr_max) {
+ return LFS_ERR_NOSPC;
+ }
+
+ return lfs_commitattr(lfs, path, type, buffer, size);
+}
+#endif
+
+#ifndef LFS_READONLY
+static int lfs_removeattr_(lfs_t *lfs, const char *path, uint8_t type) {
+ return lfs_commitattr(lfs, path, type, NULL, 0x3ff);
+}
+#endif
+
+
+/// Filesystem operations ///
+
+// compile time checks, see lfs.h for why these limits exist
+#if LFS_NAME_MAX > 1022
+#error "Invalid LFS_NAME_MAX, must be <= 1022"
+#endif
+
+#if LFS_FILE_MAX > 2147483647
+#error "Invalid LFS_FILE_MAX, must be <= 2147483647"
+#endif
+
+#if LFS_ATTR_MAX > 1022
+#error "Invalid LFS_ATTR_MAX, must be <= 1022"
+#endif
+
+// common filesystem initialization
+static int lfs_init(lfs_t *lfs, const struct lfs_config *cfg) {
+ lfs->cfg = cfg;
+ lfs->block_count = cfg->block_count; // May be 0
+ int err = 0;
+
+#ifdef LFS_MULTIVERSION
+ // this driver only supports minor version < current minor version
+ LFS_ASSERT(!lfs->cfg->disk_version || (
+ (0xffff & (lfs->cfg->disk_version >> 16))
+ == LFS_DISK_VERSION_MAJOR
+ && (0xffff & (lfs->cfg->disk_version >> 0))
+ <= LFS_DISK_VERSION_MINOR));
+#endif
+
+ // check that bool is a truthy-preserving type
+ //
+ // note the most common reason for this failure is a before-c99 compiler,
+ // which littlefs currently does not support
+ LFS_ASSERT((bool)0x80000000);
+
+ // check that the required io functions are provided
+ LFS_ASSERT(lfs->cfg->read != NULL);
+#ifndef LFS_READONLY
+ LFS_ASSERT(lfs->cfg->prog != NULL);
+ LFS_ASSERT(lfs->cfg->erase != NULL);
+ LFS_ASSERT(lfs->cfg->sync != NULL);
+#endif
+
+ // validate that the lfs-cfg sizes were initiated properly before
+ // performing any arithmetic logics with them
+ LFS_ASSERT(lfs->cfg->read_size != 0);
+ LFS_ASSERT(lfs->cfg->prog_size != 0);
+ LFS_ASSERT(lfs->cfg->cache_size != 0);
+
+ // check that block size is a multiple of cache size is a multiple
+ // of prog and read sizes
+ LFS_ASSERT(lfs->cfg->cache_size % lfs->cfg->read_size == 0);
+ LFS_ASSERT(lfs->cfg->cache_size % lfs->cfg->prog_size == 0);
+ LFS_ASSERT(lfs->cfg->block_size % lfs->cfg->cache_size == 0);
+
+ // check that the block size is large enough to fit all ctz pointers
+ LFS_ASSERT(lfs->cfg->block_size >= 128);
+ // this is the exact calculation for all ctz pointers, if this fails
+ // and the simpler assert above does not, math must be broken
+ LFS_ASSERT(4*lfs_npw2(0xffffffff / (lfs->cfg->block_size-2*4))
+ <= lfs->cfg->block_size);
+
+ // block_cycles = 0 is no longer supported.
+ //
+ // block_cycles is the number of erase cycles before littlefs evicts
+ // metadata logs as a part of wear leveling. Suggested values are in the
+ // range of 100-1000, or set block_cycles to -1 to disable block-level
+ // wear-leveling.
+ LFS_ASSERT(lfs->cfg->block_cycles != 0);
+
+ // check that compact_thresh makes sense
+ //
+ // metadata can't be compacted below block_size/2, and metadata can't
+ // exceed a block_size
+ LFS_ASSERT(lfs->cfg->compact_thresh == 0
+ || lfs->cfg->compact_thresh >= lfs->cfg->block_size/2);
+ LFS_ASSERT(lfs->cfg->compact_thresh == (lfs_size_t)-1
+ || lfs->cfg->compact_thresh <= lfs->cfg->block_size);
+
+ // check that metadata_max is a multiple of read_size and prog_size,
+ // and a factor of the block_size
+ LFS_ASSERT(!lfs->cfg->metadata_max
+ || lfs->cfg->metadata_max % lfs->cfg->read_size == 0);
+ LFS_ASSERT(!lfs->cfg->metadata_max
+ || lfs->cfg->metadata_max % lfs->cfg->prog_size == 0);
+ LFS_ASSERT(!lfs->cfg->metadata_max
+ || lfs->cfg->block_size % lfs->cfg->metadata_max == 0);
+
+ // setup read cache
+ if (lfs->cfg->read_buffer) {
+ lfs->rcache.buffer = lfs->cfg->read_buffer;
+ } else {
+ lfs->rcache.buffer = lfs_malloc(lfs->cfg->cache_size);
+ if (!lfs->rcache.buffer) {
+ err = LFS_ERR_NOMEM;
+ goto cleanup;
+ }
+ }
+
+ // setup program cache
+ if (lfs->cfg->prog_buffer) {
+ lfs->pcache.buffer = lfs->cfg->prog_buffer;
+ } else {
+ lfs->pcache.buffer = lfs_malloc(lfs->cfg->cache_size);
+ if (!lfs->pcache.buffer) {
+ err = LFS_ERR_NOMEM;
+ goto cleanup;
+ }
+ }
+
+ // zero to avoid information leaks
+ lfs_cache_zero(lfs, &lfs->rcache);
+ lfs_cache_zero(lfs, &lfs->pcache);
+
+ // setup lookahead buffer, note mount finishes initializing this after
+ // we establish a decent pseudo-random seed
+ LFS_ASSERT(lfs->cfg->lookahead_size > 0);
+ if (lfs->cfg->lookahead_buffer) {
+ lfs->lookahead.buffer = lfs->cfg->lookahead_buffer;
+ } else {
+ lfs->lookahead.buffer = lfs_malloc(lfs->cfg->lookahead_size);
+ if (!lfs->lookahead.buffer) {
+ err = LFS_ERR_NOMEM;
+ goto cleanup;
+ }
+ }
+
+ // check that the size limits are sane
+ LFS_ASSERT(lfs->cfg->name_max <= LFS_NAME_MAX);
+ lfs->name_max = lfs->cfg->name_max;
+ if (!lfs->name_max) {
+ lfs->name_max = LFS_NAME_MAX;
+ }
+
+ LFS_ASSERT(lfs->cfg->file_max <= LFS_FILE_MAX);
+ lfs->file_max = lfs->cfg->file_max;
+ if (!lfs->file_max) {
+ lfs->file_max = LFS_FILE_MAX;
+ }
+
+ LFS_ASSERT(lfs->cfg->attr_max <= LFS_ATTR_MAX);
+ lfs->attr_max = lfs->cfg->attr_max;
+ if (!lfs->attr_max) {
+ lfs->attr_max = LFS_ATTR_MAX;
+ }
+
+ LFS_ASSERT(lfs->cfg->metadata_max <= lfs->cfg->block_size);
+
+ LFS_ASSERT(lfs->cfg->inline_max == (lfs_size_t)-1
+ || lfs->cfg->inline_max <= lfs->cfg->cache_size);
+ LFS_ASSERT(lfs->cfg->inline_max == (lfs_size_t)-1
+ || lfs->cfg->inline_max <= lfs->attr_max);
+ LFS_ASSERT(lfs->cfg->inline_max == (lfs_size_t)-1
+ || lfs->cfg->inline_max <= ((lfs->cfg->metadata_max)
+ ? lfs->cfg->metadata_max
+ : lfs->cfg->block_size)/8);
+ lfs->inline_max = lfs->cfg->inline_max;
+ if (lfs->inline_max == (lfs_size_t)-1) {
+ lfs->inline_max = 0;
+ } else if (lfs->inline_max == 0) {
+ lfs->inline_max = lfs_min(
+ lfs->cfg->cache_size,
+ lfs_min(
+ lfs->attr_max,
+ ((lfs->cfg->metadata_max)
+ ? lfs->cfg->metadata_max
+ : lfs->cfg->block_size)/8));
+ }
+
+ // setup default state
+ lfs->root[0] = LFS_BLOCK_NULL;
+ lfs->root[1] = LFS_BLOCK_NULL;
+ lfs->mlist = NULL;
+ lfs->seed = 0;
+ lfs->gdisk = (lfs_gstate_t){0};
+ lfs->gstate = (lfs_gstate_t){0};
+ lfs->gdelta = (lfs_gstate_t){0};
+#ifdef LFS_MIGRATE
+ lfs->lfs1 = NULL;
+#endif
+
+ return 0;
+
+cleanup:
+ lfs_deinit(lfs);
+ return err;
+}
+
+static int lfs_deinit(lfs_t *lfs) {
+ // free allocated memory
+ if (!lfs->cfg->read_buffer) {
+ lfs_free(lfs->rcache.buffer);
+ }
+
+ if (!lfs->cfg->prog_buffer) {
+ lfs_free(lfs->pcache.buffer);
+ }
+
+ if (!lfs->cfg->lookahead_buffer) {
+ lfs_free(lfs->lookahead.buffer);
+ }
+
+ return 0;
+}
+
+
+
+#ifndef LFS_READONLY
+static int lfs_format_(lfs_t *lfs, const struct lfs_config *cfg) {
+ int err = 0;
+ {
+ err = lfs_init(lfs, cfg);
+ if (err) {
+ return err;
+ }
+
+ LFS_ASSERT(cfg->block_count != 0);
+
+ // create free lookahead
+ memset(lfs->lookahead.buffer, 0, lfs->cfg->lookahead_size);
+ lfs->lookahead.start = 0;
+ lfs->lookahead.size = lfs_min(8*lfs->cfg->lookahead_size,
+ lfs->block_count);
+ lfs->lookahead.next = 0;
+ lfs_alloc_ckpoint(lfs);
+
+ // create root dir
+ lfs_mdir_t root;
+ err = lfs_dir_alloc(lfs, &root);
+ if (err) {
+ goto cleanup;
+ }
+
+ // write one superblock
+ lfs_superblock_t superblock = {
+ .version = lfs_fs_disk_version(lfs),
+ .block_size = lfs->cfg->block_size,
+ .block_count = lfs->block_count,
+ .name_max = lfs->name_max,
+ .file_max = lfs->file_max,
+ .attr_max = lfs->attr_max,
+ };
+
+ lfs_superblock_tole32(&superblock);
+ err = lfs_dir_commit(lfs, &root, LFS_MKATTRS(
+ {LFS_MKTAG(LFS_TYPE_CREATE, 0, 0), NULL},
+ {LFS_MKTAG(LFS_TYPE_SUPERBLOCK, 0, 8), "littlefs"},
+ {LFS_MKTAG(LFS_TYPE_INLINESTRUCT, 0, sizeof(superblock)),
+ &superblock}));
+ if (err) {
+ goto cleanup;
+ }
+
+ // force compaction to prevent accidentally mounting any
+ // older version of littlefs that may live on disk
+ root.erased = false;
+ err = lfs_dir_commit(lfs, &root, NULL, 0);
+ if (err) {
+ goto cleanup;
+ }
+
+ // sanity check that fetch works
+ err = lfs_dir_fetch(lfs, &root, (const lfs_block_t[2]){0, 1});
+ if (err) {
+ goto cleanup;
+ }
+ }
+
+cleanup:
+ lfs_deinit(lfs);
+ return err;
+
+}
+#endif
+
+struct lfs_tortoise_t {
+ lfs_block_t pair[2];
+ lfs_size_t i;
+ lfs_size_t period;
+};
+
+static int lfs_tortoise_detectcycles(
+ const lfs_mdir_t *dir, struct lfs_tortoise_t *tortoise) {
+ // detect cycles with Brent's algorithm
+ if (lfs_pair_issync(dir->tail, tortoise->pair)) {
+ LFS_WARN("Cycle detected in tail list");
+ return LFS_ERR_CORRUPT;
+ }
+ if (tortoise->i == tortoise->period) {
+ tortoise->pair[0] = dir->tail[0];
+ tortoise->pair[1] = dir->tail[1];
+ tortoise->i = 0;
+ tortoise->period *= 2;
+ }
+ tortoise->i += 1;
+
+ return LFS_ERR_OK;
+}
+
+static int lfs_mount_(lfs_t *lfs, const struct lfs_config *cfg) {
+ int err = lfs_init(lfs, cfg);
+ if (err) {
+ return err;
+ }
+
+ // scan directory blocks for superblock and any global updates
+ lfs_mdir_t dir = {.tail = {0, 1}};
+ struct lfs_tortoise_t tortoise = {
+ .pair = {LFS_BLOCK_NULL, LFS_BLOCK_NULL},
+ .i = 1,
+ .period = 1,
+ };
+ while (!lfs_pair_isnull(dir.tail)) {
+ err = lfs_tortoise_detectcycles(&dir, &tortoise);
+ if (err < 0) {
+ goto cleanup;
+ }
+
+ // fetch next block in tail list
+ lfs_stag_t tag = lfs_dir_fetchmatch(lfs, &dir, dir.tail,
+ LFS_MKTAG(0x7ff, 0x3ff, 0),
+ LFS_MKTAG(LFS_TYPE_SUPERBLOCK, 0, 8),
+ NULL,
+ lfs_dir_find_match, &(struct lfs_dir_find_match){
+ lfs, "littlefs", 8});
+ if (tag < 0) {
+ err = tag;
+ goto cleanup;
+ }
+
+ // has superblock?
+ if (tag && !lfs_tag_isdelete(tag)) {
+ // update root
+ lfs->root[0] = dir.pair[0];
+ lfs->root[1] = dir.pair[1];
+
+ // grab superblock
+ lfs_superblock_t superblock;
+ tag = lfs_dir_get(lfs, &dir, LFS_MKTAG(0x7ff, 0x3ff, 0),
+ LFS_MKTAG(LFS_TYPE_INLINESTRUCT, 0, sizeof(superblock)),
+ &superblock);
+ if (tag < 0) {
+ err = tag;
+ goto cleanup;
+ }
+ lfs_superblock_fromle32(&superblock);
+
+ // check version
+ uint16_t major_version = (0xffff & (superblock.version >> 16));
+ uint16_t minor_version = (0xffff & (superblock.version >> 0));
+ if (major_version != lfs_fs_disk_version_major(lfs)
+ || minor_version > lfs_fs_disk_version_minor(lfs)) {
+ LFS_ERROR("Invalid version "
+ "v%"PRIu16".%"PRIu16" != v%"PRIu16".%"PRIu16,
+ major_version,
+ minor_version,
+ lfs_fs_disk_version_major(lfs),
+ lfs_fs_disk_version_minor(lfs));
+ err = LFS_ERR_INVAL;
+ goto cleanup;
+ }
+
+ // found older minor version? set an in-device only bit in the
+ // gstate so we know we need to rewrite the superblock before
+ // the first write
+ bool needssuperblock = false;
+ if (minor_version < lfs_fs_disk_version_minor(lfs)) {
+ LFS_DEBUG("Found older minor version "
+ "v%"PRIu16".%"PRIu16" < v%"PRIu16".%"PRIu16,
+ major_version,
+ minor_version,
+ lfs_fs_disk_version_major(lfs),
+ lfs_fs_disk_version_minor(lfs));
+ needssuperblock = true;
+ }
+ // note this bit is reserved on disk, so fetching more gstate
+ // will not interfere here
+ lfs_fs_prepsuperblock(lfs, needssuperblock);
+
+ // check superblock configuration
+ if (superblock.name_max) {
+ if (superblock.name_max > lfs->name_max) {
+ LFS_ERROR("Unsupported name_max (%"PRIu32" > %"PRIu32")",
+ superblock.name_max, lfs->name_max);
+ err = LFS_ERR_INVAL;
+ goto cleanup;
+ }
+
+ lfs->name_max = superblock.name_max;
+ }
+
+ if (superblock.file_max) {
+ if (superblock.file_max > lfs->file_max) {
+ LFS_ERROR("Unsupported file_max (%"PRIu32" > %"PRIu32")",
+ superblock.file_max, lfs->file_max);
+ err = LFS_ERR_INVAL;
+ goto cleanup;
+ }
+
+ lfs->file_max = superblock.file_max;
+ }
+
+ if (superblock.attr_max) {
+ if (superblock.attr_max > lfs->attr_max) {
+ LFS_ERROR("Unsupported attr_max (%"PRIu32" > %"PRIu32")",
+ superblock.attr_max, lfs->attr_max);
+ err = LFS_ERR_INVAL;
+ goto cleanup;
+ }
+
+ lfs->attr_max = superblock.attr_max;
+
+ // we also need to update inline_max in case attr_max changed
+ lfs->inline_max = lfs_min(lfs->inline_max, lfs->attr_max);
+ }
+
+ // this is where we get the block_count from disk if block_count=0
+ if (lfs->cfg->block_count
+ && superblock.block_count != lfs->cfg->block_count) {
+ LFS_ERROR("Invalid block count (%"PRIu32" != %"PRIu32")",
+ superblock.block_count, lfs->cfg->block_count);
+ err = LFS_ERR_INVAL;
+ goto cleanup;
+ }
+
+ lfs->block_count = superblock.block_count;
+
+ if (superblock.block_size != lfs->cfg->block_size) {
+ LFS_ERROR("Invalid block size (%"PRIu32" != %"PRIu32")",
+ superblock.block_size, lfs->cfg->block_size);
+ err = LFS_ERR_INVAL;
+ goto cleanup;
+ }
+ }
+
+ // has gstate?
+ err = lfs_dir_getgstate(lfs, &dir, &lfs->gstate);
+ if (err) {
+ goto cleanup;
+ }
+ }
+
+ // update littlefs with gstate
+ if (!lfs_gstate_iszero(&lfs->gstate)) {
+ LFS_DEBUG("Found pending gstate 0x%08"PRIx32"%08"PRIx32"%08"PRIx32,
+ lfs->gstate.tag,
+ lfs->gstate.pair[0],
+ lfs->gstate.pair[1]);
+ }
+ lfs->gstate.tag += !lfs_tag_isvalid(lfs->gstate.tag);
+ lfs->gdisk = lfs->gstate;
+
+ // setup free lookahead, to distribute allocations uniformly across
+ // boots, we start the allocator at a random location
+ lfs->lookahead.start = lfs->seed % lfs->block_count;
+ lfs_alloc_drop(lfs);
+
+ return 0;
+
+cleanup:
+ lfs_unmount_(lfs);
+ return err;
+}
+
+static int lfs_unmount_(lfs_t *lfs) {
+ return lfs_deinit(lfs);
+}
+
+
+/// Filesystem filesystem operations ///
+static int lfs_fs_stat_(lfs_t *lfs, struct lfs_fsinfo *fsinfo) {
+ // if the superblock is up-to-date, we must be on the most recent
+ // minor version of littlefs
+ if (!lfs_gstate_needssuperblock(&lfs->gstate)) {
+ fsinfo->disk_version = lfs_fs_disk_version(lfs);
+
+ // otherwise we need to read the minor version on disk
+ } else {
+ // fetch the superblock
+ lfs_mdir_t dir;
+ int err = lfs_dir_fetch(lfs, &dir, lfs->root);
+ if (err) {
+ return err;
+ }
+
+ lfs_superblock_t superblock;
+ lfs_stag_t tag = lfs_dir_get(lfs, &dir, LFS_MKTAG(0x7ff, 0x3ff, 0),
+ LFS_MKTAG(LFS_TYPE_INLINESTRUCT, 0, sizeof(superblock)),
+ &superblock);
+ if (tag < 0) {
+ return tag;
+ }
+ lfs_superblock_fromle32(&superblock);
+
+ // read the on-disk version
+ fsinfo->disk_version = superblock.version;
+ }
+
+ // filesystem geometry
+ fsinfo->block_size = lfs->cfg->block_size;
+ fsinfo->block_count = lfs->block_count;
+
+ // other on-disk configuration, we cache all of these for internal use
+ fsinfo->name_max = lfs->name_max;
+ fsinfo->file_max = lfs->file_max;
+ fsinfo->attr_max = lfs->attr_max;
+
+ return 0;
+}
+
+int lfs_fs_traverse_(lfs_t *lfs,
+ int (*cb)(void *data, lfs_block_t block), void *data,
+ bool includeorphans) {
+ // iterate over metadata pairs
+ lfs_mdir_t dir = {.tail = {0, 1}};
+
+#ifdef LFS_MIGRATE
+ // also consider v1 blocks during migration
+ if (lfs->lfs1) {
+ int err = lfs1_traverse(lfs, cb, data);
+ if (err) {
+ return err;
+ }
+
+ dir.tail[0] = lfs->root[0];
+ dir.tail[1] = lfs->root[1];
+ }
+#endif
+
+ struct lfs_tortoise_t tortoise = {
+ .pair = {LFS_BLOCK_NULL, LFS_BLOCK_NULL},
+ .i = 1,
+ .period = 1,
+ };
+ int err = LFS_ERR_OK;
+ while (!lfs_pair_isnull(dir.tail)) {
+ err = lfs_tortoise_detectcycles(&dir, &tortoise);
+ if (err < 0) {
+ return LFS_ERR_CORRUPT;
+ }
+
+ for (int i = 0; i < 2; i++) {
+ int err = cb(data, dir.tail[i]);
+ if (err) {
+ return err;
+ }
+ }
+
+ // iterate through ids in directory
+ int err = lfs_dir_fetch(lfs, &dir, dir.tail);
+ if (err) {
+ return err;
+ }
+
+ for (uint16_t id = 0; id < dir.count; id++) {
+ struct lfs_ctz ctz;
+ lfs_stag_t tag = lfs_dir_get(lfs, &dir, LFS_MKTAG(0x700, 0x3ff, 0),
+ LFS_MKTAG(LFS_TYPE_STRUCT, id, sizeof(ctz)), &ctz);
+ if (tag < 0) {
+ if (tag == LFS_ERR_NOENT) {
+ continue;
+ }
+ return tag;
+ }
+ lfs_ctz_fromle32(&ctz);
+
+ if (lfs_tag_type3(tag) == LFS_TYPE_CTZSTRUCT) {
+ err = lfs_ctz_traverse(lfs, NULL, &lfs->rcache,
+ ctz.head, ctz.size, cb, data);
+ if (err) {
+ return err;
+ }
+ } else if (includeorphans &&
+ lfs_tag_type3(tag) == LFS_TYPE_DIRSTRUCT) {
+ for (int i = 0; i < 2; i++) {
+ err = cb(data, (&ctz.head)[i]);
+ if (err) {
+ return err;
+ }
+ }
+ }
+ }
+ }
+
+#ifndef LFS_READONLY
+ // iterate over any open files
+ for (lfs_file_t *f = (lfs_file_t*)lfs->mlist; f; f = f->next) {
+ if (f->type != LFS_TYPE_REG) {
+ continue;
+ }
+
+ if ((f->flags & LFS_F_DIRTY) && !(f->flags & LFS_F_INLINE)) {
+ int err = lfs_ctz_traverse(lfs, &f->cache, &lfs->rcache,
+ f->ctz.head, f->ctz.size, cb, data);
+ if (err) {
+ return err;
+ }
+ }
+
+ if ((f->flags & LFS_F_WRITING) && !(f->flags & LFS_F_INLINE)) {
+ int err = lfs_ctz_traverse(lfs, &f->cache, &lfs->rcache,
+ f->block, f->pos, cb, data);
+ if (err) {
+ return err;
+ }
+ }
+ }
+#endif
+
+ return 0;
+}
+
+#ifndef LFS_READONLY
+static int lfs_fs_pred(lfs_t *lfs,
+ const lfs_block_t pair[2], lfs_mdir_t *pdir) {
+ // iterate over all directory directory entries
+ pdir->tail[0] = 0;
+ pdir->tail[1] = 1;
+ struct lfs_tortoise_t tortoise = {
+ .pair = {LFS_BLOCK_NULL, LFS_BLOCK_NULL},
+ .i = 1,
+ .period = 1,
+ };
+ int err = LFS_ERR_OK;
+ while (!lfs_pair_isnull(pdir->tail)) {
+ err = lfs_tortoise_detectcycles(pdir, &tortoise);
+ if (err < 0) {
+ return LFS_ERR_CORRUPT;
+ }
+
+ if (lfs_pair_cmp(pdir->tail, pair) == 0) {
+ return 0;
+ }
+
+ int err = lfs_dir_fetch(lfs, pdir, pdir->tail);
+ if (err) {
+ return err;
+ }
+ }
+
+ return LFS_ERR_NOENT;
+}
+#endif
+
+#ifndef LFS_READONLY
+struct lfs_fs_parent_match {
+ lfs_t *lfs;
+ const lfs_block_t pair[2];
+};
+#endif
+
+#ifndef LFS_READONLY
+static int lfs_fs_parent_match(void *data,
+ lfs_tag_t tag, const void *buffer) {
+ struct lfs_fs_parent_match *find = data;
+ lfs_t *lfs = find->lfs;
+ const struct lfs_diskoff *disk = buffer;
+ (void)tag;
+
+ lfs_block_t child[2];
+ int err = lfs_bd_read(lfs,
+ &lfs->pcache, &lfs->rcache, lfs->cfg->block_size,
+ disk->block, disk->off, &child, sizeof(child));
+ if (err) {
+ return err;
+ }
+
+ lfs_pair_fromle32(child);
+ return (lfs_pair_cmp(child, find->pair) == 0) ? LFS_CMP_EQ : LFS_CMP_LT;
+}
+#endif
+
+#ifndef LFS_READONLY
+static lfs_stag_t lfs_fs_parent(lfs_t *lfs, const lfs_block_t pair[2],
+ lfs_mdir_t *parent) {
+ // use fetchmatch with callback to find pairs
+ parent->tail[0] = 0;
+ parent->tail[1] = 1;
+ struct lfs_tortoise_t tortoise = {
+ .pair = {LFS_BLOCK_NULL, LFS_BLOCK_NULL},
+ .i = 1,
+ .period = 1,
+ };
+ int err = LFS_ERR_OK;
+ while (!lfs_pair_isnull(parent->tail)) {
+ err = lfs_tortoise_detectcycles(parent, &tortoise);
+ if (err < 0) {
+ return err;
+ }
+
+ lfs_stag_t tag = lfs_dir_fetchmatch(lfs, parent, parent->tail,
+ LFS_MKTAG(0x7ff, 0, 0x3ff),
+ LFS_MKTAG(LFS_TYPE_DIRSTRUCT, 0, 8),
+ NULL,
+ lfs_fs_parent_match, &(struct lfs_fs_parent_match){
+ lfs, {pair[0], pair[1]}});
+ if (tag && tag != LFS_ERR_NOENT) {
+ return tag;
+ }
+ }
+
+ return LFS_ERR_NOENT;
+}
+#endif
+
+static void lfs_fs_prepsuperblock(lfs_t *lfs, bool needssuperblock) {
+ lfs->gstate.tag = (lfs->gstate.tag & ~LFS_MKTAG(0, 0, 0x200))
+ | (uint32_t)needssuperblock << 9;
+}
+
+#ifndef LFS_READONLY
+static int lfs_fs_preporphans(lfs_t *lfs, int8_t orphans) {
+ LFS_ASSERT(lfs_tag_size(lfs->gstate.tag) > 0x000 || orphans >= 0);
+ LFS_ASSERT(lfs_tag_size(lfs->gstate.tag) < 0x1ff || orphans <= 0);
+ lfs->gstate.tag += orphans;
+ lfs->gstate.tag = ((lfs->gstate.tag & ~LFS_MKTAG(0x800, 0, 0)) |
+ ((uint32_t)lfs_gstate_hasorphans(&lfs->gstate) << 31));
+
+ return 0;
+}
+#endif
+
+#ifndef LFS_READONLY
+static void lfs_fs_prepmove(lfs_t *lfs,
+ uint16_t id, const lfs_block_t pair[2]) {
+ lfs->gstate.tag = ((lfs->gstate.tag & ~LFS_MKTAG(0x7ff, 0x3ff, 0)) |
+ ((id != 0x3ff) ? LFS_MKTAG(LFS_TYPE_DELETE, id, 0) : 0));
+ lfs->gstate.pair[0] = (id != 0x3ff) ? pair[0] : 0;
+ lfs->gstate.pair[1] = (id != 0x3ff) ? pair[1] : 0;
+}
+#endif
+
+#ifndef LFS_READONLY
+static int lfs_fs_desuperblock(lfs_t *lfs) {
+ if (!lfs_gstate_needssuperblock(&lfs->gstate)) {
+ return 0;
+ }
+
+ LFS_DEBUG("Rewriting superblock {0x%"PRIx32", 0x%"PRIx32"}",
+ lfs->root[0],
+ lfs->root[1]);
+
+ lfs_mdir_t root;
+ int err = lfs_dir_fetch(lfs, &root, lfs->root);
+ if (err) {
+ return err;
+ }
+
+ // write a new superblock
+ lfs_superblock_t superblock = {
+ .version = lfs_fs_disk_version(lfs),
+ .block_size = lfs->cfg->block_size,
+ .block_count = lfs->block_count,
+ .name_max = lfs->name_max,
+ .file_max = lfs->file_max,
+ .attr_max = lfs->attr_max,
+ };
+
+ lfs_superblock_tole32(&superblock);
+ err = lfs_dir_commit(lfs, &root, LFS_MKATTRS(
+ {LFS_MKTAG(LFS_TYPE_INLINESTRUCT, 0, sizeof(superblock)),
+ &superblock}));
+ if (err) {
+ return err;
+ }
+
+ lfs_fs_prepsuperblock(lfs, false);
+ return 0;
+}
+#endif
+
+#ifndef LFS_READONLY
+static int lfs_fs_demove(lfs_t *lfs) {
+ if (!lfs_gstate_hasmove(&lfs->gdisk)) {
+ return 0;
+ }
+
+ // Fix bad moves
+ LFS_DEBUG("Fixing move {0x%"PRIx32", 0x%"PRIx32"} 0x%"PRIx16,
+ lfs->gdisk.pair[0],
+ lfs->gdisk.pair[1],
+ lfs_tag_id(lfs->gdisk.tag));
+
+ // no other gstate is supported at this time, so if we found something else
+ // something most likely went wrong in gstate calculation
+ LFS_ASSERT(lfs_tag_type3(lfs->gdisk.tag) == LFS_TYPE_DELETE);
+
+ // fetch and delete the moved entry
+ lfs_mdir_t movedir;
+ int err = lfs_dir_fetch(lfs, &movedir, lfs->gdisk.pair);
+ if (err) {
+ return err;
+ }
+
+ // prep gstate and delete move id
+ uint16_t moveid = lfs_tag_id(lfs->gdisk.tag);
+ lfs_fs_prepmove(lfs, 0x3ff, NULL);
+ err = lfs_dir_commit(lfs, &movedir, LFS_MKATTRS(
+ {LFS_MKTAG(LFS_TYPE_DELETE, moveid, 0), NULL}));
+ if (err) {
+ return err;
+ }
+
+ return 0;
+}
+#endif
+
+#ifndef LFS_READONLY
+static int lfs_fs_deorphan(lfs_t *lfs, bool powerloss) {
+ if (!lfs_gstate_hasorphans(&lfs->gstate)) {
+ return 0;
+ }
+
+ // Check for orphans in two separate passes:
+ // - 1 for half-orphans (relocations)
+ // - 2 for full-orphans (removes/renames)
+ //
+ // Two separate passes are needed as half-orphans can contain outdated
+ // references to full-orphans, effectively hiding them from the deorphan
+ // search.
+ //
+ int pass = 0;
+ while (pass < 2) {
+ // Fix any orphans
+ lfs_mdir_t pdir = {.split = true, .tail = {0, 1}};
+ lfs_mdir_t dir;
+ bool moreorphans = false;
+
+ // iterate over all directory directory entries
+ while (!lfs_pair_isnull(pdir.tail)) {
+ int err = lfs_dir_fetch(lfs, &dir, pdir.tail);
+ if (err) {
+ return err;
+ }
+
+ // check head blocks for orphans
+ if (!pdir.split) {
+ // check if we have a parent
+ lfs_mdir_t parent;
+ lfs_stag_t tag = lfs_fs_parent(lfs, pdir.tail, &parent);
+ if (tag < 0 && tag != LFS_ERR_NOENT) {
+ return tag;
+ }
+
+ if (pass == 0 && tag != LFS_ERR_NOENT) {
+ lfs_block_t pair[2];
+ lfs_stag_t state = lfs_dir_get(lfs, &parent,
+ LFS_MKTAG(0x7ff, 0x3ff, 0), tag, pair);
+ if (state < 0) {
+ return state;
+ }
+ lfs_pair_fromle32(pair);
+
+ if (!lfs_pair_issync(pair, pdir.tail)) {
+ // we have desynced
+ LFS_DEBUG("Fixing half-orphan "
+ "{0x%"PRIx32", 0x%"PRIx32"} "
+ "-> {0x%"PRIx32", 0x%"PRIx32"}",
+ pdir.tail[0], pdir.tail[1], pair[0], pair[1]);
+
+ // fix pending move in this pair? this looks like an
+ // optimization but is in fact _required_ since
+ // relocating may outdate the move.
+ uint16_t moveid = 0x3ff;
+ if (lfs_gstate_hasmovehere(&lfs->gstate, pdir.pair)) {
+ moveid = lfs_tag_id(lfs->gstate.tag);
+ LFS_DEBUG("Fixing move while fixing orphans "
+ "{0x%"PRIx32", 0x%"PRIx32"} 0x%"PRIx16"\n",
+ pdir.pair[0], pdir.pair[1], moveid);
+ lfs_fs_prepmove(lfs, 0x3ff, NULL);
+ }
+
+ lfs_pair_tole32(pair);
+ state = lfs_dir_orphaningcommit(lfs, &pdir, LFS_MKATTRS(
+ {LFS_MKTAG_IF(moveid != 0x3ff,
+ LFS_TYPE_DELETE, moveid, 0), NULL},
+ {LFS_MKTAG(LFS_TYPE_SOFTTAIL, 0x3ff, 8),
+ pair}));
+ lfs_pair_fromle32(pair);
+ if (state < 0) {
+ return state;
+ }
+
+ // did our commit create more orphans?
+ if (state == LFS_OK_ORPHANED) {
+ moreorphans = true;
+ }
+
+ // refetch tail
+ continue;
+ }
+ }
+
+ // note we only check for full orphans if we may have had a
+ // power-loss, otherwise orphans are created intentionally
+ // during operations such as lfs_mkdir
+ if (pass == 1 && tag == LFS_ERR_NOENT && powerloss) {
+ // we are an orphan
+ LFS_DEBUG("Fixing orphan {0x%"PRIx32", 0x%"PRIx32"}",
+ pdir.tail[0], pdir.tail[1]);
+
+ // steal state
+ err = lfs_dir_getgstate(lfs, &dir, &lfs->gdelta);
+ if (err) {
+ return err;
+ }
+
+ // steal tail
+ lfs_pair_tole32(dir.tail);
+ int state = lfs_dir_orphaningcommit(lfs, &pdir, LFS_MKATTRS(
+ {LFS_MKTAG(LFS_TYPE_TAIL + dir.split, 0x3ff, 8),
+ dir.tail}));
+ lfs_pair_fromle32(dir.tail);
+ if (state < 0) {
+ return state;
+ }
+
+ // did our commit create more orphans?
+ if (state == LFS_OK_ORPHANED) {
+ moreorphans = true;
+ }
+
+ // refetch tail
+ continue;
+ }
+ }
+
+ pdir = dir;
+ }
+
+ pass = moreorphans ? 0 : pass+1;
+ }
+
+ // mark orphans as fixed
+ return lfs_fs_preporphans(lfs, -lfs_gstate_getorphans(&lfs->gstate));
+}
+#endif
+
+#ifndef LFS_READONLY
+static int lfs_fs_forceconsistency(lfs_t *lfs) {
+ int err = lfs_fs_desuperblock(lfs);
+ if (err) {
+ return err;
+ }
+
+ err = lfs_fs_demove(lfs);
+ if (err) {
+ return err;
+ }
+
+ err = lfs_fs_deorphan(lfs, true);
+ if (err) {
+ return err;
+ }
+
+ return 0;
+}
+#endif
+
+#ifndef LFS_READONLY
+static int lfs_fs_mkconsistent_(lfs_t *lfs) {
+ // lfs_fs_forceconsistency does most of the work here
+ int err = lfs_fs_forceconsistency(lfs);
+ if (err) {
+ return err;
+ }
+
+ // do we have any pending gstate?
+ lfs_gstate_t delta = {0};
+ lfs_gstate_xor(&delta, &lfs->gdisk);
+ lfs_gstate_xor(&delta, &lfs->gstate);
+ if (!lfs_gstate_iszero(&delta)) {
+ // lfs_dir_commit will implicitly write out any pending gstate
+ lfs_mdir_t root;
+ err = lfs_dir_fetch(lfs, &root, lfs->root);
+ if (err) {
+ return err;
+ }
+
+ err = lfs_dir_commit(lfs, &root, NULL, 0);
+ if (err) {
+ return err;
+ }
+ }
+
+ return 0;
+}
+#endif
+
+static int lfs_fs_size_count(void *p, lfs_block_t block) {
+ (void)block;
+ lfs_size_t *size = p;
+ *size += 1;
+ return 0;
+}
+
+static lfs_ssize_t lfs_fs_size_(lfs_t *lfs) {
+ lfs_size_t size = 0;
+ int err = lfs_fs_traverse_(lfs, lfs_fs_size_count, &size, false);
+ if (err) {
+ return err;
+ }
+
+ return size;
+}
+
+// explicit garbage collection
+#ifndef LFS_READONLY
+static int lfs_fs_gc_(lfs_t *lfs) {
+ // force consistency, even if we're not necessarily going to write,
+ // because this function is supposed to take care of janitorial work
+ // isn't it?
+ int err = lfs_fs_forceconsistency(lfs);
+ if (err) {
+ return err;
+ }
+
+ // try to compact metadata pairs, note we can't really accomplish
+ // anything if compact_thresh doesn't at least leave a prog_size
+ // available
+ if (lfs->cfg->compact_thresh
+ < lfs->cfg->block_size - lfs->cfg->prog_size) {
+ // iterate over all mdirs
+ lfs_mdir_t mdir = {.tail = {0, 1}};
+ while (!lfs_pair_isnull(mdir.tail)) {
+ err = lfs_dir_fetch(lfs, &mdir, mdir.tail);
+ if (err) {
+ return err;
+ }
+
+ // not erased? exceeds our compaction threshold?
+ if (!mdir.erased || ((lfs->cfg->compact_thresh == 0)
+ ? mdir.off > lfs->cfg->block_size - lfs->cfg->block_size/8
+ : mdir.off > lfs->cfg->compact_thresh)) {
+ // the easiest way to trigger a compaction is to mark
+ // the mdir as unerased and add an empty commit
+ mdir.erased = false;
+ err = lfs_dir_commit(lfs, &mdir, NULL, 0);
+ if (err) {
+ return err;
+ }
+ }
+ }
+ }
+
+ // try to populate the lookahead buffer, unless it's already full
+ if (lfs->lookahead.size < 8*lfs->cfg->lookahead_size) {
+ err = lfs_alloc_scan(lfs);
+ if (err) {
+ return err;
+ }
+ }
+
+ return 0;
+}
+#endif
+
+#ifndef LFS_READONLY
+static int lfs_fs_grow_(lfs_t *lfs, lfs_size_t block_count) {
+ // shrinking is not supported
+ LFS_ASSERT(block_count >= lfs->block_count);
+
+ if (block_count > lfs->block_count) {
+ lfs->block_count = block_count;
+
+ // fetch the root
+ lfs_mdir_t root;
+ int err = lfs_dir_fetch(lfs, &root, lfs->root);
+ if (err) {
+ return err;
+ }
+
+ // update the superblock
+ lfs_superblock_t superblock;
+ lfs_stag_t tag = lfs_dir_get(lfs, &root, LFS_MKTAG(0x7ff, 0x3ff, 0),
+ LFS_MKTAG(LFS_TYPE_INLINESTRUCT, 0, sizeof(superblock)),
+ &superblock);
+ if (tag < 0) {
+ return tag;
+ }
+ lfs_superblock_fromle32(&superblock);
+
+ superblock.block_count = lfs->block_count;
+
+ lfs_superblock_tole32(&superblock);
+ err = lfs_dir_commit(lfs, &root, LFS_MKATTRS(
+ {tag, &superblock}));
+ if (err) {
+ return err;
+ }
+ }
+
+ return 0;
+}
+#endif
+
+#ifdef LFS_MIGRATE
+////// Migration from littelfs v1 below this //////
+
+/// Version info ///
+
+// Software library version
+// Major (top-nibble), incremented on backwards incompatible changes
+// Minor (bottom-nibble), incremented on feature additions
+#define LFS1_VERSION 0x00010007
+#define LFS1_VERSION_MAJOR (0xffff & (LFS1_VERSION >> 16))
+#define LFS1_VERSION_MINOR (0xffff & (LFS1_VERSION >> 0))
+
+// Version of On-disk data structures
+// Major (top-nibble), incremented on backwards incompatible changes
+// Minor (bottom-nibble), incremented on feature additions
+#define LFS1_DISK_VERSION 0x00010001
+#define LFS1_DISK_VERSION_MAJOR (0xffff & (LFS1_DISK_VERSION >> 16))
+#define LFS1_DISK_VERSION_MINOR (0xffff & (LFS1_DISK_VERSION >> 0))
+
+
+/// v1 Definitions ///
+
+// File types
+enum lfs1_type {
+ LFS1_TYPE_REG = 0x11,
+ LFS1_TYPE_DIR = 0x22,
+ LFS1_TYPE_SUPERBLOCK = 0x2e,
+};
+
+typedef struct lfs1 {
+ lfs_block_t root[2];
+} lfs1_t;
+
+typedef struct lfs1_entry {
+ lfs_off_t off;
+
+ struct lfs1_disk_entry {
+ uint8_t type;
+ uint8_t elen;
+ uint8_t alen;
+ uint8_t nlen;
+ union {
+ struct {
+ lfs_block_t head;
+ lfs_size_t size;
+ } file;
+ lfs_block_t dir[2];
+ } u;
+ } d;
+} lfs1_entry_t;
+
+typedef struct lfs1_dir {
+ struct lfs1_dir *next;
+ lfs_block_t pair[2];
+ lfs_off_t off;
+
+ lfs_block_t head[2];
+ lfs_off_t pos;
+
+ struct lfs1_disk_dir {
+ uint32_t rev;
+ lfs_size_t size;
+ lfs_block_t tail[2];
+ } d;
+} lfs1_dir_t;
+
+typedef struct lfs1_superblock {
+ lfs_off_t off;
+
+ struct lfs1_disk_superblock {
+ uint8_t type;
+ uint8_t elen;
+ uint8_t alen;
+ uint8_t nlen;
+ lfs_block_t root[2];
+ uint32_t block_size;
+ uint32_t block_count;
+ uint32_t version;
+ char magic[8];
+ } d;
+} lfs1_superblock_t;
+
+
+/// Low-level wrappers v1->v2 ///
+static void lfs1_crc(uint32_t *crc, const void *buffer, size_t size) {
+ *crc = lfs_crc(*crc, buffer, size);
+}
+
+static int lfs1_bd_read(lfs_t *lfs, lfs_block_t block,
+ lfs_off_t off, void *buffer, lfs_size_t size) {
+ // if we ever do more than writes to alternating pairs,
+ // this may need to consider pcache
+ return lfs_bd_read(lfs, &lfs->pcache, &lfs->rcache, size,
+ block, off, buffer, size);
+}
+
+static int lfs1_bd_crc(lfs_t *lfs, lfs_block_t block,
+ lfs_off_t off, lfs_size_t size, uint32_t *crc) {
+ for (lfs_off_t i = 0; i < size; i++) {
+ uint8_t c;
+ int err = lfs1_bd_read(lfs, block, off+i, &c, 1);
+ if (err) {
+ return err;
+ }
+
+ lfs1_crc(crc, &c, 1);
+ }
+
+ return 0;
+}
+
+
+/// Endian swapping functions ///
+static void lfs1_dir_fromle32(struct lfs1_disk_dir *d) {
+ d->rev = lfs_fromle32(d->rev);
+ d->size = lfs_fromle32(d->size);
+ d->tail[0] = lfs_fromle32(d->tail[0]);
+ d->tail[1] = lfs_fromle32(d->tail[1]);
+}
+
+static void lfs1_dir_tole32(struct lfs1_disk_dir *d) {
+ d->rev = lfs_tole32(d->rev);
+ d->size = lfs_tole32(d->size);
+ d->tail[0] = lfs_tole32(d->tail[0]);
+ d->tail[1] = lfs_tole32(d->tail[1]);
+}
+
+static void lfs1_entry_fromle32(struct lfs1_disk_entry *d) {
+ d->u.dir[0] = lfs_fromle32(d->u.dir[0]);
+ d->u.dir[1] = lfs_fromle32(d->u.dir[1]);
+}
+
+static void lfs1_entry_tole32(struct lfs1_disk_entry *d) {
+ d->u.dir[0] = lfs_tole32(d->u.dir[0]);
+ d->u.dir[1] = lfs_tole32(d->u.dir[1]);
+}
+
+static void lfs1_superblock_fromle32(struct lfs1_disk_superblock *d) {
+ d->root[0] = lfs_fromle32(d->root[0]);
+ d->root[1] = lfs_fromle32(d->root[1]);
+ d->block_size = lfs_fromle32(d->block_size);
+ d->block_count = lfs_fromle32(d->block_count);
+ d->version = lfs_fromle32(d->version);
+}
+
+
+///// Metadata pair and directory operations ///
+static inline lfs_size_t lfs1_entry_size(const lfs1_entry_t *entry) {
+ return 4 + entry->d.elen + entry->d.alen + entry->d.nlen;
+}
+
+static int lfs1_dir_fetch(lfs_t *lfs,
+ lfs1_dir_t *dir, const lfs_block_t pair[2]) {
+ // copy out pair, otherwise may be aliasing dir
+ const lfs_block_t tpair[2] = {pair[0], pair[1]};
+ bool valid = false;
+
+ // check both blocks for the most recent revision
+ for (int i = 0; i < 2; i++) {
+ struct lfs1_disk_dir test;
+ int err = lfs1_bd_read(lfs, tpair[i], 0, &test, sizeof(test));
+ lfs1_dir_fromle32(&test);
+ if (err) {
+ if (err == LFS_ERR_CORRUPT) {
+ continue;
+ }
+ return err;
+ }
+
+ if (valid && lfs_scmp(test.rev, dir->d.rev) < 0) {
+ continue;
+ }
+
+ if ((0x7fffffff & test.size) < sizeof(test)+4 ||
+ (0x7fffffff & test.size) > lfs->cfg->block_size) {
+ continue;
+ }
+
+ uint32_t crc = 0xffffffff;
+ lfs1_dir_tole32(&test);
+ lfs1_crc(&crc, &test, sizeof(test));
+ lfs1_dir_fromle32(&test);
+ err = lfs1_bd_crc(lfs, tpair[i], sizeof(test),
+ (0x7fffffff & test.size) - sizeof(test), &crc);
+ if (err) {
+ if (err == LFS_ERR_CORRUPT) {
+ continue;
+ }
+ return err;
+ }
+
+ if (crc != 0) {
+ continue;
+ }
+
+ valid = true;
+
+ // setup dir in case it's valid
+ dir->pair[0] = tpair[(i+0) % 2];
+ dir->pair[1] = tpair[(i+1) % 2];
+ dir->off = sizeof(dir->d);
+ dir->d = test;
+ }
+
+ if (!valid) {
+ LFS_ERROR("Corrupted dir pair at {0x%"PRIx32", 0x%"PRIx32"}",
+ tpair[0], tpair[1]);
+ return LFS_ERR_CORRUPT;
+ }
+
+ return 0;
+}
+
+static int lfs1_dir_next(lfs_t *lfs, lfs1_dir_t *dir, lfs1_entry_t *entry) {
+ while (dir->off + sizeof(entry->d) > (0x7fffffff & dir->d.size)-4) {
+ if (!(0x80000000 & dir->d.size)) {
+ entry->off = dir->off;
+ return LFS_ERR_NOENT;
+ }
+
+ int err = lfs1_dir_fetch(lfs, dir, dir->d.tail);
+ if (err) {
+ return err;
+ }
+
+ dir->off = sizeof(dir->d);
+ dir->pos += sizeof(dir->d) + 4;
+ }
+
+ int err = lfs1_bd_read(lfs, dir->pair[0], dir->off,
+ &entry->d, sizeof(entry->d));
+ lfs1_entry_fromle32(&entry->d);
+ if (err) {
+ return err;
+ }
+
+ entry->off = dir->off;
+ dir->off += lfs1_entry_size(entry);
+ dir->pos += lfs1_entry_size(entry);
+ return 0;
+}
+
+/// littlefs v1 specific operations ///
+int lfs1_traverse(lfs_t *lfs, int (*cb)(void*, lfs_block_t), void *data) {
+ if (lfs_pair_isnull(lfs->lfs1->root)) {
+ return 0;
+ }
+
+ // iterate over metadata pairs
+ lfs1_dir_t dir;
+ lfs1_entry_t entry;
+ lfs_block_t cwd[2] = {0, 1};
+
+ while (true) {
+ for (int i = 0; i < 2; i++) {
+ int err = cb(data, cwd[i]);
+ if (err) {
+ return err;
+ }
+ }
+
+ int err = lfs1_dir_fetch(lfs, &dir, cwd);
+ if (err) {
+ return err;
+ }
+
+ // iterate over contents
+ while (dir.off + sizeof(entry.d) <= (0x7fffffff & dir.d.size)-4) {
+ err = lfs1_bd_read(lfs, dir.pair[0], dir.off,
+ &entry.d, sizeof(entry.d));
+ lfs1_entry_fromle32(&entry.d);
+ if (err) {
+ return err;
+ }
+
+ dir.off += lfs1_entry_size(&entry);
+ if ((0x70 & entry.d.type) == (0x70 & LFS1_TYPE_REG)) {
+ err = lfs_ctz_traverse(lfs, NULL, &lfs->rcache,
+ entry.d.u.file.head, entry.d.u.file.size, cb, data);
+ if (err) {
+ return err;
+ }
+ }
+ }
+
+ // we also need to check if we contain a threaded v2 directory
+ lfs_mdir_t dir2 = {.split=true, .tail={cwd[0], cwd[1]}};
+ while (dir2.split) {
+ err = lfs_dir_fetch(lfs, &dir2, dir2.tail);
+ if (err) {
+ break;
+ }
+
+ for (int i = 0; i < 2; i++) {
+ err = cb(data, dir2.pair[i]);
+ if (err) {
+ return err;
+ }
+ }
+ }
+
+ cwd[0] = dir.d.tail[0];
+ cwd[1] = dir.d.tail[1];
+
+ if (lfs_pair_isnull(cwd)) {
+ break;
+ }
+ }
+
+ return 0;
+}
+
+static int lfs1_moved(lfs_t *lfs, const void *e) {
+ if (lfs_pair_isnull(lfs->lfs1->root)) {
+ return 0;
+ }
+
+ // skip superblock
+ lfs1_dir_t cwd;
+ int err = lfs1_dir_fetch(lfs, &cwd, (const lfs_block_t[2]){0, 1});
+ if (err) {
+ return err;
+ }
+
+ // iterate over all directory directory entries
+ lfs1_entry_t entry;
+ while (!lfs_pair_isnull(cwd.d.tail)) {
+ err = lfs1_dir_fetch(lfs, &cwd, cwd.d.tail);
+ if (err) {
+ return err;
+ }
+
+ while (true) {
+ err = lfs1_dir_next(lfs, &cwd, &entry);
+ if (err && err != LFS_ERR_NOENT) {
+ return err;
+ }
+
+ if (err == LFS_ERR_NOENT) {
+ break;
+ }
+
+ if (!(0x80 & entry.d.type) &&
+ memcmp(&entry.d.u, e, sizeof(entry.d.u)) == 0) {
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+/// Filesystem operations ///
+static int lfs1_mount(lfs_t *lfs, struct lfs1 *lfs1,
+ const struct lfs_config *cfg) {
+ int err = 0;
+ {
+ err = lfs_init(lfs, cfg);
+ if (err) {
+ return err;
+ }
+
+ lfs->lfs1 = lfs1;
+ lfs->lfs1->root[0] = LFS_BLOCK_NULL;
+ lfs->lfs1->root[1] = LFS_BLOCK_NULL;
+
+ // setup free lookahead
+ lfs->lookahead.start = 0;
+ lfs->lookahead.size = 0;
+ lfs->lookahead.next = 0;
+ lfs_alloc_ckpoint(lfs);
+
+ // load superblock
+ lfs1_dir_t dir;
+ lfs1_superblock_t superblock;
+ err = lfs1_dir_fetch(lfs, &dir, (const lfs_block_t[2]){0, 1});
+ if (err && err != LFS_ERR_CORRUPT) {
+ goto cleanup;
+ }
+
+ if (!err) {
+ err = lfs1_bd_read(lfs, dir.pair[0], sizeof(dir.d),
+ &superblock.d, sizeof(superblock.d));
+ lfs1_superblock_fromle32(&superblock.d);
+ if (err) {
+ goto cleanup;
+ }
+
+ lfs->lfs1->root[0] = superblock.d.root[0];
+ lfs->lfs1->root[1] = superblock.d.root[1];
+ }
+
+ if (err || memcmp(superblock.d.magic, "littlefs", 8) != 0) {
+ LFS_ERROR("Invalid superblock at {0x%"PRIx32", 0x%"PRIx32"}",
+ 0, 1);
+ err = LFS_ERR_CORRUPT;
+ goto cleanup;
+ }
+
+ uint16_t major_version = (0xffff & (superblock.d.version >> 16));
+ uint16_t minor_version = (0xffff & (superblock.d.version >> 0));
+ if ((major_version != LFS1_DISK_VERSION_MAJOR ||
+ minor_version > LFS1_DISK_VERSION_MINOR)) {
+ LFS_ERROR("Invalid version v%d.%d", major_version, minor_version);
+ err = LFS_ERR_INVAL;
+ goto cleanup;
+ }
+
+ return 0;
+ }
+
+cleanup:
+ lfs_deinit(lfs);
+ return err;
+}
+
+static int lfs1_unmount(lfs_t *lfs) {
+ return lfs_deinit(lfs);
+}
+
+/// v1 migration ///
+static int lfs_migrate_(lfs_t *lfs, const struct lfs_config *cfg) {
+ struct lfs1 lfs1;
+
+ // Indeterminate filesystem size not allowed for migration.
+ LFS_ASSERT(cfg->block_count != 0);
+
+ int err = lfs1_mount(lfs, &lfs1, cfg);
+ if (err) {
+ return err;
+ }
+
+ {
+ // iterate through each directory, copying over entries
+ // into new directory
+ lfs1_dir_t dir1;
+ lfs_mdir_t dir2;
+ dir1.d.tail[0] = lfs->lfs1->root[0];
+ dir1.d.tail[1] = lfs->lfs1->root[1];
+ while (!lfs_pair_isnull(dir1.d.tail)) {
+ // iterate old dir
+ err = lfs1_dir_fetch(lfs, &dir1, dir1.d.tail);
+ if (err) {
+ goto cleanup;
+ }
+
+ // create new dir and bind as temporary pretend root
+ err = lfs_dir_alloc(lfs, &dir2);
+ if (err) {
+ goto cleanup;
+ }
+
+ dir2.rev = dir1.d.rev;
+ dir1.head[0] = dir1.pair[0];
+ dir1.head[1] = dir1.pair[1];
+ lfs->root[0] = dir2.pair[0];
+ lfs->root[1] = dir2.pair[1];
+
+ err = lfs_dir_commit(lfs, &dir2, NULL, 0);
+ if (err) {
+ goto cleanup;
+ }
+
+ while (true) {
+ lfs1_entry_t entry1;
+ err = lfs1_dir_next(lfs, &dir1, &entry1);
+ if (err && err != LFS_ERR_NOENT) {
+ goto cleanup;
+ }
+
+ if (err == LFS_ERR_NOENT) {
+ break;
+ }
+
+ // check that entry has not been moved
+ if (entry1.d.type & 0x80) {
+ int moved = lfs1_moved(lfs, &entry1.d.u);
+ if (moved < 0) {
+ err = moved;
+ goto cleanup;
+ }
+
+ if (moved) {
+ continue;
+ }
+
+ entry1.d.type &= ~0x80;
+ }
+
+ // also fetch name
+ char name[LFS_NAME_MAX+1];
+ memset(name, 0, sizeof(name));
+ err = lfs1_bd_read(lfs, dir1.pair[0],
+ entry1.off + 4+entry1.d.elen+entry1.d.alen,
+ name, entry1.d.nlen);
+ if (err) {
+ goto cleanup;
+ }
+
+ bool isdir = (entry1.d.type == LFS1_TYPE_DIR);
+
+ // create entry in new dir
+ err = lfs_dir_fetch(lfs, &dir2, lfs->root);
+ if (err) {
+ goto cleanup;
+ }
+
+ uint16_t id;
+ err = lfs_dir_find(lfs, &dir2, &(const char*){name}, &id);
+ if (!(err == LFS_ERR_NOENT && id != 0x3ff)) {
+ err = (err < 0) ? err : LFS_ERR_EXIST;
+ goto cleanup;
+ }
+
+ lfs1_entry_tole32(&entry1.d);
+ err = lfs_dir_commit(lfs, &dir2, LFS_MKATTRS(
+ {LFS_MKTAG(LFS_TYPE_CREATE, id, 0), NULL},
+ {LFS_MKTAG_IF_ELSE(isdir,
+ LFS_TYPE_DIR, id, entry1.d.nlen,
+ LFS_TYPE_REG, id, entry1.d.nlen),
+ name},
+ {LFS_MKTAG_IF_ELSE(isdir,
+ LFS_TYPE_DIRSTRUCT, id, sizeof(entry1.d.u),
+ LFS_TYPE_CTZSTRUCT, id, sizeof(entry1.d.u)),
+ &entry1.d.u}));
+ lfs1_entry_fromle32(&entry1.d);
+ if (err) {
+ goto cleanup;
+ }
+ }
+
+ if (!lfs_pair_isnull(dir1.d.tail)) {
+ // find last block and update tail to thread into fs
+ err = lfs_dir_fetch(lfs, &dir2, lfs->root);
+ if (err) {
+ goto cleanup;
+ }
+
+ while (dir2.split) {
+ err = lfs_dir_fetch(lfs, &dir2, dir2.tail);
+ if (err) {
+ goto cleanup;
+ }
+ }
+
+ lfs_pair_tole32(dir2.pair);
+ err = lfs_dir_commit(lfs, &dir2, LFS_MKATTRS(
+ {LFS_MKTAG(LFS_TYPE_SOFTTAIL, 0x3ff, 8), dir1.d.tail}));
+ lfs_pair_fromle32(dir2.pair);
+ if (err) {
+ goto cleanup;
+ }
+ }
+
+ // Copy over first block to thread into fs. Unfortunately
+ // if this fails there is not much we can do.
+ LFS_DEBUG("Migrating {0x%"PRIx32", 0x%"PRIx32"} "
+ "-> {0x%"PRIx32", 0x%"PRIx32"}",
+ lfs->root[0], lfs->root[1], dir1.head[0], dir1.head[1]);
+
+ err = lfs_bd_erase(lfs, dir1.head[1]);
+ if (err) {
+ goto cleanup;
+ }
+
+ err = lfs_dir_fetch(lfs, &dir2, lfs->root);
+ if (err) {
+ goto cleanup;
+ }
+
+ for (lfs_off_t i = 0; i < dir2.off; i++) {
+ uint8_t dat;
+ err = lfs_bd_read(lfs,
+ NULL, &lfs->rcache, dir2.off,
+ dir2.pair[0], i, &dat, 1);
+ if (err) {
+ goto cleanup;
+ }
+
+ err = lfs_bd_prog(lfs,
+ &lfs->pcache, &lfs->rcache, true,
+ dir1.head[1], i, &dat, 1);
+ if (err) {
+ goto cleanup;
+ }
+ }
+
+ err = lfs_bd_flush(lfs, &lfs->pcache, &lfs->rcache, true);
+ if (err) {
+ goto cleanup;
+ }
+ }
+
+ // Create new superblock. This marks a successful migration!
+ err = lfs1_dir_fetch(lfs, &dir1, (const lfs_block_t[2]){0, 1});
+ if (err) {
+ goto cleanup;
+ }
+
+ dir2.pair[0] = dir1.pair[0];
+ dir2.pair[1] = dir1.pair[1];
+ dir2.rev = dir1.d.rev;
+ dir2.off = sizeof(dir2.rev);
+ dir2.etag = 0xffffffff;
+ dir2.count = 0;
+ dir2.tail[0] = lfs->lfs1->root[0];
+ dir2.tail[1] = lfs->lfs1->root[1];
+ dir2.erased = false;
+ dir2.split = true;
+
+ lfs_superblock_t superblock = {
+ .version = LFS_DISK_VERSION,
+ .block_size = lfs->cfg->block_size,
+ .block_count = lfs->cfg->block_count,
+ .name_max = lfs->name_max,
+ .file_max = lfs->file_max,
+ .attr_max = lfs->attr_max,
+ };
+
+ lfs_superblock_tole32(&superblock);
+ err = lfs_dir_commit(lfs, &dir2, LFS_MKATTRS(
+ {LFS_MKTAG(LFS_TYPE_CREATE, 0, 0), NULL},
+ {LFS_MKTAG(LFS_TYPE_SUPERBLOCK, 0, 8), "littlefs"},
+ {LFS_MKTAG(LFS_TYPE_INLINESTRUCT, 0, sizeof(superblock)),
+ &superblock}));
+ if (err) {
+ goto cleanup;
+ }
+
+ // sanity check that fetch works
+ err = lfs_dir_fetch(lfs, &dir2, (const lfs_block_t[2]){0, 1});
+ if (err) {
+ goto cleanup;
+ }
+
+ // force compaction to prevent accidentally mounting v1
+ dir2.erased = false;
+ err = lfs_dir_commit(lfs, &dir2, NULL, 0);
+ if (err) {
+ goto cleanup;
+ }
+ }
+
+cleanup:
+ lfs1_unmount(lfs);
+ return err;
+}
+
+#endif
+
+
+/// Public API wrappers ///
+
+// Here we can add tracing/thread safety easily
+
+// Thread-safe wrappers if enabled
+#ifdef LFS_THREADSAFE
+#define LFS_LOCK(cfg) cfg->lock(cfg)
+#define LFS_UNLOCK(cfg) cfg->unlock(cfg)
+#else
+#define LFS_LOCK(cfg) ((void)cfg, 0)
+#define LFS_UNLOCK(cfg) ((void)cfg)
+#endif
+
+// Public API
+#ifndef LFS_READONLY
+int lfs_format(lfs_t *lfs, const struct lfs_config *cfg) {
+ int err = LFS_LOCK(cfg);
+ if (err) {
+ return err;
+ }
+ LFS_TRACE("lfs_format(%p, %p {.context=%p, "
+ ".read=%p, .prog=%p, .erase=%p, .sync=%p, "
+ ".read_size=%"PRIu32", .prog_size=%"PRIu32", "
+ ".block_size=%"PRIu32", .block_count=%"PRIu32", "
+ ".block_cycles=%"PRId32", .cache_size=%"PRIu32", "
+ ".lookahead_size=%"PRIu32", .read_buffer=%p, "
+ ".prog_buffer=%p, .lookahead_buffer=%p, "
+ ".name_max=%"PRIu32", .file_max=%"PRIu32", "
+ ".attr_max=%"PRIu32"})",
+ (void*)lfs, (void*)cfg, cfg->context,
+ (void*)(uintptr_t)cfg->read, (void*)(uintptr_t)cfg->prog,
+ (void*)(uintptr_t)cfg->erase, (void*)(uintptr_t)cfg->sync,
+ cfg->read_size, cfg->prog_size, cfg->block_size, cfg->block_count,
+ cfg->block_cycles, cfg->cache_size, cfg->lookahead_size,
+ cfg->read_buffer, cfg->prog_buffer, cfg->lookahead_buffer,
+ cfg->name_max, cfg->file_max, cfg->attr_max);
+
+ err = lfs_format_(lfs, cfg);
+
+ LFS_TRACE("lfs_format -> %d", err);
+ LFS_UNLOCK(cfg);
+ return err;
+}
+#endif
+
+int lfs_mount(lfs_t *lfs, const struct lfs_config *cfg) {
+ int err = LFS_LOCK(cfg);
+ if (err) {
+ return err;
+ }
+ LFS_TRACE("lfs_mount(%p, %p {.context=%p, "
+ ".read=%p, .prog=%p, .erase=%p, .sync=%p, "
+ ".read_size=%"PRIu32", .prog_size=%"PRIu32", "
+ ".block_size=%"PRIu32", .block_count=%"PRIu32", "
+ ".block_cycles=%"PRId32", .cache_size=%"PRIu32", "
+ ".lookahead_size=%"PRIu32", .read_buffer=%p, "
+ ".prog_buffer=%p, .lookahead_buffer=%p, "
+ ".name_max=%"PRIu32", .file_max=%"PRIu32", "
+ ".attr_max=%"PRIu32"})",
+ (void*)lfs, (void*)cfg, cfg->context,
+ (void*)(uintptr_t)cfg->read, (void*)(uintptr_t)cfg->prog,
+ (void*)(uintptr_t)cfg->erase, (void*)(uintptr_t)cfg->sync,
+ cfg->read_size, cfg->prog_size, cfg->block_size, cfg->block_count,
+ cfg->block_cycles, cfg->cache_size, cfg->lookahead_size,
+ cfg->read_buffer, cfg->prog_buffer, cfg->lookahead_buffer,
+ cfg->name_max, cfg->file_max, cfg->attr_max);
+
+ err = lfs_mount_(lfs, cfg);
+
+ LFS_TRACE("lfs_mount -> %d", err);
+ LFS_UNLOCK(cfg);
+ return err;
+}
+
+int lfs_unmount(lfs_t *lfs) {
+ int err = LFS_LOCK(lfs->cfg);
+ if (err) {
+ return err;
+ }
+ LFS_TRACE("lfs_unmount(%p)", (void*)lfs);
+
+ err = lfs_unmount_(lfs);
+
+ LFS_TRACE("lfs_unmount -> %d", err);
+ LFS_UNLOCK(lfs->cfg);
+ return err;
+}
+
+#ifndef LFS_READONLY
+int lfs_remove(lfs_t *lfs, const char *path) {
+ int err = LFS_LOCK(lfs->cfg);
+ if (err) {
+ return err;
+ }
+ LFS_TRACE("lfs_remove(%p, \"%s\")", (void*)lfs, path);
+
+ err = lfs_remove_(lfs, path);
+
+ LFS_TRACE("lfs_remove -> %d", err);
+ LFS_UNLOCK(lfs->cfg);
+ return err;
+}
+#endif
+
+#ifndef LFS_READONLY
+int lfs_rename(lfs_t *lfs, const char *oldpath, const char *newpath) {
+ int err = LFS_LOCK(lfs->cfg);
+ if (err) {
+ return err;
+ }
+ LFS_TRACE("lfs_rename(%p, \"%s\", \"%s\")", (void*)lfs, oldpath, newpath);
+
+ err = lfs_rename_(lfs, oldpath, newpath);
+
+ LFS_TRACE("lfs_rename -> %d", err);
+ LFS_UNLOCK(lfs->cfg);
+ return err;
+}
+#endif
+
+int lfs_stat(lfs_t *lfs, const char *path, struct lfs_info *info) {
+ int err = LFS_LOCK(lfs->cfg);
+ if (err) {
+ return err;
+ }
+ LFS_TRACE("lfs_stat(%p, \"%s\", %p)", (void*)lfs, path, (void*)info);
+
+ err = lfs_stat_(lfs, path, info);
+
+ LFS_TRACE("lfs_stat -> %d", err);
+ LFS_UNLOCK(lfs->cfg);
+ return err;
+}
+
+lfs_ssize_t lfs_getattr(lfs_t *lfs, const char *path,
+ uint8_t type, void *buffer, lfs_size_t size) {
+ int err = LFS_LOCK(lfs->cfg);
+ if (err) {
+ return err;
+ }
+ LFS_TRACE("lfs_getattr(%p, \"%s\", %"PRIu8", %p, %"PRIu32")",
+ (void*)lfs, path, type, buffer, size);
+
+ lfs_ssize_t res = lfs_getattr_(lfs, path, type, buffer, size);
+
+ LFS_TRACE("lfs_getattr -> %"PRId32, res);
+ LFS_UNLOCK(lfs->cfg);
+ return res;
+}
+
+#ifndef LFS_READONLY
+int lfs_setattr(lfs_t *lfs, const char *path,
+ uint8_t type, const void *buffer, lfs_size_t size) {
+ int err = LFS_LOCK(lfs->cfg);
+ if (err) {
+ return err;
+ }
+ LFS_TRACE("lfs_setattr(%p, \"%s\", %"PRIu8", %p, %"PRIu32")",
+ (void*)lfs, path, type, buffer, size);
+
+ err = lfs_setattr_(lfs, path, type, buffer, size);
+
+ LFS_TRACE("lfs_setattr -> %d", err);
+ LFS_UNLOCK(lfs->cfg);
+ return err;
+}
+#endif
+
+#ifndef LFS_READONLY
+int lfs_removeattr(lfs_t *lfs, const char *path, uint8_t type) {
+ int err = LFS_LOCK(lfs->cfg);
+ if (err) {
+ return err;
+ }
+ LFS_TRACE("lfs_removeattr(%p, \"%s\", %"PRIu8")", (void*)lfs, path, type);
+
+ err = lfs_removeattr_(lfs, path, type);
+
+ LFS_TRACE("lfs_removeattr -> %d", err);
+ LFS_UNLOCK(lfs->cfg);
+ return err;
+}
+#endif
+
+#ifndef LFS_NO_MALLOC
+int lfs_file_open(lfs_t *lfs, lfs_file_t *file, const char *path, int flags) {
+ int err = LFS_LOCK(lfs->cfg);
+ if (err) {
+ return err;
+ }
+ LFS_TRACE("lfs_file_open(%p, %p, \"%s\", %x)",
+ (void*)lfs, (void*)file, path, (unsigned)flags);
+ LFS_ASSERT(!lfs_mlist_isopen(lfs->mlist, (struct lfs_mlist*)file));
+
+ err = lfs_file_open_(lfs, file, path, flags);
+
+ LFS_TRACE("lfs_file_open -> %d", err);
+ LFS_UNLOCK(lfs->cfg);
+ return err;
+}
+#endif
+
+int lfs_file_opencfg(lfs_t *lfs, lfs_file_t *file,
+ const char *path, int flags,
+ const struct lfs_file_config *cfg) {
+ int err = LFS_LOCK(lfs->cfg);
+ if (err) {
+ return err;
+ }
+ LFS_TRACE("lfs_file_opencfg(%p, %p, \"%s\", %x, %p {"
+ ".buffer=%p, .attrs=%p, .attr_count=%"PRIu32"})",
+ (void*)lfs, (void*)file, path, (unsigned)flags,
+ (void*)cfg, cfg->buffer, (void*)cfg->attrs, cfg->attr_count);
+ LFS_ASSERT(!lfs_mlist_isopen(lfs->mlist, (struct lfs_mlist*)file));
+
+ err = lfs_file_opencfg_(lfs, file, path, flags, cfg);
+
+ LFS_TRACE("lfs_file_opencfg -> %d", err);
+ LFS_UNLOCK(lfs->cfg);
+ return err;
+}
+
+int lfs_file_close(lfs_t *lfs, lfs_file_t *file) {
+ int err = LFS_LOCK(lfs->cfg);
+ if (err) {
+ return err;
+ }
+ LFS_TRACE("lfs_file_close(%p, %p)", (void*)lfs, (void*)file);
+ LFS_ASSERT(lfs_mlist_isopen(lfs->mlist, (struct lfs_mlist*)file));
+
+ err = lfs_file_close_(lfs, file);
+
+ LFS_TRACE("lfs_file_close -> %d", err);
+ LFS_UNLOCK(lfs->cfg);
+ return err;
+}
+
+#ifndef LFS_READONLY
+int lfs_file_sync(lfs_t *lfs, lfs_file_t *file) {
+ int err = LFS_LOCK(lfs->cfg);
+ if (err) {
+ return err;
+ }
+ LFS_TRACE("lfs_file_sync(%p, %p)", (void*)lfs, (void*)file);
+ LFS_ASSERT(lfs_mlist_isopen(lfs->mlist, (struct lfs_mlist*)file));
+
+ err = lfs_file_sync_(lfs, file);
+
+ LFS_TRACE("lfs_file_sync -> %d", err);
+ LFS_UNLOCK(lfs->cfg);
+ return err;
+}
+#endif
+
+lfs_ssize_t lfs_file_read(lfs_t *lfs, lfs_file_t *file,
+ void *buffer, lfs_size_t size) {
+ int err = LFS_LOCK(lfs->cfg);
+ if (err) {
+ return err;
+ }
+ LFS_TRACE("lfs_file_read(%p, %p, %p, %"PRIu32")",
+ (void*)lfs, (void*)file, buffer, size);
+ LFS_ASSERT(lfs_mlist_isopen(lfs->mlist, (struct lfs_mlist*)file));
+
+ lfs_ssize_t res = lfs_file_read_(lfs, file, buffer, size);
+
+ LFS_TRACE("lfs_file_read -> %"PRId32, res);
+ LFS_UNLOCK(lfs->cfg);
+ return res;
+}
+
+#ifndef LFS_READONLY
+lfs_ssize_t lfs_file_write(lfs_t *lfs, lfs_file_t *file,
+ const void *buffer, lfs_size_t size) {
+ int err = LFS_LOCK(lfs->cfg);
+ if (err) {
+ return err;
+ }
+ LFS_TRACE("lfs_file_write(%p, %p, %p, %"PRIu32")",
+ (void*)lfs, (void*)file, buffer, size);
+ LFS_ASSERT(lfs_mlist_isopen(lfs->mlist, (struct lfs_mlist*)file));
+
+ lfs_ssize_t res = lfs_file_write_(lfs, file, buffer, size);
+
+ LFS_TRACE("lfs_file_write -> %"PRId32, res);
+ LFS_UNLOCK(lfs->cfg);
+ return res;
+}
+#endif
+
+lfs_soff_t lfs_file_seek(lfs_t *lfs, lfs_file_t *file,
+ lfs_soff_t off, int whence) {
+ int err = LFS_LOCK(lfs->cfg);
+ if (err) {
+ return err;
+ }
+ LFS_TRACE("lfs_file_seek(%p, %p, %"PRId32", %d)",
+ (void*)lfs, (void*)file, off, whence);
+ LFS_ASSERT(lfs_mlist_isopen(lfs->mlist, (struct lfs_mlist*)file));
+
+ lfs_soff_t res = lfs_file_seek_(lfs, file, off, whence);
+
+ LFS_TRACE("lfs_file_seek -> %"PRId32, res);
+ LFS_UNLOCK(lfs->cfg);
+ return res;
+}
+
+#ifndef LFS_READONLY
+int lfs_file_truncate(lfs_t *lfs, lfs_file_t *file, lfs_off_t size) {
+ int err = LFS_LOCK(lfs->cfg);
+ if (err) {
+ return err;
+ }
+ LFS_TRACE("lfs_file_truncate(%p, %p, %"PRIu32")",
+ (void*)lfs, (void*)file, size);
+ LFS_ASSERT(lfs_mlist_isopen(lfs->mlist, (struct lfs_mlist*)file));
+
+ err = lfs_file_truncate_(lfs, file, size);
+
+ LFS_TRACE("lfs_file_truncate -> %d", err);
+ LFS_UNLOCK(lfs->cfg);
+ return err;
+}
+#endif
+
+lfs_soff_t lfs_file_tell(lfs_t *lfs, lfs_file_t *file) {
+ int err = LFS_LOCK(lfs->cfg);
+ if (err) {
+ return err;
+ }
+ LFS_TRACE("lfs_file_tell(%p, %p)", (void*)lfs, (void*)file);
+ LFS_ASSERT(lfs_mlist_isopen(lfs->mlist, (struct lfs_mlist*)file));
+
+ lfs_soff_t res = lfs_file_tell_(lfs, file);
+
+ LFS_TRACE("lfs_file_tell -> %"PRId32, res);
+ LFS_UNLOCK(lfs->cfg);
+ return res;
+}
+
+int lfs_file_rewind(lfs_t *lfs, lfs_file_t *file) {
+ int err = LFS_LOCK(lfs->cfg);
+ if (err) {
+ return err;
+ }
+ LFS_TRACE("lfs_file_rewind(%p, %p)", (void*)lfs, (void*)file);
+
+ err = lfs_file_rewind_(lfs, file);
+
+ LFS_TRACE("lfs_file_rewind -> %d", err);
+ LFS_UNLOCK(lfs->cfg);
+ return err;
+}
+
+lfs_soff_t lfs_file_size(lfs_t *lfs, lfs_file_t *file) {
+ int err = LFS_LOCK(lfs->cfg);
+ if (err) {
+ return err;
+ }
+ LFS_TRACE("lfs_file_size(%p, %p)", (void*)lfs, (void*)file);
+ LFS_ASSERT(lfs_mlist_isopen(lfs->mlist, (struct lfs_mlist*)file));
+
+ lfs_soff_t res = lfs_file_size_(lfs, file);
+
+ LFS_TRACE("lfs_file_size -> %"PRIu32, res);
+ LFS_UNLOCK(lfs->cfg);
+ return res;
+}
+
+#ifndef LFS_READONLY
+int lfs_mkdir(lfs_t *lfs, const char *path) {
+ int err = LFS_LOCK(lfs->cfg);
+ if (err) {
+ return err;
+ }
+ LFS_TRACE("lfs_mkdir(%p, \"%s\")", (void*)lfs, path);
+
+ err = lfs_mkdir_(lfs, path);
+
+ LFS_TRACE("lfs_mkdir -> %d", err);
+ LFS_UNLOCK(lfs->cfg);
+ return err;
+}
+#endif
+
+int lfs_dir_open(lfs_t *lfs, lfs_dir_t *dir, const char *path) {
+ int err = LFS_LOCK(lfs->cfg);
+ if (err) {
+ return err;
+ }
+ LFS_TRACE("lfs_dir_open(%p, %p, \"%s\")", (void*)lfs, (void*)dir, path);
+ LFS_ASSERT(!lfs_mlist_isopen(lfs->mlist, (struct lfs_mlist*)dir));
+
+ err = lfs_dir_open_(lfs, dir, path);
+
+ LFS_TRACE("lfs_dir_open -> %d", err);
+ LFS_UNLOCK(lfs->cfg);
+ return err;
+}
+
+int lfs_dir_close(lfs_t *lfs, lfs_dir_t *dir) {
+ int err = LFS_LOCK(lfs->cfg);
+ if (err) {
+ return err;
+ }
+ LFS_TRACE("lfs_dir_close(%p, %p)", (void*)lfs, (void*)dir);
+
+ err = lfs_dir_close_(lfs, dir);
+
+ LFS_TRACE("lfs_dir_close -> %d", err);
+ LFS_UNLOCK(lfs->cfg);
+ return err;
+}
+
+int lfs_dir_read(lfs_t *lfs, lfs_dir_t *dir, struct lfs_info *info) {
+ int err = LFS_LOCK(lfs->cfg);
+ if (err) {
+ return err;
+ }
+ LFS_TRACE("lfs_dir_read(%p, %p, %p)",
+ (void*)lfs, (void*)dir, (void*)info);
+
+ err = lfs_dir_read_(lfs, dir, info);
+
+ LFS_TRACE("lfs_dir_read -> %d", err);
+ LFS_UNLOCK(lfs->cfg);
+ return err;
+}
+
+int lfs_dir_seek(lfs_t *lfs, lfs_dir_t *dir, lfs_off_t off) {
+ int err = LFS_LOCK(lfs->cfg);
+ if (err) {
+ return err;
+ }
+ LFS_TRACE("lfs_dir_seek(%p, %p, %"PRIu32")",
+ (void*)lfs, (void*)dir, off);
+
+ err = lfs_dir_seek_(lfs, dir, off);
+
+ LFS_TRACE("lfs_dir_seek -> %d", err);
+ LFS_UNLOCK(lfs->cfg);
+ return err;
+}
+
+lfs_soff_t lfs_dir_tell(lfs_t *lfs, lfs_dir_t *dir) {
+ int err = LFS_LOCK(lfs->cfg);
+ if (err) {
+ return err;
+ }
+ LFS_TRACE("lfs_dir_tell(%p, %p)", (void*)lfs, (void*)dir);
+
+ lfs_soff_t res = lfs_dir_tell_(lfs, dir);
+
+ LFS_TRACE("lfs_dir_tell -> %"PRId32, res);
+ LFS_UNLOCK(lfs->cfg);
+ return res;
+}
+
+int lfs_dir_rewind(lfs_t *lfs, lfs_dir_t *dir) {
+ int err = LFS_LOCK(lfs->cfg);
+ if (err) {
+ return err;
+ }
+ LFS_TRACE("lfs_dir_rewind(%p, %p)", (void*)lfs, (void*)dir);
+
+ err = lfs_dir_rewind_(lfs, dir);
+
+ LFS_TRACE("lfs_dir_rewind -> %d", err);
+ LFS_UNLOCK(lfs->cfg);
+ return err;
+}
+
+int lfs_fs_stat(lfs_t *lfs, struct lfs_fsinfo *fsinfo) {
+ int err = LFS_LOCK(lfs->cfg);
+ if (err) {
+ return err;
+ }
+ LFS_TRACE("lfs_fs_stat(%p, %p)", (void*)lfs, (void*)fsinfo);
+
+ err = lfs_fs_stat_(lfs, fsinfo);
+
+ LFS_TRACE("lfs_fs_stat -> %d", err);
+ LFS_UNLOCK(lfs->cfg);
+ return err;
+}
+
+lfs_ssize_t lfs_fs_size(lfs_t *lfs) {
+ int err = LFS_LOCK(lfs->cfg);
+ if (err) {
+ return err;
+ }
+ LFS_TRACE("lfs_fs_size(%p)", (void*)lfs);
+
+ lfs_ssize_t res = lfs_fs_size_(lfs);
+
+ LFS_TRACE("lfs_fs_size -> %"PRId32, res);
+ LFS_UNLOCK(lfs->cfg);
+ return res;
+}
+
+int lfs_fs_traverse(lfs_t *lfs, int (*cb)(void *, lfs_block_t), void *data) {
+ int err = LFS_LOCK(lfs->cfg);
+ if (err) {
+ return err;
+ }
+ LFS_TRACE("lfs_fs_traverse(%p, %p, %p)",
+ (void*)lfs, (void*)(uintptr_t)cb, data);
+
+ err = lfs_fs_traverse_(lfs, cb, data, true);
+
+ LFS_TRACE("lfs_fs_traverse -> %d", err);
+ LFS_UNLOCK(lfs->cfg);
+ return err;
+}
+
+#ifndef LFS_READONLY
+int lfs_fs_mkconsistent(lfs_t *lfs) {
+ int err = LFS_LOCK(lfs->cfg);
+ if (err) {
+ return err;
+ }
+ LFS_TRACE("lfs_fs_mkconsistent(%p)", (void*)lfs);
+
+ err = lfs_fs_mkconsistent_(lfs);
+
+ LFS_TRACE("lfs_fs_mkconsistent -> %d", err);
+ LFS_UNLOCK(lfs->cfg);
+ return err;
+}
+#endif
+
+#ifndef LFS_READONLY
+int lfs_fs_gc(lfs_t *lfs) {
+ int err = LFS_LOCK(lfs->cfg);
+ if (err) {
+ return err;
+ }
+ LFS_TRACE("lfs_fs_gc(%p)", (void*)lfs);
+
+ err = lfs_fs_gc_(lfs);
+
+ LFS_TRACE("lfs_fs_gc -> %d", err);
+ LFS_UNLOCK(lfs->cfg);
+ return err;
+}
+#endif
+
+#ifndef LFS_READONLY
+int lfs_fs_grow(lfs_t *lfs, lfs_size_t block_count) {
+ int err = LFS_LOCK(lfs->cfg);
+ if (err) {
+ return err;
+ }
+ LFS_TRACE("lfs_fs_grow(%p, %"PRIu32")", (void*)lfs, block_count);
+
+ err = lfs_fs_grow_(lfs, block_count);
+
+ LFS_TRACE("lfs_fs_grow -> %d", err);
+ LFS_UNLOCK(lfs->cfg);
+ return err;
+}
+#endif
+
+#ifdef LFS_MIGRATE
+int lfs_migrate(lfs_t *lfs, const struct lfs_config *cfg) {
+ int err = LFS_LOCK(cfg);
+ if (err) {
+ return err;
+ }
+ LFS_TRACE("lfs_migrate(%p, %p {.context=%p, "
+ ".read=%p, .prog=%p, .erase=%p, .sync=%p, "
+ ".read_size=%"PRIu32", .prog_size=%"PRIu32", "
+ ".block_size=%"PRIu32", .block_count=%"PRIu32", "
+ ".block_cycles=%"PRId32", .cache_size=%"PRIu32", "
+ ".lookahead_size=%"PRIu32", .read_buffer=%p, "
+ ".prog_buffer=%p, .lookahead_buffer=%p, "
+ ".name_max=%"PRIu32", .file_max=%"PRIu32", "
+ ".attr_max=%"PRIu32"})",
+ (void*)lfs, (void*)cfg, cfg->context,
+ (void*)(uintptr_t)cfg->read, (void*)(uintptr_t)cfg->prog,
+ (void*)(uintptr_t)cfg->erase, (void*)(uintptr_t)cfg->sync,
+ cfg->read_size, cfg->prog_size, cfg->block_size, cfg->block_count,
+ cfg->block_cycles, cfg->cache_size, cfg->lookahead_size,
+ cfg->read_buffer, cfg->prog_buffer, cfg->lookahead_buffer,
+ cfg->name_max, cfg->file_max, cfg->attr_max);
+
+ err = lfs_migrate_(lfs, cfg);
+
+ LFS_TRACE("lfs_migrate -> %d", err);
+ LFS_UNLOCK(cfg);
+ return err;
+}
+#endif
+
diff --git a/Ganesha_II_V2/Core/Src/littlefs/lfs_util.c b/Ganesha_II_V2/Core/Src/littlefs/lfs_util.c
new file mode 100644
index 0000000..dac72ab
--- /dev/null
+++ b/Ganesha_II_V2/Core/Src/littlefs/lfs_util.c
@@ -0,0 +1,37 @@
+/*
+ * lfs util functions
+ *
+ * Copyright (c) 2022, The littlefs authors.
+ * Copyright (c) 2017, Arm Limited. All rights reserved.
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include "lfs_util.h"
+
+// Only compile if user does not provide custom config
+#ifndef LFS_CONFIG
+
+
+// If user provides their own CRC impl we don't need this
+#ifndef LFS_CRC
+// Software CRC implementation with small lookup table
+uint32_t lfs_crc(uint32_t crc, const void *buffer, size_t size) {
+ static const uint32_t rtable[16] = {
+ 0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac,
+ 0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c,
+ 0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c,
+ 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c,
+ };
+
+ const uint8_t *data = buffer;
+
+ for (size_t i = 0; i < size; i++) {
+ crc = (crc >> 4) ^ rtable[(crc ^ (data[i] >> 0)) & 0xf];
+ crc = (crc >> 4) ^ rtable[(crc ^ (data[i] >> 4)) & 0xf];
+ }
+
+ return crc;
+}
+#endif
+
+
+#endif
diff --git a/Ganesha_II_V2/Core/Src/main.c b/Ganesha_II_V2/Core/Src/main.c
index 7e59e2c..4e0981f 100644
--- a/Ganesha_II_V2/Core/Src/main.c
+++ b/Ganesha_II_V2/Core/Src/main.c
@@ -3,7 +3,7 @@
******************************************************************************
* @file : main.c
* @brief : Main program body
- * @author : Mahir Shah (mahir.shah@rutgers.edu), Tyler-Odeh Abbassi (tfa21@scarletmail.rutgers.edu)
+ * @author : Mahir Shah (mahir.shah@rutgers.edu), Tyler-Odeh Abbassi (tfa21@scarletmail.rutgers.edu)
******************************************************************************
* @attention
*
@@ -20,21 +20,33 @@
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
+#include "usb_device.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
+#include "usbd_cdc_if.h"
#include "bmi08_defs.h"
#include "bmi088.h"
#include "CD-PA1616S.h"
#include "bmp581.h"
+#include "flash.h"
+#include "gd5f1gq5xe.h"
+#include "STRUCTS.h"
+
#include
#include
#include
#include
+
#include "STRUCTS.h"
+
#include "orientation_estimator.h"
#include "dumb_timer.h"
#include "us_timer.h"
+
+#include "lfs.h"
+#include "lfs_util.h"
+
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
@@ -71,12 +83,54 @@ UART_HandleTypeDef huart5;
UART_HandleTypeDef huart8;
DMA_HandleTypeDef hdma_uart8_rx;
-PCD_HandleTypeDef hpcd_USB_OTG_FS;
-
/* USER CODE BEGIN PV */
//char gps_receive_buffer[BUFFER_SIZE];
//uint8_t gps_dma_buffer[BUFFER_SIZE];
+struct flash_dev flash;
+lfs_file_t packet_file;
+bool flash_enabled = true;
+
+static int flash_sync(const struct lfs_config *c)
+{
+ return LFS_ERR_OK;
+}
+
+static int lfs_read(const struct lfs_config *c, lfs_block_t block, lfs_off_t offset,
+ void *data, lfs_size_t size)
+{
+ if (!gd5f1gq5xe_read(block, offset, data, size)) return LFS_ERR_IO;
+ return LFS_ERR_OK;
+}
+
+static int lfs_prog(const struct lfs_config *c, lfs_block_t block, lfs_off_t offset,
+ const void *data, lfs_size_t size)
+{
+ if (!gd5f1gq5xe_write(block, offset, data, size)) return LFS_ERR_IO;
+ return LFS_ERR_OK;
+}
+
+static int lfs_erase(const struct lfs_config *c, lfs_block_t block)
+{
+ if (!gd5f1gq5xe_erase(block)) return LFS_ERR_IO;
+ return LFS_ERR_OK;
+}
+
+static const struct lfs_config flash_cfg = {
+ .read = &lfs_read,
+ .prog = &lfs_prog,
+ .erase = &lfs_erase,
+ .sync = flash_sync,
+
+ .read_size = GD5F_PAGE_SIZE,
+ .prog_size = GD5F_PAGE_SIZE,
+ .block_size = GD5F_BLOCK_SIZE,
+ .block_count = GD5F_BLOCK_COUNT,
+ .cache_size = GD5F_PAGE_SIZE,
+ .lookahead_size = 128,
+ .block_cycles = 512,
+};
+
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
@@ -88,7 +142,6 @@ static void MX_SPI1_Init(void);
static void MX_SPI4_Init(void);
static void MX_UART5_Init(void);
static void MX_UART8_Init(void);
-static void MX_USB_OTG_FS_PCD_Init(void);
static void MX_SPI2_Init(void);
static void MX_TIM1_Init(void);
static void MX_CRC_Init(void);
@@ -109,42 +162,57 @@ struct BMP581 bmp581;
struct bmp5_sensor_data bmp_data;
uint8_t bmp581_init_ok = 0;
-void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart){
-if(huart->Instance == UART5){
- if(memcmp(camera_buffer, "FIRE", 4) == 0){
- HAL_GPIO_TogglePin(GPIOD, CAM_FIRE_Pin);
- // Timer started
- dumb_timer_clear(&camera_timer);
- dumb_timer_start(&camera_timer);
- camera_fired ^= 1;
-
- }
- // __HAL_UART_CLEAR_OREFLAG(&huart5);
- //HAL_UART_Receive_IT(&huart5, camera_buffer, 4);
- }
- __HAL_UART_CLEAR_OREFLAG(&huart5);
- HAL_UART_Receive_IT(&huart5, camera_buffer, 4);
+void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
+{
+ if (huart->Instance == UART5) {
+ if (memcmp(camera_buffer, "FIRE", 4) == 0) {
+ HAL_GPIO_TogglePin(GPIOD, CAM_FIRE_Pin);
+ // Timer started
+ dumb_timer_clear(&camera_timer);
+ dumb_timer_start(&camera_timer);
+ camera_fired ^= 1;
+ }
+ // __HAL_UART_CLEAR_OREFLAG(&huart5);
+ // HAL_UART_Receive_IT(&huart5, camera_buffer, 4);
+ }
+ __HAL_UART_CLEAR_OREFLAG(&huart5);
+ HAL_UART_Receive_IT(&huart5, camera_buffer, 4);
}
+void handle_usb_cdc(uint8_t* buf, uint32_t len)
+{
+ if (memcpy(buf, "PING", len) == 0) {
+ const char msg[] = "Hello!";
+ CDC_Transmit_FS(msg, sizeof(msg));
+ } else if (memcmp(buf, "PACKET", len) == 0) {
+ uint8_t bytes[2048];
+ lfs_ssize_t bytes_read;
+
+ lfs_file_seek(&(flash.lfs), &packet_file, 0, LFS_SEEK_SET);
+ while ((bytes_read = lfs_file_read(&(flash.lfs), &packet_file, bytes, sizeof(bytes))) > 0)
+ CDC_Transmit_FS(bytes, sizeof(bytes));
+ }
+}
-uint32_t calculate_checksum(const uint8_t *data, size_t length) {
- return HAL_CRC_Calculate(&hcrc, (uint32_t *)data, length);
+uint32_t calculate_checksum(const uint8_t *data, size_t length)
+{
+ return HAL_CRC_Calculate(&hcrc, (uint32_t *)data, length);
}
// Triggers when the timer has run, shutdowns the camera
-void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim){
-// if (camera_fired == 1){
-// // Timer Stopped
-// HAL_TIM_Base_Stop_IT(&htim1);
-// // Camera Stopped
-// HAL_GPIO_TogglePin(GPIOD, CAM_FIRE_Pin);
-// camera_fired ^= 1;
-// }
-
- // Timer Notes
- // Prescaler = 999, Counter = 3999, APB2 Timer Clock = 8MHZ, Div By 2, Time = 0.5s
- //Prescaler = 999, Counter = 7999, APB2 Timer Clock = 8MHZ, Div By 2, Time = 1s
- //Prescaler = 59999, Counter = 9999, APB2 Timer Clock = 8MHZ, Div By 2, Time = 180s
+void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
+{
+ // if (camera_fired == 1){
+ // // Timer Stopped
+ // HAL_TIM_Base_Stop_IT(&htim1);
+ // // Camera Stopped
+ // HAL_GPIO_TogglePin(GPIOD, CAM_FIRE_Pin);
+ // camera_fired ^= 1;
+ // }
+ // Timer Notes:
+ // Prescaler = 999, Counter = 3999, APB2 Timer Clock = 8MHZ, Div By 2, Time = 0.5s
+ // Prescaler = 999, Counter = 7999, APB2 Timer Clock = 8MHZ, Div By 2, Time = 1s
+ // Prescaler = 59999, Counter = 9999, APB2 Timer Clock = 8MHZ, Div By 2, Time = 180s
}
uint8_t bmi088_init_ok = 0;
@@ -155,23 +223,23 @@ volatile uint8_t accel_ready;
volatile uint8_t gyro_ready;
void HAL_GPIO_EXTI_Callback(uint16_t pin) {
- if (pin == BMI088_GYRO_INT_PIN) {
- if (bmi088_init_ok == 0) return;
+ if (pin == BMI088_GYRO_INT_PIN) {
+ if (bmi088_init_ok == 0) return;
- if (!gyro_ready){
- gyro_ready = 1;
- }
+ if (!gyro_ready){
+ gyro_ready = 1;
+ }
- } else if (pin == BMI088_ACCEL_INT_PIN) {
- if (bmi088_init_ok == 0) return;
+ } else if (pin == BMI088_ACCEL_INT_PIN) {
+ if (bmi088_init_ok == 0) return;
- if (!accel_ready){
- accel_ready = 1;
- }
+ if (!accel_ready){
+ accel_ready = 1;
+ }
- }
+ }
- __HAL_GPIO_EXTI_CLEAR_FLAG(pin);
+ __HAL_GPIO_EXTI_CLEAR_FLAG(pin);
}
struct Orientation_Estimator estimator;
@@ -187,9 +255,9 @@ int main(void)
{
/* USER CODE BEGIN 1 */
- char uart_buf[50];
- int uart_buf_len;
- uint16_t timer_val;
+ char uart_buf[50];
+ int uart_buf_len;
+ uint16_t timer_val;
/* USER CODE END 1 */
@@ -217,11 +285,11 @@ int main(void)
MX_SPI4_Init();
MX_UART5_Init();
MX_UART8_Init();
- MX_USB_OTG_FS_PCD_Init();
MX_SPI2_Init();
MX_TIM1_Init();
MX_CRC_Init();
MX_TIM2_Init();
+ MX_USB_DEVICE_Init();
/* USER CODE BEGIN 2 */
us_timer_init();
@@ -231,146 +299,133 @@ int main(void)
dumb_timer_init(&camera_timer, HRS_TO_MS(2));
uint32_t prev_baro_read_time = HAL_GetTick();
-
+ uint32_t prev_flash_write_time = HAL_GetTick();
+
uint8_t bmi088_init_try_count = 1;
while (bmi088_init_ok == 0 && bmi088_init_try_count <= 3) {
- if (bmi088_init(&bmi088, &hspi2) == BMI08_OK) {
- bmi088_init_ok = 1;
- break;
- } else {
- bmi088_init_try_count++;
- HAL_Delay(500);
- }
+ if (bmi088_init(&bmi088, &hspi2) == BMI08_OK) {
+ bmi088_init_ok = 1;
+ break;
+ } else {
+ bmi088_init_try_count++;
+ HAL_Delay(500);
+ }
}
if (bmp581_init(&bmp581, &hi2c2) == BMP5_OK) {
- bmp581_init_ok = 1;
+ bmp581_init_ok = 1;
}
+ packet = (ganesha_II_packet){0};
short magic = 0xBEEF;
packet.magic = magic;
- packet.status = 0;
- packet.time_us =0;
- packet.main_voltage_v = 0.0f;
- packet.pyro_voltage_v = 0.0f;
- packet.numSatellites = 0;
- packet.gpsFixType = 0;
- packet.latitude_degrees = 0.0f;
- packet.longitude_degrees = 0.0f;
- packet.gps_hMSL_m = 0.0f;
- packet.barometer_hMSL_m = 0.0f;
- packet.temperature_c = 0.0f;
- packet.acceleration_x_mss = 0.0f;
- packet.acceleration_y_mss = 0.0f;
- packet.acceleration_z_mss = 0.0f;
- packet.angular_velocity_x_rads = 0.0f;
- packet.angular_velocity_y_rads = 0.0f;
- packet.angular_velocity_z_rads = 0.0f;
- packet.gauss_x = 0.0f;
- packet.gauss_y = 0.0f;
- packet.gauss_z = 0.0f;
- packet.kf_acceleration_mss = 0.0f;
- packet.kf_velocity_ms = 0.0f;
- packet.kf_position_m = 0.0f;
- packet.w = 0.0f;
- packet.x = 0.0f;
- packet.y = 0.0f;
- packet.z = 0.0f;
- packet.checksum = 0;
-
- __HAL_UART_CLEAR_OREFLAG(&huart5);
- HAL_UART_Receive_IT(&huart5, camera_buffer, 4);
-
+ __HAL_UART_CLEAR_OREFLAG(&huart5);
+ HAL_UART_Receive_IT(&huart5, camera_buffer, 4);
+
+ flash_init(&flash, GD5F1GQ5XE);
+ int32_t fs_size = flash_mount(&flash, &flash_cfg);
+ if (fs_size < 0) flash_enabled = false;
+ if (flash_enabled) {
+ uint32_t boot_count = flash_boot_count(&flash, false);
+ uint32_t file_size = flash_open(&flash, &packet_file, "packets");
+ const char msg[] = "Flash enabled!";
+ HAL_UART_Transmit(&huart5, msg, sizeof(msg), HAL_MAX_DELAY);
+ }
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
- while (1)
- {
-// // If enough time has passed (1 second), toggle LED and get new timestamp
-// if (__HAL_TIM_GET_COUNTER(&htim17) - timer_val >= 10000)
-// {
-// HAL_GPIO_TogglePin(GPIOB, LED_Pin);
-// timer_val = __HAL_TIM_GET_COUNTER(&htim17);
-// }
+ while (1) {
+ /* HAL_GPIO_WritePin(GPIOE, GPIO_PIN_3, GPIO_PIN_SET); */
+ // // If enough time has passed (1 second), toggle LED and get new timestamp
+ // if (__HAL_TIM_GET_COUNTER(&htim17) - timer_val >= 10000)
+ // {
+ // HAL_GPIO_TogglePin(GPIOB, LED_Pin);
+ // timer_val = __HAL_TIM_GET_COUNTER(&htim17);
+ // }
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
- packet.latitude_degrees = gps_packet.latitude_degrees;
- packet.longitude_degrees = gps_packet.longitude_degrees;
- packet.numSatellites = gps_packet.numSatellites;
- packet.gpsFixType = gps_packet.gpsFixType;
- packet.gps_hMSL_m = gps_packet.gps_hMSL_m;
-
- if (accel_ready && gyro_ready){
-
- bmi088_update_gyro_data(&bmi088, &bmi088_gyro_data);
- bmi088_update_accel_data(&bmi088, &bmi088_accel_data);
-
- packet.acceleration_x_mss = bmi088_convert_accel_axis_data(&bmi088, bmi088_accel_data.x);
- packet.acceleration_y_mss = bmi088_convert_accel_axis_data(&bmi088, bmi088_accel_data.y);
- packet.acceleration_z_mss = bmi088_convert_accel_axis_data(&bmi088, bmi088_accel_data.z);
-
- packet.angular_velocity_x_rads = bmi088_convert_gyro_axis_data(&bmi088, bmi088_gyro_data.x);
- packet.angular_velocity_y_rads = bmi088_convert_gyro_axis_data(&bmi088, bmi088_gyro_data.y);
- packet.angular_velocity_z_rads = bmi088_convert_gyro_axis_data(&bmi088, bmi088_gyro_data.z);
-
- if (!estimator_init) {
- orientation_estimator_reset_from_accel(&estimator, packet.acceleration_x_mss, packet.acceleration_y_mss, packet.acceleration_z_mss);
- estimator_init = 1;
- }
-
- orientation_estimator_add_gyro_reading(
- &estimator,
- packet.angular_velocity_x_rads,
- packet.angular_velocity_y_rads,
- packet.angular_velocity_z_rads
- );
-
- packet.w = orientation_estimator_get_w(&estimator);
- packet.x = -orientation_estimator_get_x(&estimator);
- packet.y = -orientation_estimator_get_y(&estimator);
- packet.z = -orientation_estimator_get_z(&estimator);
-
- accel_ready = 0;
- gyro_ready = 0;
-
- }
-
- uint32_t current_time = HAL_GetTick();
-
- if (current_time - prev_baro_read_time >= 2) {
- prev_baro_read_time = current_time;
- bmp581_update_data(&bmp581, &bmp_data);
- }
-
- packet.barometer_hMSL_m = bmp581_estimate_altitude_msl(&bmp581, &bmp_data);
- packet.temperature_c = bmp_data.temperature;
-
- if (dumb_timer_done(&camera_timer)) {
- dumb_timer_clear(&camera_timer);
-
- HAL_GPIO_TogglePin(GPIOD, CAM_FIRE_Pin);
- camera_fired ^= 1;
- }
-
- if (camera_fired == 1){
- packet.status = 1;
- } else {
- packet.status = 0;
- }
-
- packet.kf_position_m = bmp_data.pressure;
-
- packet.time_us = get_time_us();
- packet.checksum = calculate_checksum((const uint8_t *)&packet+sizeof(short), sizeof(packet)-6);
-
- HAL_UART_Transmit(&huart5, (uint8_t*)&packet, sizeof(packet), HAL_MAX_DELAY);
+ packet.latitude_degrees = gps_packet.latitude_degrees;
+ packet.longitude_degrees = gps_packet.longitude_degrees;
+ packet.numSatellites = gps_packet.numSatellites;
+ packet.gpsFixType = gps_packet.gpsFixType;
+ packet.gps_hMSL_m = gps_packet.gps_hMSL_m;
+
+ if (accel_ready && gyro_ready) {
+ bmi088_update_gyro_data(&bmi088, &bmi088_gyro_data);
+ bmi088_update_accel_data(&bmi088, &bmi088_accel_data);
+
+ packet.acceleration_x_mss = bmi088_convert_accel_axis_data(&bmi088, bmi088_accel_data.x);
+ packet.acceleration_y_mss = bmi088_convert_accel_axis_data(&bmi088, bmi088_accel_data.y);
+ packet.acceleration_z_mss = bmi088_convert_accel_axis_data(&bmi088, bmi088_accel_data.z);
+
+ packet.angular_velocity_x_rads = bmi088_convert_gyro_axis_data(&bmi088, bmi088_gyro_data.x);
+ packet.angular_velocity_y_rads = bmi088_convert_gyro_axis_data(&bmi088, bmi088_gyro_data.y);
+ packet.angular_velocity_z_rads = bmi088_convert_gyro_axis_data(&bmi088, bmi088_gyro_data.z);
+
+ if (!estimator_init) {
+ orientation_estimator_reset_from_accel(&estimator, packet.acceleration_x_mss,
+ packet.acceleration_y_mss, packet.acceleration_z_mss);
+ estimator_init = 1;
+ }
+
+ orientation_estimator_add_gyro_reading(&estimator, packet.angular_velocity_x_rads,
+ packet.angular_velocity_y_rads,
+ packet.angular_velocity_z_rads);
+ packet.w = orientation_estimator_get_w(&estimator);
+ packet.x = -orientation_estimator_get_x(&estimator);
+ packet.y = -orientation_estimator_get_y(&estimator);
+ packet.z = -orientation_estimator_get_z(&estimator);
+
+ accel_ready = 0;
+ gyro_ready = 0;
+ }
+
+ uint32_t current_time = HAL_GetTick();
+
+ if (current_time - prev_baro_read_time >= 2) {
+ prev_baro_read_time = current_time;
+ bmp581_update_data(&bmp581, &bmp_data);
+ }
+
+ packet.barometer_hMSL_m = bmp581_estimate_altitude_msl(&bmp581, &bmp_data);
+ packet.temperature_c = bmp_data.temperature;
+
+ if (dumb_timer_done(&camera_timer)) {
+ dumb_timer_clear(&camera_timer);
+
+ HAL_GPIO_TogglePin(GPIOD, CAM_FIRE_Pin);
+ camera_fired ^= 1;
+
+ if (flash_enabled) {
+ flash_enabled = false;
+ flash_close(&flash, &packet_file);
+ flash_unmount(&flash);
+ }
+ }
+
+ packet.status = (camera_fired == 1) ? 1 : 0;
+ packet.time_us = get_time_us();
+ packet.kf_position_m = bmp_data.pressure;
+ packet.checksum = calculate_checksum((const uint8_t *) &packet + sizeof(short), sizeof(packet) - 6);
+
+ HAL_UART_Transmit(&huart5, (uint8_t*)&packet, sizeof(packet), HAL_MAX_DELAY);
+
+ if (flash_enabled && (current_time - prev_flash_write_time >= 10)) {
+ prev_flash_write_time = current_time;
+ flash_append(&flash, &packet_file, (uint8_t*) &packet, sizeof(packet));
+ }
+
+ HAL_GPIO_TogglePin(GPIOB, LED_Pin);
+ }
- HAL_GPIO_TogglePin(GPIOB, LED_Pin);
+ if (flash_enabled) {
+ flash_close(&flash, &packet_file);
+ flash_unmount(&flash);
}
/* USER CODE END 3 */
}
@@ -629,11 +684,11 @@ static void MX_SPI4_Init(void)
hspi4.Instance = SPI4;
hspi4.Init.Mode = SPI_MODE_MASTER;
hspi4.Init.Direction = SPI_DIRECTION_2LINES;
- hspi4.Init.DataSize = SPI_DATASIZE_4BIT;
+ hspi4.Init.DataSize = SPI_DATASIZE_8BIT;
hspi4.Init.CLKPolarity = SPI_POLARITY_LOW;
hspi4.Init.CLKPhase = SPI_PHASE_1EDGE;
hspi4.Init.NSS = SPI_NSS_SOFT;
- hspi4.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2;
+ hspi4.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_16;
hspi4.Init.FirstBit = SPI_FIRSTBIT_MSB;
hspi4.Init.TIMode = SPI_TIMODE_DISABLE;
hspi4.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
@@ -851,42 +906,6 @@ static void MX_UART8_Init(void)
}
-/**
- * @brief USB_OTG_FS Initialization Function
- * @param None
- * @retval None
- */
-static void MX_USB_OTG_FS_PCD_Init(void)
-{
-
- /* USER CODE BEGIN USB_OTG_FS_Init 0 */
-
- /* USER CODE END USB_OTG_FS_Init 0 */
-
- /* USER CODE BEGIN USB_OTG_FS_Init 1 */
-
- /* USER CODE END USB_OTG_FS_Init 1 */
- hpcd_USB_OTG_FS.Instance = USB_OTG_FS;
- hpcd_USB_OTG_FS.Init.dev_endpoints = 9;
- hpcd_USB_OTG_FS.Init.speed = PCD_SPEED_FULL;
- hpcd_USB_OTG_FS.Init.dma_enable = DISABLE;
- hpcd_USB_OTG_FS.Init.phy_itface = PCD_PHY_EMBEDDED;
- hpcd_USB_OTG_FS.Init.Sof_enable = DISABLE;
- hpcd_USB_OTG_FS.Init.low_power_enable = DISABLE;
- hpcd_USB_OTG_FS.Init.lpm_enable = DISABLE;
- hpcd_USB_OTG_FS.Init.battery_charging_enable = DISABLE;
- hpcd_USB_OTG_FS.Init.vbus_sensing_enable = DISABLE;
- hpcd_USB_OTG_FS.Init.use_dedicated_ep1 = DISABLE;
- if (HAL_PCD_Init(&hpcd_USB_OTG_FS) != HAL_OK)
- {
- Error_Handler();
- }
- /* USER CODE BEGIN USB_OTG_FS_Init 2 */
-
- /* USER CODE END USB_OTG_FS_Init 2 */
-
-}
-
/**
* Enable DMA controller clock
*/
diff --git a/Ganesha_II_V2/Core/Src/stm32h7xx_hal_msp.c b/Ganesha_II_V2/Core/Src/stm32h7xx_hal_msp.c
index ad976d6..3670a88 100644
--- a/Ganesha_II_V2/Core/Src/stm32h7xx_hal_msp.c
+++ b/Ganesha_II_V2/Core/Src/stm32h7xx_hal_msp.c
@@ -622,86 +622,6 @@ void HAL_UART_MspDeInit(UART_HandleTypeDef* huart)
}
-/**
- * @brief PCD MSP Initialization
- * This function configures the hardware resources used in this example
- * @param hpcd: PCD handle pointer
- * @retval None
- */
-void HAL_PCD_MspInit(PCD_HandleTypeDef* hpcd)
-{
- GPIO_InitTypeDef GPIO_InitStruct = {0};
- RCC_PeriphCLKInitTypeDef PeriphClkInitStruct = {0};
- if(hpcd->Instance==USB_OTG_FS)
- {
- /* USER CODE BEGIN USB_OTG_FS_MspInit 0 */
-
- /* USER CODE END USB_OTG_FS_MspInit 0 */
-
- /** Initializes the peripherals clock
- */
- PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_USB;
- PeriphClkInitStruct.UsbClockSelection = RCC_USBCLKSOURCE_PLL;
- if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK)
- {
- Error_Handler();
- }
-
- /** Enable USB Voltage detector
- */
- HAL_PWREx_EnableUSBVoltageDetector();
-
- __HAL_RCC_GPIOA_CLK_ENABLE();
- /**USB_OTG_FS GPIO Configuration
- PA11 ------> USB_OTG_FS_DM
- PA12 ------> USB_OTG_FS_DP
- */
- GPIO_InitStruct.Pin = GPIO_PIN_11|GPIO_PIN_12;
- GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
- GPIO_InitStruct.Pull = GPIO_NOPULL;
- GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
- GPIO_InitStruct.Alternate = GPIO_AF10_OTG1_FS;
- HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
-
- /* Peripheral clock enable */
- __HAL_RCC_USB_OTG_FS_CLK_ENABLE();
- /* USER CODE BEGIN USB_OTG_FS_MspInit 1 */
-
- /* USER CODE END USB_OTG_FS_MspInit 1 */
-
- }
-
-}
-
-/**
- * @brief PCD MSP De-Initialization
- * This function freeze the hardware resources used in this example
- * @param hpcd: PCD handle pointer
- * @retval None
- */
-void HAL_PCD_MspDeInit(PCD_HandleTypeDef* hpcd)
-{
- if(hpcd->Instance==USB_OTG_FS)
- {
- /* USER CODE BEGIN USB_OTG_FS_MspDeInit 0 */
-
- /* USER CODE END USB_OTG_FS_MspDeInit 0 */
- /* Peripheral clock disable */
- __HAL_RCC_USB_OTG_FS_CLK_DISABLE();
-
- /**USB_OTG_FS GPIO Configuration
- PA11 ------> USB_OTG_FS_DM
- PA12 ------> USB_OTG_FS_DP
- */
- HAL_GPIO_DeInit(GPIOA, GPIO_PIN_11|GPIO_PIN_12);
-
- /* USER CODE BEGIN USB_OTG_FS_MspDeInit 1 */
-
- /* USER CODE END USB_OTG_FS_MspDeInit 1 */
- }
-
-}
-
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
diff --git a/Ganesha_II_V2/Core/Src/stm32h7xx_it.c b/Ganesha_II_V2/Core/Src/stm32h7xx_it.c
index d2e8bec..22f2cc3 100644
--- a/Ganesha_II_V2/Core/Src/stm32h7xx_it.c
+++ b/Ganesha_II_V2/Core/Src/stm32h7xx_it.c
@@ -56,6 +56,7 @@
/* USER CODE END 0 */
/* External variables --------------------------------------------------------*/
+extern PCD_HandleTypeDef hpcd_USB_OTG_FS;
extern TIM_HandleTypeDef htim1;
extern DMA_HandleTypeDef hdma_uart8_rx;
extern UART_HandleTypeDef huart5;
@@ -285,6 +286,20 @@ void UART5_IRQHandler(void)
/* USER CODE END UART5_IRQn 1 */
}
+/**
+ * @brief This function handles USB On The Go FS global interrupt.
+ */
+void OTG_FS_IRQHandler(void)
+{
+ /* USER CODE BEGIN OTG_FS_IRQn 0 */
+
+ /* USER CODE END OTG_FS_IRQn 0 */
+ HAL_PCD_IRQHandler(&hpcd_USB_OTG_FS);
+ /* USER CODE BEGIN OTG_FS_IRQn 1 */
+
+ /* USER CODE END OTG_FS_IRQn 1 */
+}
+
/* USER CODE BEGIN 1 */
//extern UART_HandleTypeDef huart8;
/**
diff --git a/Ganesha_II_V2/Ganesha_II_V2.ioc b/Ganesha_II_V2/Ganesha_II_V2.ioc
index 05f4f94..a45298c 100644
--- a/Ganesha_II_V2/Ganesha_II_V2.ioc
+++ b/Ganesha_II_V2/Ganesha_II_V2.ioc
@@ -29,6 +29,7 @@ I2C2.Timing=0x00707CBB
KeepUserPlacement=false
MMTAppRegionsCount=0
MMTConfigApplied=false
+MMTSectionSuffix=_Section
Mcu.CPN=STM32H743VIT6
Mcu.Family=STM32H7
Mcu.IP0=CORTEX_M7
@@ -39,7 +40,8 @@ Mcu.IP12=TIM1
Mcu.IP13=TIM2
Mcu.IP14=UART5
Mcu.IP15=UART8
-Mcu.IP16=USB_OTG_FS
+Mcu.IP16=USB_DEVICE
+Mcu.IP17=USB_OTG_FS
Mcu.IP2=DEBUG
Mcu.IP3=DMA
Mcu.IP4=I2C2
@@ -48,7 +50,7 @@ Mcu.IP6=NVIC
Mcu.IP7=RCC
Mcu.IP8=SPI1
Mcu.IP9=SPI2
-Mcu.IPNb=17
+Mcu.IPNb=18
Mcu.Name=STM32H743VITx
Mcu.Package=LQFP100
Mcu.Pin0=PE2
@@ -92,15 +94,15 @@ Mcu.Pin42=VP_CRC_VS_CRC
Mcu.Pin43=VP_SYS_VS_Systick
Mcu.Pin44=VP_TIM1_VS_ClockSourceINT
Mcu.Pin45=VP_TIM2_VS_ClockSourceINT
-Mcu.Pin46=VP_MEMORYMAP_VS_MEMORYMAP
+Mcu.Pin46=VP_USB_DEVICE_VS_USB_DEVICE_CDC_FS
+Mcu.Pin47=VP_MEMORYMAP_VS_MEMORYMAP
Mcu.Pin5=PH1-OSC_OUT (PH1)
Mcu.Pin6=PC1
Mcu.Pin7=PC2_C
Mcu.Pin8=PA0
Mcu.Pin9=PA1
-Mcu.PinsNb=47
-Mcu.ThirdParty0=STMicroelectronics.X-CUBE-ALGOBUILD.1.4.0
-Mcu.ThirdPartyNb=1
+Mcu.PinsNb=48
+Mcu.ThirdPartyNb=0
Mcu.UserConstants=
Mcu.UserName=STM32H743VITx
MxCube.Version=6.15.0
@@ -115,6 +117,7 @@ NVIC.ForceEnableDMAVector=true
NVIC.HardFault_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false
NVIC.MemoryManagement_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false
NVIC.NonMaskableInt_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false
+NVIC.OTG_FS_IRQn=true\:0\:0\:false\:false\:true\:false\:true\:true
NVIC.PendSV_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false
NVIC.PriorityGroup=NVIC_PRIORITYGROUP_4
NVIC.SVCall_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false
@@ -251,6 +254,7 @@ ProjectManager.DeletePrevious=true
ProjectManager.DeviceId=STM32H743VITx
ProjectManager.FirmwarePackage=STM32Cube FW_H7 V1.12.1
ProjectManager.FreePins=false
+ProjectManager.FreePinsContext=
ProjectManager.HalAssertFull=false
ProjectManager.HeapSize=0x200
ProjectManager.KeepUserCode=true
@@ -265,12 +269,12 @@ ProjectManager.ProjectName=Ganesha_II_V2
ProjectManager.ProjectStructure=
ProjectManager.RegisterCallBack=
ProjectManager.StackSize=0x400
-ProjectManager.TargetToolchain=STM32CubeIDE
+ProjectManager.TargetToolchain=Makefile
ProjectManager.ToolChainLocation=
ProjectManager.UAScriptAfterPath=
ProjectManager.UAScriptBeforePath=
-ProjectManager.UnderRoot=true
-ProjectManager.functionlistsort=1-SystemClock_Config-RCC-false-HAL-false,2-MX_GPIO_Init-GPIO-false-HAL-true,3-MX_DMA_Init-DMA-false-HAL-true,4-MX_I2C2_Init-I2C2-false-HAL-true,5-MX_SPI1_Init-SPI1-false-HAL-true,6-MX_SPI4_Init-SPI4-false-HAL-true,7-MX_UART5_Init-UART5-false-HAL-true,8-MX_UART8_Init-UART8-false-HAL-true,9-MX_USB_OTG_FS_PCD_Init-USB_OTG_FS-false-HAL-true,10-MX_SPI2_Init-SPI2-false-HAL-true,11-MX_TIM1_Init-TIM1-false-HAL-true,12-MX_CRC_Init-CRC-false-HAL-true,13-MX_TIM2_Init-TIM2-false-HAL-true,0-MX_CORTEX_M7_Init-CORTEX_M7-false-HAL-true
+ProjectManager.UnderRoot=false
+ProjectManager.functionlistsort=1-SystemClock_Config-RCC-false-HAL-false,2-MX_GPIO_Init-GPIO-false-HAL-true,3-MX_DMA_Init-DMA-false-HAL-true,4-MX_I2C2_Init-I2C2-false-HAL-true,5-MX_SPI1_Init-SPI1-false-HAL-true,6-MX_SPI4_Init-SPI4-false-HAL-true,7-MX_UART5_Init-UART5-false-HAL-true,8-MX_UART8_Init-UART8-false-HAL-true,9-MX_SPI2_Init-SPI2-false-HAL-true,10-MX_TIM1_Init-TIM1-false-HAL-true,11-MX_CRC_Init-CRC-false-HAL-true,12-MX_TIM2_Init-TIM2-false-HAL-true,13-MX_USB_DEVICE_Init-USB_DEVICE-false-HAL-false,0-MX_CORTEX_M7_Init-CORTEX_M7-false-HAL-true
RCC.ADCFreq_Value=50390625
RCC.AHB12Freq_Value=64000000
RCC.AHB4Freq_Value=64000000
@@ -367,13 +371,13 @@ SPI2.Direction=SPI_DIRECTION_2LINES
SPI2.IPParameters=VirtualType,Mode,Direction,CalculateBaudRate,DataSize,BaudRatePrescaler
SPI2.Mode=SPI_MODE_MASTER
SPI2.VirtualType=VM_MASTER
-SPI4.CalculateBaudRate=2.0 MBits/s
+SPI4.BaudRatePrescaler=SPI_BAUDRATEPRESCALER_16
+SPI4.CalculateBaudRate=250.0 KBits/s
+SPI4.DataSize=SPI_DATASIZE_8BIT
SPI4.Direction=SPI_DIRECTION_2LINES
-SPI4.IPParameters=VirtualType,Mode,Direction,CalculateBaudRate
+SPI4.IPParameters=VirtualType,Mode,Direction,CalculateBaudRate,DataSize,BaudRatePrescaler
SPI4.Mode=SPI_MODE_MASTER
SPI4.VirtualType=VM_MASTER
-STMicroelectronics.X-CUBE-ALGOBUILD.1.4.0.DSPOoLibraryJjLibrary_Checked=false
-STMicroelectronics.X-CUBE-ALGOBUILD.1.4.0_SwParameter=LibraryCcDSPOoLibraryJjDSPOoLibrary\:true;
TIM1.ClockDivision=TIM_CLOCKDIVISION_DIV2
TIM1.IPParameters=Period,Prescaler,ClockDivision
TIM1.Period=65535
@@ -386,6 +390,10 @@ UART5.Parity=PARITY_NONE
UART5.WordLength=WORDLENGTH_8B
UART8.BaudRate=9600
UART8.IPParameters=BaudRate
+USB_DEVICE.CLASS_NAME_FS=CDC
+USB_DEVICE.IPParameters=VirtualMode-CDC_FS,VirtualModeFS,CLASS_NAME_FS
+USB_DEVICE.VirtualMode-CDC_FS=Cdc
+USB_DEVICE.VirtualModeFS=Cdc_FS
USB_OTG_FS.IPParameters=VirtualMode
USB_OTG_FS.VirtualMode=Device_Only
VP_CRC_VS_CRC.Mode=CRC_Activate
@@ -398,5 +406,6 @@ VP_TIM1_VS_ClockSourceINT.Mode=Internal
VP_TIM1_VS_ClockSourceINT.Signal=TIM1_VS_ClockSourceINT
VP_TIM2_VS_ClockSourceINT.Mode=Internal
VP_TIM2_VS_ClockSourceINT.Signal=TIM2_VS_ClockSourceINT
+VP_USB_DEVICE_VS_USB_DEVICE_CDC_FS.Mode=CDC_FS
+VP_USB_DEVICE_VS_USB_DEVICE_CDC_FS.Signal=USB_DEVICE_VS_USB_DEVICE_CDC_FS
board=custom
-isbadioc=false
diff --git a/Ganesha_II_V2/Makefile b/Ganesha_II_V2/Makefile
new file mode 100644
index 0000000..2c8cef1
--- /dev/null
+++ b/Ganesha_II_V2/Makefile
@@ -0,0 +1,245 @@
+##########################################################################################################################
+# File automatically-generated by tool: [projectgenerator] version: [4.9.0-B19] date: [Thu May 28 23:20:53 GMT 2026]
+##########################################################################################################################
+
+# ------------------------------------------------
+# Generic Makefile (based on gcc)
+#
+# ChangeLog :
+# 2017-02-10 - Several enhancements + project update mode
+# 2015-07-22 - first version
+# ------------------------------------------------
+
+######################################
+# target
+######################################
+TARGET = Ganesha_II_V2
+
+
+######################################
+# building variables
+######################################
+# debug build?
+DEBUG = 1
+# optimization
+OPT = -O0
+
+
+#######################################
+# paths
+#######################################
+# Build path
+BUILD_DIR = build
+
+######################################
+# source
+######################################
+# C sources
+C_SOURCES = \
+Core/Src/flash/flash.c \
+Core/Src/flash/gd5f1gq5xe.c \
+Core/Src/flash/w25n01kv.c \
+Core/Src/littlefs/lfs.c \
+Core/Src/littlefs/lfs_util.c \
+Core/Src/orientation_estimator.c \
+Core/Src/main.c \
+Core/Src/CD-PA1616S.c \
+Core/Src/bmi08a.c \
+Core/Src/bmi08g.c \
+Core/Src/bmi08xa.c \
+Core/Src/bmi088.c \
+Core/Src/bmp5.c \
+Core/Src/bmp581.c \
+Core/Src/dumb_timer.c \
+Core/Src/us_timer.c \
+Core/Src/stm32h7xx_it.c \
+Core/Src/stm32h7xx_hal_msp.c \
+Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_cortex.c \
+Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_crc.c \
+Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_crc_ex.c \
+Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_rcc.c \
+Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_rcc_ex.c \
+Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_flash.c \
+Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_flash_ex.c \
+Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_gpio.c \
+Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_hsem.c \
+Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_dma.c \
+Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_dma_ex.c \
+Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_mdma.c \
+Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_pwr.c \
+Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_pwr_ex.c \
+Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal.c \
+Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_i2c.c \
+Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_i2c_ex.c \
+Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_exti.c \
+Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_spi.c \
+Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_spi_ex.c \
+Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_tim.c \
+Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_tim_ex.c \
+Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_uart.c \
+Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_uart_ex.c \
+Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_pcd.c \
+Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_pcd_ex.c \
+Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_ll_usb.c \
+Core/Src/system_stm32h7xx.c \
+Core/Src/sysmem.c \
+Core/Src/syscalls.c \
+USB_DEVICE/App/usbd_cdc_if.c \
+USB_DEVICE/App/usbd_desc.c \
+USB_DEVICE/App/usb_device.c \
+Middlewares/ST/STM32_USB_Device_Library/Core/Src/usbd_core.c \
+Middlewares/ST/STM32_USB_Device_Library/Core/Src/usbd_ctlreq.c \
+Middlewares/ST/STM32_USB_Device_Library/Core/Src/usbd_ioreq.c \
+USB_DEVICE/Target/usbd_conf.c \
+Middlewares/ST/STM32_USB_Device_Library/Class/CDC/Src/usbd_cdc.c
+
+# ASM sources
+ASM_SOURCES = \
+startup_stm32h743xx.s
+
+# ASMM sources
+ASMM_SOURCES =
+
+# ASMMC sources
+ASMMC_SOURCE =
+
+
+#######################################
+# binaries
+#######################################
+PREFIX = arm-none-eabi-
+# The gcc compiler bin path can be either defined in make command via GCC_PATH variable (> make GCC_PATH=xxx)
+# either it can be added to the PATH environment variable.
+ifdef GCC_PATH
+CC = $(GCC_PATH)/$(PREFIX)gcc
+AS = $(GCC_PATH)/$(PREFIX)gcc -x assembler-with-cpp
+CP = $(GCC_PATH)/$(PREFIX)objcopy
+SZ = $(GCC_PATH)/$(PREFIX)size
+else
+CC = $(PREFIX)gcc
+AS = $(PREFIX)gcc -x assembler-with-cpp
+CP = $(PREFIX)objcopy
+SZ = $(PREFIX)size
+endif
+HEX = $(CP) -O ihex
+BIN = $(CP) -O binary -S
+
+#######################################
+# CFLAGS
+#######################################
+# cpu
+CPU = -mcpu=cortex-m7
+
+# fpu
+FPU = -mfpu=fpv5-d16
+
+# float-abi
+FLOAT-ABI = -mfloat-abi=hard
+
+# mcu
+MCU = $(CPU) -mthumb $(FPU) $(FLOAT-ABI)
+
+# macros for gcc
+# AS defines
+AS_DEFS =
+
+# C defines
+C_DEFS = \
+-DUSE_PWR_LDO_SUPPLY \
+-DUSE_HAL_DRIVER \
+-DSTM32H743xx
+
+
+# AS includes
+AS_INCLUDES =
+
+# C includes
+C_INCLUDES = \
+-ICore/Inc \
+-ICore/Inc/flash \
+-ICore/Inc/littlefs \
+-IDrivers/STM32H7xx_HAL_Driver/Inc \
+-IDrivers/STM32H7xx_HAL_Driver/Inc/Legacy \
+-IDrivers/CMSIS/Device/ST/STM32H7xx/Include \
+-IDrivers/CMSIS/Include \
+-IUSB_DEVICE/App \
+-IUSB_DEVICE/Target \
+-IMiddlewares/ST/STM32_USB_Device_Library/Core/Inc \
+-IMiddlewares/ST/STM32_USB_Device_Library/Class/CDC/Inc
+
+# compile gcc flags
+ASFLAGS = $(MCU) $(AS_DEFS) $(AS_INCLUDES) $(OPT) -Wall -fdata-sections -ffunction-sections
+
+CFLAGS += $(MCU) $(C_DEFS) $(C_INCLUDES) $(OPT) -Wall -fdata-sections -ffunction-sections
+
+ifeq ($(DEBUG), 1)
+CFLAGS += -g -gdwarf-2
+endif
+
+
+# Generate dependency information
+CFLAGS += -MMD -MP -MF"$(@:%.o=%.d)"
+
+
+#######################################
+# LDFLAGS
+#######################################
+# link script
+LDSCRIPT = STM32H743XX_FLASH.ld
+
+# libraries
+LIBS = -lc -lm -lnosys
+LIBDIR =
+LDFLAGS = $(MCU) -specs=nano.specs -T$(LDSCRIPT) $(LIBDIR) $(LIBS) -Wl,-Map=$(BUILD_DIR)/$(TARGET).map,--cref -Wl,--gc-sections
+
+# default action: build all
+all: $(BUILD_DIR)/$(TARGET).elf $(BUILD_DIR)/$(TARGET).hex $(BUILD_DIR)/$(TARGET).bin
+
+
+#######################################
+# build the application
+#######################################
+# list of objects
+OBJECTS = $(addprefix $(BUILD_DIR)/,$(notdir $(C_SOURCES:.c=.o)))
+vpath %.c $(sort $(dir $(C_SOURCES)))
+# list of ASM program objects
+OBJECTS += $(addprefix $(BUILD_DIR)/,$(notdir $(ASM_SOURCES:.s=.o)))
+vpath %.s $(sort $(dir $(ASM_SOURCES)))
+OBJECTS += $(addprefix $(BUILD_DIR)/,$(notdir $(ASMM_SOURCES:.S=.o)))
+vpath %.S $(sort $(dir $(ASMM_SOURCES)))
+OBJECTS += $(addprefix $(BUILD_DIR)/,$(notdir $(ASMMC_SOURCES:.c=.o)))
+vpath %.S $(sort $(dir $(ASMMC_SOURCES)))
+
+$(BUILD_DIR)/%.o: %.c Makefile | $(BUILD_DIR)
+ $(CC) -c $(CFLAGS) -Wa,-a,-ad,-alms=$(BUILD_DIR)/$(notdir $(<:.c=.lst)) $< -o $@
+
+$(BUILD_DIR)/%.o: %.s Makefile | $(BUILD_DIR)
+ $(AS) -c $(CFLAGS) $< -o $@
+$(BUILD_DIR)/%.o: %.S Makefile | $(BUILD_DIR)
+ $(AS) -c $(CFLAGS) $< -o $@
+
+$(BUILD_DIR)/$(TARGET).elf: $(OBJECTS) Makefile
+ $(CC) $(OBJECTS) $(LDFLAGS) -o $@
+ $(SZ) $@
+
+$(BUILD_DIR)/%.hex: $(BUILD_DIR)/%.elf | $(BUILD_DIR)
+ $(HEX) $< $@
+
+$(BUILD_DIR)/%.bin: $(BUILD_DIR)/%.elf | $(BUILD_DIR)
+ $(BIN) $< $@
+
+$(BUILD_DIR):
+ mkdir $@
+
+#######################################
+# clean up
+#######################################
+clean:
+ -rm -fR $(BUILD_DIR)
+
+#######################################
+# dependencies
+#######################################
+-include $(wildcard $(BUILD_DIR)/*.d)
+
+# *** EOF ***
diff --git a/Ganesha_II_V2/Middlewares/ST/STM32_USB_Device_Library/Class/CDC/Inc/usbd_cdc.h b/Ganesha_II_V2/Middlewares/ST/STM32_USB_Device_Library/Class/CDC/Inc/usbd_cdc.h
new file mode 100644
index 0000000..aeac6bf
--- /dev/null
+++ b/Ganesha_II_V2/Middlewares/ST/STM32_USB_Device_Library/Class/CDC/Inc/usbd_cdc.h
@@ -0,0 +1,184 @@
+/**
+ ******************************************************************************
+ * @file usbd_cdc.h
+ * @author MCD Application Team
+ * @brief header file for the usbd_cdc.c file.
+ ******************************************************************************
+ * @attention
+ *
+ * Copyright (c) 2015 STMicroelectronics.
+ * All rights reserved.
+ *
+ * This software is licensed under terms that can be found in the LICENSE file
+ * in the root directory of this software component.
+ * If no LICENSE file comes with this software, it is provided AS-IS.
+ *
+ ******************************************************************************
+ */
+
+/* Define to prevent recursive inclusion -------------------------------------*/
+#ifndef __USB_CDC_H
+#define __USB_CDC_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Includes ------------------------------------------------------------------*/
+#include "usbd_ioreq.h"
+
+/** @addtogroup STM32_USB_DEVICE_LIBRARY
+ * @{
+ */
+
+/** @defgroup usbd_cdc
+ * @brief This file is the Header file for usbd_cdc.c
+ * @{
+ */
+
+
+/** @defgroup usbd_cdc_Exported_Defines
+ * @{
+ */
+#ifndef CDC_IN_EP
+#define CDC_IN_EP 0x81U /* EP1 for data IN */
+#endif /* CDC_IN_EP */
+#ifndef CDC_OUT_EP
+#define CDC_OUT_EP 0x01U /* EP1 for data OUT */
+#endif /* CDC_OUT_EP */
+#ifndef CDC_CMD_EP
+#define CDC_CMD_EP 0x82U /* EP2 for CDC commands */
+#endif /* CDC_CMD_EP */
+
+#ifndef CDC_HS_BINTERVAL
+#define CDC_HS_BINTERVAL 0x10U
+#endif /* CDC_HS_BINTERVAL */
+
+#ifndef CDC_FS_BINTERVAL
+#define CDC_FS_BINTERVAL 0x10U
+#endif /* CDC_FS_BINTERVAL */
+
+/* CDC Endpoints parameters: you can fine tune these values depending on the needed baudrates and performance. */
+#define CDC_DATA_HS_MAX_PACKET_SIZE 512U /* Endpoint IN & OUT Packet size */
+#define CDC_DATA_FS_MAX_PACKET_SIZE 64U /* Endpoint IN & OUT Packet size */
+#define CDC_CMD_PACKET_SIZE 8U /* Control Endpoint Packet size */
+
+#define USB_CDC_CONFIG_DESC_SIZ 67U
+#define CDC_DATA_HS_IN_PACKET_SIZE CDC_DATA_HS_MAX_PACKET_SIZE
+#define CDC_DATA_HS_OUT_PACKET_SIZE CDC_DATA_HS_MAX_PACKET_SIZE
+
+#define CDC_DATA_FS_IN_PACKET_SIZE CDC_DATA_FS_MAX_PACKET_SIZE
+#define CDC_DATA_FS_OUT_PACKET_SIZE CDC_DATA_FS_MAX_PACKET_SIZE
+
+#define CDC_REQ_MAX_DATA_SIZE 0x7U
+/*---------------------------------------------------------------------*/
+/* CDC definitions */
+/*---------------------------------------------------------------------*/
+#define CDC_SEND_ENCAPSULATED_COMMAND 0x00U
+#define CDC_GET_ENCAPSULATED_RESPONSE 0x01U
+#define CDC_SET_COMM_FEATURE 0x02U
+#define CDC_GET_COMM_FEATURE 0x03U
+#define CDC_CLEAR_COMM_FEATURE 0x04U
+#define CDC_SET_LINE_CODING 0x20U
+#define CDC_GET_LINE_CODING 0x21U
+#define CDC_SET_CONTROL_LINE_STATE 0x22U
+#define CDC_SEND_BREAK 0x23U
+
+/**
+ * @}
+ */
+
+
+/** @defgroup USBD_CORE_Exported_TypesDefinitions
+ * @{
+ */
+
+/**
+ * @}
+ */
+typedef struct
+{
+ uint32_t bitrate;
+ uint8_t format;
+ uint8_t paritytype;
+ uint8_t datatype;
+} USBD_CDC_LineCodingTypeDef;
+
+typedef struct _USBD_CDC_Itf
+{
+ int8_t (* Init)(void);
+ int8_t (* DeInit)(void);
+ int8_t (* Control)(uint8_t cmd, uint8_t *pbuf, uint16_t length);
+ int8_t (* Receive)(uint8_t *Buf, uint32_t *Len);
+ int8_t (* TransmitCplt)(uint8_t *Buf, uint32_t *Len, uint8_t epnum);
+} USBD_CDC_ItfTypeDef;
+
+
+typedef struct
+{
+ uint32_t data[CDC_DATA_HS_MAX_PACKET_SIZE / 4U]; /* Force 32-bit alignment */
+ uint8_t CmdOpCode;
+ uint8_t CmdLength;
+ uint8_t *RxBuffer;
+ uint8_t *TxBuffer;
+ uint32_t RxLength;
+ uint32_t TxLength;
+
+ __IO uint32_t TxState;
+ __IO uint32_t RxState;
+} USBD_CDC_HandleTypeDef;
+
+
+
+/** @defgroup USBD_CORE_Exported_Macros
+ * @{
+ */
+
+/**
+ * @}
+ */
+
+/** @defgroup USBD_CORE_Exported_Variables
+ * @{
+ */
+
+extern USBD_ClassTypeDef USBD_CDC;
+#define USBD_CDC_CLASS &USBD_CDC
+/**
+ * @}
+ */
+
+/** @defgroup USB_CORE_Exported_Functions
+ * @{
+ */
+uint8_t USBD_CDC_RegisterInterface(USBD_HandleTypeDef *pdev,
+ USBD_CDC_ItfTypeDef *fops);
+
+#ifdef USE_USBD_COMPOSITE
+uint8_t USBD_CDC_SetTxBuffer(USBD_HandleTypeDef *pdev, uint8_t *pbuff,
+ uint32_t length, uint8_t ClassId);
+uint8_t USBD_CDC_TransmitPacket(USBD_HandleTypeDef *pdev, uint8_t ClassId);
+#else
+uint8_t USBD_CDC_SetTxBuffer(USBD_HandleTypeDef *pdev, uint8_t *pbuff,
+ uint32_t length);
+uint8_t USBD_CDC_TransmitPacket(USBD_HandleTypeDef *pdev);
+#endif /* USE_USBD_COMPOSITE */
+uint8_t USBD_CDC_SetRxBuffer(USBD_HandleTypeDef *pdev, uint8_t *pbuff);
+uint8_t USBD_CDC_ReceivePacket(USBD_HandleTypeDef *pdev);
+/**
+ * @}
+ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __USB_CDC_H */
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
diff --git a/Ganesha_II_V2/Middlewares/ST/STM32_USB_Device_Library/Class/CDC/Src/usbd_cdc.c b/Ganesha_II_V2/Middlewares/ST/STM32_USB_Device_Library/Class/CDC/Src/usbd_cdc.c
new file mode 100644
index 0000000..ad8da25
--- /dev/null
+++ b/Ganesha_II_V2/Middlewares/ST/STM32_USB_Device_Library/Class/CDC/Src/usbd_cdc.c
@@ -0,0 +1,893 @@
+/**
+ ******************************************************************************
+ * @file usbd_cdc.c
+ * @author MCD Application Team
+ * @brief This file provides the high layer firmware functions to manage the
+ * following functionalities of the USB CDC Class:
+ * - Initialization and Configuration of high and low layer
+ * - Enumeration as CDC Device (and enumeration for each implemented memory interface)
+ * - OUT/IN data transfer
+ * - Command IN transfer (class requests management)
+ * - Error management
+ *
+ ******************************************************************************
+ * @attention
+ *
+ * Copyright (c) 2015 STMicroelectronics.
+ * All rights reserved.
+ *
+ * This software is licensed under terms that can be found in the LICENSE file
+ * in the root directory of this software component.
+ * If no LICENSE file comes with this software, it is provided AS-IS.
+ *
+ ******************************************************************************
+ * @verbatim
+ *
+ * ===================================================================
+ * CDC Class Driver Description
+ * ===================================================================
+ * This driver manages the "Universal Serial Bus Class Definitions for Communications Devices
+ * Revision 1.2 November 16, 2007" and the sub-protocol specification of "Universal Serial Bus
+ * Communications Class Subclass Specification for PSTN Devices Revision 1.2 February 9, 2007"
+ * This driver implements the following aspects of the specification:
+ * - Device descriptor management
+ * - Configuration descriptor management
+ * - Enumeration as CDC device with 2 data endpoints (IN and OUT) and 1 command endpoint (IN)
+ * - Requests management (as described in section 6.2 in specification)
+ * - Abstract Control Model compliant
+ * - Union Functional collection (using 1 IN endpoint for control)
+ * - Data interface class
+ *
+ * These aspects may be enriched or modified for a specific user application.
+ *
+ * This driver doesn't implement the following aspects of the specification
+ * (but it is possible to manage these features with some modifications on this driver):
+ * - Any class-specific aspect relative to communication classes should be managed by user application.
+ * - All communication classes other than PSTN are not managed
+ *
+ * @endverbatim
+ *
+ ******************************************************************************
+ */
+
+/* BSPDependencies
+- "stm32xxxxx_{eval}{discovery}{nucleo_144}.c"
+- "stm32xxxxx_{eval}{discovery}_io.c"
+EndBSPDependencies */
+
+/* Includes ------------------------------------------------------------------*/
+#include "usbd_cdc.h"
+#include "usbd_ctlreq.h"
+
+
+/** @addtogroup STM32_USB_DEVICE_LIBRARY
+ * @{
+ */
+
+
+/** @defgroup USBD_CDC
+ * @brief usbd core module
+ * @{
+ */
+
+/** @defgroup USBD_CDC_Private_TypesDefinitions
+ * @{
+ */
+/**
+ * @}
+ */
+
+
+/** @defgroup USBD_CDC_Private_Defines
+ * @{
+ */
+/**
+ * @}
+ */
+
+
+/** @defgroup USBD_CDC_Private_Macros
+ * @{
+ */
+
+/**
+ * @}
+ */
+
+
+/** @defgroup USBD_CDC_Private_FunctionPrototypes
+ * @{
+ */
+
+static uint8_t USBD_CDC_Init(USBD_HandleTypeDef *pdev, uint8_t cfgidx);
+static uint8_t USBD_CDC_DeInit(USBD_HandleTypeDef *pdev, uint8_t cfgidx);
+static uint8_t USBD_CDC_Setup(USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req);
+static uint8_t USBD_CDC_DataIn(USBD_HandleTypeDef *pdev, uint8_t epnum);
+static uint8_t USBD_CDC_DataOut(USBD_HandleTypeDef *pdev, uint8_t epnum);
+static uint8_t USBD_CDC_EP0_RxReady(USBD_HandleTypeDef *pdev);
+#ifndef USE_USBD_COMPOSITE
+static uint8_t *USBD_CDC_GetFSCfgDesc(uint16_t *length);
+static uint8_t *USBD_CDC_GetHSCfgDesc(uint16_t *length);
+static uint8_t *USBD_CDC_GetOtherSpeedCfgDesc(uint16_t *length);
+uint8_t *USBD_CDC_GetDeviceQualifierDescriptor(uint16_t *length);
+#endif /* USE_USBD_COMPOSITE */
+
+#ifndef USE_USBD_COMPOSITE
+/* USB Standard Device Descriptor */
+__ALIGN_BEGIN static uint8_t USBD_CDC_DeviceQualifierDesc[USB_LEN_DEV_QUALIFIER_DESC] __ALIGN_END =
+{
+ USB_LEN_DEV_QUALIFIER_DESC,
+ USB_DESC_TYPE_DEVICE_QUALIFIER,
+ 0x00,
+ 0x02,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x40,
+ 0x01,
+ 0x00,
+};
+#endif /* USE_USBD_COMPOSITE */
+/**
+ * @}
+ */
+
+/** @defgroup USBD_CDC_Private_Variables
+ * @{
+ */
+
+
+/* CDC interface class callbacks structure */
+USBD_ClassTypeDef USBD_CDC =
+{
+ USBD_CDC_Init,
+ USBD_CDC_DeInit,
+ USBD_CDC_Setup,
+ NULL, /* EP0_TxSent */
+ USBD_CDC_EP0_RxReady,
+ USBD_CDC_DataIn,
+ USBD_CDC_DataOut,
+ NULL,
+ NULL,
+ NULL,
+#ifdef USE_USBD_COMPOSITE
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+#else
+ USBD_CDC_GetHSCfgDesc,
+ USBD_CDC_GetFSCfgDesc,
+ USBD_CDC_GetOtherSpeedCfgDesc,
+ USBD_CDC_GetDeviceQualifierDescriptor,
+#endif /* USE_USBD_COMPOSITE */
+};
+
+#ifndef USE_USBD_COMPOSITE
+/* USB CDC device Configuration Descriptor */
+__ALIGN_BEGIN static uint8_t USBD_CDC_CfgDesc[USB_CDC_CONFIG_DESC_SIZ] __ALIGN_END =
+{
+ /* Configuration Descriptor */
+ 0x09, /* bLength: Configuration Descriptor size */
+ USB_DESC_TYPE_CONFIGURATION, /* bDescriptorType: Configuration */
+ USB_CDC_CONFIG_DESC_SIZ, /* wTotalLength */
+ 0x00,
+ 0x02, /* bNumInterfaces: 2 interfaces */
+ 0x01, /* bConfigurationValue: Configuration value */
+ 0x00, /* iConfiguration: Index of string descriptor
+ describing the configuration */
+#if (USBD_SELF_POWERED == 1U)
+ 0xC0, /* bmAttributes: Bus Powered according to user configuration */
+#else
+ 0x80, /* bmAttributes: Bus Powered according to user configuration */
+#endif /* USBD_SELF_POWERED */
+ USBD_MAX_POWER, /* MaxPower (mA) */
+
+ /*---------------------------------------------------------------------------*/
+
+ /* Interface Descriptor */
+ 0x09, /* bLength: Interface Descriptor size */
+ USB_DESC_TYPE_INTERFACE, /* bDescriptorType: Interface */
+ /* Interface descriptor type */
+ 0x00, /* bInterfaceNumber: Number of Interface */
+ 0x00, /* bAlternateSetting: Alternate setting */
+ 0x01, /* bNumEndpoints: One endpoint used */
+ 0x02, /* bInterfaceClass: Communication Interface Class */
+ 0x02, /* bInterfaceSubClass: Abstract Control Model */
+ 0x01, /* bInterfaceProtocol: Common AT commands */
+ 0x00, /* iInterface */
+
+ /* Header Functional Descriptor */
+ 0x05, /* bLength: Endpoint Descriptor size */
+ 0x24, /* bDescriptorType: CS_INTERFACE */
+ 0x00, /* bDescriptorSubtype: Header Func Desc */
+ 0x10, /* bcdCDC: spec release number */
+ 0x01,
+
+ /* Call Management Functional Descriptor */
+ 0x05, /* bFunctionLength */
+ 0x24, /* bDescriptorType: CS_INTERFACE */
+ 0x01, /* bDescriptorSubtype: Call Management Func Desc */
+ 0x00, /* bmCapabilities: D0+D1 */
+ 0x01, /* bDataInterface */
+
+ /* ACM Functional Descriptor */
+ 0x04, /* bFunctionLength */
+ 0x24, /* bDescriptorType: CS_INTERFACE */
+ 0x02, /* bDescriptorSubtype: Abstract Control Management desc */
+ 0x02, /* bmCapabilities */
+
+ /* Union Functional Descriptor */
+ 0x05, /* bFunctionLength */
+ 0x24, /* bDescriptorType: CS_INTERFACE */
+ 0x06, /* bDescriptorSubtype: Union func desc */
+ 0x00, /* bMasterInterface: Communication class interface */
+ 0x01, /* bSlaveInterface0: Data Class Interface */
+
+ /* Endpoint 2 Descriptor */
+ 0x07, /* bLength: Endpoint Descriptor size */
+ USB_DESC_TYPE_ENDPOINT, /* bDescriptorType: Endpoint */
+ CDC_CMD_EP, /* bEndpointAddress */
+ 0x03, /* bmAttributes: Interrupt */
+ LOBYTE(CDC_CMD_PACKET_SIZE), /* wMaxPacketSize */
+ HIBYTE(CDC_CMD_PACKET_SIZE),
+ CDC_FS_BINTERVAL, /* bInterval */
+ /*---------------------------------------------------------------------------*/
+
+ /* Data class interface descriptor */
+ 0x09, /* bLength: Endpoint Descriptor size */
+ USB_DESC_TYPE_INTERFACE, /* bDescriptorType: */
+ 0x01, /* bInterfaceNumber: Number of Interface */
+ 0x00, /* bAlternateSetting: Alternate setting */
+ 0x02, /* bNumEndpoints: Two endpoints used */
+ 0x0A, /* bInterfaceClass: CDC */
+ 0x00, /* bInterfaceSubClass */
+ 0x00, /* bInterfaceProtocol */
+ 0x00, /* iInterface */
+
+ /* Endpoint OUT Descriptor */
+ 0x07, /* bLength: Endpoint Descriptor size */
+ USB_DESC_TYPE_ENDPOINT, /* bDescriptorType: Endpoint */
+ CDC_OUT_EP, /* bEndpointAddress */
+ 0x02, /* bmAttributes: Bulk */
+ LOBYTE(CDC_DATA_FS_MAX_PACKET_SIZE), /* wMaxPacketSize */
+ HIBYTE(CDC_DATA_FS_MAX_PACKET_SIZE),
+ 0x00, /* bInterval */
+
+ /* Endpoint IN Descriptor */
+ 0x07, /* bLength: Endpoint Descriptor size */
+ USB_DESC_TYPE_ENDPOINT, /* bDescriptorType: Endpoint */
+ CDC_IN_EP, /* bEndpointAddress */
+ 0x02, /* bmAttributes: Bulk */
+ LOBYTE(CDC_DATA_FS_MAX_PACKET_SIZE), /* wMaxPacketSize */
+ HIBYTE(CDC_DATA_FS_MAX_PACKET_SIZE),
+ 0x00 /* bInterval */
+};
+#endif /* USE_USBD_COMPOSITE */
+
+static uint8_t CDCInEpAdd = CDC_IN_EP;
+static uint8_t CDCOutEpAdd = CDC_OUT_EP;
+static uint8_t CDCCmdEpAdd = CDC_CMD_EP;
+
+/**
+ * @}
+ */
+
+/** @defgroup USBD_CDC_Private_Functions
+ * @{
+ */
+
+/**
+ * @brief USBD_CDC_Init
+ * Initialize the CDC interface
+ * @param pdev: device instance
+ * @param cfgidx: Configuration index
+ * @retval status
+ */
+static uint8_t USBD_CDC_Init(USBD_HandleTypeDef *pdev, uint8_t cfgidx)
+{
+ UNUSED(cfgidx);
+ USBD_CDC_HandleTypeDef *hcdc;
+
+ hcdc = (USBD_CDC_HandleTypeDef *)USBD_malloc(sizeof(USBD_CDC_HandleTypeDef));
+
+ if (hcdc == NULL)
+ {
+ pdev->pClassDataCmsit[pdev->classId] = NULL;
+ return (uint8_t)USBD_EMEM;
+ }
+
+ (void)USBD_memset(hcdc, 0, sizeof(USBD_CDC_HandleTypeDef));
+
+ pdev->pClassDataCmsit[pdev->classId] = (void *)hcdc;
+ pdev->pClassData = pdev->pClassDataCmsit[pdev->classId];
+
+#ifdef USE_USBD_COMPOSITE
+ /* Get the Endpoints addresses allocated for this class instance */
+ CDCInEpAdd = USBD_CoreGetEPAdd(pdev, USBD_EP_IN, USBD_EP_TYPE_BULK, (uint8_t)pdev->classId);
+ CDCOutEpAdd = USBD_CoreGetEPAdd(pdev, USBD_EP_OUT, USBD_EP_TYPE_BULK, (uint8_t)pdev->classId);
+ CDCCmdEpAdd = USBD_CoreGetEPAdd(pdev, USBD_EP_IN, USBD_EP_TYPE_INTR, (uint8_t)pdev->classId);
+#endif /* USE_USBD_COMPOSITE */
+
+ if (pdev->dev_speed == USBD_SPEED_HIGH)
+ {
+ /* Open EP IN */
+ (void)USBD_LL_OpenEP(pdev, CDCInEpAdd, USBD_EP_TYPE_BULK,
+ CDC_DATA_HS_IN_PACKET_SIZE);
+
+ pdev->ep_in[CDCInEpAdd & 0xFU].is_used = 1U;
+
+ /* Open EP OUT */
+ (void)USBD_LL_OpenEP(pdev, CDCOutEpAdd, USBD_EP_TYPE_BULK,
+ CDC_DATA_HS_OUT_PACKET_SIZE);
+
+ pdev->ep_out[CDCOutEpAdd & 0xFU].is_used = 1U;
+
+ /* Set bInterval for CDC CMD Endpoint */
+ pdev->ep_in[CDCCmdEpAdd & 0xFU].bInterval = CDC_HS_BINTERVAL;
+ }
+ else
+ {
+ /* Open EP IN */
+ (void)USBD_LL_OpenEP(pdev, CDCInEpAdd, USBD_EP_TYPE_BULK,
+ CDC_DATA_FS_IN_PACKET_SIZE);
+
+ pdev->ep_in[CDCInEpAdd & 0xFU].is_used = 1U;
+
+ /* Open EP OUT */
+ (void)USBD_LL_OpenEP(pdev, CDCOutEpAdd, USBD_EP_TYPE_BULK,
+ CDC_DATA_FS_OUT_PACKET_SIZE);
+
+ pdev->ep_out[CDCOutEpAdd & 0xFU].is_used = 1U;
+
+ /* Set bInterval for CMD Endpoint */
+ pdev->ep_in[CDCCmdEpAdd & 0xFU].bInterval = CDC_FS_BINTERVAL;
+ }
+
+ /* Open Command IN EP */
+ (void)USBD_LL_OpenEP(pdev, CDCCmdEpAdd, USBD_EP_TYPE_INTR, CDC_CMD_PACKET_SIZE);
+ pdev->ep_in[CDCCmdEpAdd & 0xFU].is_used = 1U;
+
+ hcdc->RxBuffer = NULL;
+
+ /* Init physical Interface components */
+ ((USBD_CDC_ItfTypeDef *)pdev->pUserData[pdev->classId])->Init();
+
+ /* Init Xfer states */
+ hcdc->TxState = 0U;
+ hcdc->RxState = 0U;
+
+ if (hcdc->RxBuffer == NULL)
+ {
+ return (uint8_t)USBD_EMEM;
+ }
+
+ if (pdev->dev_speed == USBD_SPEED_HIGH)
+ {
+ /* Prepare Out endpoint to receive next packet */
+ (void)USBD_LL_PrepareReceive(pdev, CDCOutEpAdd, hcdc->RxBuffer,
+ CDC_DATA_HS_OUT_PACKET_SIZE);
+ }
+ else
+ {
+ /* Prepare Out endpoint to receive next packet */
+ (void)USBD_LL_PrepareReceive(pdev, CDCOutEpAdd, hcdc->RxBuffer,
+ CDC_DATA_FS_OUT_PACKET_SIZE);
+ }
+
+ return (uint8_t)USBD_OK;
+}
+
+/**
+ * @brief USBD_CDC_Init
+ * DeInitialize the CDC layer
+ * @param pdev: device instance
+ * @param cfgidx: Configuration index
+ * @retval status
+ */
+static uint8_t USBD_CDC_DeInit(USBD_HandleTypeDef *pdev, uint8_t cfgidx)
+{
+ UNUSED(cfgidx);
+
+
+#ifdef USE_USBD_COMPOSITE
+ /* Get the Endpoints addresses allocated for this CDC class instance */
+ CDCInEpAdd = USBD_CoreGetEPAdd(pdev, USBD_EP_IN, USBD_EP_TYPE_BULK, (uint8_t)pdev->classId);
+ CDCOutEpAdd = USBD_CoreGetEPAdd(pdev, USBD_EP_OUT, USBD_EP_TYPE_BULK, (uint8_t)pdev->classId);
+ CDCCmdEpAdd = USBD_CoreGetEPAdd(pdev, USBD_EP_IN, USBD_EP_TYPE_INTR, (uint8_t)pdev->classId);
+#endif /* USE_USBD_COMPOSITE */
+
+ /* Close EP IN */
+ (void)USBD_LL_CloseEP(pdev, CDCInEpAdd);
+ pdev->ep_in[CDCInEpAdd & 0xFU].is_used = 0U;
+
+ /* Close EP OUT */
+ (void)USBD_LL_CloseEP(pdev, CDCOutEpAdd);
+ pdev->ep_out[CDCOutEpAdd & 0xFU].is_used = 0U;
+
+ /* Close Command IN EP */
+ (void)USBD_LL_CloseEP(pdev, CDCCmdEpAdd);
+ pdev->ep_in[CDCCmdEpAdd & 0xFU].is_used = 0U;
+ pdev->ep_in[CDCCmdEpAdd & 0xFU].bInterval = 0U;
+
+ /* DeInit physical Interface components */
+ if (pdev->pClassDataCmsit[pdev->classId] != NULL)
+ {
+ ((USBD_CDC_ItfTypeDef *)pdev->pUserData[pdev->classId])->DeInit();
+ (void)USBD_free(pdev->pClassDataCmsit[pdev->classId]);
+ pdev->pClassDataCmsit[pdev->classId] = NULL;
+ pdev->pClassData = NULL;
+ }
+
+ return (uint8_t)USBD_OK;
+}
+
+/**
+ * @brief USBD_CDC_Setup
+ * Handle the CDC specific requests
+ * @param pdev: instance
+ * @param req: usb requests
+ * @retval status
+ */
+static uint8_t USBD_CDC_Setup(USBD_HandleTypeDef *pdev,
+ USBD_SetupReqTypedef *req)
+{
+ USBD_CDC_HandleTypeDef *hcdc = (USBD_CDC_HandleTypeDef *)pdev->pClassDataCmsit[pdev->classId];
+ uint16_t len;
+ uint8_t ifalt = 0U;
+ uint16_t status_info = 0U;
+ USBD_StatusTypeDef ret = USBD_OK;
+
+ if (hcdc == NULL)
+ {
+ return (uint8_t)USBD_FAIL;
+ }
+
+ switch (req->bmRequest & USB_REQ_TYPE_MASK)
+ {
+ case USB_REQ_TYPE_CLASS:
+ if (req->wLength != 0U)
+ {
+ if ((req->bmRequest & 0x80U) != 0U)
+ {
+ ((USBD_CDC_ItfTypeDef *)pdev->pUserData[pdev->classId])->Control(req->bRequest,
+ (uint8_t *)hcdc->data,
+ req->wLength);
+
+ len = MIN(CDC_REQ_MAX_DATA_SIZE, req->wLength);
+ (void)USBD_CtlSendData(pdev, (uint8_t *)hcdc->data, len);
+ }
+ else
+ {
+ hcdc->CmdOpCode = req->bRequest;
+ hcdc->CmdLength = (uint8_t)MIN(req->wLength, USB_MAX_EP0_SIZE);
+
+ (void)USBD_CtlPrepareRx(pdev, (uint8_t *)hcdc->data, hcdc->CmdLength);
+ }
+ }
+ else
+ {
+ ((USBD_CDC_ItfTypeDef *)pdev->pUserData[pdev->classId])->Control(req->bRequest,
+ (uint8_t *)req, 0U);
+ }
+ break;
+
+ case USB_REQ_TYPE_STANDARD:
+ switch (req->bRequest)
+ {
+ case USB_REQ_GET_STATUS:
+ if (pdev->dev_state == USBD_STATE_CONFIGURED)
+ {
+ (void)USBD_CtlSendData(pdev, (uint8_t *)&status_info, 2U);
+ }
+ else
+ {
+ USBD_CtlError(pdev, req);
+ ret = USBD_FAIL;
+ }
+ break;
+
+ case USB_REQ_GET_INTERFACE:
+ if (pdev->dev_state == USBD_STATE_CONFIGURED)
+ {
+ (void)USBD_CtlSendData(pdev, &ifalt, 1U);
+ }
+ else
+ {
+ USBD_CtlError(pdev, req);
+ ret = USBD_FAIL;
+ }
+ break;
+
+ case USB_REQ_SET_INTERFACE:
+ if (pdev->dev_state != USBD_STATE_CONFIGURED)
+ {
+ USBD_CtlError(pdev, req);
+ ret = USBD_FAIL;
+ }
+ break;
+
+ case USB_REQ_CLEAR_FEATURE:
+ break;
+
+ default:
+ USBD_CtlError(pdev, req);
+ ret = USBD_FAIL;
+ break;
+ }
+ break;
+
+ default:
+ USBD_CtlError(pdev, req);
+ ret = USBD_FAIL;
+ break;
+ }
+
+ return (uint8_t)ret;
+}
+
+/**
+ * @brief USBD_CDC_DataIn
+ * Data sent on non-control IN endpoint
+ * @param pdev: device instance
+ * @param epnum: endpoint number
+ * @retval status
+ */
+static uint8_t USBD_CDC_DataIn(USBD_HandleTypeDef *pdev, uint8_t epnum)
+{
+ USBD_CDC_HandleTypeDef *hcdc;
+ PCD_HandleTypeDef *hpcd = (PCD_HandleTypeDef *)pdev->pData;
+
+ if (pdev->pClassDataCmsit[pdev->classId] == NULL)
+ {
+ return (uint8_t)USBD_FAIL;
+ }
+
+ hcdc = (USBD_CDC_HandleTypeDef *)pdev->pClassDataCmsit[pdev->classId];
+
+ if ((pdev->ep_in[epnum & 0xFU].total_length > 0U) &&
+ ((pdev->ep_in[epnum & 0xFU].total_length % hpcd->IN_ep[epnum & 0xFU].maxpacket) == 0U))
+ {
+ /* Update the packet total length */
+ pdev->ep_in[epnum & 0xFU].total_length = 0U;
+
+ /* Send ZLP */
+ (void)USBD_LL_Transmit(pdev, epnum, NULL, 0U);
+ }
+ else
+ {
+ hcdc->TxState = 0U;
+
+ if (((USBD_CDC_ItfTypeDef *)pdev->pUserData[pdev->classId])->TransmitCplt != NULL)
+ {
+ ((USBD_CDC_ItfTypeDef *)pdev->pUserData[pdev->classId])->TransmitCplt(hcdc->TxBuffer, &hcdc->TxLength, epnum);
+ }
+ }
+
+ return (uint8_t)USBD_OK;
+}
+
+/**
+ * @brief USBD_CDC_DataOut
+ * Data received on non-control Out endpoint
+ * @param pdev: device instance
+ * @param epnum: endpoint number
+ * @retval status
+ */
+static uint8_t USBD_CDC_DataOut(USBD_HandleTypeDef *pdev, uint8_t epnum)
+{
+ USBD_CDC_HandleTypeDef *hcdc = (USBD_CDC_HandleTypeDef *)pdev->pClassDataCmsit[pdev->classId];
+
+ if (pdev->pClassDataCmsit[pdev->classId] == NULL)
+ {
+ return (uint8_t)USBD_FAIL;
+ }
+
+ /* Get the received data length */
+ hcdc->RxLength = USBD_LL_GetRxDataSize(pdev, epnum);
+
+ /* USB data will be immediately processed, this allow next USB traffic being
+ NAKed till the end of the application Xfer */
+
+ ((USBD_CDC_ItfTypeDef *)pdev->pUserData[pdev->classId])->Receive(hcdc->RxBuffer, &hcdc->RxLength);
+
+ return (uint8_t)USBD_OK;
+}
+
+/**
+ * @brief USBD_CDC_EP0_RxReady
+ * Handle EP0 Rx Ready event
+ * @param pdev: device instance
+ * @retval status
+ */
+static uint8_t USBD_CDC_EP0_RxReady(USBD_HandleTypeDef *pdev)
+{
+ USBD_CDC_HandleTypeDef *hcdc = (USBD_CDC_HandleTypeDef *)pdev->pClassDataCmsit[pdev->classId];
+
+ if (hcdc == NULL)
+ {
+ return (uint8_t)USBD_FAIL;
+ }
+
+ if ((pdev->pUserData[pdev->classId] != NULL) && (hcdc->CmdOpCode != 0xFFU))
+ {
+ ((USBD_CDC_ItfTypeDef *)pdev->pUserData[pdev->classId])->Control(hcdc->CmdOpCode,
+ (uint8_t *)hcdc->data,
+ (uint16_t)hcdc->CmdLength);
+ hcdc->CmdOpCode = 0xFFU;
+ }
+
+ return (uint8_t)USBD_OK;
+}
+#ifndef USE_USBD_COMPOSITE
+/**
+ * @brief USBD_CDC_GetFSCfgDesc
+ * Return configuration descriptor
+ * @param length : pointer data length
+ * @retval pointer to descriptor buffer
+ */
+static uint8_t *USBD_CDC_GetFSCfgDesc(uint16_t *length)
+{
+ USBD_EpDescTypeDef *pEpCmdDesc = USBD_GetEpDesc(USBD_CDC_CfgDesc, CDC_CMD_EP);
+ USBD_EpDescTypeDef *pEpOutDesc = USBD_GetEpDesc(USBD_CDC_CfgDesc, CDC_OUT_EP);
+ USBD_EpDescTypeDef *pEpInDesc = USBD_GetEpDesc(USBD_CDC_CfgDesc, CDC_IN_EP);
+
+ if (pEpCmdDesc != NULL)
+ {
+ pEpCmdDesc->bInterval = CDC_FS_BINTERVAL;
+ }
+
+ if (pEpOutDesc != NULL)
+ {
+ pEpOutDesc->wMaxPacketSize = CDC_DATA_FS_MAX_PACKET_SIZE;
+ }
+
+ if (pEpInDesc != NULL)
+ {
+ pEpInDesc->wMaxPacketSize = CDC_DATA_FS_MAX_PACKET_SIZE;
+ }
+
+ *length = (uint16_t)sizeof(USBD_CDC_CfgDesc);
+ return USBD_CDC_CfgDesc;
+}
+
+/**
+ * @brief USBD_CDC_GetHSCfgDesc
+ * Return configuration descriptor
+ * @param length : pointer data length
+ * @retval pointer to descriptor buffer
+ */
+static uint8_t *USBD_CDC_GetHSCfgDesc(uint16_t *length)
+{
+ USBD_EpDescTypeDef *pEpCmdDesc = USBD_GetEpDesc(USBD_CDC_CfgDesc, CDC_CMD_EP);
+ USBD_EpDescTypeDef *pEpOutDesc = USBD_GetEpDesc(USBD_CDC_CfgDesc, CDC_OUT_EP);
+ USBD_EpDescTypeDef *pEpInDesc = USBD_GetEpDesc(USBD_CDC_CfgDesc, CDC_IN_EP);
+
+ if (pEpCmdDesc != NULL)
+ {
+ pEpCmdDesc->bInterval = CDC_HS_BINTERVAL;
+ }
+
+ if (pEpOutDesc != NULL)
+ {
+ pEpOutDesc->wMaxPacketSize = CDC_DATA_HS_MAX_PACKET_SIZE;
+ }
+
+ if (pEpInDesc != NULL)
+ {
+ pEpInDesc->wMaxPacketSize = CDC_DATA_HS_MAX_PACKET_SIZE;
+ }
+
+ *length = (uint16_t)sizeof(USBD_CDC_CfgDesc);
+ return USBD_CDC_CfgDesc;
+}
+
+/**
+ * @brief USBD_CDC_GetOtherSpeedCfgDesc
+ * Return configuration descriptor
+ * @param length : pointer data length
+ * @retval pointer to descriptor buffer
+ */
+static uint8_t *USBD_CDC_GetOtherSpeedCfgDesc(uint16_t *length)
+{
+ USBD_EpDescTypeDef *pEpCmdDesc = USBD_GetEpDesc(USBD_CDC_CfgDesc, CDC_CMD_EP);
+ USBD_EpDescTypeDef *pEpOutDesc = USBD_GetEpDesc(USBD_CDC_CfgDesc, CDC_OUT_EP);
+ USBD_EpDescTypeDef *pEpInDesc = USBD_GetEpDesc(USBD_CDC_CfgDesc, CDC_IN_EP);
+
+ if (pEpCmdDesc != NULL)
+ {
+ pEpCmdDesc->bInterval = CDC_FS_BINTERVAL;
+ }
+
+ if (pEpOutDesc != NULL)
+ {
+ pEpOutDesc->wMaxPacketSize = CDC_DATA_FS_MAX_PACKET_SIZE;
+ }
+
+ if (pEpInDesc != NULL)
+ {
+ pEpInDesc->wMaxPacketSize = CDC_DATA_FS_MAX_PACKET_SIZE;
+ }
+
+ *length = (uint16_t)sizeof(USBD_CDC_CfgDesc);
+ return USBD_CDC_CfgDesc;
+}
+
+/**
+ * @brief USBD_CDC_GetDeviceQualifierDescriptor
+ * return Device Qualifier descriptor
+ * @param length : pointer data length
+ * @retval pointer to descriptor buffer
+ */
+uint8_t *USBD_CDC_GetDeviceQualifierDescriptor(uint16_t *length)
+{
+ *length = (uint16_t)sizeof(USBD_CDC_DeviceQualifierDesc);
+
+ return USBD_CDC_DeviceQualifierDesc;
+}
+#endif /* USE_USBD_COMPOSITE */
+/**
+ * @brief USBD_CDC_RegisterInterface
+ * @param pdev: device instance
+ * @param fops: CD Interface callback
+ * @retval status
+ */
+uint8_t USBD_CDC_RegisterInterface(USBD_HandleTypeDef *pdev,
+ USBD_CDC_ItfTypeDef *fops)
+{
+ if (fops == NULL)
+ {
+ return (uint8_t)USBD_FAIL;
+ }
+
+ pdev->pUserData[pdev->classId] = fops;
+
+ return (uint8_t)USBD_OK;
+}
+
+
+/**
+ * @brief USBD_CDC_SetTxBuffer
+ * @param pdev: device instance
+ * @param pbuff: Tx Buffer
+ * @param length: length of data to be sent
+ * @param ClassId: The Class ID
+ * @retval status
+ */
+#ifdef USE_USBD_COMPOSITE
+uint8_t USBD_CDC_SetTxBuffer(USBD_HandleTypeDef *pdev,
+ uint8_t *pbuff, uint32_t length, uint8_t ClassId)
+{
+ USBD_CDC_HandleTypeDef *hcdc = (USBD_CDC_HandleTypeDef *)pdev->pClassDataCmsit[ClassId];
+#else
+uint8_t USBD_CDC_SetTxBuffer(USBD_HandleTypeDef *pdev,
+ uint8_t *pbuff, uint32_t length)
+{
+ USBD_CDC_HandleTypeDef *hcdc = (USBD_CDC_HandleTypeDef *)pdev->pClassDataCmsit[pdev->classId];
+#endif /* USE_USBD_COMPOSITE */
+
+ if (hcdc == NULL)
+ {
+ return (uint8_t)USBD_FAIL;
+ }
+
+ hcdc->TxBuffer = pbuff;
+ hcdc->TxLength = length;
+
+ return (uint8_t)USBD_OK;
+}
+
+/**
+ * @brief USBD_CDC_SetRxBuffer
+ * @param pdev: device instance
+ * @param pbuff: Rx Buffer
+ * @retval status
+ */
+uint8_t USBD_CDC_SetRxBuffer(USBD_HandleTypeDef *pdev, uint8_t *pbuff)
+{
+ USBD_CDC_HandleTypeDef *hcdc = (USBD_CDC_HandleTypeDef *)pdev->pClassDataCmsit[pdev->classId];
+
+ if (hcdc == NULL)
+ {
+ return (uint8_t)USBD_FAIL;
+ }
+
+ hcdc->RxBuffer = pbuff;
+
+ return (uint8_t)USBD_OK;
+}
+
+
+/**
+ * @brief USBD_CDC_TransmitPacket
+ * Transmit packet on IN endpoint
+ * @param pdev: device instance
+ * @param ClassId: The Class ID
+ * @retval status
+ */
+#ifdef USE_USBD_COMPOSITE
+uint8_t USBD_CDC_TransmitPacket(USBD_HandleTypeDef *pdev, uint8_t ClassId)
+{
+ USBD_CDC_HandleTypeDef *hcdc = (USBD_CDC_HandleTypeDef *)pdev->pClassDataCmsit[ClassId];
+#else
+uint8_t USBD_CDC_TransmitPacket(USBD_HandleTypeDef *pdev)
+{
+ USBD_CDC_HandleTypeDef *hcdc = (USBD_CDC_HandleTypeDef *)pdev->pClassDataCmsit[pdev->classId];
+#endif /* USE_USBD_COMPOSITE */
+
+ USBD_StatusTypeDef ret = USBD_BUSY;
+
+#ifdef USE_USBD_COMPOSITE
+ /* Get the Endpoints addresses allocated for this class instance */
+ CDCInEpAdd = USBD_CoreGetEPAdd(pdev, USBD_EP_IN, USBD_EP_TYPE_BULK, ClassId);
+#endif /* USE_USBD_COMPOSITE */
+
+ if (hcdc == NULL)
+ {
+ return (uint8_t)USBD_FAIL;
+ }
+
+ if (hcdc->TxState == 0U)
+ {
+ /* Tx Transfer in progress */
+ hcdc->TxState = 1U;
+
+ /* Update the packet total length */
+ pdev->ep_in[CDCInEpAdd & 0xFU].total_length = hcdc->TxLength;
+
+ /* Transmit next packet */
+ (void)USBD_LL_Transmit(pdev, CDCInEpAdd, hcdc->TxBuffer, hcdc->TxLength);
+
+ ret = USBD_OK;
+ }
+
+ return (uint8_t)ret;
+}
+
+/**
+ * @brief USBD_CDC_ReceivePacket
+ * prepare OUT Endpoint for reception
+ * @param pdev: device instance
+ * @retval status
+ */
+uint8_t USBD_CDC_ReceivePacket(USBD_HandleTypeDef *pdev)
+{
+ USBD_CDC_HandleTypeDef *hcdc = (USBD_CDC_HandleTypeDef *)pdev->pClassDataCmsit[pdev->classId];
+
+#ifdef USE_USBD_COMPOSITE
+ /* Get the Endpoints addresses allocated for this class instance */
+ CDCOutEpAdd = USBD_CoreGetEPAdd(pdev, USBD_EP_OUT, USBD_EP_TYPE_BULK, (uint8_t)pdev->classId);
+#endif /* USE_USBD_COMPOSITE */
+
+ if (pdev->pClassDataCmsit[pdev->classId] == NULL)
+ {
+ return (uint8_t)USBD_FAIL;
+ }
+
+ if (pdev->dev_speed == USBD_SPEED_HIGH)
+ {
+ /* Prepare Out endpoint to receive next packet */
+ (void)USBD_LL_PrepareReceive(pdev, CDCOutEpAdd, hcdc->RxBuffer,
+ CDC_DATA_HS_OUT_PACKET_SIZE);
+ }
+ else
+ {
+ /* Prepare Out endpoint to receive next packet */
+ (void)USBD_LL_PrepareReceive(pdev, CDCOutEpAdd, hcdc->RxBuffer,
+ CDC_DATA_FS_OUT_PACKET_SIZE);
+ }
+
+ return (uint8_t)USBD_OK;
+}
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
diff --git a/Ganesha_II_V2/Middlewares/ST/STM32_USB_Device_Library/Core/Inc/usbd_core.h b/Ganesha_II_V2/Middlewares/ST/STM32_USB_Device_Library/Core/Inc/usbd_core.h
new file mode 100644
index 0000000..4672921
--- /dev/null
+++ b/Ganesha_II_V2/Middlewares/ST/STM32_USB_Device_Library/Core/Inc/usbd_core.h
@@ -0,0 +1,175 @@
+/**
+ ******************************************************************************
+ * @file usbd_core.h
+ * @author MCD Application Team
+ * @brief Header file for usbd_core.c file
+ ******************************************************************************
+ * @attention
+ *
+ * Copyright (c) 2015 STMicroelectronics.
+ * All rights reserved.
+ *
+ * This software is licensed under terms that can be found in the LICENSE file
+ * in the root directory of this software component.
+ * If no LICENSE file comes with this software, it is provided AS-IS.
+ *
+ ******************************************************************************
+ */
+
+/* Define to prevent recursive inclusion -------------------------------------*/
+#ifndef __USBD_CORE_H
+#define __USBD_CORE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Includes ------------------------------------------------------------------*/
+#include "usbd_conf.h"
+#include "usbd_def.h"
+#include "usbd_ioreq.h"
+#include "usbd_ctlreq.h"
+
+/** @addtogroup STM32_USB_DEVICE_LIBRARY
+ * @{
+ */
+
+/** @defgroup USBD_CORE
+ * @brief This file is the Header file for usbd_core.c file
+ * @{
+ */
+
+
+/** @defgroup USBD_CORE_Exported_Defines
+ * @{
+ */
+#ifndef USBD_DEBUG_LEVEL
+#define USBD_DEBUG_LEVEL 0U
+#endif /* USBD_DEBUG_LEVEL */
+/**
+ * @}
+ */
+
+
+/** @defgroup USBD_CORE_Exported_TypesDefinitions
+ * @{
+ */
+
+
+/**
+ * @}
+ */
+
+
+
+/** @defgroup USBD_CORE_Exported_Macros
+ * @{
+ */
+
+/**
+ * @}
+ */
+
+/** @defgroup USBD_CORE_Exported_Variables
+ * @{
+ */
+#define USBD_SOF USBD_LL_SOF
+/**
+ * @}
+ */
+
+/** @defgroup USBD_CORE_Exported_FunctionsPrototype
+ * @{
+ */
+USBD_StatusTypeDef USBD_Init(USBD_HandleTypeDef *pdev, USBD_DescriptorsTypeDef *pdesc, uint8_t id);
+USBD_StatusTypeDef USBD_DeInit(USBD_HandleTypeDef *pdev);
+USBD_StatusTypeDef USBD_Start(USBD_HandleTypeDef *pdev);
+USBD_StatusTypeDef USBD_Stop(USBD_HandleTypeDef *pdev);
+USBD_StatusTypeDef USBD_RegisterClass(USBD_HandleTypeDef *pdev, USBD_ClassTypeDef *pclass);
+#if (USBD_USER_REGISTER_CALLBACK == 1U)
+USBD_StatusTypeDef USBD_RegisterDevStateCallback(USBD_HandleTypeDef *pdev, USBD_DevStateCallbackTypeDef pUserCallback);
+#endif /* USBD_USER_REGISTER_CALLBACK */
+
+#ifdef USE_USBD_COMPOSITE
+USBD_StatusTypeDef USBD_RegisterClassComposite(USBD_HandleTypeDef *pdev, USBD_ClassTypeDef *pclass,
+ USBD_CompositeClassTypeDef classtype, uint8_t *EpAddr);
+
+USBD_StatusTypeDef USBD_UnRegisterClassComposite(USBD_HandleTypeDef *pdev);
+uint8_t USBD_CoreGetEPAdd(USBD_HandleTypeDef *pdev, uint8_t ep_dir, uint8_t ep_type, uint8_t ClassId);
+#endif /* USE_USBD_COMPOSITE */
+
+uint8_t USBD_CoreFindIF(USBD_HandleTypeDef *pdev, uint8_t index);
+uint8_t USBD_CoreFindEP(USBD_HandleTypeDef *pdev, uint8_t index);
+
+USBD_StatusTypeDef USBD_RunTestMode(USBD_HandleTypeDef *pdev);
+USBD_StatusTypeDef USBD_SetClassConfig(USBD_HandleTypeDef *pdev, uint8_t cfgidx);
+USBD_StatusTypeDef USBD_ClrClassConfig(USBD_HandleTypeDef *pdev, uint8_t cfgidx);
+
+USBD_StatusTypeDef USBD_LL_SetupStage(USBD_HandleTypeDef *pdev, uint8_t *psetup);
+USBD_StatusTypeDef USBD_LL_DataOutStage(USBD_HandleTypeDef *pdev, uint8_t epnum, uint8_t *pdata);
+USBD_StatusTypeDef USBD_LL_DataInStage(USBD_HandleTypeDef *pdev, uint8_t epnum, uint8_t *pdata);
+
+USBD_StatusTypeDef USBD_LL_Reset(USBD_HandleTypeDef *pdev);
+USBD_StatusTypeDef USBD_LL_SetSpeed(USBD_HandleTypeDef *pdev, USBD_SpeedTypeDef speed);
+USBD_StatusTypeDef USBD_LL_Suspend(USBD_HandleTypeDef *pdev);
+USBD_StatusTypeDef USBD_LL_Resume(USBD_HandleTypeDef *pdev);
+
+USBD_StatusTypeDef USBD_LL_SOF(USBD_HandleTypeDef *pdev);
+USBD_StatusTypeDef USBD_LL_IsoINIncomplete(USBD_HandleTypeDef *pdev, uint8_t epnum);
+USBD_StatusTypeDef USBD_LL_IsoOUTIncomplete(USBD_HandleTypeDef *pdev, uint8_t epnum);
+
+USBD_StatusTypeDef USBD_LL_DevConnected(USBD_HandleTypeDef *pdev);
+USBD_StatusTypeDef USBD_LL_DevDisconnected(USBD_HandleTypeDef *pdev);
+
+/* USBD Low Level Driver */
+USBD_StatusTypeDef USBD_LL_Init(USBD_HandleTypeDef *pdev);
+USBD_StatusTypeDef USBD_LL_DeInit(USBD_HandleTypeDef *pdev);
+USBD_StatusTypeDef USBD_LL_Start(USBD_HandleTypeDef *pdev);
+USBD_StatusTypeDef USBD_LL_Stop(USBD_HandleTypeDef *pdev);
+
+USBD_StatusTypeDef USBD_LL_OpenEP(USBD_HandleTypeDef *pdev, uint8_t ep_addr,
+ uint8_t ep_type, uint16_t ep_mps);
+
+USBD_StatusTypeDef USBD_LL_CloseEP(USBD_HandleTypeDef *pdev, uint8_t ep_addr);
+USBD_StatusTypeDef USBD_LL_FlushEP(USBD_HandleTypeDef *pdev, uint8_t ep_addr);
+USBD_StatusTypeDef USBD_LL_StallEP(USBD_HandleTypeDef *pdev, uint8_t ep_addr);
+USBD_StatusTypeDef USBD_LL_ClearStallEP(USBD_HandleTypeDef *pdev, uint8_t ep_addr);
+USBD_StatusTypeDef USBD_LL_SetUSBAddress(USBD_HandleTypeDef *pdev, uint8_t dev_addr);
+
+USBD_StatusTypeDef USBD_LL_Transmit(USBD_HandleTypeDef *pdev, uint8_t ep_addr,
+ uint8_t *pbuf, uint32_t size);
+
+USBD_StatusTypeDef USBD_LL_PrepareReceive(USBD_HandleTypeDef *pdev, uint8_t ep_addr,
+ uint8_t *pbuf, uint32_t size);
+
+#ifdef USBD_HS_TESTMODE_ENABLE
+USBD_StatusTypeDef USBD_LL_SetTestMode(USBD_HandleTypeDef *pdev, uint8_t testmode);
+#endif /* USBD_HS_TESTMODE_ENABLE */
+
+uint8_t USBD_LL_IsStallEP(USBD_HandleTypeDef *pdev, uint8_t ep_addr);
+uint32_t USBD_LL_GetRxDataSize(USBD_HandleTypeDef *pdev, uint8_t ep_addr);
+
+void USBD_LL_Delay(uint32_t Delay);
+
+void *USBD_GetEpDesc(uint8_t *pConfDesc, uint8_t EpAddr);
+USBD_DescHeaderTypeDef *USBD_GetNextDesc(uint8_t *pbuf, uint16_t *ptr);
+
+/**
+ * @}
+ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __USBD_CORE_H */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+
diff --git a/Ganesha_II_V2/Middlewares/ST/STM32_USB_Device_Library/Core/Inc/usbd_ctlreq.h b/Ganesha_II_V2/Middlewares/ST/STM32_USB_Device_Library/Core/Inc/usbd_ctlreq.h
new file mode 100644
index 0000000..6c45d6c
--- /dev/null
+++ b/Ganesha_II_V2/Middlewares/ST/STM32_USB_Device_Library/Core/Inc/usbd_ctlreq.h
@@ -0,0 +1,101 @@
+/**
+ ******************************************************************************
+ * @file usbd_req.h
+ * @author MCD Application Team
+ * @brief Header file for the usbd_req.c file
+ ******************************************************************************
+ * @attention
+ *
+ * Copyright (c) 2015 STMicroelectronics.
+ * All rights reserved.
+ *
+ * This software is licensed under terms that can be found in the LICENSE file
+ * in the root directory of this software component.
+ * If no LICENSE file comes with this software, it is provided AS-IS.
+ *
+ ******************************************************************************
+ */
+
+/* Define to prevent recursive inclusion -------------------------------------*/
+#ifndef __USB_REQUEST_H
+#define __USB_REQUEST_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Includes ------------------------------------------------------------------*/
+#include "usbd_def.h"
+
+
+/** @addtogroup STM32_USB_DEVICE_LIBRARY
+ * @{
+ */
+
+/** @defgroup USBD_REQ
+ * @brief header file for the usbd_req.c file
+ * @{
+ */
+
+/** @defgroup USBD_REQ_Exported_Defines
+ * @{
+ */
+/**
+ * @}
+ */
+
+
+/** @defgroup USBD_REQ_Exported_Types
+ * @{
+ */
+/**
+ * @}
+ */
+
+
+
+/** @defgroup USBD_REQ_Exported_Macros
+ * @{
+ */
+/**
+ * @}
+ */
+
+/** @defgroup USBD_REQ_Exported_Variables
+ * @{
+ */
+/**
+ * @}
+ */
+
+/** @defgroup USBD_REQ_Exported_FunctionsPrototype
+ * @{
+ */
+
+USBD_StatusTypeDef USBD_StdDevReq(USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req);
+USBD_StatusTypeDef USBD_StdItfReq(USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req);
+USBD_StatusTypeDef USBD_StdEPReq(USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req);
+
+void USBD_CtlError(USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req);
+void USBD_ParseSetupRequest(USBD_SetupReqTypedef *req, uint8_t *pdata);
+void USBD_GetString(uint8_t *desc, uint8_t *unicode, uint16_t *len);
+
+/**
+ * @}
+ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __USB_REQUEST_H */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+
diff --git a/Ganesha_II_V2/Middlewares/ST/STM32_USB_Device_Library/Core/Inc/usbd_def.h b/Ganesha_II_V2/Middlewares/ST/STM32_USB_Device_Library/Core/Inc/usbd_def.h
new file mode 100644
index 0000000..2a295d7
--- /dev/null
+++ b/Ganesha_II_V2/Middlewares/ST/STM32_USB_Device_Library/Core/Inc/usbd_def.h
@@ -0,0 +1,523 @@
+/**
+ ******************************************************************************
+ * @file usbd_def.h
+ * @author MCD Application Team
+ * @brief General defines for the usb device library
+ ******************************************************************************
+ * @attention
+ *
+ * Copyright (c) 2015 STMicroelectronics.
+ * All rights reserved.
+ *
+ * This software is licensed under terms that can be found in the LICENSE file
+ * in the root directory of this software component.
+ * If no LICENSE file comes with this software, it is provided AS-IS.
+ *
+ ******************************************************************************
+ */
+
+/* Define to prevent recursive inclusion -------------------------------------*/
+#ifndef __USBD_DEF_H
+#define __USBD_DEF_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Includes ------------------------------------------------------------------*/
+#include "usbd_conf.h"
+
+/** @addtogroup STM32_USBD_DEVICE_LIBRARY
+ * @{
+ */
+
+/** @defgroup USB_DEF
+ * @brief general defines for the usb device library file
+ * @{
+ */
+
+/** @defgroup USB_DEF_Exported_Defines
+ * @{
+ */
+
+#ifndef NULL
+#define NULL 0U
+#endif /* NULL */
+
+#ifndef USBD_MAX_NUM_INTERFACES
+#define USBD_MAX_NUM_INTERFACES 1U
+#endif /* USBD_MAX_NUM_CONFIGURATION */
+
+#ifndef USBD_MAX_NUM_CONFIGURATION
+#define USBD_MAX_NUM_CONFIGURATION 1U
+#endif /* USBD_MAX_NUM_CONFIGURATION */
+
+#ifdef USE_USBD_COMPOSITE
+#ifndef USBD_MAX_SUPPORTED_CLASS
+#define USBD_MAX_SUPPORTED_CLASS 4U
+#endif /* USBD_MAX_SUPPORTED_CLASS */
+#else
+#ifndef USBD_MAX_SUPPORTED_CLASS
+#define USBD_MAX_SUPPORTED_CLASS 1U
+#endif /* USBD_MAX_SUPPORTED_CLASS */
+#endif /* USE_USBD_COMPOSITE */
+
+#ifndef USBD_MAX_CLASS_ENDPOINTS
+#define USBD_MAX_CLASS_ENDPOINTS 5U
+#endif /* USBD_MAX_CLASS_ENDPOINTS */
+
+#ifndef USBD_MAX_CLASS_INTERFACES
+#define USBD_MAX_CLASS_INTERFACES 5U
+#endif /* USBD_MAX_CLASS_INTERFACES */
+
+#ifndef USBD_LPM_ENABLED
+#define USBD_LPM_ENABLED 0U
+#endif /* USBD_LPM_ENABLED */
+
+#ifndef USBD_SELF_POWERED
+#define USBD_SELF_POWERED 1U
+#endif /*USBD_SELF_POWERED */
+
+#ifndef USBD_MAX_POWER
+#define USBD_MAX_POWER 0x32U /* 100 mA */
+#endif /* USBD_MAX_POWER */
+
+#ifndef USBD_SUPPORT_USER_STRING_DESC
+#define USBD_SUPPORT_USER_STRING_DESC 0U
+#endif /* USBD_SUPPORT_USER_STRING_DESC */
+
+#ifndef USBD_CLASS_USER_STRING_DESC
+#define USBD_CLASS_USER_STRING_DESC 0U
+#endif /* USBD_CLASS_USER_STRING_DESC */
+
+#define USB_LEN_DEV_QUALIFIER_DESC 0x0AU
+#define USB_LEN_DEV_DESC 0x12U
+#define USB_LEN_CFG_DESC 0x09U
+#define USB_LEN_IF_DESC 0x09U
+#define USB_LEN_EP_DESC 0x07U
+#define USB_LEN_OTG_DESC 0x03U
+#define USB_LEN_LANGID_STR_DESC 0x04U
+#define USB_LEN_OTHER_SPEED_DESC_SIZ 0x09U
+
+#define USBD_IDX_LANGID_STR 0x00U
+#define USBD_IDX_MFC_STR 0x01U
+#define USBD_IDX_PRODUCT_STR 0x02U
+#define USBD_IDX_SERIAL_STR 0x03U
+#define USBD_IDX_CONFIG_STR 0x04U
+#define USBD_IDX_INTERFACE_STR 0x05U
+
+#define USB_REQ_TYPE_STANDARD 0x00U
+#define USB_REQ_TYPE_CLASS 0x20U
+#define USB_REQ_TYPE_VENDOR 0x40U
+#define USB_REQ_TYPE_MASK 0x60U
+
+#define USB_REQ_RECIPIENT_DEVICE 0x00U
+#define USB_REQ_RECIPIENT_INTERFACE 0x01U
+#define USB_REQ_RECIPIENT_ENDPOINT 0x02U
+#define USB_REQ_RECIPIENT_MASK 0x03U
+
+#define USB_REQ_GET_STATUS 0x00U
+#define USB_REQ_CLEAR_FEATURE 0x01U
+#define USB_REQ_SET_FEATURE 0x03U
+#define USB_REQ_SET_ADDRESS 0x05U
+#define USB_REQ_GET_DESCRIPTOR 0x06U
+#define USB_REQ_SET_DESCRIPTOR 0x07U
+#define USB_REQ_GET_CONFIGURATION 0x08U
+#define USB_REQ_SET_CONFIGURATION 0x09U
+#define USB_REQ_GET_INTERFACE 0x0AU
+#define USB_REQ_SET_INTERFACE 0x0BU
+#define USB_REQ_SYNCH_FRAME 0x0CU
+
+#define USB_DESC_TYPE_DEVICE 0x01U
+#define USB_DESC_TYPE_CONFIGURATION 0x02U
+#define USB_DESC_TYPE_STRING 0x03U
+#define USB_DESC_TYPE_INTERFACE 0x04U
+#define USB_DESC_TYPE_ENDPOINT 0x05U
+#define USB_DESC_TYPE_DEVICE_QUALIFIER 0x06U
+#define USB_DESC_TYPE_OTHER_SPEED_CONFIGURATION 0x07U
+#define USB_DESC_TYPE_IAD 0x0BU
+#define USB_DESC_TYPE_BOS 0x0FU
+
+#define USB_CONFIG_REMOTE_WAKEUP 0x02U
+#define USB_CONFIG_SELF_POWERED 0x01U
+
+#define USB_FEATURE_EP_HALT 0x00U
+#define USB_FEATURE_REMOTE_WAKEUP 0x01U
+#define USB_FEATURE_TEST_MODE 0x02U
+
+#define USB_DEVICE_CAPABITY_TYPE 0x10U
+
+#define USB_CONF_DESC_SIZE 0x09U
+#define USB_IF_DESC_SIZE 0x09U
+#define USB_EP_DESC_SIZE 0x07U
+#define USB_IAD_DESC_SIZE 0x08U
+
+#define USB_HS_MAX_PACKET_SIZE 512U
+#define USB_FS_MAX_PACKET_SIZE 64U
+#define USB_MAX_EP0_SIZE 64U
+
+/* Device Status */
+#define USBD_STATE_DEFAULT 0x01U
+#define USBD_STATE_ADDRESSED 0x02U
+#define USBD_STATE_CONFIGURED 0x03U
+#define USBD_STATE_SUSPENDED 0x04U
+
+
+/* EP0 State */
+#define USBD_EP0_IDLE 0x00U
+#define USBD_EP0_SETUP 0x01U
+#define USBD_EP0_DATA_IN 0x02U
+#define USBD_EP0_DATA_OUT 0x03U
+#define USBD_EP0_STATUS_IN 0x04U
+#define USBD_EP0_STATUS_OUT 0x05U
+#define USBD_EP0_STALL 0x06U
+
+#define USBD_EP_TYPE_CTRL 0x00U
+#define USBD_EP_TYPE_ISOC 0x01U
+#define USBD_EP_TYPE_BULK 0x02U
+#define USBD_EP_TYPE_INTR 0x03U
+
+#ifdef USE_USBD_COMPOSITE
+#define USBD_EP_IN 0x80U
+#define USBD_EP_OUT 0x00U
+#define USBD_FUNC_DESCRIPTOR_TYPE 0x24U
+#define USBD_DESC_SUBTYPE_ACM 0x0FU
+#define USBD_DESC_ECM_BCD_LOW 0x00U
+#define USBD_DESC_ECM_BCD_HIGH 0x10U
+#endif /* USE_USBD_COMPOSITE */
+/**
+ * @}
+ */
+
+
+/** @defgroup USBD_DEF_Exported_TypesDefinitions
+ * @{
+ */
+
+typedef struct usb_setup_req
+{
+ uint8_t bmRequest;
+ uint8_t bRequest;
+ uint16_t wValue;
+ uint16_t wIndex;
+ uint16_t wLength;
+} USBD_SetupReqTypedef;
+
+typedef struct
+{
+ uint8_t bLength;
+ uint8_t bDescriptorType;
+ uint16_t wTotalLength;
+ uint8_t bNumInterfaces;
+ uint8_t bConfigurationValue;
+ uint8_t iConfiguration;
+ uint8_t bmAttributes;
+ uint8_t bMaxPower;
+} __PACKED USBD_ConfigDescTypeDef;
+
+typedef struct
+{
+ uint8_t bLength;
+ uint8_t bDescriptorType;
+ uint16_t wTotalLength;
+ uint8_t bNumDeviceCaps;
+} USBD_BosDescTypeDef;
+
+typedef struct
+{
+ uint8_t bLength;
+ uint8_t bDescriptorType;
+ uint8_t bEndpointAddress;
+ uint8_t bmAttributes;
+ uint16_t wMaxPacketSize;
+ uint8_t bInterval;
+} __PACKED USBD_EpDescTypeDef;
+
+typedef struct
+{
+ uint8_t bLength;
+ uint8_t bDescriptorType;
+ uint8_t bDescriptorSubType;
+} USBD_DescHeaderTypeDef;
+
+struct _USBD_HandleTypeDef;
+
+typedef struct _Device_cb
+{
+ uint8_t (*Init)(struct _USBD_HandleTypeDef *pdev, uint8_t cfgidx);
+ uint8_t (*DeInit)(struct _USBD_HandleTypeDef *pdev, uint8_t cfgidx);
+ /* Control Endpoints*/
+ uint8_t (*Setup)(struct _USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req);
+ uint8_t (*EP0_TxSent)(struct _USBD_HandleTypeDef *pdev);
+ uint8_t (*EP0_RxReady)(struct _USBD_HandleTypeDef *pdev);
+ /* Class Specific Endpoints*/
+ uint8_t (*DataIn)(struct _USBD_HandleTypeDef *pdev, uint8_t epnum);
+ uint8_t (*DataOut)(struct _USBD_HandleTypeDef *pdev, uint8_t epnum);
+ uint8_t (*SOF)(struct _USBD_HandleTypeDef *pdev);
+ uint8_t (*IsoINIncomplete)(struct _USBD_HandleTypeDef *pdev, uint8_t epnum);
+ uint8_t (*IsoOUTIncomplete)(struct _USBD_HandleTypeDef *pdev, uint8_t epnum);
+
+ uint8_t *(*GetHSConfigDescriptor)(uint16_t *length);
+ uint8_t *(*GetFSConfigDescriptor)(uint16_t *length);
+ uint8_t *(*GetOtherSpeedConfigDescriptor)(uint16_t *length);
+ uint8_t *(*GetDeviceQualifierDescriptor)(uint16_t *length);
+#if (USBD_SUPPORT_USER_STRING_DESC == 1U)
+ uint8_t *(*GetUsrStrDescriptor)(struct _USBD_HandleTypeDef *pdev, uint8_t index, uint16_t *length);
+#endif /* USBD_SUPPORT_USER_STRING_DESC */
+
+} USBD_ClassTypeDef;
+
+/* Following USB Device Speed */
+typedef enum
+{
+ USBD_SPEED_HIGH = 0U,
+ USBD_SPEED_FULL = 1U,
+ USBD_SPEED_LOW = 2U,
+} USBD_SpeedTypeDef;
+
+/* Following USB Device status */
+typedef enum
+{
+ USBD_OK = 0U,
+ USBD_BUSY,
+ USBD_EMEM,
+ USBD_FAIL,
+} USBD_StatusTypeDef;
+
+/* USB Device descriptors structure */
+typedef struct
+{
+ uint8_t *(*GetDeviceDescriptor)(USBD_SpeedTypeDef speed, uint16_t *length);
+ uint8_t *(*GetLangIDStrDescriptor)(USBD_SpeedTypeDef speed, uint16_t *length);
+ uint8_t *(*GetManufacturerStrDescriptor)(USBD_SpeedTypeDef speed, uint16_t *length);
+ uint8_t *(*GetProductStrDescriptor)(USBD_SpeedTypeDef speed, uint16_t *length);
+ uint8_t *(*GetSerialStrDescriptor)(USBD_SpeedTypeDef speed, uint16_t *length);
+ uint8_t *(*GetConfigurationStrDescriptor)(USBD_SpeedTypeDef speed, uint16_t *length);
+ uint8_t *(*GetInterfaceStrDescriptor)(USBD_SpeedTypeDef speed, uint16_t *length);
+#if (USBD_CLASS_USER_STRING_DESC == 1)
+ uint8_t *(*GetUserStrDescriptor)(USBD_SpeedTypeDef speed, uint8_t idx, uint16_t *length);
+#endif /* USBD_CLASS_USER_STRING_DESC */
+#if ((USBD_LPM_ENABLED == 1U) || (USBD_CLASS_BOS_ENABLED == 1))
+ uint8_t *(*GetBOSDescriptor)(USBD_SpeedTypeDef speed, uint16_t *length);
+#endif /* (USBD_LPM_ENABLED == 1U) || (USBD_CLASS_BOS_ENABLED == 1) */
+} USBD_DescriptorsTypeDef;
+
+/* USB Device handle structure */
+typedef struct
+{
+ uint32_t status;
+ uint32_t total_length;
+ uint32_t rem_length;
+ uint32_t maxpacket;
+ uint16_t is_used;
+ uint16_t bInterval;
+} USBD_EndpointTypeDef;
+
+#ifdef USE_USBD_COMPOSITE
+typedef enum
+{
+ CLASS_TYPE_NONE = 0,
+ CLASS_TYPE_HID = 1,
+ CLASS_TYPE_CDC = 2,
+ CLASS_TYPE_MSC = 3,
+ CLASS_TYPE_DFU = 4,
+ CLASS_TYPE_CHID = 5,
+ CLASS_TYPE_AUDIO = 6,
+ CLASS_TYPE_ECM = 7,
+ CLASS_TYPE_RNDIS = 8,
+ CLASS_TYPE_MTP = 9,
+ CLASS_TYPE_VIDEO = 10,
+ CLASS_TYPE_PRINTER = 11,
+ CLASS_TYPE_CCID = 12,
+} USBD_CompositeClassTypeDef;
+
+
+/* USB Device handle structure */
+typedef struct
+{
+ uint8_t add;
+ uint8_t type;
+ uint8_t size;
+ uint8_t is_used;
+} USBD_EPTypeDef;
+
+/* USB Device handle structure */
+typedef struct
+{
+ USBD_CompositeClassTypeDef ClassType;
+ uint32_t ClassId;
+ uint32_t Active;
+ uint32_t NumEps;
+ USBD_EPTypeDef Eps[USBD_MAX_CLASS_ENDPOINTS];
+ uint8_t *EpAdd;
+ uint32_t NumIf;
+ uint8_t Ifs[USBD_MAX_CLASS_INTERFACES];
+ uint32_t CurrPcktSze;
+} USBD_CompositeElementTypeDef;
+#endif /* USE_USBD_COMPOSITE */
+
+/* USB Device handle structure */
+typedef struct _USBD_HandleTypeDef
+{
+ uint8_t id;
+ uint32_t dev_config;
+ uint32_t dev_default_config;
+ uint32_t dev_config_status;
+ USBD_SpeedTypeDef dev_speed;
+ USBD_EndpointTypeDef ep_in[16];
+ USBD_EndpointTypeDef ep_out[16];
+ __IO uint32_t ep0_state;
+ uint32_t ep0_data_len;
+ __IO uint8_t dev_state;
+ __IO uint8_t dev_old_state;
+ uint8_t dev_address;
+ uint8_t dev_connection_status;
+ uint8_t dev_test_mode;
+ uint32_t dev_remote_wakeup;
+ uint8_t ConfIdx;
+
+ USBD_SetupReqTypedef request;
+ USBD_DescriptorsTypeDef *pDesc;
+ USBD_ClassTypeDef *pClass[USBD_MAX_SUPPORTED_CLASS];
+ void *pClassData;
+ void *pClassDataCmsit[USBD_MAX_SUPPORTED_CLASS];
+ void *pUserData[USBD_MAX_SUPPORTED_CLASS];
+ void *pData;
+ void *pBosDesc;
+ void *pConfDesc;
+ uint32_t classId;
+ uint32_t NumClasses;
+#ifdef USE_USBD_COMPOSITE
+ USBD_CompositeElementTypeDef tclasslist[USBD_MAX_SUPPORTED_CLASS];
+#endif /* USE_USBD_COMPOSITE */
+#if (USBD_USER_REGISTER_CALLBACK == 1U)
+ void (* DevStateCallback)(uint8_t dev_state, uint8_t cfgidx); /*!< User Notification callback */
+#endif /* USBD_USER_REGISTER_CALLBACK */
+} USBD_HandleTypeDef;
+
+#if (USBD_USER_REGISTER_CALLBACK == 1U)
+typedef void (*USBD_DevStateCallbackTypeDef)(uint8_t dev_state, uint8_t cfgidx); /*!< pointer to User callback function */
+#endif /* USBD_USER_REGISTER_CALLBACK */
+
+/* USB Device endpoint direction */
+typedef enum
+{
+ OUT = 0x00,
+ IN = 0x80,
+} USBD_EPDirectionTypeDef;
+
+typedef enum
+{
+ NETWORK_CONNECTION = 0x00,
+ RESPONSE_AVAILABLE = 0x01,
+ CONNECTION_SPEED_CHANGE = 0x2A
+} USBD_CDC_NotifCodeTypeDef;
+/**
+ * @}
+ */
+
+
+
+/** @defgroup USBD_DEF_Exported_Macros
+ * @{
+ */
+__STATIC_INLINE uint16_t SWAPBYTE(uint8_t *addr)
+{
+ uint16_t _SwapVal;
+ uint16_t _Byte1;
+ uint16_t _Byte2;
+ uint8_t *_pbuff = addr;
+
+ _Byte1 = *(uint8_t *)_pbuff;
+ _pbuff++;
+ _Byte2 = *(uint8_t *)_pbuff;
+
+ _SwapVal = (_Byte2 << 8) | _Byte1;
+
+ return _SwapVal;
+}
+
+#ifndef LOBYTE
+#define LOBYTE(x) ((uint8_t)((x) & 0x00FFU))
+#endif /* LOBYTE */
+
+#ifndef HIBYTE
+#define HIBYTE(x) ((uint8_t)(((x) & 0xFF00U) >> 8U))
+#endif /* HIBYTE */
+
+#ifndef MIN
+#define MIN(a, b) (((a) < (b)) ? (a) : (b))
+#endif /* MIN */
+
+#ifndef MAX
+#define MAX(a, b) (((a) > (b)) ? (a) : (b))
+#endif /* MAX */
+
+#if defined ( __GNUC__ )
+#ifndef __weak
+#define __weak __attribute__((weak))
+#endif /* __weak */
+#ifndef __packed
+#define __packed __attribute__((__packed__))
+#endif /* __packed */
+#endif /* __GNUC__ */
+
+
+/* In HS mode and when the DMA is used, all variables and data structures dealing
+ with the DMA during the transaction process should be 4-bytes aligned */
+
+#if defined ( __GNUC__ ) && !defined (__CC_ARM) /* GNU Compiler */
+#ifndef __ALIGN_END
+#define __ALIGN_END __attribute__ ((aligned (4U)))
+#endif /* __ALIGN_END */
+#ifndef __ALIGN_BEGIN
+#define __ALIGN_BEGIN
+#endif /* __ALIGN_BEGIN */
+#else
+#ifndef __ALIGN_END
+#define __ALIGN_END
+#endif /* __ALIGN_END */
+#ifndef __ALIGN_BEGIN
+#if defined (__CC_ARM) /* ARM Compiler */
+#define __ALIGN_BEGIN __align(4U)
+#elif defined (__ICCARM__) /* IAR Compiler */
+#define __ALIGN_BEGIN
+#endif /* __CC_ARM */
+#endif /* __ALIGN_BEGIN */
+#endif /* __GNUC__ */
+
+
+/**
+ * @}
+ */
+
+/** @defgroup USBD_DEF_Exported_Variables
+ * @{
+ */
+
+/**
+ * @}
+ */
+
+/** @defgroup USBD_DEF_Exported_FunctionsPrototype
+ * @{
+ */
+
+/**
+ * @}
+ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __USBD_DEF_H */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
diff --git a/Ganesha_II_V2/Middlewares/ST/STM32_USB_Device_Library/Core/Inc/usbd_ioreq.h b/Ganesha_II_V2/Middlewares/ST/STM32_USB_Device_Library/Core/Inc/usbd_ioreq.h
new file mode 100644
index 0000000..15197b9
--- /dev/null
+++ b/Ganesha_II_V2/Middlewares/ST/STM32_USB_Device_Library/Core/Inc/usbd_ioreq.h
@@ -0,0 +1,113 @@
+/**
+ ******************************************************************************
+ * @file usbd_ioreq.h
+ * @author MCD Application Team
+ * @brief Header file for the usbd_ioreq.c file
+ ******************************************************************************
+ * @attention
+ *
+ * Copyright (c) 2015 STMicroelectronics.
+ * All rights reserved.
+ *
+ * This software is licensed under terms that can be found in the LICENSE file
+ * in the root directory of this software component.
+ * If no LICENSE file comes with this software, it is provided AS-IS.
+ *
+ ******************************************************************************
+ */
+
+/* Define to prevent recursive inclusion -------------------------------------*/
+#ifndef __USBD_IOREQ_H
+#define __USBD_IOREQ_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Includes ------------------------------------------------------------------*/
+#include "usbd_def.h"
+#include "usbd_core.h"
+
+/** @addtogroup STM32_USB_DEVICE_LIBRARY
+ * @{
+ */
+
+/** @defgroup USBD_IOREQ
+ * @brief header file for the usbd_ioreq.c file
+ * @{
+ */
+
+/** @defgroup USBD_IOREQ_Exported_Defines
+ * @{
+ */
+/**
+ * @}
+ */
+
+
+/** @defgroup USBD_IOREQ_Exported_Types
+ * @{
+ */
+
+
+/**
+ * @}
+ */
+
+
+
+/** @defgroup USBD_IOREQ_Exported_Macros
+ * @{
+ */
+
+/**
+ * @}
+ */
+
+/** @defgroup USBD_IOREQ_Exported_Variables
+ * @{
+ */
+
+/**
+ * @}
+ */
+
+/** @defgroup USBD_IOREQ_Exported_FunctionsPrototype
+ * @{
+ */
+
+USBD_StatusTypeDef USBD_CtlSendData(USBD_HandleTypeDef *pdev,
+ uint8_t *pbuf, uint32_t len);
+
+USBD_StatusTypeDef USBD_CtlContinueSendData(USBD_HandleTypeDef *pdev,
+ uint8_t *pbuf, uint32_t len);
+
+USBD_StatusTypeDef USBD_CtlPrepareRx(USBD_HandleTypeDef *pdev,
+ uint8_t *pbuf, uint32_t len);
+
+USBD_StatusTypeDef USBD_CtlContinueRx(USBD_HandleTypeDef *pdev,
+ uint8_t *pbuf, uint32_t len);
+
+USBD_StatusTypeDef USBD_CtlSendStatus(USBD_HandleTypeDef *pdev);
+USBD_StatusTypeDef USBD_CtlReceiveStatus(USBD_HandleTypeDef *pdev);
+
+uint32_t USBD_GetRxCount(USBD_HandleTypeDef *pdev, uint8_t ep_addr);
+
+/**
+ * @}
+ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __USBD_IOREQ_H */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
diff --git a/Ganesha_II_V2/Middlewares/ST/STM32_USB_Device_Library/Core/Src/usbd_core.c b/Ganesha_II_V2/Middlewares/ST/STM32_USB_Device_Library/Core/Src/usbd_core.c
new file mode 100644
index 0000000..0576c87
--- /dev/null
+++ b/Ganesha_II_V2/Middlewares/ST/STM32_USB_Device_Library/Core/Src/usbd_core.c
@@ -0,0 +1,1215 @@
+/**
+ ******************************************************************************
+ * @file usbd_core.c
+ * @author MCD Application Team
+ * @brief This file provides all the USBD core functions.
+ ******************************************************************************
+ * @attention
+ *
+ * Copyright (c) 2015 STMicroelectronics.
+ * All rights reserved.
+ *
+ * This software is licensed under terms that can be found in the LICENSE file
+ * in the root directory of this software component.
+ * If no LICENSE file comes with this software, it is provided AS-IS.
+ *
+ ******************************************************************************
+ */
+
+/* Includes ------------------------------------------------------------------*/
+#include "usbd_core.h"
+
+#ifdef USE_USBD_COMPOSITE
+#include "usbd_composite_builder.h"
+#endif /* USE_USBD_COMPOSITE */
+
+/** @addtogroup STM32_USBD_DEVICE_LIBRARY
+ * @{
+ */
+
+
+/** @defgroup USBD_CORE
+ * @brief usbd core module
+ * @{
+ */
+
+/** @defgroup USBD_CORE_Private_TypesDefinitions
+ * @{
+ */
+
+/**
+ * @}
+ */
+
+
+/** @defgroup USBD_CORE_Private_Defines
+ * @{
+ */
+
+/**
+ * @}
+ */
+
+
+/** @defgroup USBD_CORE_Private_Macros
+ * @{
+ */
+
+/**
+ * @}
+ */
+
+
+/** @defgroup USBD_CORE_Private_FunctionPrototypes
+ * @{
+ */
+
+/**
+ * @}
+ */
+
+/** @defgroup USBD_CORE_Private_Variables
+ * @{
+ */
+
+/**
+ * @}
+ */
+
+
+/** @defgroup USBD_CORE_Private_Functions
+ * @{
+ */
+
+/**
+ * @brief USBD_Init
+ * Initialize the device stack and load the class driver
+ * @param pdev: device instance
+ * @param pdesc: Descriptor structure address
+ * @param id: Low level core index
+ * @retval status: USBD Status
+ */
+USBD_StatusTypeDef USBD_Init(USBD_HandleTypeDef *pdev,
+ USBD_DescriptorsTypeDef *pdesc, uint8_t id)
+{
+ USBD_StatusTypeDef ret;
+
+ /* Check whether the USB Host handle is valid */
+ if (pdev == NULL)
+ {
+#if (USBD_DEBUG_LEVEL > 1U)
+ USBD_ErrLog("Invalid Device handle");
+#endif /* (USBD_DEBUG_LEVEL > 1U) */
+ return USBD_FAIL;
+ }
+
+#ifdef USE_USBD_COMPOSITE
+ /* Parse the table of classes in use */
+ for (uint32_t i = 0; i < USBD_MAX_SUPPORTED_CLASS; i++)
+ {
+ /* Unlink previous class*/
+ pdev->pClass[i] = NULL;
+ pdev->pUserData[i] = NULL;
+
+ /* Set class as inactive */
+ pdev->tclasslist[i].Active = 0;
+ pdev->NumClasses = 0;
+ pdev->classId = 0;
+ }
+#else
+ /* Unlink previous class*/
+ pdev->pClass[0] = NULL;
+ pdev->pUserData[0] = NULL;
+#endif /* USE_USBD_COMPOSITE */
+
+ pdev->pConfDesc = NULL;
+
+ /* Assign USBD Descriptors */
+ if (pdesc != NULL)
+ {
+ pdev->pDesc = pdesc;
+ }
+
+ /* Set Device initial State */
+ pdev->dev_state = USBD_STATE_DEFAULT;
+ pdev->id = id;
+
+ /* Initialize low level driver */
+ ret = USBD_LL_Init(pdev);
+
+ return ret;
+}
+
+/**
+ * @brief USBD_DeInit
+ * De-Initialize the device library
+ * @param pdev: device instance
+ * @retval status: USBD Status
+ */
+USBD_StatusTypeDef USBD_DeInit(USBD_HandleTypeDef *pdev)
+{
+ USBD_StatusTypeDef ret;
+
+ /* Disconnect the USB Device */
+ (void)USBD_LL_Stop(pdev);
+
+ /* Set Default State */
+ pdev->dev_state = USBD_STATE_DEFAULT;
+
+#ifdef USE_USBD_COMPOSITE
+ /* Parse the table of classes in use */
+ for (uint32_t i = 0; i < USBD_MAX_SUPPORTED_CLASS; i++)
+ {
+ /* Check if current class is in use */
+ if ((pdev->tclasslist[i].Active) == 1U)
+ {
+ if (pdev->pClass[i] != NULL)
+ {
+ pdev->classId = i;
+ /* Free Class Resources */
+ pdev->pClass[i]->DeInit(pdev, (uint8_t)pdev->dev_config);
+ }
+ }
+ }
+#else
+ /* Free Class Resources */
+ if (pdev->pClass[0] != NULL)
+ {
+ pdev->pClass[0]->DeInit(pdev, (uint8_t)pdev->dev_config);
+ }
+
+ pdev->pUserData[0] = NULL;
+
+#endif /* USE_USBD_COMPOSITE */
+
+ /* Free Device descriptors resources */
+ pdev->pDesc = NULL;
+ pdev->pConfDesc = NULL;
+
+ /* DeInitialize low level driver */
+ ret = USBD_LL_DeInit(pdev);
+
+ return ret;
+}
+
+/**
+ * @brief USBD_RegisterClass
+ * Link class driver to Device Core.
+ * @param pdev: Device Handle
+ * @param pclass: Class handle
+ * @retval USBD Status
+ */
+USBD_StatusTypeDef USBD_RegisterClass(USBD_HandleTypeDef *pdev, USBD_ClassTypeDef *pclass)
+{
+ uint16_t len = 0U;
+
+ if (pclass == NULL)
+ {
+#if (USBD_DEBUG_LEVEL > 1U)
+ USBD_ErrLog("Invalid Class handle");
+#endif /* (USBD_DEBUG_LEVEL > 1U) */
+ return USBD_FAIL;
+ }
+
+ /* link the class to the USB Device handle */
+ pdev->pClass[0] = pclass;
+
+ /* Get Device Configuration Descriptor */
+#ifdef USE_USB_HS
+ if (pdev->pClass[pdev->classId]->GetHSConfigDescriptor != NULL)
+ {
+ pdev->pConfDesc = (void *)pdev->pClass[pdev->classId]->GetHSConfigDescriptor(&len);
+ }
+#else /* Default USE_USB_FS */
+ if (pdev->pClass[pdev->classId]->GetFSConfigDescriptor != NULL)
+ {
+ pdev->pConfDesc = (void *)pdev->pClass[pdev->classId]->GetFSConfigDescriptor(&len);
+ }
+#endif /* USE_USB_FS */
+
+ /* Increment the NumClasses */
+ pdev->NumClasses++;
+
+ return USBD_OK;
+}
+
+#ifdef USE_USBD_COMPOSITE
+/**
+ * @brief USBD_RegisterClassComposite
+ * Link class driver to Device Core.
+ * @param pdev : Device Handle
+ * @param pclass: Class handle
+ * @param classtype: Class type
+ * @param EpAddr: Endpoint Address handle
+ * @retval USBD Status
+ */
+USBD_StatusTypeDef USBD_RegisterClassComposite(USBD_HandleTypeDef *pdev, USBD_ClassTypeDef *pclass,
+ USBD_CompositeClassTypeDef classtype, uint8_t *EpAddr)
+{
+ USBD_StatusTypeDef ret = USBD_OK;
+ uint16_t len = 0U;
+
+ if ((pdev->classId < USBD_MAX_SUPPORTED_CLASS) && (pdev->NumClasses < USBD_MAX_SUPPORTED_CLASS))
+ {
+ if ((uint32_t)pclass != 0U)
+ {
+ /* Link the class to the USB Device handle */
+ pdev->pClass[pdev->classId] = pclass;
+ ret = USBD_OK;
+
+ pdev->tclasslist[pdev->classId].EpAdd = EpAddr;
+
+ /* Call the composite class builder */
+ (void)USBD_CMPSIT_AddClass(pdev, pclass, classtype, 0);
+
+ /* Increment the ClassId for the next occurrence */
+ pdev->classId ++;
+ pdev->NumClasses ++;
+ }
+ else
+ {
+#if (USBD_DEBUG_LEVEL > 1U)
+ USBD_ErrLog("Invalid Class handle");
+#endif /* (USBD_DEBUG_LEVEL > 1U) */
+ ret = USBD_FAIL;
+ }
+ }
+
+ if (ret == USBD_OK)
+ {
+ /* Get Device Configuration Descriptor */
+#ifdef USE_USB_HS
+ pdev->pConfDesc = USBD_CMPSIT.GetHSConfigDescriptor(&len);
+#else /* Default USE_USB_FS */
+ pdev->pConfDesc = USBD_CMPSIT.GetFSConfigDescriptor(&len);
+#endif /* USE_USB_FS */
+ }
+
+ return ret;
+}
+
+/**
+ * @brief USBD_UnRegisterClassComposite
+ * UnLink all composite class drivers from Device Core.
+ * @param pdev: Device Handle
+ * @retval USBD Status
+ */
+USBD_StatusTypeDef USBD_UnRegisterClassComposite(USBD_HandleTypeDef *pdev)
+{
+ USBD_StatusTypeDef ret = USBD_FAIL;
+ uint8_t idx1;
+ uint8_t idx2;
+
+ /* Unroll all activated classes */
+ for (idx1 = 0; idx1 < pdev->NumClasses; idx1++)
+ {
+ /* Check if the class correspond to the requested type and if it is active */
+ if (pdev->tclasslist[idx1].Active == 1U)
+ {
+ /* Set the new class ID */
+ pdev->classId = idx1;
+
+ /* Free resources used by the selected class */
+ if (pdev->pClass[pdev->classId] != NULL)
+ {
+ /* Free Class Resources */
+ if (pdev->pClass[pdev->classId]->DeInit(pdev, (uint8_t)pdev->dev_config) != 0U)
+ {
+#if (USBD_DEBUG_LEVEL > 1U)
+ USBD_ErrLog("Class DeInit didn't succeed!, can't unregister selected class");
+#endif /* (USBD_DEBUG_LEVEL > 1U) */
+
+ ret = USBD_FAIL;
+ }
+ }
+
+ /* Free the class pointer */
+ pdev->pClass[pdev->classId] = NULL;
+
+ /* Free the class location in classes table and reset its parameters to zero */
+ pdev->tclasslist[pdev->classId].ClassType = CLASS_TYPE_NONE;
+ pdev->tclasslist[pdev->classId].ClassId = 0U;
+ pdev->tclasslist[pdev->classId].Active = 0U;
+ pdev->tclasslist[pdev->classId].NumEps = 0U;
+ pdev->tclasslist[pdev->classId].NumIf = 0U;
+ pdev->tclasslist[pdev->classId].CurrPcktSze = 0U;
+
+ for (idx2 = 0U; idx2 < USBD_MAX_CLASS_ENDPOINTS; idx2++)
+ {
+ pdev->tclasslist[pdev->classId].Eps[idx2].add = 0U;
+ pdev->tclasslist[pdev->classId].Eps[idx2].type = 0U;
+ pdev->tclasslist[pdev->classId].Eps[idx2].size = 0U;
+ pdev->tclasslist[pdev->classId].Eps[idx2].is_used = 0U;
+ }
+
+ for (idx2 = 0U; idx2 < USBD_MAX_CLASS_INTERFACES; idx2++)
+ {
+ pdev->tclasslist[pdev->classId].Ifs[idx2] = 0U;
+ }
+ }
+ }
+
+ /* Reset the configuration descriptor */
+ (void)USBD_CMPST_ClearConfDesc(pdev);
+
+ /* Reset the class ID and number of classes */
+ pdev->classId = 0U;
+ pdev->NumClasses = 0U;
+
+ return ret;
+}
+#endif /* USE_USBD_COMPOSITE */
+
+#if (USBD_USER_REGISTER_CALLBACK == 1U)
+/**
+ * @brief USBD_RegisterDevStateCallback
+ * @param pdev : Device Handle
+ * @param pUserCallback: User Callback
+ * @retval USBD Status
+ */
+USBD_StatusTypeDef USBD_RegisterDevStateCallback(USBD_HandleTypeDef *pdev, USBD_DevStateCallbackTypeDef pUserCallback)
+{
+ pdev->DevStateCallback = pUserCallback;
+
+ return USBD_OK;
+}
+#endif /* USBD_USER_REGISTER_CALLBACK */
+
+/**
+ * @brief USBD_Start
+ * Start the USB Device Core.
+ * @param pdev: Device Handle
+ * @retval USBD Status
+ */
+USBD_StatusTypeDef USBD_Start(USBD_HandleTypeDef *pdev)
+{
+#ifdef USE_USBD_COMPOSITE
+ pdev->classId = 0U;
+#endif /* USE_USBD_COMPOSITE */
+
+ /* Start the low level driver */
+ return USBD_LL_Start(pdev);
+}
+
+/**
+ * @brief USBD_Stop
+ * Stop the USB Device Core.
+ * @param pdev: Device Handle
+ * @retval USBD Status
+ */
+USBD_StatusTypeDef USBD_Stop(USBD_HandleTypeDef *pdev)
+{
+ /* Disconnect USB Device */
+ (void)USBD_LL_Stop(pdev);
+
+ /* Free Class Resources */
+#ifdef USE_USBD_COMPOSITE
+ /* Parse the table of classes in use */
+ for (uint32_t i = 0U; i < USBD_MAX_SUPPORTED_CLASS; i++)
+ {
+ /* Check if current class is in use */
+ if ((pdev->tclasslist[i].Active) == 1U)
+ {
+ if (pdev->pClass[i] != NULL)
+ {
+ pdev->classId = i;
+ /* Free Class Resources */
+ (void)pdev->pClass[i]->DeInit(pdev, (uint8_t)pdev->dev_config);
+ }
+ }
+ }
+
+ /* Reset the class ID */
+ pdev->classId = 0U;
+#else
+ if (pdev->pClass[0] != NULL)
+ {
+ (void)pdev->pClass[0]->DeInit(pdev, (uint8_t)pdev->dev_config);
+ }
+#endif /* USE_USBD_COMPOSITE */
+
+ return USBD_OK;
+}
+
+/**
+ * @brief USBD_RunTestMode
+ * Launch test mode process
+ * @param pdev: device instance
+ * @retval status
+ */
+USBD_StatusTypeDef USBD_RunTestMode(USBD_HandleTypeDef *pdev)
+{
+#ifdef USBD_HS_TESTMODE_ENABLE
+ USBD_StatusTypeDef ret;
+
+ /* Run USB HS test mode */
+ ret = USBD_LL_SetTestMode(pdev, pdev->dev_test_mode);
+
+ return ret;
+#else
+ /* Prevent unused argument compilation warning */
+ UNUSED(pdev);
+
+ return USBD_OK;
+#endif /* USBD_HS_TESTMODE_ENABLE */
+}
+
+/**
+ * @brief USBD_SetClassConfig
+ * Configure device and start the interface
+ * @param pdev: device instance
+ * @param cfgidx: configuration index
+ * @retval status
+ */
+
+USBD_StatusTypeDef USBD_SetClassConfig(USBD_HandleTypeDef *pdev, uint8_t cfgidx)
+{
+ USBD_StatusTypeDef ret = USBD_OK;
+
+#ifdef USE_USBD_COMPOSITE
+ /* Parse the table of classes in use */
+ for (uint32_t i = 0U; i < USBD_MAX_SUPPORTED_CLASS; i++)
+ {
+ /* Check if current class is in use */
+ if ((pdev->tclasslist[i].Active) == 1U)
+ {
+ if (pdev->pClass[i] != NULL)
+ {
+ pdev->classId = i;
+ /* Set configuration and Start the Class*/
+ if (pdev->pClass[i]->Init(pdev, cfgidx) != 0U)
+ {
+ ret = USBD_FAIL;
+ }
+ }
+ }
+ }
+#else
+ if (pdev->pClass[0] != NULL)
+ {
+ /* Set configuration and Start the Class */
+ ret = (USBD_StatusTypeDef)pdev->pClass[0]->Init(pdev, cfgidx);
+ }
+#endif /* USE_USBD_COMPOSITE */
+
+ return ret;
+}
+
+/**
+ * @brief USBD_ClrClassConfig
+ * Clear current configuration
+ * @param pdev: device instance
+ * @param cfgidx: configuration index
+ * @retval status
+ */
+USBD_StatusTypeDef USBD_ClrClassConfig(USBD_HandleTypeDef *pdev, uint8_t cfgidx)
+{
+ USBD_StatusTypeDef ret = USBD_OK;
+
+#ifdef USE_USBD_COMPOSITE
+ /* Parse the table of classes in use */
+ for (uint32_t i = 0U; i < USBD_MAX_SUPPORTED_CLASS; i++)
+ {
+ /* Check if current class is in use */
+ if ((pdev->tclasslist[i].Active) == 1U)
+ {
+ if (pdev->pClass[i] != NULL)
+ {
+ pdev->classId = i;
+ /* Clear configuration and De-initialize the Class process */
+ if (pdev->pClass[i]->DeInit(pdev, cfgidx) != 0U)
+ {
+ ret = USBD_FAIL;
+ }
+ }
+ }
+ }
+#else
+ /* Clear configuration and De-initialize the Class process */
+ if (pdev->pClass[0]->DeInit(pdev, cfgidx) != 0U)
+ {
+ ret = USBD_FAIL;
+ }
+#endif /* USE_USBD_COMPOSITE */
+
+ return ret;
+}
+
+
+/**
+ * @brief USBD_LL_SetupStage
+ * Handle the setup stage
+ * @param pdev: device instance
+ * @param psetup: setup packet buffer pointer
+ * @retval status
+ */
+USBD_StatusTypeDef USBD_LL_SetupStage(USBD_HandleTypeDef *pdev, uint8_t *psetup)
+{
+ USBD_StatusTypeDef ret;
+
+ USBD_ParseSetupRequest(&pdev->request, psetup);
+
+ pdev->ep0_state = USBD_EP0_SETUP;
+
+ pdev->ep0_data_len = pdev->request.wLength;
+
+ switch (pdev->request.bmRequest & 0x1FU)
+ {
+ case USB_REQ_RECIPIENT_DEVICE:
+ ret = USBD_StdDevReq(pdev, &pdev->request);
+ break;
+
+ case USB_REQ_RECIPIENT_INTERFACE:
+ ret = USBD_StdItfReq(pdev, &pdev->request);
+ break;
+
+ case USB_REQ_RECIPIENT_ENDPOINT:
+ ret = USBD_StdEPReq(pdev, &pdev->request);
+ break;
+
+ default:
+ ret = USBD_LL_StallEP(pdev, (pdev->request.bmRequest & 0x80U));
+ break;
+ }
+
+ return ret;
+}
+
+/**
+ * @brief USBD_LL_DataOutStage
+ * Handle data OUT stage
+ * @param pdev: device instance
+ * @param epnum: endpoint index
+ * @param pdata: data pointer
+ * @retval status
+ */
+USBD_StatusTypeDef USBD_LL_DataOutStage(USBD_HandleTypeDef *pdev,
+ uint8_t epnum, uint8_t *pdata)
+{
+ USBD_EndpointTypeDef *pep;
+ USBD_StatusTypeDef ret = USBD_OK;
+ uint8_t idx;
+
+ if (epnum == 0U)
+ {
+ pep = &pdev->ep_out[0];
+
+ if (pdev->ep0_state == USBD_EP0_DATA_OUT)
+ {
+ if (pep->rem_length > pep->maxpacket)
+ {
+ pep->rem_length -= pep->maxpacket;
+
+ (void)USBD_CtlContinueRx(pdev, pdata, MIN(pep->rem_length, pep->maxpacket));
+ }
+ else
+ {
+ /* Find the class ID relative to the current request */
+ switch (pdev->request.bmRequest & 0x1FU)
+ {
+ case USB_REQ_RECIPIENT_DEVICE:
+ /* Device requests must be managed by the first instantiated class
+ (or duplicated by all classes for simplicity) */
+ idx = 0U;
+ break;
+
+ case USB_REQ_RECIPIENT_INTERFACE:
+ idx = USBD_CoreFindIF(pdev, LOBYTE(pdev->request.wIndex));
+ break;
+
+ case USB_REQ_RECIPIENT_ENDPOINT:
+ idx = USBD_CoreFindEP(pdev, LOBYTE(pdev->request.wIndex));
+ break;
+
+ default:
+ /* Back to the first class in case of doubt */
+ idx = 0U;
+ break;
+ }
+
+ if (idx < USBD_MAX_SUPPORTED_CLASS)
+ {
+ /* Setup the class ID and route the request to the relative class function */
+ if (pdev->dev_state == USBD_STATE_CONFIGURED)
+ {
+ if (pdev->pClass[idx]->EP0_RxReady != NULL)
+ {
+ pdev->classId = idx;
+ pdev->pClass[idx]->EP0_RxReady(pdev);
+ }
+ }
+ }
+
+ (void)USBD_CtlSendStatus(pdev);
+ }
+ }
+ }
+ else
+ {
+ /* Get the class index relative to this interface */
+ idx = USBD_CoreFindEP(pdev, (epnum & 0x7FU));
+
+ if (((uint16_t)idx != 0xFFU) && (idx < USBD_MAX_SUPPORTED_CLASS))
+ {
+ /* Call the class data out function to manage the request */
+ if (pdev->dev_state == USBD_STATE_CONFIGURED)
+ {
+ if (pdev->pClass[idx]->DataOut != NULL)
+ {
+ pdev->classId = idx;
+ ret = (USBD_StatusTypeDef)pdev->pClass[idx]->DataOut(pdev, epnum);
+ }
+ }
+ if (ret != USBD_OK)
+ {
+ return ret;
+ }
+ }
+ }
+
+ return USBD_OK;
+}
+
+/**
+ * @brief USBD_LL_DataInStage
+ * Handle data in stage
+ * @param pdev: device instance
+ * @param epnum: endpoint index
+ * @param pdata: data pointer
+ * @retval status
+ */
+USBD_StatusTypeDef USBD_LL_DataInStage(USBD_HandleTypeDef *pdev,
+ uint8_t epnum, uint8_t *pdata)
+{
+ USBD_EndpointTypeDef *pep;
+ USBD_StatusTypeDef ret;
+ uint8_t idx;
+
+ if (epnum == 0U)
+ {
+ pep = &pdev->ep_in[0];
+
+ if (pdev->ep0_state == USBD_EP0_DATA_IN)
+ {
+ if (pep->rem_length > pep->maxpacket)
+ {
+ pep->rem_length -= pep->maxpacket;
+
+ (void)USBD_CtlContinueSendData(pdev, pdata, pep->rem_length);
+
+ /* Prepare endpoint for premature end of transfer */
+ (void)USBD_LL_PrepareReceive(pdev, 0U, NULL, 0U);
+ }
+ else
+ {
+ /* last packet is MPS multiple, so send ZLP packet */
+ if ((pep->maxpacket == pep->rem_length) &&
+ (pep->total_length >= pep->maxpacket) &&
+ (pep->total_length < pdev->ep0_data_len))
+ {
+ (void)USBD_CtlContinueSendData(pdev, NULL, 0U);
+ pdev->ep0_data_len = 0U;
+
+ /* Prepare endpoint for premature end of transfer */
+ (void)USBD_LL_PrepareReceive(pdev, 0U, NULL, 0U);
+ }
+ else
+ {
+ if (pdev->dev_state == USBD_STATE_CONFIGURED)
+ {
+ if (pdev->pClass[0]->EP0_TxSent != NULL)
+ {
+ pdev->classId = 0U;
+ pdev->pClass[0]->EP0_TxSent(pdev);
+ }
+ }
+ (void)USBD_LL_StallEP(pdev, 0x80U);
+ (void)USBD_CtlReceiveStatus(pdev);
+ }
+ }
+ }
+
+ if (pdev->dev_test_mode != 0U)
+ {
+ (void)USBD_RunTestMode(pdev);
+ pdev->dev_test_mode = 0U;
+ }
+ }
+ else
+ {
+ /* Get the class index relative to this interface */
+ idx = USBD_CoreFindEP(pdev, ((uint8_t)epnum | 0x80U));
+
+ if (((uint16_t)idx != 0xFFU) && (idx < USBD_MAX_SUPPORTED_CLASS))
+ {
+ /* Call the class data out function to manage the request */
+ if (pdev->dev_state == USBD_STATE_CONFIGURED)
+ {
+ if (pdev->pClass[idx]->DataIn != NULL)
+ {
+ pdev->classId = idx;
+ ret = (USBD_StatusTypeDef)pdev->pClass[idx]->DataIn(pdev, epnum);
+
+ if (ret != USBD_OK)
+ {
+ return ret;
+ }
+ }
+ }
+ }
+ }
+
+ return USBD_OK;
+}
+
+/**
+ * @brief USBD_LL_Reset
+ * Handle Reset event
+ * @param pdev: device instance
+ * @retval status
+ */
+USBD_StatusTypeDef USBD_LL_Reset(USBD_HandleTypeDef *pdev)
+{
+ USBD_StatusTypeDef ret = USBD_OK;
+
+ /* Upon Reset call user call back */
+ pdev->dev_state = USBD_STATE_DEFAULT;
+ pdev->ep0_state = USBD_EP0_IDLE;
+ pdev->dev_config = 0U;
+ pdev->dev_remote_wakeup = 0U;
+ pdev->dev_test_mode = 0U;
+
+#ifdef USE_USBD_COMPOSITE
+ /* Parse the table of classes in use */
+ for (uint32_t i = 0U; i < USBD_MAX_SUPPORTED_CLASS; i++)
+ {
+ /* Check if current class is in use */
+ if ((pdev->tclasslist[i].Active) == 1U)
+ {
+ if (pdev->pClass[i] != NULL)
+ {
+ pdev->classId = i;
+ /* Clear configuration and De-initialize the Class process*/
+
+ if (pdev->pClass[i]->DeInit != NULL)
+ {
+ if (pdev->pClass[i]->DeInit(pdev, (uint8_t)pdev->dev_config) != USBD_OK)
+ {
+ ret = USBD_FAIL;
+ }
+ }
+ }
+ }
+ }
+#else
+
+ if (pdev->pClass[0] != NULL)
+ {
+ if (pdev->pClass[0]->DeInit != NULL)
+ {
+ if (pdev->pClass[0]->DeInit(pdev, (uint8_t)pdev->dev_config) != USBD_OK)
+ {
+ ret = USBD_FAIL;
+ }
+ }
+ }
+#endif /* USE_USBD_COMPOSITE */
+
+ /* Open EP0 OUT */
+ (void)USBD_LL_OpenEP(pdev, 0x00U, USBD_EP_TYPE_CTRL, USB_MAX_EP0_SIZE);
+ pdev->ep_out[0x00U & 0xFU].is_used = 1U;
+
+ pdev->ep_out[0].maxpacket = USB_MAX_EP0_SIZE;
+
+ /* Open EP0 IN */
+ (void)USBD_LL_OpenEP(pdev, 0x80U, USBD_EP_TYPE_CTRL, USB_MAX_EP0_SIZE);
+ pdev->ep_in[0x80U & 0xFU].is_used = 1U;
+
+ pdev->ep_in[0].maxpacket = USB_MAX_EP0_SIZE;
+
+ return ret;
+}
+
+/**
+ * @brief USBD_LL_SetSpeed
+ * Handle Reset event
+ * @param pdev: device instance
+ * @retval status
+ */
+USBD_StatusTypeDef USBD_LL_SetSpeed(USBD_HandleTypeDef *pdev,
+ USBD_SpeedTypeDef speed)
+{
+ pdev->dev_speed = speed;
+
+ return USBD_OK;
+}
+
+/**
+ * @brief USBD_LL_Suspend
+ * Handle Suspend event
+ * @param pdev: device instance
+ * @retval status
+ */
+USBD_StatusTypeDef USBD_LL_Suspend(USBD_HandleTypeDef *pdev)
+{
+ if (pdev->dev_state != USBD_STATE_SUSPENDED)
+ {
+ pdev->dev_old_state = pdev->dev_state;
+ }
+
+ pdev->dev_state = USBD_STATE_SUSPENDED;
+
+ return USBD_OK;
+}
+
+/**
+ * @brief USBD_LL_Resume
+ * Handle Resume event
+ * @param pdev: device instance
+ * @retval status
+ */
+USBD_StatusTypeDef USBD_LL_Resume(USBD_HandleTypeDef *pdev)
+{
+ if (pdev->dev_state == USBD_STATE_SUSPENDED)
+ {
+ pdev->dev_state = pdev->dev_old_state;
+ }
+
+ return USBD_OK;
+}
+
+/**
+ * @brief USBD_LL_SOF
+ * Handle SOF event
+ * @param pdev: device instance
+ * @retval status
+ */
+USBD_StatusTypeDef USBD_LL_SOF(USBD_HandleTypeDef *pdev)
+{
+ /* The SOF event can be distributed for all classes that support it */
+ if (pdev->dev_state == USBD_STATE_CONFIGURED)
+ {
+#ifdef USE_USBD_COMPOSITE
+ /* Parse the table of classes in use */
+ for (uint32_t i = 0; i < USBD_MAX_SUPPORTED_CLASS; i++)
+ {
+ /* Check if current class is in use */
+ if ((pdev->tclasslist[i].Active) == 1U)
+ {
+ if (pdev->pClass[i] != NULL)
+ {
+ if (pdev->pClass[i]->SOF != NULL)
+ {
+ pdev->classId = i;
+ (void)pdev->pClass[i]->SOF(pdev);
+ }
+ }
+ }
+ }
+#else
+ if (pdev->pClass[0] != NULL)
+ {
+ if (pdev->pClass[0]->SOF != NULL)
+ {
+ (void)pdev->pClass[0]->SOF(pdev);
+ }
+ }
+#endif /* USE_USBD_COMPOSITE */
+ }
+
+ return USBD_OK;
+}
+
+/**
+ * @brief USBD_LL_IsoINIncomplete
+ * Handle iso in incomplete event
+ * @param pdev: device instance
+ * @param epnum: Endpoint number
+ * @retval status
+ */
+USBD_StatusTypeDef USBD_LL_IsoINIncomplete(USBD_HandleTypeDef *pdev,
+ uint8_t epnum)
+{
+ if (pdev->pClass[pdev->classId] == NULL)
+ {
+ return USBD_FAIL;
+ }
+
+ if (pdev->dev_state == USBD_STATE_CONFIGURED)
+ {
+ if (pdev->pClass[pdev->classId]->IsoINIncomplete != NULL)
+ {
+ (void)pdev->pClass[pdev->classId]->IsoINIncomplete(pdev, epnum);
+ }
+ }
+
+ return USBD_OK;
+}
+
+/**
+ * @brief USBD_LL_IsoOUTIncomplete
+ * Handle iso out incomplete event
+ * @param pdev: device instance
+ * @param epnum: Endpoint number
+ * @retval status
+ */
+USBD_StatusTypeDef USBD_LL_IsoOUTIncomplete(USBD_HandleTypeDef *pdev,
+ uint8_t epnum)
+{
+ if (pdev->pClass[pdev->classId] == NULL)
+ {
+ return USBD_FAIL;
+ }
+
+ if (pdev->dev_state == USBD_STATE_CONFIGURED)
+ {
+ if (pdev->pClass[pdev->classId]->IsoOUTIncomplete != NULL)
+ {
+ (void)pdev->pClass[pdev->classId]->IsoOUTIncomplete(pdev, epnum);
+ }
+ }
+
+ return USBD_OK;
+}
+
+/**
+ * @brief USBD_LL_DevConnected
+ * Handle device connection event
+ * @param pdev: device instance
+ * @retval status
+ */
+USBD_StatusTypeDef USBD_LL_DevConnected(USBD_HandleTypeDef *pdev)
+{
+ /* Prevent unused argument compilation warning */
+ UNUSED(pdev);
+
+ return USBD_OK;
+}
+
+/**
+ * @brief USBD_LL_DevDisconnected
+ * Handle device disconnection event
+ * @param pdev: device instance
+ * @retval status
+ */
+USBD_StatusTypeDef USBD_LL_DevDisconnected(USBD_HandleTypeDef *pdev)
+{
+ USBD_StatusTypeDef ret = USBD_OK;
+
+ /* Free Class Resources */
+ pdev->dev_state = USBD_STATE_DEFAULT;
+
+#ifdef USE_USBD_COMPOSITE
+ /* Parse the table of classes in use */
+ for (uint32_t i = 0; i < USBD_MAX_SUPPORTED_CLASS; i++)
+ {
+ /* Check if current class is in use */
+ if ((pdev->tclasslist[i].Active) == 1U)
+ {
+ if (pdev->pClass[i] != NULL)
+ {
+ pdev->classId = i;
+ /* Clear configuration and De-initialize the Class process*/
+ if (pdev->pClass[i]->DeInit(pdev, (uint8_t)pdev->dev_config) != 0U)
+ {
+ ret = USBD_FAIL;
+ }
+ }
+ }
+ }
+#else
+ if (pdev->pClass[0] != NULL)
+ {
+ if (pdev->pClass[0]->DeInit(pdev, (uint8_t)pdev->dev_config) != 0U)
+ {
+ ret = USBD_FAIL;
+ }
+ }
+#endif /* USE_USBD_COMPOSITE */
+
+ return ret;
+}
+
+/**
+ * @brief USBD_CoreFindIF
+ * return the class index relative to the selected interface
+ * @param pdev: device instance
+ * @param index : selected interface number
+ * @retval index of the class using the selected interface number. OxFF if no class found.
+ */
+uint8_t USBD_CoreFindIF(USBD_HandleTypeDef *pdev, uint8_t index)
+{
+#ifdef USE_USBD_COMPOSITE
+ /* Parse the table of classes in use */
+ for (uint32_t i = 0U; i < USBD_MAX_SUPPORTED_CLASS; i++)
+ {
+ /* Check if current class is in use */
+ if ((pdev->tclasslist[i].Active) == 1U)
+ {
+ /* Parse all interfaces listed in the current class */
+ for (uint32_t j = 0U; j < pdev->tclasslist[i].NumIf; j++)
+ {
+ /* Check if requested Interface matches the current class interface */
+ if (pdev->tclasslist[i].Ifs[j] == index)
+ {
+ if (pdev->pClass[i]->Setup != NULL)
+ {
+ return (uint8_t)i;
+ }
+ }
+ }
+ }
+ }
+
+ return 0xFFU;
+#else
+ UNUSED(pdev);
+ UNUSED(index);
+
+ return 0x00U;
+#endif /* USE_USBD_COMPOSITE */
+}
+
+/**
+ * @brief USBD_CoreFindEP
+ * return the class index relative to the selected endpoint
+ * @param pdev: device instance
+ * @param index : selected endpoint number
+ * @retval index of the class using the selected endpoint number. 0xFF if no class found.
+ */
+uint8_t USBD_CoreFindEP(USBD_HandleTypeDef *pdev, uint8_t index)
+{
+#ifdef USE_USBD_COMPOSITE
+ /* Parse the table of classes in use */
+ for (uint32_t i = 0U; i < USBD_MAX_SUPPORTED_CLASS; i++)
+ {
+ /* Check if current class is in use */
+ if ((pdev->tclasslist[i].Active) == 1U)
+ {
+ /* Parse all endpoints listed in the current class */
+ for (uint32_t j = 0U; j < pdev->tclasslist[i].NumEps; j++)
+ {
+ /* Check if requested endpoint matches the current class endpoint */
+ if (pdev->tclasslist[i].Eps[j].add == index)
+ {
+ if (pdev->pClass[i]->Setup != NULL)
+ {
+ return (uint8_t)i;
+ }
+ }
+ }
+ }
+ }
+
+ return 0xFFU;
+#else
+ UNUSED(pdev);
+ UNUSED(index);
+
+ return 0x00U;
+#endif /* USE_USBD_COMPOSITE */
+}
+
+#ifdef USE_USBD_COMPOSITE
+/**
+ * @brief USBD_CoreGetEPAdd
+ * Get the endpoint address relative to a selected class
+ * @param pdev: device instance
+ * @param ep_dir: USBD_EP_IN or USBD_EP_OUT
+ * @param ep_type: USBD_EP_TYPE_CTRL, USBD_EP_TYPE_ISOC, USBD_EP_TYPE_BULK or USBD_EP_TYPE_INTR
+ * @param ClassId: The Class ID
+ * @retval Address of the selected endpoint or 0xFFU if no endpoint found.
+ */
+uint8_t USBD_CoreGetEPAdd(USBD_HandleTypeDef *pdev, uint8_t ep_dir, uint8_t ep_type, uint8_t ClassId)
+{
+ uint8_t idx;
+
+ /* Find the EP address in the selected class table */
+ for (idx = 0; idx < pdev->tclasslist[ClassId].NumEps; idx++)
+ {
+ if (((pdev->tclasslist[ClassId].Eps[idx].add & USBD_EP_IN) == ep_dir) && \
+ (pdev->tclasslist[ClassId].Eps[idx].type == ep_type) && \
+ (pdev->tclasslist[ClassId].Eps[idx].is_used != 0U))
+ {
+ return (pdev->tclasslist[ClassId].Eps[idx].add);
+ }
+ }
+
+ /* If reaching this point, then no endpoint was found */
+ return 0xFFU;
+}
+#endif /* USE_USBD_COMPOSITE */
+
+/**
+ * @brief USBD_GetEpDesc
+ * This function return the Endpoint descriptor
+ * @param pdev: device instance
+ * @param pConfDesc: pointer to Bos descriptor
+ * @param EpAddr: endpoint address
+ * @retval pointer to video endpoint descriptor
+ */
+void *USBD_GetEpDesc(uint8_t *pConfDesc, uint8_t EpAddr)
+{
+ USBD_DescHeaderTypeDef *pdesc = (USBD_DescHeaderTypeDef *)(void *)pConfDesc;
+ USBD_ConfigDescTypeDef *desc = (USBD_ConfigDescTypeDef *)(void *)pConfDesc;
+ USBD_EpDescTypeDef *pEpDesc = NULL;
+ uint16_t ptr;
+
+ if (desc->wTotalLength > desc->bLength)
+ {
+ ptr = desc->bLength;
+
+ while (ptr < desc->wTotalLength)
+ {
+ pdesc = USBD_GetNextDesc((uint8_t *)pdesc, &ptr);
+
+ if (pdesc->bDescriptorType == USB_DESC_TYPE_ENDPOINT)
+ {
+ pEpDesc = (USBD_EpDescTypeDef *)(void *)pdesc;
+
+ if (pEpDesc->bEndpointAddress == EpAddr)
+ {
+ break;
+ }
+ else
+ {
+ pEpDesc = NULL;
+ }
+ }
+ }
+ }
+
+ return (void *)pEpDesc;
+}
+
+/**
+ * @brief USBD_GetNextDesc
+ * This function return the next descriptor header
+ * @param buf: Buffer where the descriptor is available
+ * @param ptr: data pointer inside the descriptor
+ * @retval next header
+ */
+USBD_DescHeaderTypeDef *USBD_GetNextDesc(uint8_t *pbuf, uint16_t *ptr)
+{
+ USBD_DescHeaderTypeDef *pnext = (USBD_DescHeaderTypeDef *)(void *)pbuf;
+
+ *ptr += pnext->bLength;
+ pnext = (USBD_DescHeaderTypeDef *)(void *)(pbuf + pnext->bLength);
+
+ return (pnext);
+}
+
+/**
+ * @}
+ */
+
+
+/**
+ * @}
+ */
+
+
+/**
+ * @}
+ */
+
diff --git a/Ganesha_II_V2/Middlewares/ST/STM32_USB_Device_Library/Core/Src/usbd_ctlreq.c b/Ganesha_II_V2/Middlewares/ST/STM32_USB_Device_Library/Core/Src/usbd_ctlreq.c
new file mode 100644
index 0000000..814b810
--- /dev/null
+++ b/Ganesha_II_V2/Middlewares/ST/STM32_USB_Device_Library/Core/Src/usbd_ctlreq.c
@@ -0,0 +1,1058 @@
+/**
+ ******************************************************************************
+ * @file usbd_req.c
+ * @author MCD Application Team
+ * @brief This file provides the standard USB requests following chapter 9.
+ ******************************************************************************
+ * @attention
+ *
+ * Copyright (c) 2015 STMicroelectronics.
+ * All rights reserved.
+ *
+ * This software is licensed under terms that can be found in the LICENSE file
+ * in the root directory of this software component.
+ * If no LICENSE file comes with this software, it is provided AS-IS.
+ *
+ ******************************************************************************
+ */
+
+/* Includes ------------------------------------------------------------------*/
+#include "usbd_ctlreq.h"
+#include "usbd_ioreq.h"
+
+#ifdef USE_USBD_COMPOSITE
+#include "usbd_composite_builder.h"
+#endif /* USE_USBD_COMPOSITE */
+
+/** @addtogroup STM32_USBD_STATE_DEVICE_LIBRARY
+ * @{
+ */
+
+
+/** @defgroup USBD_REQ
+ * @brief USB standard requests module
+ * @{
+ */
+
+/** @defgroup USBD_REQ_Private_TypesDefinitions
+ * @{
+ */
+
+/**
+ * @}
+ */
+
+
+/** @defgroup USBD_REQ_Private_Defines
+ * @{
+ */
+#ifndef USBD_MAX_STR_DESC_SIZ
+#define USBD_MAX_STR_DESC_SIZ 64U
+#endif /* USBD_MAX_STR_DESC_SIZ */
+/**
+ * @}
+ */
+
+
+/** @defgroup USBD_REQ_Private_Macros
+ * @{
+ */
+
+/**
+ * @}
+ */
+
+
+/** @defgroup USBD_REQ_Private_Variables
+ * @{
+ */
+
+/**
+ * @}
+ */
+
+
+/** @defgroup USBD_REQ_Private_FunctionPrototypes
+ * @{
+ */
+static void USBD_GetDescriptor(USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req);
+static void USBD_SetAddress(USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req);
+static USBD_StatusTypeDef USBD_SetConfig(USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req);
+static void USBD_GetConfig(USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req);
+static void USBD_GetStatus(USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req);
+static void USBD_SetFeature(USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req);
+static void USBD_ClrFeature(USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req);
+static uint8_t USBD_GetLen(uint8_t *buf);
+
+/**
+ * @}
+ */
+
+
+/** @defgroup USBD_REQ_Private_Functions
+ * @{
+ */
+
+
+/**
+ * @brief USBD_StdDevReq
+ * Handle standard usb device requests
+ * @param pdev: device instance
+ * @param req: usb request
+ * @retval status
+ */
+USBD_StatusTypeDef USBD_StdDevReq(USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req)
+{
+ USBD_StatusTypeDef ret = USBD_OK;
+
+ switch (req->bmRequest & USB_REQ_TYPE_MASK)
+ {
+ case USB_REQ_TYPE_CLASS:
+ case USB_REQ_TYPE_VENDOR:
+ ret = (USBD_StatusTypeDef)pdev->pClass[pdev->classId]->Setup(pdev, req);
+ break;
+
+ case USB_REQ_TYPE_STANDARD:
+ switch (req->bRequest)
+ {
+ case USB_REQ_GET_DESCRIPTOR:
+ USBD_GetDescriptor(pdev, req);
+ break;
+
+ case USB_REQ_SET_ADDRESS:
+ USBD_SetAddress(pdev, req);
+ break;
+
+ case USB_REQ_SET_CONFIGURATION:
+ ret = USBD_SetConfig(pdev, req);
+ break;
+
+ case USB_REQ_GET_CONFIGURATION:
+ USBD_GetConfig(pdev, req);
+ break;
+
+ case USB_REQ_GET_STATUS:
+ USBD_GetStatus(pdev, req);
+ break;
+
+ case USB_REQ_SET_FEATURE:
+ USBD_SetFeature(pdev, req);
+ break;
+
+ case USB_REQ_CLEAR_FEATURE:
+ USBD_ClrFeature(pdev, req);
+ break;
+
+ default:
+ USBD_CtlError(pdev, req);
+ break;
+ }
+ break;
+
+ default:
+ USBD_CtlError(pdev, req);
+ break;
+ }
+
+ return ret;
+}
+
+/**
+ * @brief USBD_StdItfReq
+ * Handle standard usb interface requests
+ * @param pdev: device instance
+ * @param req: usb request
+ * @retval status
+ */
+USBD_StatusTypeDef USBD_StdItfReq(USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req)
+{
+ USBD_StatusTypeDef ret = USBD_OK;
+ uint8_t idx;
+
+ switch (req->bmRequest & USB_REQ_TYPE_MASK)
+ {
+ case USB_REQ_TYPE_CLASS:
+ case USB_REQ_TYPE_VENDOR:
+ case USB_REQ_TYPE_STANDARD:
+ switch (pdev->dev_state)
+ {
+ case USBD_STATE_DEFAULT:
+ case USBD_STATE_ADDRESSED:
+ case USBD_STATE_CONFIGURED:
+
+ if (LOBYTE(req->wIndex) <= USBD_MAX_NUM_INTERFACES)
+ {
+ /* Get the class index relative to this interface */
+ idx = USBD_CoreFindIF(pdev, LOBYTE(req->wIndex));
+ if (((uint8_t)idx != 0xFFU) && (idx < USBD_MAX_SUPPORTED_CLASS))
+ {
+ /* Call the class data out function to manage the request */
+ if (pdev->pClass[idx]->Setup != NULL)
+ {
+ pdev->classId = idx;
+ ret = (USBD_StatusTypeDef)(pdev->pClass[idx]->Setup(pdev, req));
+ }
+ else
+ {
+ /* should never reach this condition */
+ ret = USBD_FAIL;
+ }
+ }
+ else
+ {
+ /* No relative interface found */
+ ret = USBD_FAIL;
+ }
+
+ if ((req->wLength == 0U) && (ret == USBD_OK))
+ {
+ (void)USBD_CtlSendStatus(pdev);
+ }
+ }
+ else
+ {
+ USBD_CtlError(pdev, req);
+ }
+ break;
+
+ default:
+ USBD_CtlError(pdev, req);
+ break;
+ }
+ break;
+
+ default:
+ USBD_CtlError(pdev, req);
+ break;
+ }
+
+ return ret;
+}
+
+/**
+ * @brief USBD_StdEPReq
+ * Handle standard usb endpoint requests
+ * @param pdev: device instance
+ * @param req: usb request
+ * @retval status
+ */
+USBD_StatusTypeDef USBD_StdEPReq(USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req)
+{
+ USBD_EndpointTypeDef *pep;
+ uint8_t ep_addr;
+ uint8_t idx;
+ USBD_StatusTypeDef ret = USBD_OK;
+
+ ep_addr = LOBYTE(req->wIndex);
+
+ switch (req->bmRequest & USB_REQ_TYPE_MASK)
+ {
+ case USB_REQ_TYPE_CLASS:
+ case USB_REQ_TYPE_VENDOR:
+ /* Get the class index relative to this endpoint */
+ idx = USBD_CoreFindEP(pdev, ep_addr);
+ if (((uint8_t)idx != 0xFFU) && (idx < USBD_MAX_SUPPORTED_CLASS))
+ {
+ pdev->classId = idx;
+ /* Call the class data out function to manage the request */
+ if (pdev->pClass[idx]->Setup != NULL)
+ {
+ ret = (USBD_StatusTypeDef)pdev->pClass[idx]->Setup(pdev, req);
+ }
+ }
+ break;
+
+ case USB_REQ_TYPE_STANDARD:
+ switch (req->bRequest)
+ {
+ case USB_REQ_SET_FEATURE:
+ switch (pdev->dev_state)
+ {
+ case USBD_STATE_ADDRESSED:
+ if ((ep_addr != 0x00U) && (ep_addr != 0x80U))
+ {
+ (void)USBD_LL_StallEP(pdev, ep_addr);
+ (void)USBD_LL_StallEP(pdev, 0x80U);
+ }
+ else
+ {
+ USBD_CtlError(pdev, req);
+ }
+ break;
+
+ case USBD_STATE_CONFIGURED:
+ if (req->wValue == USB_FEATURE_EP_HALT)
+ {
+ if ((ep_addr != 0x00U) && (ep_addr != 0x80U) && (req->wLength == 0x00U))
+ {
+ (void)USBD_LL_StallEP(pdev, ep_addr);
+ }
+ }
+ (void)USBD_CtlSendStatus(pdev);
+
+ break;
+
+ default:
+ USBD_CtlError(pdev, req);
+ break;
+ }
+ break;
+
+ case USB_REQ_CLEAR_FEATURE:
+
+ switch (pdev->dev_state)
+ {
+ case USBD_STATE_ADDRESSED:
+ if ((ep_addr != 0x00U) && (ep_addr != 0x80U))
+ {
+ (void)USBD_LL_StallEP(pdev, ep_addr);
+ (void)USBD_LL_StallEP(pdev, 0x80U);
+ }
+ else
+ {
+ USBD_CtlError(pdev, req);
+ }
+ break;
+
+ case USBD_STATE_CONFIGURED:
+ if (req->wValue == USB_FEATURE_EP_HALT)
+ {
+ if ((ep_addr & 0x7FU) != 0x00U)
+ {
+ (void)USBD_LL_ClearStallEP(pdev, ep_addr);
+ }
+ (void)USBD_CtlSendStatus(pdev);
+
+ /* Get the class index relative to this interface */
+ idx = USBD_CoreFindEP(pdev, ep_addr);
+ if (((uint8_t)idx != 0xFFU) && (idx < USBD_MAX_SUPPORTED_CLASS))
+ {
+ pdev->classId = idx;
+ /* Call the class data out function to manage the request */
+ if (pdev->pClass[idx]->Setup != NULL)
+ {
+ ret = (USBD_StatusTypeDef)(pdev->pClass[idx]->Setup(pdev, req));
+ }
+ }
+ }
+ break;
+
+ default:
+ USBD_CtlError(pdev, req);
+ break;
+ }
+ break;
+
+ case USB_REQ_GET_STATUS:
+ switch (pdev->dev_state)
+ {
+ case USBD_STATE_ADDRESSED:
+ if ((ep_addr != 0x00U) && (ep_addr != 0x80U))
+ {
+ USBD_CtlError(pdev, req);
+ break;
+ }
+ pep = ((ep_addr & 0x80U) == 0x80U) ? &pdev->ep_in[ep_addr & 0x7FU] : \
+ &pdev->ep_out[ep_addr & 0x7FU];
+
+ pep->status = 0x0000U;
+
+ (void)USBD_CtlSendData(pdev, (uint8_t *)&pep->status, 2U);
+ break;
+
+ case USBD_STATE_CONFIGURED:
+ if ((ep_addr & 0x80U) == 0x80U)
+ {
+ if (pdev->ep_in[ep_addr & 0xFU].is_used == 0U)
+ {
+ USBD_CtlError(pdev, req);
+ break;
+ }
+ }
+ else
+ {
+ if (pdev->ep_out[ep_addr & 0xFU].is_used == 0U)
+ {
+ USBD_CtlError(pdev, req);
+ break;
+ }
+ }
+
+ pep = ((ep_addr & 0x80U) == 0x80U) ? &pdev->ep_in[ep_addr & 0x7FU] : \
+ &pdev->ep_out[ep_addr & 0x7FU];
+
+ if ((ep_addr == 0x00U) || (ep_addr == 0x80U))
+ {
+ pep->status = 0x0000U;
+ }
+ else if (USBD_LL_IsStallEP(pdev, ep_addr) != 0U)
+ {
+ pep->status = 0x0001U;
+ }
+ else
+ {
+ pep->status = 0x0000U;
+ }
+
+ (void)USBD_CtlSendData(pdev, (uint8_t *)&pep->status, 2U);
+ break;
+
+ default:
+ USBD_CtlError(pdev, req);
+ break;
+ }
+ break;
+
+ default:
+ USBD_CtlError(pdev, req);
+ break;
+ }
+ break;
+
+ default:
+ USBD_CtlError(pdev, req);
+ break;
+ }
+
+ return ret;
+}
+
+
+/**
+ * @brief USBD_GetDescriptor
+ * Handle Get Descriptor requests
+ * @param pdev: device instance
+ * @param req: usb request
+ * @retval None
+ */
+static void USBD_GetDescriptor(USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req)
+{
+ uint16_t len = 0U;
+ uint8_t *pbuf = NULL;
+ uint8_t err = 0U;
+
+ switch (req->wValue >> 8)
+ {
+#if ((USBD_LPM_ENABLED == 1U) || (USBD_CLASS_BOS_ENABLED == 1U))
+ case USB_DESC_TYPE_BOS:
+ if (pdev->pDesc->GetBOSDescriptor != NULL)
+ {
+ pbuf = pdev->pDesc->GetBOSDescriptor(pdev->dev_speed, &len);
+ }
+ else
+ {
+ USBD_CtlError(pdev, req);
+ err++;
+ }
+ break;
+#endif /* (USBD_LPM_ENABLED == 1U) || (USBD_CLASS_BOS_ENABLED == 1U) */
+ case USB_DESC_TYPE_DEVICE:
+ pbuf = pdev->pDesc->GetDeviceDescriptor(pdev->dev_speed, &len);
+ break;
+
+ case USB_DESC_TYPE_CONFIGURATION:
+ if (pdev->dev_speed == USBD_SPEED_HIGH)
+ {
+#ifdef USE_USBD_COMPOSITE
+ if ((uint8_t)(pdev->NumClasses) > 0U)
+ {
+ pbuf = (uint8_t *)USBD_CMPSIT.GetHSConfigDescriptor(&len);
+ }
+ else
+#endif /* USE_USBD_COMPOSITE */
+ {
+ pbuf = (uint8_t *)pdev->pClass[0]->GetHSConfigDescriptor(&len);
+ }
+ pbuf[1] = USB_DESC_TYPE_CONFIGURATION;
+ }
+ else
+ {
+#ifdef USE_USBD_COMPOSITE
+ if ((uint8_t)(pdev->NumClasses) > 0U)
+ {
+ pbuf = (uint8_t *)USBD_CMPSIT.GetFSConfigDescriptor(&len);
+ }
+ else
+#endif /* USE_USBD_COMPOSITE */
+ {
+ pbuf = (uint8_t *)pdev->pClass[0]->GetFSConfigDescriptor(&len);
+ }
+ pbuf[1] = USB_DESC_TYPE_CONFIGURATION;
+ }
+ break;
+
+ case USB_DESC_TYPE_STRING:
+ switch ((uint8_t)(req->wValue))
+ {
+ case USBD_IDX_LANGID_STR:
+ if (pdev->pDesc->GetLangIDStrDescriptor != NULL)
+ {
+ pbuf = pdev->pDesc->GetLangIDStrDescriptor(pdev->dev_speed, &len);
+ }
+ else
+ {
+ USBD_CtlError(pdev, req);
+ err++;
+ }
+ break;
+
+ case USBD_IDX_MFC_STR:
+ if (pdev->pDesc->GetManufacturerStrDescriptor != NULL)
+ {
+ pbuf = pdev->pDesc->GetManufacturerStrDescriptor(pdev->dev_speed, &len);
+ }
+ else
+ {
+ USBD_CtlError(pdev, req);
+ err++;
+ }
+ break;
+
+ case USBD_IDX_PRODUCT_STR:
+ if (pdev->pDesc->GetProductStrDescriptor != NULL)
+ {
+ pbuf = pdev->pDesc->GetProductStrDescriptor(pdev->dev_speed, &len);
+ }
+ else
+ {
+ USBD_CtlError(pdev, req);
+ err++;
+ }
+ break;
+
+ case USBD_IDX_SERIAL_STR:
+ if (pdev->pDesc->GetSerialStrDescriptor != NULL)
+ {
+ pbuf = pdev->pDesc->GetSerialStrDescriptor(pdev->dev_speed, &len);
+ }
+ else
+ {
+ USBD_CtlError(pdev, req);
+ err++;
+ }
+ break;
+
+ case USBD_IDX_CONFIG_STR:
+ if (pdev->pDesc->GetConfigurationStrDescriptor != NULL)
+ {
+ pbuf = pdev->pDesc->GetConfigurationStrDescriptor(pdev->dev_speed, &len);
+ }
+ else
+ {
+ USBD_CtlError(pdev, req);
+ err++;
+ }
+ break;
+
+ case USBD_IDX_INTERFACE_STR:
+ if (pdev->pDesc->GetInterfaceStrDescriptor != NULL)
+ {
+ pbuf = pdev->pDesc->GetInterfaceStrDescriptor(pdev->dev_speed, &len);
+ }
+ else
+ {
+ USBD_CtlError(pdev, req);
+ err++;
+ }
+ break;
+
+ default:
+#if (USBD_SUPPORT_USER_STRING_DESC == 1U)
+ pbuf = NULL;
+
+ for (uint32_t idx = 0U; (idx < pdev->NumClasses); idx++)
+ {
+ if (pdev->pClass[idx]->GetUsrStrDescriptor != NULL)
+ {
+ pdev->classId = idx;
+ pbuf = pdev->pClass[idx]->GetUsrStrDescriptor(pdev, LOBYTE(req->wValue), &len);
+
+ if (pbuf == NULL) /* This means that no class recognized the string index */
+ {
+ continue;
+ }
+ else
+ {
+ break;
+ }
+ }
+ }
+#endif /* USBD_SUPPORT_USER_STRING_DESC */
+
+#if (USBD_CLASS_USER_STRING_DESC == 1U)
+ if (pdev->pDesc->GetUserStrDescriptor != NULL)
+ {
+ pbuf = pdev->pDesc->GetUserStrDescriptor(pdev->dev_speed, LOBYTE(req->wValue), &len);
+ }
+ else
+ {
+ USBD_CtlError(pdev, req);
+ err++;
+ }
+#endif /* USBD_SUPPORT_USER_STRING_DESC */
+
+#if ((USBD_CLASS_USER_STRING_DESC == 0U) && (USBD_SUPPORT_USER_STRING_DESC == 0U))
+ USBD_CtlError(pdev, req);
+ err++;
+#endif /* (USBD_CLASS_USER_STRING_DESC == 0U) && (USBD_SUPPORT_USER_STRING_DESC == 0U) */
+ break;
+ }
+ break;
+
+ case USB_DESC_TYPE_DEVICE_QUALIFIER:
+ if (pdev->dev_speed == USBD_SPEED_HIGH)
+ {
+#ifdef USE_USBD_COMPOSITE
+ if ((uint8_t)(pdev->NumClasses) > 0U)
+ {
+ pbuf = (uint8_t *)USBD_CMPSIT.GetDeviceQualifierDescriptor(&len);
+ }
+ else
+#endif /* USE_USBD_COMPOSITE */
+ {
+ pbuf = (uint8_t *)pdev->pClass[0]->GetDeviceQualifierDescriptor(&len);
+ }
+ }
+ else
+ {
+ USBD_CtlError(pdev, req);
+ err++;
+ }
+ break;
+
+ case USB_DESC_TYPE_OTHER_SPEED_CONFIGURATION:
+ if (pdev->dev_speed == USBD_SPEED_HIGH)
+ {
+#ifdef USE_USBD_COMPOSITE
+ if ((uint8_t)(pdev->NumClasses) > 0U)
+ {
+ pbuf = (uint8_t *)USBD_CMPSIT.GetOtherSpeedConfigDescriptor(&len);
+ }
+ else
+#endif /* USE_USBD_COMPOSITE */
+ {
+ pbuf = (uint8_t *)pdev->pClass[0]->GetOtherSpeedConfigDescriptor(&len);
+ }
+ pbuf[1] = USB_DESC_TYPE_OTHER_SPEED_CONFIGURATION;
+ }
+ else
+ {
+ USBD_CtlError(pdev, req);
+ err++;
+ }
+ break;
+
+ default:
+ USBD_CtlError(pdev, req);
+ err++;
+ break;
+ }
+
+ if (err != 0U)
+ {
+ return;
+ }
+
+ if (req->wLength != 0U)
+ {
+ if (len != 0U)
+ {
+ len = MIN(len, req->wLength);
+ (void)USBD_CtlSendData(pdev, pbuf, len);
+ }
+ else
+ {
+ USBD_CtlError(pdev, req);
+ }
+ }
+ else
+ {
+ (void)USBD_CtlSendStatus(pdev);
+ }
+}
+
+
+/**
+ * @brief USBD_SetAddress
+ * Set device address
+ * @param pdev: device instance
+ * @param req: usb request
+ * @retval None
+ */
+static void USBD_SetAddress(USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req)
+{
+ uint8_t dev_addr;
+
+ if ((req->wIndex == 0U) && (req->wLength == 0U) && (req->wValue < 128U))
+ {
+ dev_addr = (uint8_t)(req->wValue) & 0x7FU;
+
+ if (pdev->dev_state == USBD_STATE_CONFIGURED)
+ {
+ USBD_CtlError(pdev, req);
+ }
+ else
+ {
+ pdev->dev_address = dev_addr;
+ (void)USBD_LL_SetUSBAddress(pdev, dev_addr);
+ (void)USBD_CtlSendStatus(pdev);
+
+ if (dev_addr != 0U)
+ {
+ pdev->dev_state = USBD_STATE_ADDRESSED;
+ }
+ else
+ {
+ pdev->dev_state = USBD_STATE_DEFAULT;
+ }
+ }
+ }
+ else
+ {
+ USBD_CtlError(pdev, req);
+ }
+}
+
+/**
+ * @brief USBD_SetConfig
+ * Handle Set device configuration request
+ * @param pdev: device instance
+ * @param req: usb request
+ * @retval status
+ */
+static USBD_StatusTypeDef USBD_SetConfig(USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req)
+{
+ USBD_StatusTypeDef ret = USBD_OK;
+ static uint8_t cfgidx;
+
+ cfgidx = (uint8_t)(req->wValue);
+
+ if (cfgidx > USBD_MAX_NUM_CONFIGURATION)
+ {
+ USBD_CtlError(pdev, req);
+ return USBD_FAIL;
+ }
+
+ switch (pdev->dev_state)
+ {
+ case USBD_STATE_ADDRESSED:
+ if (cfgidx != 0U)
+ {
+ pdev->dev_config = cfgidx;
+
+ ret = USBD_SetClassConfig(pdev, cfgidx);
+
+ if (ret != USBD_OK)
+ {
+ USBD_CtlError(pdev, req);
+ pdev->dev_state = USBD_STATE_ADDRESSED;
+ }
+ else
+ {
+ (void)USBD_CtlSendStatus(pdev);
+ pdev->dev_state = USBD_STATE_CONFIGURED;
+
+#if (USBD_USER_REGISTER_CALLBACK == 1U)
+ if (pdev->DevStateCallback != NULL)
+ {
+ pdev->DevStateCallback(USBD_STATE_CONFIGURED, cfgidx);
+ }
+#endif /* USBD_USER_REGISTER_CALLBACK */
+ }
+ }
+ else
+ {
+ (void)USBD_CtlSendStatus(pdev);
+ }
+ break;
+
+ case USBD_STATE_CONFIGURED:
+ if (cfgidx == 0U)
+ {
+ pdev->dev_state = USBD_STATE_ADDRESSED;
+ pdev->dev_config = cfgidx;
+ (void)USBD_ClrClassConfig(pdev, cfgidx);
+ (void)USBD_CtlSendStatus(pdev);
+ }
+ else if (cfgidx != pdev->dev_config)
+ {
+ /* Clear old configuration */
+ (void)USBD_ClrClassConfig(pdev, (uint8_t)pdev->dev_config);
+
+ /* set new configuration */
+ pdev->dev_config = cfgidx;
+
+ ret = USBD_SetClassConfig(pdev, cfgidx);
+
+ if (ret != USBD_OK)
+ {
+ USBD_CtlError(pdev, req);
+ (void)USBD_ClrClassConfig(pdev, (uint8_t)pdev->dev_config);
+ pdev->dev_state = USBD_STATE_ADDRESSED;
+ }
+ else
+ {
+ (void)USBD_CtlSendStatus(pdev);
+ }
+ }
+ else
+ {
+ (void)USBD_CtlSendStatus(pdev);
+ }
+ break;
+
+ default:
+ USBD_CtlError(pdev, req);
+ (void)USBD_ClrClassConfig(pdev, cfgidx);
+ ret = USBD_FAIL;
+ break;
+ }
+
+ return ret;
+}
+
+/**
+ * @brief USBD_GetConfig
+ * Handle Get device configuration request
+ * @param pdev: device instance
+ * @param req: usb request
+ * @retval None
+ */
+static void USBD_GetConfig(USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req)
+{
+ if (req->wLength != 1U)
+ {
+ USBD_CtlError(pdev, req);
+ }
+ else
+ {
+ switch (pdev->dev_state)
+ {
+ case USBD_STATE_DEFAULT:
+ case USBD_STATE_ADDRESSED:
+ pdev->dev_default_config = 0U;
+ (void)USBD_CtlSendData(pdev, (uint8_t *)&pdev->dev_default_config, 1U);
+ break;
+
+ case USBD_STATE_CONFIGURED:
+ (void)USBD_CtlSendData(pdev, (uint8_t *)&pdev->dev_config, 1U);
+ break;
+
+ default:
+ USBD_CtlError(pdev, req);
+ break;
+ }
+ }
+}
+
+/**
+ * @brief USBD_GetStatus
+ * Handle Get Status request
+ * @param pdev: device instance
+ * @param req: usb request
+ * @retval None
+ */
+static void USBD_GetStatus(USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req)
+{
+ switch (pdev->dev_state)
+ {
+ case USBD_STATE_DEFAULT:
+ case USBD_STATE_ADDRESSED:
+ case USBD_STATE_CONFIGURED:
+ if (req->wLength != 0x2U)
+ {
+ USBD_CtlError(pdev, req);
+ break;
+ }
+
+#if (USBD_SELF_POWERED == 1U)
+ pdev->dev_config_status = USB_CONFIG_SELF_POWERED;
+#else
+ pdev->dev_config_status = 0U;
+#endif /* USBD_SELF_POWERED */
+
+ if (pdev->dev_remote_wakeup != 0U)
+ {
+ pdev->dev_config_status |= USB_CONFIG_REMOTE_WAKEUP;
+ }
+
+ (void)USBD_CtlSendData(pdev, (uint8_t *)&pdev->dev_config_status, 2U);
+ break;
+
+ default:
+ USBD_CtlError(pdev, req);
+ break;
+ }
+}
+
+
+/**
+ * @brief USBD_SetFeature
+ * Handle Set device feature request
+ * @param pdev: device instance
+ * @param req: usb request
+ * @retval None
+ */
+static void USBD_SetFeature(USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req)
+{
+ if (req->wValue == USB_FEATURE_REMOTE_WAKEUP)
+ {
+ pdev->dev_remote_wakeup = 1U;
+ (void)USBD_CtlSendStatus(pdev);
+ }
+ else if (req->wValue == USB_FEATURE_TEST_MODE)
+ {
+ pdev->dev_test_mode = (uint8_t)(req->wIndex >> 8);
+ (void)USBD_CtlSendStatus(pdev);
+ }
+ else
+ {
+ USBD_CtlError(pdev, req);
+ }
+}
+
+
+/**
+ * @brief USBD_ClrFeature
+ * Handle clear device feature request
+ * @param pdev: device instance
+ * @param req: usb request
+ * @retval None
+ */
+static void USBD_ClrFeature(USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req)
+{
+ switch (pdev->dev_state)
+ {
+ case USBD_STATE_DEFAULT:
+ case USBD_STATE_ADDRESSED:
+ case USBD_STATE_CONFIGURED:
+ if (req->wValue == USB_FEATURE_REMOTE_WAKEUP)
+ {
+ pdev->dev_remote_wakeup = 0U;
+ (void)USBD_CtlSendStatus(pdev);
+ }
+ break;
+
+ default:
+ USBD_CtlError(pdev, req);
+ break;
+ }
+}
+
+
+/**
+ * @brief USBD_ParseSetupRequest
+ * Copy buffer into setup structure
+ * @param req: usb request
+ * @param pdata: setup data pointer
+ * @retval None
+ */
+void USBD_ParseSetupRequest(USBD_SetupReqTypedef *req, uint8_t *pdata)
+{
+ uint8_t *pbuff = pdata;
+
+ req->bmRequest = *(uint8_t *)(pbuff);
+
+ pbuff++;
+ req->bRequest = *(uint8_t *)(pbuff);
+
+ pbuff++;
+ req->wValue = SWAPBYTE(pbuff);
+
+ pbuff++;
+ pbuff++;
+ req->wIndex = SWAPBYTE(pbuff);
+
+ pbuff++;
+ pbuff++;
+ req->wLength = SWAPBYTE(pbuff);
+}
+
+
+/**
+ * @brief USBD_CtlError
+ * Handle USB low level Error
+ * @param pdev: device instance
+ * @param req: usb request
+ * @retval None
+ */
+void USBD_CtlError(USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req)
+{
+ UNUSED(req);
+
+ (void)USBD_LL_StallEP(pdev, 0x80U);
+ (void)USBD_LL_StallEP(pdev, 0U);
+}
+
+
+/**
+ * @brief USBD_GetString
+ * Convert Ascii string into unicode one
+ * @param desc : descriptor buffer
+ * @param unicode : Formatted string buffer (unicode)
+ * @param len : descriptor length
+ * @retval None
+ */
+void USBD_GetString(uint8_t *desc, uint8_t *unicode, uint16_t *len)
+{
+ uint8_t idx = 0U;
+ uint8_t *pdesc;
+
+ if (desc == NULL)
+ {
+ return;
+ }
+
+ pdesc = desc;
+ *len = MIN(USBD_MAX_STR_DESC_SIZ, ((uint16_t)USBD_GetLen(pdesc) * 2U) + 2U);
+
+ unicode[idx] = *(uint8_t *)len;
+ idx++;
+ unicode[idx] = USB_DESC_TYPE_STRING;
+ idx++;
+
+ while (*pdesc != (uint8_t)'\0')
+ {
+ unicode[idx] = *pdesc;
+ pdesc++;
+ idx++;
+
+ unicode[idx] = 0U;
+ idx++;
+ }
+}
+
+
+/**
+ * @brief USBD_GetLen
+ * return the string length
+ * @param buf : pointer to the ascii string buffer
+ * @retval string length
+ */
+static uint8_t USBD_GetLen(uint8_t *buf)
+{
+ uint8_t len = 0U;
+ uint8_t *pbuff = buf;
+
+ while (*pbuff != (uint8_t)'\0')
+ {
+ len++;
+ pbuff++;
+ }
+
+ return len;
+}
+/**
+ * @}
+ */
+
+
+/**
+ * @}
+ */
+
+
+/**
+ * @}
+ */
+
diff --git a/Ganesha_II_V2/Middlewares/ST/STM32_USB_Device_Library/Core/Src/usbd_ioreq.c b/Ganesha_II_V2/Middlewares/ST/STM32_USB_Device_Library/Core/Src/usbd_ioreq.c
new file mode 100644
index 0000000..7c8004a
--- /dev/null
+++ b/Ganesha_II_V2/Middlewares/ST/STM32_USB_Device_Library/Core/Src/usbd_ioreq.c
@@ -0,0 +1,224 @@
+/**
+ ******************************************************************************
+ * @file usbd_ioreq.c
+ * @author MCD Application Team
+ * @brief This file provides the IO requests APIs for control endpoints.
+ ******************************************************************************
+ * @attention
+ *
+ * Copyright (c) 2015 STMicroelectronics.
+ * All rights reserved.
+ *
+ * This software is licensed under terms that can be found in the LICENSE file
+ * in the root directory of this software component.
+ * If no LICENSE file comes with this software, it is provided AS-IS.
+ *
+ ******************************************************************************
+ */
+
+/* Includes ------------------------------------------------------------------*/
+#include "usbd_ioreq.h"
+
+/** @addtogroup STM32_USB_DEVICE_LIBRARY
+ * @{
+ */
+
+
+/** @defgroup USBD_IOREQ
+ * @brief control I/O requests module
+ * @{
+ */
+
+/** @defgroup USBD_IOREQ_Private_TypesDefinitions
+ * @{
+ */
+/**
+ * @}
+ */
+
+
+/** @defgroup USBD_IOREQ_Private_Defines
+ * @{
+ */
+
+/**
+ * @}
+ */
+
+
+/** @defgroup USBD_IOREQ_Private_Macros
+ * @{
+ */
+/**
+ * @}
+ */
+
+
+/** @defgroup USBD_IOREQ_Private_Variables
+ * @{
+ */
+
+/**
+ * @}
+ */
+
+
+/** @defgroup USBD_IOREQ_Private_FunctionPrototypes
+ * @{
+ */
+/**
+ * @}
+ */
+
+
+/** @defgroup USBD_IOREQ_Private_Functions
+ * @{
+ */
+
+/**
+ * @brief USBD_CtlSendData
+ * send data on the ctl pipe
+ * @param pdev: device instance
+ * @param buff: pointer to data buffer
+ * @param len: length of data to be sent
+ * @retval status
+ */
+USBD_StatusTypeDef USBD_CtlSendData(USBD_HandleTypeDef *pdev,
+ uint8_t *pbuf, uint32_t len)
+{
+ /* Set EP0 State */
+ pdev->ep0_state = USBD_EP0_DATA_IN;
+ pdev->ep_in[0].total_length = len;
+
+#ifdef USBD_AVOID_PACKET_SPLIT_MPS
+ pdev->ep_in[0].rem_length = 0U;
+#else
+ pdev->ep_in[0].rem_length = len;
+#endif /* USBD_AVOID_PACKET_SPLIT_MPS */
+
+ /* Start the transfer */
+ (void)USBD_LL_Transmit(pdev, 0x00U, pbuf, len);
+
+ return USBD_OK;
+}
+
+/**
+ * @brief USBD_CtlContinueSendData
+ * continue sending data on the ctl pipe
+ * @param pdev: device instance
+ * @param buff: pointer to data buffer
+ * @param len: length of data to be sent
+ * @retval status
+ */
+USBD_StatusTypeDef USBD_CtlContinueSendData(USBD_HandleTypeDef *pdev,
+ uint8_t *pbuf, uint32_t len)
+{
+ /* Start the next transfer */
+ (void)USBD_LL_Transmit(pdev, 0x00U, pbuf, len);
+
+ return USBD_OK;
+}
+
+/**
+ * @brief USBD_CtlPrepareRx
+ * receive data on the ctl pipe
+ * @param pdev: device instance
+ * @param buff: pointer to data buffer
+ * @param len: length of data to be received
+ * @retval status
+ */
+USBD_StatusTypeDef USBD_CtlPrepareRx(USBD_HandleTypeDef *pdev,
+ uint8_t *pbuf, uint32_t len)
+{
+ /* Set EP0 State */
+ pdev->ep0_state = USBD_EP0_DATA_OUT;
+ pdev->ep_out[0].total_length = len;
+
+#ifdef USBD_AVOID_PACKET_SPLIT_MPS
+ pdev->ep_out[0].rem_length = 0U;
+#else
+ pdev->ep_out[0].rem_length = len;
+#endif /* USBD_AVOID_PACKET_SPLIT_MPS */
+
+ /* Start the transfer */
+ (void)USBD_LL_PrepareReceive(pdev, 0U, pbuf, len);
+
+ return USBD_OK;
+}
+
+/**
+ * @brief USBD_CtlContinueRx
+ * continue receive data on the ctl pipe
+ * @param pdev: device instance
+ * @param buff: pointer to data buffer
+ * @param len: length of data to be received
+ * @retval status
+ */
+USBD_StatusTypeDef USBD_CtlContinueRx(USBD_HandleTypeDef *pdev,
+ uint8_t *pbuf, uint32_t len)
+{
+ (void)USBD_LL_PrepareReceive(pdev, 0U, pbuf, len);
+
+ return USBD_OK;
+}
+
+/**
+ * @brief USBD_CtlSendStatus
+ * send zero lzngth packet on the ctl pipe
+ * @param pdev: device instance
+ * @retval status
+ */
+USBD_StatusTypeDef USBD_CtlSendStatus(USBD_HandleTypeDef *pdev)
+{
+ /* Set EP0 State */
+ pdev->ep0_state = USBD_EP0_STATUS_IN;
+
+ /* Start the transfer */
+ (void)USBD_LL_Transmit(pdev, 0x00U, NULL, 0U);
+
+ return USBD_OK;
+}
+
+/**
+ * @brief USBD_CtlReceiveStatus
+ * receive zero lzngth packet on the ctl pipe
+ * @param pdev: device instance
+ * @retval status
+ */
+USBD_StatusTypeDef USBD_CtlReceiveStatus(USBD_HandleTypeDef *pdev)
+{
+ /* Set EP0 State */
+ pdev->ep0_state = USBD_EP0_STATUS_OUT;
+
+ /* Start the transfer */
+ (void)USBD_LL_PrepareReceive(pdev, 0U, NULL, 0U);
+
+ return USBD_OK;
+}
+
+/**
+ * @brief USBD_GetRxCount
+ * returns the received data length
+ * @param pdev: device instance
+ * @param ep_addr: endpoint address
+ * @retval Rx Data blength
+ */
+uint32_t USBD_GetRxCount(USBD_HandleTypeDef *pdev, uint8_t ep_addr)
+{
+ return USBD_LL_GetRxDataSize(pdev, ep_addr);
+}
+
+/**
+ * @}
+ */
+
+
+/**
+ * @}
+ */
+
+
+/**
+ * @}
+ */
+
diff --git a/Ganesha_II_V2/Middlewares/ST/STM32_USB_Device_Library/LICENSE.txt b/Ganesha_II_V2/Middlewares/ST/STM32_USB_Device_Library/LICENSE.txt
new file mode 100644
index 0000000..e66295c
--- /dev/null
+++ b/Ganesha_II_V2/Middlewares/ST/STM32_USB_Device_Library/LICENSE.txt
@@ -0,0 +1,86 @@
+This software component is provided to you as part of a software package and
+applicable license terms are in the Package_license file. If you received this
+software component outside of a package or without applicable license terms,
+the terms of the SLA0044 license shall apply and are fully reproduced below:
+
+SLA0044 Rev5/February 2018
+
+Software license agreement
+
+ULTIMATE LIBERTY SOFTWARE LICENSE AGREEMENT
+
+BY INSTALLING, COPYING, DOWNLOADING, ACCESSING OR OTHERWISE USING THIS SOFTWARE
+OR ANY PART THEREOF (AND THE RELATED DOCUMENTATION) FROM STMICROELECTRONICS
+INTERNATIONAL N.V, SWISS BRANCH AND/OR ITS AFFILIATED COMPANIES
+(STMICROELECTRONICS), THE RECIPIENT, ON BEHALF OF HIMSELF OR HERSELF, OR ON
+BEHALF OF ANY ENTITY BY WHICH SUCH RECIPIENT IS EMPLOYED AND/OR ENGAGED AGREES
+TO BE BOUND BY THIS SOFTWARE LICENSE AGREEMENT.
+
+Under STMicroelectronics’ intellectual property rights, the redistribution,
+reproduction and use in source and binary forms of the software or any part
+thereof, with or without modification, are permitted provided that the following
+conditions are met:
+
+1. Redistribution of source code (modified or not) must retain any copyright
+notice, this list of conditions and the disclaimer set forth below as items 10
+and 11.
+
+2. Redistributions in binary form, except as embedded into microcontroller or
+microprocessor device manufactured by or for STMicroelectronics or a software
+update for such device, must reproduce any copyright notice provided with the
+binary code, this list of conditions, and the disclaimer set forth below as
+items 10 and 11, in documentation and/or other materials provided with the
+distribution.
+
+3. Neither the name of STMicroelectronics nor the names of other contributors to
+this software may be used to endorse or promote products derived from this
+software or part thereof without specific written permission.
+
+4. This software or any part thereof, including modifications and/or derivative
+works of this software, must be used and execute solely and exclusively on or in
+combination with a microcontroller or microprocessor device manufactured by or
+for STMicroelectronics.
+
+5. No use, reproduction or redistribution of this software partially or totally
+may be done in any manner that would subject this software to any Open Source
+Terms. “Open Source Terms” shall mean any open source license which requires as
+part of distribution of software that the source code of such software is
+distributed therewith or otherwise made available, or open source license that
+substantially complies with the Open Source definition specified at
+www.opensource.org and any other comparable open source license such as for
+example GNU General Public License (GPL), Eclipse Public License (EPL), Apache
+Software License, BSD license or MIT license.
+
+6. STMicroelectronics has no obligation to provide any maintenance, support or
+updates for the software.
+
+7. The software is and will remain the exclusive property of STMicroelectronics
+and its licensors. The recipient will not take any action that jeopardizes
+STMicroelectronics and its licensors' proprietary rights or acquire any rights
+in the software, except the limited rights specified hereunder.
+
+8. The recipient shall comply with all applicable laws and regulations affecting
+the use of the software or any part thereof including any applicable export
+control law or regulation.
+
+9. Redistribution and use of this software or any part thereof other than as
+permitted under this license is void and will automatically terminate your
+rights under this license.
+
+10. THIS SOFTWARE IS PROVIDED BY STMICROELECTRONICS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS, IMPLIED OR STATUTORY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NON-INFRINGEMENT OF THIRD PARTY INTELLECTUAL PROPERTY RIGHTS, WHICH ARE
+DISCLAIMED TO THE FULLEST EXTENT PERMITTED BY LAW. IN NO EVENT SHALL
+STMICROELECTRONICS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+11. EXCEPT AS EXPRESSLY PERMITTED HEREUNDER, NO LICENSE OR OTHER RIGHTS, WHETHER
+EXPRESS OR IMPLIED, ARE GRANTED UNDER ANY PATENT OR OTHER INTELLECTUAL PROPERTY
+RIGHTS OF STMICROELECTRONICS OR ANY THIRD PARTY.
+
diff --git a/Ganesha_II_V2/STM32H743XX_FLASH.ld b/Ganesha_II_V2/STM32H743XX_FLASH.ld
new file mode 100644
index 0000000..102cb8d
--- /dev/null
+++ b/Ganesha_II_V2/STM32H743XX_FLASH.ld
@@ -0,0 +1,211 @@
+/*
+******************************************************************************
+**
+
+** File : LinkerScript.ld
+**
+** Author : STM32CubeMX
+**
+** Abstract : Linker script for STM32H743VITx series
+** 2048Kbytes FLASH and 1056Kbytes RAM
+**
+** Set heap size, stack size and stack location according
+** to application requirements.
+**
+** Set memory bank area and size if external memory is used.
+**
+** Target : STMicroelectronics STM32
+**
+** Distribution: The file is distributed “as is,” without any warranty
+** of any kind.
+**
+*****************************************************************************
+** @attention
+**
+** © COPYRIGHT(c) 2025 STMicroelectronics
+**
+** Redistribution and use in source and binary forms, with or without modification,
+** are permitted provided that the following conditions are met:
+** 1. Redistributions of source code must retain the above copyright notice,
+** this list of conditions and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright notice,
+** this list of conditions and the following disclaimer in the documentation
+** and/or other materials provided with the distribution.
+** 3. Neither the name of STMicroelectronics nor the names of its contributors
+** may be used to endorse or promote products derived from this software
+** without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+** AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+** DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+** SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+** CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+** OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+**
+*****************************************************************************
+*/
+
+/* Entry Point */
+ENTRY(Reset_Handler)
+
+/* Highest address of the user mode stack */
+_estack = ORIGIN(DTCMRAM) + LENGTH(DTCMRAM); /* end of RAM */
+/* Generate a link error if heap and stack don't fit into RAM */
+_Min_Heap_Size = 0x200; /* required amount of heap */
+_Min_Stack_Size = 0x400; /* required amount of stack */
+
+/* Specify the memory areas */
+MEMORY
+{
+DTCMRAM (xrw) : ORIGIN = 0x20000000, LENGTH = 128K
+RAM (xrw) : ORIGIN = 0x24000000, LENGTH = 512K
+RAM_D2 (xrw) : ORIGIN = 0x30000000, LENGTH = 288K
+RAM_D3 (xrw) : ORIGIN = 0x38000000, LENGTH = 64K
+ITCMRAM (xrw) : ORIGIN = 0x00000000, LENGTH = 64K
+FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 2048K
+}
+
+/* Define output sections */
+SECTIONS
+{
+ /* The startup code goes first into FLASH */
+ .isr_vector :
+ {
+ . = ALIGN(4);
+ KEEP(*(.isr_vector)) /* Startup code */
+ . = ALIGN(4);
+ } >FLASH
+
+ /* The program code and other data goes into FLASH */
+ .text :
+ {
+ . = ALIGN(4);
+ *(.text) /* .text sections (code) */
+ *(.text*) /* .text* sections (code) */
+ *(.glue_7) /* glue arm to thumb code */
+ *(.glue_7t) /* glue thumb to arm code */
+ *(.eh_frame)
+
+ KEEP (*(.init))
+ KEEP (*(.fini))
+
+ . = ALIGN(4);
+ _etext = .; /* define a global symbols at end of code */
+ } >FLASH
+
+ /* Constant data goes into FLASH */
+ .rodata :
+ {
+ . = ALIGN(4);
+ *(.rodata) /* .rodata sections (constants, strings, etc.) */
+ *(.rodata*) /* .rodata* sections (constants, strings, etc.) */
+ . = ALIGN(4);
+ } >FLASH
+
+ .ARM.extab (READONLY) : /* The "READONLY" keyword is only supported in GCC11 and later, remove it if using GCC10 or earlier. */
+ {
+ . = ALIGN(4);
+ *(.ARM.extab* .gnu.linkonce.armextab.*)
+ . = ALIGN(4);
+ } >FLASH
+
+ .ARM (READONLY) : /* The "READONLY" keyword is only supported in GCC11 and later, remove it if using GCC10 or earlier. */
+ {
+ . = ALIGN(4);
+ __exidx_start = .;
+ *(.ARM.exidx*)
+ __exidx_end = .;
+ . = ALIGN(4);
+ } >FLASH
+
+ .preinit_array (READONLY) : /* The "READONLY" keyword is only supported in GCC11 and later, remove it if using GCC10 or earlier. */
+ {
+ . = ALIGN(4);
+ PROVIDE_HIDDEN (__preinit_array_start = .);
+ KEEP (*(.preinit_array*))
+ PROVIDE_HIDDEN (__preinit_array_end = .);
+ . = ALIGN(4);
+ } >FLASH
+
+ .init_array (READONLY) : /* The "READONLY" keyword is only supported in GCC11 and later, remove it if using GCC10 or earlier. */
+ {
+ . = ALIGN(4);
+ PROVIDE_HIDDEN (__init_array_start = .);
+ KEEP (*(SORT(.init_array.*)))
+ KEEP (*(.init_array*))
+ PROVIDE_HIDDEN (__init_array_end = .);
+ . = ALIGN(4);
+ } >FLASH
+
+ .fini_array (READONLY) : /* The "READONLY" keyword is only supported in GCC11 and later, remove it if using GCC10 or earlier. */
+ {
+ . = ALIGN(4);
+ PROVIDE_HIDDEN (__fini_array_start = .);
+ KEEP (*(SORT(.fini_array.*)))
+ KEEP (*(.fini_array*))
+ PROVIDE_HIDDEN (__fini_array_end = .);
+ . = ALIGN(4);
+ } >FLASH
+
+ /* used by the startup to initialize data */
+ _sidata = LOADADDR(.data);
+
+ /* Initialized data sections goes into RAM, load LMA copy after code */
+ .data :
+ {
+ . = ALIGN(4);
+ _sdata = .; /* create a global symbol at data start */
+ *(.data) /* .data sections */
+ *(.data*) /* .data* sections */
+ *(.RamFunc) /* .RamFunc sections */
+ *(.RamFunc*) /* .RamFunc* sections */
+
+ . = ALIGN(4);
+ _edata = .; /* define a global symbol at data end */
+ } >DTCMRAM AT> FLASH
+
+
+ /* Uninitialized data section */
+ . = ALIGN(4);
+ .bss :
+ {
+ /* This is used by the startup in order to initialize the .bss secion */
+ _sbss = .; /* define a global symbol at bss start */
+ __bss_start__ = _sbss;
+ *(.bss)
+ *(.bss*)
+ *(COMMON)
+
+ . = ALIGN(4);
+ _ebss = .; /* define a global symbol at bss end */
+ __bss_end__ = _ebss;
+ } >DTCMRAM
+
+ /* User_heap_stack section, used to check that there is enough RAM left */
+ ._user_heap_stack :
+ {
+ . = ALIGN(8);
+ PROVIDE ( end = . );
+ PROVIDE ( _end = . );
+ . = . + _Min_Heap_Size;
+ . = . + _Min_Stack_Size;
+ . = ALIGN(8);
+ } >DTCMRAM
+
+
+
+ /* Remove information from the standard libraries */
+ /DISCARD/ :
+ {
+ libc.a ( * )
+ libm.a ( * )
+ libgcc.a ( * )
+ }
+
+}
+
+
diff --git a/Ganesha_II_V2/USB_DEVICE/App/usb_device.c b/Ganesha_II_V2/USB_DEVICE/App/usb_device.c
new file mode 100644
index 0000000..5ff9ec7
--- /dev/null
+++ b/Ganesha_II_V2/USB_DEVICE/App/usb_device.c
@@ -0,0 +1,101 @@
+/* USER CODE BEGIN Header */
+/**
+ ******************************************************************************
+ * @file : usb_device.c
+ * @version : v1.0_Cube
+ * @brief : This file implements the USB Device
+ ******************************************************************************
+ * @attention
+ *
+ * Copyright (c) 2026 STMicroelectronics.
+ * All rights reserved.
+ *
+ * This software is licensed under terms that can be found in the LICENSE file
+ * in the root directory of this software component.
+ * If no LICENSE file comes with this software, it is provided AS-IS.
+ *
+ ******************************************************************************
+ */
+/* USER CODE END Header */
+
+/* Includes ------------------------------------------------------------------*/
+
+#include "usb_device.h"
+#include "usbd_core.h"
+#include "usbd_desc.h"
+#include "usbd_cdc.h"
+#include "usbd_cdc_if.h"
+
+/* USER CODE BEGIN Includes */
+
+/* USER CODE END Includes */
+
+/* USER CODE BEGIN PV */
+/* Private variables ---------------------------------------------------------*/
+
+/* USER CODE END PV */
+
+/* USER CODE BEGIN PFP */
+/* Private function prototypes -----------------------------------------------*/
+
+/* USER CODE END PFP */
+
+/* USB Device Core handle declaration. */
+USBD_HandleTypeDef hUsbDeviceFS;
+
+/*
+ * -- Insert your variables declaration here --
+ */
+/* USER CODE BEGIN 0 */
+
+/* USER CODE END 0 */
+
+/*
+ * -- Insert your external function declaration here --
+ */
+/* USER CODE BEGIN 1 */
+
+/* USER CODE END 1 */
+
+/**
+ * Init USB device Library, add supported class and start the library
+ * @retval None
+ */
+void MX_USB_DEVICE_Init(void)
+{
+ /* USER CODE BEGIN USB_DEVICE_Init_PreTreatment */
+
+ /* USER CODE END USB_DEVICE_Init_PreTreatment */
+
+ /* Init Device Library, add supported class and start the library. */
+ if (USBD_Init(&hUsbDeviceFS, &FS_Desc, DEVICE_FS) != USBD_OK)
+ {
+ Error_Handler();
+ }
+ if (USBD_RegisterClass(&hUsbDeviceFS, &USBD_CDC) != USBD_OK)
+ {
+ Error_Handler();
+ }
+ if (USBD_CDC_RegisterInterface(&hUsbDeviceFS, &USBD_Interface_fops_FS) != USBD_OK)
+ {
+ Error_Handler();
+ }
+ if (USBD_Start(&hUsbDeviceFS) != USBD_OK)
+ {
+ Error_Handler();
+ }
+
+ /* USER CODE BEGIN USB_DEVICE_Init_PostTreatment */
+ HAL_PWREx_EnableUSBVoltageDetector();
+
+ /* USER CODE END USB_DEVICE_Init_PostTreatment */
+}
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
diff --git a/Ganesha_II_V2/USB_DEVICE/App/usb_device.h b/Ganesha_II_V2/USB_DEVICE/App/usb_device.h
new file mode 100644
index 0000000..b7e1b20
--- /dev/null
+++ b/Ganesha_II_V2/USB_DEVICE/App/usb_device.h
@@ -0,0 +1,102 @@
+/* USER CODE BEGIN Header */
+/**
+ ******************************************************************************
+ * @file : usb_device.h
+ * @version : v1.0_Cube
+ * @brief : Header for usb_device.c file.
+ ******************************************************************************
+ * @attention
+ *
+ * Copyright (c) 2026 STMicroelectronics.
+ * All rights reserved.
+ *
+ * This software is licensed under terms that can be found in the LICENSE file
+ * in the root directory of this software component.
+ * If no LICENSE file comes with this software, it is provided AS-IS.
+ *
+ ******************************************************************************
+ */
+/* USER CODE END Header */
+
+/* Define to prevent recursive inclusion -------------------------------------*/
+#ifndef __USB_DEVICE__H__
+#define __USB_DEVICE__H__
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+/* Includes ------------------------------------------------------------------*/
+#include "stm32h7xx.h"
+#include "stm32h7xx_hal.h"
+#include "usbd_def.h"
+
+/* USER CODE BEGIN INCLUDE */
+
+/* USER CODE END INCLUDE */
+
+/** @addtogroup USBD_OTG_DRIVER
+ * @{
+ */
+
+/** @defgroup USBD_DEVICE USBD_DEVICE
+ * @brief Device file for Usb otg low level driver.
+ * @{
+ */
+
+/** @defgroup USBD_DEVICE_Exported_Variables USBD_DEVICE_Exported_Variables
+ * @brief Public variables.
+ * @{
+ */
+
+/* Private variables ---------------------------------------------------------*/
+/* USER CODE BEGIN PV */
+
+/* USER CODE END PV */
+
+/* Private function prototypes -----------------------------------------------*/
+/* USER CODE BEGIN PFP */
+
+/* USER CODE END PFP */
+
+/*
+ * -- Insert your variables declaration here --
+ */
+/* USER CODE BEGIN VARIABLES */
+
+/* USER CODE END VARIABLES */
+/**
+ * @}
+ */
+
+/** @defgroup USBD_DEVICE_Exported_FunctionsPrototype USBD_DEVICE_Exported_FunctionsPrototype
+ * @brief Declaration of public functions for Usb device.
+ * @{
+ */
+
+/** USB Device initialization function. */
+void MX_USB_DEVICE_Init(void);
+
+/*
+ * -- Insert functions declaration here --
+ */
+/* USER CODE BEGIN FD */
+
+/* USER CODE END FD */
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __USB_DEVICE__H__ */
diff --git a/Ganesha_II_V2/USB_DEVICE/App/usbd_cdc_if.c b/Ganesha_II_V2/USB_DEVICE/App/usbd_cdc_if.c
new file mode 100644
index 0000000..2a87f66
--- /dev/null
+++ b/Ganesha_II_V2/USB_DEVICE/App/usbd_cdc_if.c
@@ -0,0 +1,330 @@
+/* USER CODE BEGIN Header */
+/**
+ ******************************************************************************
+ * @file : usbd_cdc_if.c
+ * @version : v1.0_Cube
+ * @brief : Usb device for Virtual Com Port.
+ ******************************************************************************
+ * @attention
+ *
+ * Copyright (c) 2026 STMicroelectronics.
+ * All rights reserved.
+ *
+ * This software is licensed under terms that can be found in the LICENSE file
+ * in the root directory of this software component.
+ * If no LICENSE file comes with this software, it is provided AS-IS.
+ *
+ ******************************************************************************
+ */
+/* USER CODE END Header */
+
+/* Includes ------------------------------------------------------------------*/
+#include "usbd_cdc_if.h"
+
+/* USER CODE BEGIN INCLUDE */
+#include "main.h"
+/* USER CODE END INCLUDE */
+
+/* Private typedef -----------------------------------------------------------*/
+/* Private define ------------------------------------------------------------*/
+/* Private macro -------------------------------------------------------------*/
+
+/* USER CODE BEGIN PV */
+/* Private variables ---------------------------------------------------------*/
+
+/* USER CODE END PV */
+
+/** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY
+ * @brief Usb device library.
+ * @{
+ */
+
+/** @addtogroup USBD_CDC_IF
+ * @{
+ */
+
+/** @defgroup USBD_CDC_IF_Private_TypesDefinitions USBD_CDC_IF_Private_TypesDefinitions
+ * @brief Private types.
+ * @{
+ */
+
+/* USER CODE BEGIN PRIVATE_TYPES */
+
+/* USER CODE END PRIVATE_TYPES */
+
+/**
+ * @}
+ */
+
+/** @defgroup USBD_CDC_IF_Private_Defines USBD_CDC_IF_Private_Defines
+ * @brief Private defines.
+ * @{
+ */
+
+/* USER CODE BEGIN PRIVATE_DEFINES */
+/* USER CODE END PRIVATE_DEFINES */
+
+/**
+ * @}
+ */
+
+/** @defgroup USBD_CDC_IF_Private_Macros USBD_CDC_IF_Private_Macros
+ * @brief Private macros.
+ * @{
+ */
+
+/* USER CODE BEGIN PRIVATE_MACRO */
+
+/* USER CODE END PRIVATE_MACRO */
+
+/**
+ * @}
+ */
+
+/** @defgroup USBD_CDC_IF_Private_Variables USBD_CDC_IF_Private_Variables
+ * @brief Private variables.
+ * @{
+ */
+/* Create buffer for reception and transmission */
+/* It's up to user to redefine and/or remove those define */
+/** Received data over USB are stored in this buffer */
+uint8_t UserRxBufferFS[APP_RX_DATA_SIZE];
+
+/** Data to send over USB CDC are stored in this buffer */
+uint8_t UserTxBufferFS[APP_TX_DATA_SIZE];
+
+/* USER CODE BEGIN PRIVATE_VARIABLES */
+
+/* USER CODE END PRIVATE_VARIABLES */
+
+/**
+ * @}
+ */
+
+/** @defgroup USBD_CDC_IF_Exported_Variables USBD_CDC_IF_Exported_Variables
+ * @brief Public variables.
+ * @{
+ */
+
+extern USBD_HandleTypeDef hUsbDeviceFS;
+
+/* USER CODE BEGIN EXPORTED_VARIABLES */
+
+/* USER CODE END EXPORTED_VARIABLES */
+
+/**
+ * @}
+ */
+
+/** @defgroup USBD_CDC_IF_Private_FunctionPrototypes USBD_CDC_IF_Private_FunctionPrototypes
+ * @brief Private functions declaration.
+ * @{
+ */
+
+static int8_t CDC_Init_FS(void);
+static int8_t CDC_DeInit_FS(void);
+static int8_t CDC_Control_FS(uint8_t cmd, uint8_t* pbuf, uint16_t length);
+static int8_t CDC_Receive_FS(uint8_t* pbuf, uint32_t *Len);
+static int8_t CDC_TransmitCplt_FS(uint8_t *pbuf, uint32_t *Len, uint8_t epnum);
+
+/* USER CODE BEGIN PRIVATE_FUNCTIONS_DECLARATION */
+
+/* USER CODE END PRIVATE_FUNCTIONS_DECLARATION */
+
+/**
+ * @}
+ */
+
+USBD_CDC_ItfTypeDef USBD_Interface_fops_FS =
+{
+ CDC_Init_FS,
+ CDC_DeInit_FS,
+ CDC_Control_FS,
+ CDC_Receive_FS,
+ CDC_TransmitCplt_FS
+};
+
+/* Private functions ---------------------------------------------------------*/
+/**
+ * @brief Initializes the CDC media low layer over the FS USB IP
+ * @retval USBD_OK if all operations are OK else USBD_FAIL
+ */
+static int8_t CDC_Init_FS(void)
+{
+ /* USER CODE BEGIN 3 */
+ /* Set Application Buffers */
+ USBD_CDC_SetTxBuffer(&hUsbDeviceFS, UserTxBufferFS, 0);
+ USBD_CDC_SetRxBuffer(&hUsbDeviceFS, UserRxBufferFS);
+ return (USBD_OK);
+ /* USER CODE END 3 */
+}
+
+/**
+ * @brief DeInitializes the CDC media low layer
+ * @retval USBD_OK if all operations are OK else USBD_FAIL
+ */
+static int8_t CDC_DeInit_FS(void)
+{
+ /* USER CODE BEGIN 4 */
+ return (USBD_OK);
+ /* USER CODE END 4 */
+}
+
+/**
+ * @brief Manage the CDC class requests
+ * @param cmd: Command code
+ * @param pbuf: Buffer containing command data (request parameters)
+ * @param length: Number of data to be sent (in bytes)
+ * @retval Result of the operation: USBD_OK if all operations are OK else USBD_FAIL
+ */
+static int8_t CDC_Control_FS(uint8_t cmd, uint8_t* pbuf, uint16_t length)
+{
+ /* USER CODE BEGIN 5 */
+ switch(cmd)
+ {
+ case CDC_SEND_ENCAPSULATED_COMMAND:
+
+ break;
+
+ case CDC_GET_ENCAPSULATED_RESPONSE:
+
+ break;
+
+ case CDC_SET_COMM_FEATURE:
+
+ break;
+
+ case CDC_GET_COMM_FEATURE:
+
+ break;
+
+ case CDC_CLEAR_COMM_FEATURE:
+
+ break;
+
+ /*******************************************************************************/
+ /* Line Coding Structure */
+ /*-----------------------------------------------------------------------------*/
+ /* Offset | Field | Size | Value | Description */
+ /* 0 | dwDTERate | 4 | Number |Data terminal rate, in bits per second*/
+ /* 4 | bCharFormat | 1 | Number | Stop bits */
+ /* 0 - 1 Stop bit */
+ /* 1 - 1.5 Stop bits */
+ /* 2 - 2 Stop bits */
+ /* 5 | bParityType | 1 | Number | Parity */
+ /* 0 - None */
+ /* 1 - Odd */
+ /* 2 - Even */
+ /* 3 - Mark */
+ /* 4 - Space */
+ /* 6 | bDataBits | 1 | Number Data bits (5, 6, 7, 8 or 16). */
+ /*******************************************************************************/
+ case CDC_SET_LINE_CODING:
+
+ break;
+
+ case CDC_GET_LINE_CODING:
+
+ break;
+
+ case CDC_SET_CONTROL_LINE_STATE:
+
+ break;
+
+ case CDC_SEND_BREAK:
+
+ break;
+
+ default:
+ break;
+ }
+
+ return (USBD_OK);
+ /* USER CODE END 5 */
+}
+
+/**
+ * @brief Data received over USB OUT endpoint are sent over CDC interface
+ * through this function.
+ *
+ * @note
+ * This function will issue a NAK packet on any OUT packet received on
+ * USB endpoint until exiting this function. If you exit this function
+ * before transfer is complete on CDC interface (ie. using DMA controller)
+ * it will result in receiving more data while previous ones are still
+ * not sent.
+ *
+ * @param Buf: Buffer of data to be received
+ * @param Len: Number of data received (in bytes)
+ * @retval Result of the operation: USBD_OK if all operations are OK else USBD_FAIL
+ */
+static int8_t CDC_Receive_FS(uint8_t* Buf, uint32_t *Len)
+{
+ /* USER CODE BEGIN 6 */
+ USBD_CDC_SetRxBuffer(&hUsbDeviceFS, &Buf[0]);
+ USBD_CDC_ReceivePacket(&hUsbDeviceFS);
+ handle_usb_cdc(UserRxBufferFS, *Len);
+ memset(UserRxBufferFS, '\0', *Len);
+ return (USBD_OK);
+ /* USER CODE END 6 */
+}
+
+/**
+ * @brief CDC_Transmit_FS
+ * Data to send over USB IN endpoint are sent over CDC interface
+ * through this function.
+ * @note
+ *
+ *
+ * @param Buf: Buffer of data to be sent
+ * @param Len: Number of data to be sent (in bytes)
+ * @retval USBD_OK if all operations are OK else USBD_FAIL or USBD_BUSY
+ */
+uint8_t CDC_Transmit_FS(uint8_t* Buf, uint16_t Len)
+{
+ uint8_t result = USBD_OK;
+ /* USER CODE BEGIN 7 */
+ USBD_CDC_HandleTypeDef *hcdc = (USBD_CDC_HandleTypeDef*)hUsbDeviceFS.pClassData;
+ if (hcdc->TxState != 0){
+ return USBD_BUSY;
+ }
+ USBD_CDC_SetTxBuffer(&hUsbDeviceFS, Buf, Len);
+ result = USBD_CDC_TransmitPacket(&hUsbDeviceFS);
+ /* USER CODE END 7 */
+ return result;
+}
+
+/**
+ * @brief CDC_TransmitCplt_FS
+ * Data transmitted callback
+ *
+ * @note
+ * This function is IN transfer complete callback used to inform user that
+ * the submitted Data is successfully sent over USB.
+ *
+ * @param Buf: Buffer of data to be received
+ * @param Len: Number of data received (in bytes)
+ * @retval Result of the operation: USBD_OK if all operations are OK else USBD_FAIL
+ */
+static int8_t CDC_TransmitCplt_FS(uint8_t *Buf, uint32_t *Len, uint8_t epnum)
+{
+ uint8_t result = USBD_OK;
+ /* USER CODE BEGIN 13 */
+ UNUSED(Buf);
+ UNUSED(Len);
+ UNUSED(epnum);
+ /* USER CODE END 13 */
+ return result;
+}
+
+/* USER CODE BEGIN PRIVATE_FUNCTIONS_IMPLEMENTATION */
+
+/* USER CODE END PRIVATE_FUNCTIONS_IMPLEMENTATION */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
diff --git a/Ganesha_II_V2/USB_DEVICE/App/usbd_cdc_if.h b/Ganesha_II_V2/USB_DEVICE/App/usbd_cdc_if.h
new file mode 100644
index 0000000..b8ca58d
--- /dev/null
+++ b/Ganesha_II_V2/USB_DEVICE/App/usbd_cdc_if.h
@@ -0,0 +1,132 @@
+/* USER CODE BEGIN Header */
+/**
+ ******************************************************************************
+ * @file : usbd_cdc_if.h
+ * @version : v1.0_Cube
+ * @brief : Header for usbd_cdc_if.c file.
+ ******************************************************************************
+ * @attention
+ *
+ * Copyright (c) 2026 STMicroelectronics.
+ * All rights reserved.
+ *
+ * This software is licensed under terms that can be found in the LICENSE file
+ * in the root directory of this software component.
+ * If no LICENSE file comes with this software, it is provided AS-IS.
+ *
+ ******************************************************************************
+ */
+/* USER CODE END Header */
+
+/* Define to prevent recursive inclusion -------------------------------------*/
+
+#ifndef __USBD_CDC_IF_H__
+#define __USBD_CDC_IF_H__
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+/* Includes ------------------------------------------------------------------*/
+#include "usbd_cdc.h"
+
+/* USER CODE BEGIN INCLUDE */
+
+/* USER CODE END INCLUDE */
+
+/** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY
+ * @brief For Usb device.
+ * @{
+ */
+
+/** @defgroup USBD_CDC_IF USBD_CDC_IF
+ * @brief Usb VCP device module
+ * @{
+ */
+
+/** @defgroup USBD_CDC_IF_Exported_Defines USBD_CDC_IF_Exported_Defines
+ * @brief Defines.
+ * @{
+ */
+/* Define size for the receive and transmit buffer over CDC */
+#define APP_RX_DATA_SIZE 2048
+#define APP_TX_DATA_SIZE 2048
+/* USER CODE BEGIN EXPORTED_DEFINES */
+
+/* USER CODE END EXPORTED_DEFINES */
+
+/**
+ * @}
+ */
+
+/** @defgroup USBD_CDC_IF_Exported_Types USBD_CDC_IF_Exported_Types
+ * @brief Types.
+ * @{
+ */
+
+/* USER CODE BEGIN EXPORTED_TYPES */
+
+/* USER CODE END EXPORTED_TYPES */
+
+/**
+ * @}
+ */
+
+/** @defgroup USBD_CDC_IF_Exported_Macros USBD_CDC_IF_Exported_Macros
+ * @brief Aliases.
+ * @{
+ */
+
+/* USER CODE BEGIN EXPORTED_MACRO */
+
+/* USER CODE END EXPORTED_MACRO */
+
+/**
+ * @}
+ */
+
+/** @defgroup USBD_CDC_IF_Exported_Variables USBD_CDC_IF_Exported_Variables
+ * @brief Public variables.
+ * @{
+ */
+
+/** CDC Interface callback. */
+extern USBD_CDC_ItfTypeDef USBD_Interface_fops_FS;
+
+/* USER CODE BEGIN EXPORTED_VARIABLES */
+
+/* USER CODE END EXPORTED_VARIABLES */
+
+/**
+ * @}
+ */
+
+/** @defgroup USBD_CDC_IF_Exported_FunctionsPrototype USBD_CDC_IF_Exported_FunctionsPrototype
+ * @brief Public functions declaration.
+ * @{
+ */
+
+uint8_t CDC_Transmit_FS(uint8_t* Buf, uint16_t Len);
+
+/* USER CODE BEGIN EXPORTED_FUNCTIONS */
+
+/* USER CODE END EXPORTED_FUNCTIONS */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __USBD_CDC_IF_H__ */
+
diff --git a/Ganesha_II_V2/USB_DEVICE/App/usbd_desc.c b/Ganesha_II_V2/USB_DEVICE/App/usbd_desc.c
new file mode 100644
index 0000000..a18dd89
--- /dev/null
+++ b/Ganesha_II_V2/USB_DEVICE/App/usbd_desc.c
@@ -0,0 +1,418 @@
+/* USER CODE BEGIN Header */
+/**
+ ******************************************************************************
+ * @file : App/usbd_desc.c
+ * @version : v1.0_Cube
+ * @brief : This file implements the USB device descriptors.
+ ******************************************************************************
+ * @attention
+ *
+ * Copyright (c) 2026 STMicroelectronics.
+ * All rights reserved.
+ *
+ * This software is licensed under terms that can be found in the LICENSE file
+ * in the root directory of this software component.
+ * If no LICENSE file comes with this software, it is provided AS-IS.
+ *
+ ******************************************************************************
+ */
+/* USER CODE END Header */
+
+/* Includes ------------------------------------------------------------------*/
+#include "usbd_core.h"
+#include "usbd_desc.h"
+#include "usbd_conf.h"
+
+/* USER CODE BEGIN INCLUDE */
+
+/* USER CODE END INCLUDE */
+
+/* Private typedef -----------------------------------------------------------*/
+/* Private define ------------------------------------------------------------*/
+/* Private macro -------------------------------------------------------------*/
+
+/* USER CODE BEGIN PV */
+/* Private variables ---------------------------------------------------------*/
+
+/* USER CODE END PV */
+
+/** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY
+ * @{
+ */
+
+/** @addtogroup USBD_DESC
+ * @{
+ */
+
+/** @defgroup USBD_DESC_Private_TypesDefinitions USBD_DESC_Private_TypesDefinitions
+ * @brief Private types.
+ * @{
+ */
+
+/* USER CODE BEGIN PRIVATE_TYPES */
+
+/* USER CODE END PRIVATE_TYPES */
+
+/**
+ * @}
+ */
+
+/** @defgroup USBD_DESC_Private_Defines USBD_DESC_Private_Defines
+ * @brief Private defines.
+ * @{
+ */
+
+#define USBD_VID 1155
+#define USBD_LANGID_STRING 1033
+#define USBD_MANUFACTURER_STRING "STMicroelectronics"
+#define USBD_PID_FS 22336
+#define USBD_PRODUCT_STRING_FS "STM32 Virtual ComPort"
+#define USBD_CONFIGURATION_STRING_FS "CDC Config"
+#define USBD_INTERFACE_STRING_FS "CDC Interface"
+
+#define USB_SIZ_BOS_DESC 0x0C
+
+/* USER CODE BEGIN PRIVATE_DEFINES */
+
+/* USER CODE END PRIVATE_DEFINES */
+
+/**
+ * @}
+ */
+
+/* USER CODE BEGIN 0 */
+
+/* USER CODE END 0 */
+
+/** @defgroup USBD_DESC_Private_Macros USBD_DESC_Private_Macros
+ * @brief Private macros.
+ * @{
+ */
+
+/* USER CODE BEGIN PRIVATE_MACRO */
+
+/* USER CODE END PRIVATE_MACRO */
+
+/**
+ * @}
+ */
+
+/** @defgroup USBD_DESC_Private_FunctionPrototypes USBD_DESC_Private_FunctionPrototypes
+ * @brief Private functions declaration.
+ * @{
+ */
+
+static void Get_SerialNum(void);
+static void IntToUnicode(uint32_t value, uint8_t * pbuf, uint8_t len);
+
+/**
+ * @}
+ */
+
+/** @defgroup USBD_DESC_Private_FunctionPrototypes USBD_DESC_Private_FunctionPrototypes
+ * @brief Private functions declaration for FS.
+ * @{
+ */
+
+uint8_t * USBD_FS_DeviceDescriptor(USBD_SpeedTypeDef speed, uint16_t *length);
+uint8_t * USBD_FS_LangIDStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length);
+uint8_t * USBD_FS_ManufacturerStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length);
+uint8_t * USBD_FS_ProductStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length);
+uint8_t * USBD_FS_SerialStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length);
+uint8_t * USBD_FS_ConfigStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length);
+uint8_t * USBD_FS_InterfaceStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length);
+
+/**
+ * @}
+ */
+
+/** @defgroup USBD_DESC_Private_Variables USBD_DESC_Private_Variables
+ * @brief Private variables.
+ * @{
+ */
+
+USBD_DescriptorsTypeDef FS_Desc =
+{
+ USBD_FS_DeviceDescriptor
+, USBD_FS_LangIDStrDescriptor
+, USBD_FS_ManufacturerStrDescriptor
+, USBD_FS_ProductStrDescriptor
+, USBD_FS_SerialStrDescriptor
+, USBD_FS_ConfigStrDescriptor
+, USBD_FS_InterfaceStrDescriptor
+};
+
+#if defined ( __ICCARM__ ) /* IAR Compiler */
+ #pragma data_alignment=4
+#endif /* defined ( __ICCARM__ ) */
+/** USB standard device descriptor. */
+__ALIGN_BEGIN uint8_t USBD_FS_DeviceDesc[USB_LEN_DEV_DESC] __ALIGN_END =
+{
+ 0x12, /*bLength */
+ USB_DESC_TYPE_DEVICE, /*bDescriptorType*/
+ 0x00, /*bcdUSB */
+ 0x02,
+ 0x02, /*bDeviceClass*/
+ 0x02, /*bDeviceSubClass*/
+ 0x00, /*bDeviceProtocol*/
+ USB_MAX_EP0_SIZE, /*bMaxPacketSize*/
+ LOBYTE(USBD_VID), /*idVendor*/
+ HIBYTE(USBD_VID), /*idVendor*/
+ LOBYTE(USBD_PID_FS), /*idProduct*/
+ HIBYTE(USBD_PID_FS), /*idProduct*/
+ 0x00, /*bcdDevice rel. 2.00*/
+ 0x02,
+ USBD_IDX_MFC_STR, /*Index of manufacturer string*/
+ USBD_IDX_PRODUCT_STR, /*Index of product string*/
+ USBD_IDX_SERIAL_STR, /*Index of serial number string*/
+ USBD_MAX_NUM_CONFIGURATION /*bNumConfigurations*/
+};
+
+/* USB_DeviceDescriptor */
+/** BOS descriptor. */
+#if (USBD_LPM_ENABLED == 1)
+#if defined ( __ICCARM__ ) /* IAR Compiler */
+ #pragma data_alignment=4
+#endif /* defined ( __ICCARM__ ) */
+__ALIGN_BEGIN uint8_t USBD_FS_BOSDesc[USB_SIZ_BOS_DESC] __ALIGN_END =
+{
+ 0x5,
+ USB_DESC_TYPE_BOS,
+ 0xC,
+ 0x0,
+ 0x1, /* 1 device capability*/
+ /* device capability*/
+ 0x7,
+ USB_DEVICE_CAPABITY_TYPE,
+ 0x2,
+ 0x2, /* LPM capability bit set*/
+ 0x0,
+ 0x0,
+ 0x0
+};
+#endif /* (USBD_LPM_ENABLED == 1) */
+
+/**
+ * @}
+ */
+
+/** @defgroup USBD_DESC_Private_Variables USBD_DESC_Private_Variables
+ * @brief Private variables.
+ * @{
+ */
+
+#if defined ( __ICCARM__ ) /* IAR Compiler */
+ #pragma data_alignment=4
+#endif /* defined ( __ICCARM__ ) */
+
+/** USB lang identifier descriptor. */
+__ALIGN_BEGIN uint8_t USBD_LangIDDesc[USB_LEN_LANGID_STR_DESC] __ALIGN_END =
+{
+ USB_LEN_LANGID_STR_DESC,
+ USB_DESC_TYPE_STRING,
+ LOBYTE(USBD_LANGID_STRING),
+ HIBYTE(USBD_LANGID_STRING)
+};
+
+#if defined ( __ICCARM__ ) /* IAR Compiler */
+ #pragma data_alignment=4
+#endif /* defined ( __ICCARM__ ) */
+/* Internal string descriptor. */
+__ALIGN_BEGIN uint8_t USBD_StrDesc[USBD_MAX_STR_DESC_SIZ] __ALIGN_END;
+
+#if defined ( __ICCARM__ ) /*!< IAR Compiler */
+ #pragma data_alignment=4
+#endif
+__ALIGN_BEGIN uint8_t USBD_StringSerial[USB_SIZ_STRING_SERIAL] __ALIGN_END = {
+ USB_SIZ_STRING_SERIAL,
+ USB_DESC_TYPE_STRING,
+};
+
+/**
+ * @}
+ */
+
+/** @defgroup USBD_DESC_Private_Functions USBD_DESC_Private_Functions
+ * @brief Private functions.
+ * @{
+ */
+
+/**
+ * @brief Return the device descriptor
+ * @param speed : Current device speed
+ * @param length : Pointer to data length variable
+ * @retval Pointer to descriptor buffer
+ */
+uint8_t * USBD_FS_DeviceDescriptor(USBD_SpeedTypeDef speed, uint16_t *length)
+{
+ UNUSED(speed);
+ *length = sizeof(USBD_FS_DeviceDesc);
+ return USBD_FS_DeviceDesc;
+}
+
+/**
+ * @brief Return the LangID string descriptor
+ * @param speed : Current device speed
+ * @param length : Pointer to data length variable
+ * @retval Pointer to descriptor buffer
+ */
+uint8_t * USBD_FS_LangIDStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length)
+{
+ UNUSED(speed);
+ *length = sizeof(USBD_LangIDDesc);
+ return USBD_LangIDDesc;
+}
+
+/**
+ * @brief Return the product string descriptor
+ * @param speed : Current device speed
+ * @param length : Pointer to data length variable
+ * @retval Pointer to descriptor buffer
+ */
+uint8_t * USBD_FS_ProductStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length)
+{
+ if(speed == 0)
+ {
+ USBD_GetString((uint8_t *)USBD_PRODUCT_STRING_FS, USBD_StrDesc, length);
+ }
+ else
+ {
+ USBD_GetString((uint8_t *)USBD_PRODUCT_STRING_FS, USBD_StrDesc, length);
+ }
+ return USBD_StrDesc;
+}
+
+/**
+ * @brief Return the manufacturer string descriptor
+ * @param speed : Current device speed
+ * @param length : Pointer to data length variable
+ * @retval Pointer to descriptor buffer
+ */
+uint8_t * USBD_FS_ManufacturerStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length)
+{
+ UNUSED(speed);
+ USBD_GetString((uint8_t *)USBD_MANUFACTURER_STRING, USBD_StrDesc, length);
+ return USBD_StrDesc;
+}
+
+/**
+ * @brief Return the serial number string descriptor
+ * @param speed : Current device speed
+ * @param length : Pointer to data length variable
+ * @retval Pointer to descriptor buffer
+ */
+uint8_t * USBD_FS_SerialStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length)
+{
+ UNUSED(speed);
+ *length = USB_SIZ_STRING_SERIAL;
+
+ /* Update the serial number string descriptor with the data from the unique
+ * ID */
+ Get_SerialNum();
+ /* USER CODE BEGIN USBD_FS_SerialStrDescriptor */
+
+ /* USER CODE END USBD_FS_SerialStrDescriptor */
+ return (uint8_t *) USBD_StringSerial;
+}
+
+/**
+ * @brief Return the configuration string descriptor
+ * @param speed : Current device speed
+ * @param length : Pointer to data length variable
+ * @retval Pointer to descriptor buffer
+ */
+uint8_t * USBD_FS_ConfigStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length)
+{
+ if(speed == USBD_SPEED_HIGH)
+ {
+ USBD_GetString((uint8_t *)USBD_CONFIGURATION_STRING_FS, USBD_StrDesc, length);
+ }
+ else
+ {
+ USBD_GetString((uint8_t *)USBD_CONFIGURATION_STRING_FS, USBD_StrDesc, length);
+ }
+ return USBD_StrDesc;
+}
+
+/**
+ * @brief Return the interface string descriptor
+ * @param speed : Current device speed
+ * @param length : Pointer to data length variable
+ * @retval Pointer to descriptor buffer
+ */
+uint8_t * USBD_FS_InterfaceStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length)
+{
+ if(speed == 0)
+ {
+ USBD_GetString((uint8_t *)USBD_INTERFACE_STRING_FS, USBD_StrDesc, length);
+ }
+ else
+ {
+ USBD_GetString((uint8_t *)USBD_INTERFACE_STRING_FS, USBD_StrDesc, length);
+ }
+ return USBD_StrDesc;
+}
+
+/**
+ * @brief Create the serial number string descriptor
+ * @param None
+ * @retval None
+ */
+static void Get_SerialNum(void)
+{
+ uint32_t deviceserial0;
+ uint32_t deviceserial1;
+ uint32_t deviceserial2;
+
+ deviceserial0 = *(uint32_t *) DEVICE_ID1;
+ deviceserial1 = *(uint32_t *) DEVICE_ID2;
+ deviceserial2 = *(uint32_t *) DEVICE_ID3;
+
+ deviceserial0 += deviceserial2;
+
+ if (deviceserial0 != 0)
+ {
+ IntToUnicode(deviceserial0, &USBD_StringSerial[2], 8);
+ IntToUnicode(deviceserial1, &USBD_StringSerial[18], 4);
+ }
+}
+
+/**
+ * @brief Convert Hex 32Bits value into char
+ * @param value: value to convert
+ * @param pbuf: pointer to the buffer
+ * @param len: buffer length
+ * @retval None
+ */
+static void IntToUnicode(uint32_t value, uint8_t * pbuf, uint8_t len)
+{
+ uint8_t idx = 0;
+
+ for (idx = 0; idx < len; idx++)
+ {
+ if (((value >> 28)) < 0xA)
+ {
+ pbuf[2 * idx] = (value >> 28) + '0';
+ }
+ else
+ {
+ pbuf[2 * idx] = (value >> 28) + 'A' - 10;
+ }
+
+ value = value << 4;
+
+ pbuf[2 * idx + 1] = 0;
+ }
+}
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
diff --git a/Ganesha_II_V2/USB_DEVICE/App/usbd_desc.h b/Ganesha_II_V2/USB_DEVICE/App/usbd_desc.h
new file mode 100644
index 0000000..ab82d2f
--- /dev/null
+++ b/Ganesha_II_V2/USB_DEVICE/App/usbd_desc.h
@@ -0,0 +1,143 @@
+/* USER CODE BEGIN Header */
+/**
+ ******************************************************************************
+ * @file : usbd_desc.c
+ * @version : v1.0_Cube
+ * @brief : Header for usbd_conf.c file.
+ ******************************************************************************
+ * @attention
+ *
+ * Copyright (c) 2026 STMicroelectronics.
+ * All rights reserved.
+ *
+ * This software is licensed under terms that can be found in the LICENSE file
+ * in the root directory of this software component.
+ * If no LICENSE file comes with this software, it is provided AS-IS.
+ *
+ ******************************************************************************
+ */
+/* USER CODE END Header */
+/* Define to prevent recursive inclusion -------------------------------------*/
+#ifndef __USBD_DESC__C__
+#define __USBD_DESC__C__
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+/* Includes ------------------------------------------------------------------*/
+#include "usbd_def.h"
+
+/* USER CODE BEGIN INCLUDE */
+
+/* USER CODE END INCLUDE */
+
+/** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY
+ * @{
+ */
+
+/** @defgroup USBD_DESC USBD_DESC
+ * @brief Usb device descriptors module.
+ * @{
+ */
+
+/** @defgroup USBD_DESC_Exported_Constants USBD_DESC_Exported_Constants
+ * @brief Constants.
+ * @{
+ */
+#define DEVICE_ID1 (UID_BASE)
+#define DEVICE_ID2 (UID_BASE + 0x4)
+#define DEVICE_ID3 (UID_BASE + 0x8)
+
+#define USB_SIZ_STRING_SERIAL 0x1A
+
+/* USER CODE BEGIN EXPORTED_CONSTANTS */
+
+/* USER CODE END EXPORTED_CONSTANTS */
+
+/**
+ * @}
+ */
+
+/** @defgroup USBD_DESC_Exported_Defines USBD_DESC_Exported_Defines
+ * @brief Defines.
+ * @{
+ */
+
+/* USER CODE BEGIN EXPORTED_DEFINES */
+
+/* USER CODE END EXPORTED_DEFINES */
+
+/**
+ * @}
+ */
+
+/** @defgroup USBD_DESC_Exported_TypesDefinitions USBD_DESC_Exported_TypesDefinitions
+ * @brief Types.
+ * @{
+ */
+
+/* USER CODE BEGIN EXPORTED_TYPES */
+
+/* USER CODE END EXPORTED_TYPES */
+
+/**
+ * @}
+ */
+
+/** @defgroup USBD_DESC_Exported_Macros USBD_DESC_Exported_Macros
+ * @brief Aliases.
+ * @{
+ */
+
+/* USER CODE BEGIN EXPORTED_MACRO */
+
+/* USER CODE END EXPORTED_MACRO */
+
+/**
+ * @}
+ */
+
+/** @defgroup USBD_DESC_Exported_Variables USBD_DESC_Exported_Variables
+ * @brief Public variables.
+ * @{
+ */
+
+/** Descriptor for the Usb device. */
+extern USBD_DescriptorsTypeDef FS_Desc;
+
+/* USER CODE BEGIN EXPORTED_VARIABLES */
+
+/* USER CODE END EXPORTED_VARIABLES */
+
+/**
+ * @}
+ */
+
+/** @defgroup USBD_DESC_Exported_FunctionsPrototype USBD_DESC_Exported_FunctionsPrototype
+ * @brief Public functions declaration.
+ * @{
+ */
+
+/* USER CODE BEGIN EXPORTED_FUNCTIONS */
+
+/* USER CODE END EXPORTED_FUNCTIONS */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __USBD_DESC__C__ */
+
diff --git a/Ganesha_II_V2/USB_DEVICE/Target/usbd_conf.c b/Ganesha_II_V2/USB_DEVICE/Target/usbd_conf.c
new file mode 100644
index 0000000..c674c81
--- /dev/null
+++ b/Ganesha_II_V2/USB_DEVICE/Target/usbd_conf.c
@@ -0,0 +1,693 @@
+/* USER CODE BEGIN Header */
+/**
+ ******************************************************************************
+ * @file : Target/usbd_conf.c
+ * @version : v1.0_Cube
+ * @brief : This file implements the board support package for the USB device library
+ ******************************************************************************
+ * @attention
+ *
+ * Copyright (c) 2026 STMicroelectronics.
+ * All rights reserved.
+ *
+ * This software is licensed under terms that can be found in the LICENSE file
+ * in the root directory of this software component.
+ * If no LICENSE file comes with this software, it is provided AS-IS.
+ *
+ ******************************************************************************
+ */
+/* USER CODE END Header */
+
+/* Includes ------------------------------------------------------------------*/
+#include "stm32h7xx.h"
+#include "stm32h7xx_hal.h"
+#include "usbd_def.h"
+#include "usbd_core.h"
+#include "usbd_cdc.h"
+
+/* USER CODE BEGIN Includes */
+
+/* USER CODE END Includes */
+
+/* Private typedef -----------------------------------------------------------*/
+/* Private define ------------------------------------------------------------*/
+/* Private macro -------------------------------------------------------------*/
+
+/* USER CODE BEGIN PV */
+/* Private variables ---------------------------------------------------------*/
+
+/* USER CODE END PV */
+
+PCD_HandleTypeDef hpcd_USB_OTG_FS;
+void Error_Handler(void);
+
+/* External functions --------------------------------------------------------*/
+
+/* USER CODE BEGIN 0 */
+
+/* USER CODE END 0 */
+
+/* USER CODE BEGIN PFP */
+/* Private function prototypes -----------------------------------------------*/
+USBD_StatusTypeDef USBD_Get_USB_Status(HAL_StatusTypeDef hal_status);
+
+/* USER CODE END PFP */
+
+/* Private functions ---------------------------------------------------------*/
+
+/* USER CODE BEGIN 1 */
+/* USER CODE END 1 */
+
+/*******************************************************************************
+ LL Driver Callbacks (PCD -> USB Device Library)
+*******************************************************************************/
+/* MSP Init */
+
+void HAL_PCD_MspInit(PCD_HandleTypeDef* pcdHandle)
+{
+ GPIO_InitTypeDef GPIO_InitStruct = {0};
+ RCC_PeriphCLKInitTypeDef PeriphClkInitStruct = {0};
+ if(pcdHandle->Instance==USB_OTG_FS)
+ {
+ /* USER CODE BEGIN USB_OTG_FS_MspInit 0 */
+
+ /* USER CODE END USB_OTG_FS_MspInit 0 */
+
+ /** Initializes the peripherals clock
+ */
+ PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_USB;
+ PeriphClkInitStruct.UsbClockSelection = RCC_USBCLKSOURCE_PLL;
+ if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK)
+ {
+ Error_Handler();
+ }
+
+ /** Enable USB Voltage detector
+ */
+ HAL_PWREx_EnableUSBVoltageDetector();
+
+ __HAL_RCC_GPIOA_CLK_ENABLE();
+ /**USB_OTG_FS GPIO Configuration
+ PA11 ------> USB_OTG_FS_DM
+ PA12 ------> USB_OTG_FS_DP
+ */
+ GPIO_InitStruct.Pin = GPIO_PIN_11|GPIO_PIN_12;
+ GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
+ GPIO_InitStruct.Pull = GPIO_NOPULL;
+ GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
+ GPIO_InitStruct.Alternate = GPIO_AF10_OTG1_FS;
+ HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
+
+ /* Peripheral clock enable */
+ __HAL_RCC_USB_OTG_FS_CLK_ENABLE();
+
+ /* Peripheral interrupt init */
+ HAL_NVIC_SetPriority(OTG_FS_IRQn, 0, 0);
+ HAL_NVIC_EnableIRQ(OTG_FS_IRQn);
+ /* USER CODE BEGIN USB_OTG_FS_MspInit 1 */
+
+ /* USER CODE END USB_OTG_FS_MspInit 1 */
+ }
+}
+
+void HAL_PCD_MspDeInit(PCD_HandleTypeDef* pcdHandle)
+{
+ if(pcdHandle->Instance==USB_OTG_FS)
+ {
+ /* USER CODE BEGIN USB_OTG_FS_MspDeInit 0 */
+
+ /* USER CODE END USB_OTG_FS_MspDeInit 0 */
+ /* Peripheral clock disable */
+ __HAL_RCC_USB_OTG_FS_CLK_DISABLE();
+
+ /**USB_OTG_FS GPIO Configuration
+ PA11 ------> USB_OTG_FS_DM
+ PA12 ------> USB_OTG_FS_DP
+ */
+ HAL_GPIO_DeInit(GPIOA, GPIO_PIN_11|GPIO_PIN_12);
+
+ /* Peripheral interrupt Deinit*/
+ HAL_NVIC_DisableIRQ(OTG_FS_IRQn);
+
+ /* USER CODE BEGIN USB_OTG_FS_MspDeInit 1 */
+
+ /* USER CODE END USB_OTG_FS_MspDeInit 1 */
+ }
+}
+
+/**
+ * @brief Setup stage callback
+ * @param hpcd: PCD handle
+ * @retval None
+ */
+#if (USE_HAL_PCD_REGISTER_CALLBACKS == 1U)
+static void PCD_SetupStageCallback(PCD_HandleTypeDef *hpcd)
+#else
+void HAL_PCD_SetupStageCallback(PCD_HandleTypeDef *hpcd)
+#endif /* USE_HAL_PCD_REGISTER_CALLBACKS */
+{
+ USBD_LL_SetupStage((USBD_HandleTypeDef*)hpcd->pData, (uint8_t *)hpcd->Setup);
+}
+
+/**
+ * @brief Data Out stage callback.
+ * @param hpcd: PCD handle
+ * @param epnum: Endpoint number
+ * @retval None
+ */
+#if (USE_HAL_PCD_REGISTER_CALLBACKS == 1U)
+static void PCD_DataOutStageCallback(PCD_HandleTypeDef *hpcd, uint8_t epnum)
+#else
+void HAL_PCD_DataOutStageCallback(PCD_HandleTypeDef *hpcd, uint8_t epnum)
+#endif /* USE_HAL_PCD_REGISTER_CALLBACKS */
+{
+ USBD_LL_DataOutStage((USBD_HandleTypeDef*)hpcd->pData, epnum, hpcd->OUT_ep[epnum].xfer_buff);
+}
+
+/**
+ * @brief Data In stage callback.
+ * @param hpcd: PCD handle
+ * @param epnum: Endpoint number
+ * @retval None
+ */
+#if (USE_HAL_PCD_REGISTER_CALLBACKS == 1U)
+static void PCD_DataInStageCallback(PCD_HandleTypeDef *hpcd, uint8_t epnum)
+#else
+void HAL_PCD_DataInStageCallback(PCD_HandleTypeDef *hpcd, uint8_t epnum)
+#endif /* USE_HAL_PCD_REGISTER_CALLBACKS */
+{
+ USBD_LL_DataInStage((USBD_HandleTypeDef*)hpcd->pData, epnum, hpcd->IN_ep[epnum].xfer_buff);
+}
+
+/**
+ * @brief SOF callback.
+ * @param hpcd: PCD handle
+ * @retval None
+ */
+#if (USE_HAL_PCD_REGISTER_CALLBACKS == 1U)
+static void PCD_SOFCallback(PCD_HandleTypeDef *hpcd)
+#else
+void HAL_PCD_SOFCallback(PCD_HandleTypeDef *hpcd)
+#endif /* USE_HAL_PCD_REGISTER_CALLBACKS */
+{
+ USBD_LL_SOF((USBD_HandleTypeDef*)hpcd->pData);
+}
+
+/**
+ * @brief Reset callback.
+ * @param hpcd: PCD handle
+ * @retval None
+ */
+#if (USE_HAL_PCD_REGISTER_CALLBACKS == 1U)
+static void PCD_ResetCallback(PCD_HandleTypeDef *hpcd)
+#else
+void HAL_PCD_ResetCallback(PCD_HandleTypeDef *hpcd)
+#endif /* USE_HAL_PCD_REGISTER_CALLBACKS */
+{
+ USBD_SpeedTypeDef speed = USBD_SPEED_FULL;
+
+ if ( hpcd->Init.speed == PCD_SPEED_HIGH)
+ {
+ speed = USBD_SPEED_HIGH;
+ }
+ else if ( hpcd->Init.speed == PCD_SPEED_FULL)
+ {
+ speed = USBD_SPEED_FULL;
+ }
+ else
+ {
+ Error_Handler();
+ }
+ /* Set Speed. */
+ USBD_LL_SetSpeed((USBD_HandleTypeDef*)hpcd->pData, speed);
+
+ /* Reset Device. */
+ USBD_LL_Reset((USBD_HandleTypeDef*)hpcd->pData);
+}
+
+/**
+ * @brief Suspend callback.
+ * When Low power mode is enabled the debug cannot be used (IAR, Keil doesn't support it)
+ * @param hpcd: PCD handle
+ * @retval None
+ */
+#if (USE_HAL_PCD_REGISTER_CALLBACKS == 1U)
+static void PCD_SuspendCallback(PCD_HandleTypeDef *hpcd)
+#else
+void HAL_PCD_SuspendCallback(PCD_HandleTypeDef *hpcd)
+#endif /* USE_HAL_PCD_REGISTER_CALLBACKS */
+{
+ /* Inform USB library that core enters in suspend Mode. */
+ USBD_LL_Suspend((USBD_HandleTypeDef*)hpcd->pData);
+ __HAL_PCD_GATE_PHYCLOCK(hpcd);
+ /* Enter in STOP mode. */
+ /* USER CODE BEGIN 2 */
+ if (hpcd->Init.low_power_enable)
+ {
+ /* Set SLEEPDEEP bit and SleepOnExit of Cortex System Control Register. */
+ SCB->SCR |= (uint32_t)((uint32_t)(SCB_SCR_SLEEPDEEP_Msk | SCB_SCR_SLEEPONEXIT_Msk));
+ }
+ /* USER CODE END 2 */
+}
+
+/**
+ * @brief Resume callback.
+ * When Low power mode is enabled the debug cannot be used (IAR, Keil doesn't support it)
+ * @param hpcd: PCD handle
+ * @retval None
+ */
+#if (USE_HAL_PCD_REGISTER_CALLBACKS == 1U)
+static void PCD_ResumeCallback(PCD_HandleTypeDef *hpcd)
+#else
+void HAL_PCD_ResumeCallback(PCD_HandleTypeDef *hpcd)
+#endif /* USE_HAL_PCD_REGISTER_CALLBACKS */
+{
+ /* USER CODE BEGIN 3 */
+
+ /* USER CODE END 3 */
+ USBD_LL_Resume((USBD_HandleTypeDef*)hpcd->pData);
+}
+
+/**
+ * @brief ISOOUTIncomplete callback.
+ * @param hpcd: PCD handle
+ * @param epnum: Endpoint number
+ * @retval None
+ */
+#if (USE_HAL_PCD_REGISTER_CALLBACKS == 1U)
+static void PCD_ISOOUTIncompleteCallback(PCD_HandleTypeDef *hpcd, uint8_t epnum)
+#else
+void HAL_PCD_ISOOUTIncompleteCallback(PCD_HandleTypeDef *hpcd, uint8_t epnum)
+#endif /* USE_HAL_PCD_REGISTER_CALLBACKS */
+{
+ USBD_LL_IsoOUTIncomplete((USBD_HandleTypeDef*)hpcd->pData, epnum);
+}
+
+/**
+ * @brief ISOINIncomplete callback.
+ * @param hpcd: PCD handle
+ * @param epnum: Endpoint number
+ * @retval None
+ */
+#if (USE_HAL_PCD_REGISTER_CALLBACKS == 1U)
+static void PCD_ISOINIncompleteCallback(PCD_HandleTypeDef *hpcd, uint8_t epnum)
+#else
+void HAL_PCD_ISOINIncompleteCallback(PCD_HandleTypeDef *hpcd, uint8_t epnum)
+#endif /* USE_HAL_PCD_REGISTER_CALLBACKS */
+{
+ USBD_LL_IsoINIncomplete((USBD_HandleTypeDef*)hpcd->pData, epnum);
+}
+
+/**
+ * @brief Connect callback.
+ * @param hpcd: PCD handle
+ * @retval None
+ */
+#if (USE_HAL_PCD_REGISTER_CALLBACKS == 1U)
+static void PCD_ConnectCallback(PCD_HandleTypeDef *hpcd)
+#else
+void HAL_PCD_ConnectCallback(PCD_HandleTypeDef *hpcd)
+#endif /* USE_HAL_PCD_REGISTER_CALLBACKS */
+{
+ USBD_LL_DevConnected((USBD_HandleTypeDef*)hpcd->pData);
+}
+
+/**
+ * @brief Disconnect callback.
+ * @param hpcd: PCD handle
+ * @retval None
+ */
+#if (USE_HAL_PCD_REGISTER_CALLBACKS == 1U)
+static void PCD_DisconnectCallback(PCD_HandleTypeDef *hpcd)
+#else
+void HAL_PCD_DisconnectCallback(PCD_HandleTypeDef *hpcd)
+#endif /* USE_HAL_PCD_REGISTER_CALLBACKS */
+{
+ USBD_LL_DevDisconnected((USBD_HandleTypeDef*)hpcd->pData);
+}
+
+/*******************************************************************************
+ LL Driver Interface (USB Device Library --> PCD)
+*******************************************************************************/
+
+/**
+ * @brief Initializes the low level portion of the device driver.
+ * @param pdev: Device handle
+ * @retval USBD status
+ */
+USBD_StatusTypeDef USBD_LL_Init(USBD_HandleTypeDef *pdev)
+{
+ /* Init USB Ip. */
+ if (pdev->id == DEVICE_FS) {
+ /* Link the driver to the stack. */
+ hpcd_USB_OTG_FS.pData = pdev;
+ pdev->pData = &hpcd_USB_OTG_FS;
+
+ hpcd_USB_OTG_FS.Instance = USB_OTG_FS;
+ hpcd_USB_OTG_FS.Init.dev_endpoints = 9;
+ hpcd_USB_OTG_FS.Init.speed = PCD_SPEED_FULL;
+ hpcd_USB_OTG_FS.Init.dma_enable = DISABLE;
+ hpcd_USB_OTG_FS.Init.phy_itface = PCD_PHY_EMBEDDED;
+ hpcd_USB_OTG_FS.Init.Sof_enable = DISABLE;
+ hpcd_USB_OTG_FS.Init.low_power_enable = DISABLE;
+ hpcd_USB_OTG_FS.Init.lpm_enable = DISABLE;
+ hpcd_USB_OTG_FS.Init.battery_charging_enable = DISABLE;
+ hpcd_USB_OTG_FS.Init.vbus_sensing_enable = DISABLE;
+ hpcd_USB_OTG_FS.Init.use_dedicated_ep1 = DISABLE;
+ if (HAL_PCD_Init(&hpcd_USB_OTG_FS) != HAL_OK)
+ {
+ Error_Handler( );
+ }
+
+#if (USE_HAL_PCD_REGISTER_CALLBACKS == 1U)
+ /* Register USB PCD CallBacks */
+ HAL_PCD_RegisterCallback(&hpcd_USB_OTG_FS, HAL_PCD_SOF_CB_ID, PCD_SOFCallback);
+ HAL_PCD_RegisterCallback(&hpcd_USB_OTG_FS, HAL_PCD_SETUPSTAGE_CB_ID, PCD_SetupStageCallback);
+ HAL_PCD_RegisterCallback(&hpcd_USB_OTG_FS, HAL_PCD_RESET_CB_ID, PCD_ResetCallback);
+ HAL_PCD_RegisterCallback(&hpcd_USB_OTG_FS, HAL_PCD_SUSPEND_CB_ID, PCD_SuspendCallback);
+ HAL_PCD_RegisterCallback(&hpcd_USB_OTG_FS, HAL_PCD_RESUME_CB_ID, PCD_ResumeCallback);
+ HAL_PCD_RegisterCallback(&hpcd_USB_OTG_FS, HAL_PCD_CONNECT_CB_ID, PCD_ConnectCallback);
+ HAL_PCD_RegisterCallback(&hpcd_USB_OTG_FS, HAL_PCD_DISCONNECT_CB_ID, PCD_DisconnectCallback);
+
+ HAL_PCD_RegisterDataOutStageCallback(&hpcd_USB_OTG_FS, PCD_DataOutStageCallback);
+ HAL_PCD_RegisterDataInStageCallback(&hpcd_USB_OTG_FS, PCD_DataInStageCallback);
+ HAL_PCD_RegisterIsoOutIncpltCallback(&hpcd_USB_OTG_FS, PCD_ISOOUTIncompleteCallback);
+ HAL_PCD_RegisterIsoInIncpltCallback(&hpcd_USB_OTG_FS, PCD_ISOINIncompleteCallback);
+#endif /* USE_HAL_PCD_REGISTER_CALLBACKS */
+ /* USER CODE BEGIN TxRx_Configuration */
+ HAL_PCDEx_SetRxFiFo(&hpcd_USB_OTG_FS, 0x80);
+ HAL_PCDEx_SetTxFiFo(&hpcd_USB_OTG_FS, 0, 0x40);
+ HAL_PCDEx_SetTxFiFo(&hpcd_USB_OTG_FS, 1, 0x80);
+ /* USER CODE END TxRx_Configuration */
+ }
+ return USBD_OK;
+}
+
+/**
+ * @brief De-Initializes the low level portion of the device driver.
+ * @param pdev: Device handle
+ * @retval USBD status
+ */
+USBD_StatusTypeDef USBD_LL_DeInit(USBD_HandleTypeDef *pdev)
+{
+ HAL_StatusTypeDef hal_status = HAL_OK;
+ USBD_StatusTypeDef usb_status = USBD_OK;
+
+ hal_status = HAL_PCD_DeInit(pdev->pData);
+
+ usb_status = USBD_Get_USB_Status(hal_status);
+
+ return usb_status;
+}
+
+/**
+ * @brief Starts the low level portion of the device driver.
+ * @param pdev: Device handle
+ * @retval USBD status
+ */
+USBD_StatusTypeDef USBD_LL_Start(USBD_HandleTypeDef *pdev)
+{
+ HAL_StatusTypeDef hal_status = HAL_OK;
+ USBD_StatusTypeDef usb_status = USBD_OK;
+
+ hal_status = HAL_PCD_Start(pdev->pData);
+
+ usb_status = USBD_Get_USB_Status(hal_status);
+
+ return usb_status;
+}
+
+/**
+ * @brief Stops the low level portion of the device driver.
+ * @param pdev: Device handle
+ * @retval USBD status
+ */
+USBD_StatusTypeDef USBD_LL_Stop(USBD_HandleTypeDef *pdev)
+{
+ HAL_StatusTypeDef hal_status = HAL_OK;
+ USBD_StatusTypeDef usb_status = USBD_OK;
+
+ hal_status = HAL_PCD_Stop(pdev->pData);
+
+ usb_status = USBD_Get_USB_Status(hal_status);
+
+ return usb_status;
+}
+
+/**
+ * @brief Opens an endpoint of the low level driver.
+ * @param pdev: Device handle
+ * @param ep_addr: Endpoint number
+ * @param ep_type: Endpoint type
+ * @param ep_mps: Endpoint max packet size
+ * @retval USBD status
+ */
+USBD_StatusTypeDef USBD_LL_OpenEP(USBD_HandleTypeDef *pdev, uint8_t ep_addr, uint8_t ep_type, uint16_t ep_mps)
+{
+ HAL_StatusTypeDef hal_status = HAL_OK;
+ USBD_StatusTypeDef usb_status = USBD_OK;
+
+ hal_status = HAL_PCD_EP_Open(pdev->pData, ep_addr, ep_mps, ep_type);
+
+ usb_status = USBD_Get_USB_Status(hal_status);
+
+ return usb_status;
+}
+
+/**
+ * @brief Closes an endpoint of the low level driver.
+ * @param pdev: Device handle
+ * @param ep_addr: Endpoint number
+ * @retval USBD status
+ */
+USBD_StatusTypeDef USBD_LL_CloseEP(USBD_HandleTypeDef *pdev, uint8_t ep_addr)
+{
+ HAL_StatusTypeDef hal_status = HAL_OK;
+ USBD_StatusTypeDef usb_status = USBD_OK;
+
+ hal_status = HAL_PCD_EP_Close(pdev->pData, ep_addr);
+
+ usb_status = USBD_Get_USB_Status(hal_status);
+
+ return usb_status;
+}
+
+/**
+ * @brief Flushes an endpoint of the Low Level Driver.
+ * @param pdev: Device handle
+ * @param ep_addr: Endpoint number
+ * @retval USBD status
+ */
+USBD_StatusTypeDef USBD_LL_FlushEP(USBD_HandleTypeDef *pdev, uint8_t ep_addr)
+{
+ HAL_StatusTypeDef hal_status = HAL_OK;
+ USBD_StatusTypeDef usb_status = USBD_OK;
+
+ hal_status = HAL_PCD_EP_Flush(pdev->pData, ep_addr);
+
+ usb_status = USBD_Get_USB_Status(hal_status);
+
+ return usb_status;
+}
+
+/**
+ * @brief Sets a Stall condition on an endpoint of the Low Level Driver.
+ * @param pdev: Device handle
+ * @param ep_addr: Endpoint number
+ * @retval USBD status
+ */
+USBD_StatusTypeDef USBD_LL_StallEP(USBD_HandleTypeDef *pdev, uint8_t ep_addr)
+{
+ HAL_StatusTypeDef hal_status = HAL_OK;
+ USBD_StatusTypeDef usb_status = USBD_OK;
+
+ hal_status = HAL_PCD_EP_SetStall(pdev->pData, ep_addr);
+
+ usb_status = USBD_Get_USB_Status(hal_status);
+
+ return usb_status;
+}
+
+/**
+ * @brief Clears a Stall condition on an endpoint of the Low Level Driver.
+ * @param pdev: Device handle
+ * @param ep_addr: Endpoint number
+ * @retval USBD status
+ */
+USBD_StatusTypeDef USBD_LL_ClearStallEP(USBD_HandleTypeDef *pdev, uint8_t ep_addr)
+{
+ HAL_StatusTypeDef hal_status = HAL_OK;
+ USBD_StatusTypeDef usb_status = USBD_OK;
+
+ hal_status = HAL_PCD_EP_ClrStall(pdev->pData, ep_addr);
+
+ usb_status = USBD_Get_USB_Status(hal_status);
+
+ return usb_status;
+}
+
+/**
+ * @brief Returns Stall condition.
+ * @param pdev: Device handle
+ * @param ep_addr: Endpoint number
+ * @retval Stall (1: Yes, 0: No)
+ */
+uint8_t USBD_LL_IsStallEP(USBD_HandleTypeDef *pdev, uint8_t ep_addr)
+{
+ PCD_HandleTypeDef *hpcd = (PCD_HandleTypeDef*) pdev->pData;
+
+ if((ep_addr & 0x80) == 0x80)
+ {
+ return hpcd->IN_ep[ep_addr & 0x7F].is_stall;
+ }
+ else
+ {
+ return hpcd->OUT_ep[ep_addr & 0x7F].is_stall;
+ }
+}
+
+/**
+ * @brief Assigns a USB address to the device.
+ * @param pdev: Device handle
+ * @param dev_addr: Device address
+ * @retval USBD status
+ */
+USBD_StatusTypeDef USBD_LL_SetUSBAddress(USBD_HandleTypeDef *pdev, uint8_t dev_addr)
+{
+ HAL_StatusTypeDef hal_status = HAL_OK;
+ USBD_StatusTypeDef usb_status = USBD_OK;
+
+ hal_status = HAL_PCD_SetAddress(pdev->pData, dev_addr);
+
+ usb_status = USBD_Get_USB_Status(hal_status);
+
+ return usb_status;
+}
+
+/**
+ * @brief Transmits data over an endpoint.
+ * @param pdev: Device handle
+ * @param ep_addr: Endpoint number
+ * @param pbuf: Pointer to data to be sent
+ * @param size: Data size
+ * @retval USBD status
+ */
+USBD_StatusTypeDef USBD_LL_Transmit(USBD_HandleTypeDef *pdev, uint8_t ep_addr, uint8_t *pbuf, uint32_t size)
+{
+ HAL_StatusTypeDef hal_status = HAL_OK;
+ USBD_StatusTypeDef usb_status = USBD_OK;
+
+ hal_status = HAL_PCD_EP_Transmit(pdev->pData, ep_addr, pbuf, size);
+
+ usb_status = USBD_Get_USB_Status(hal_status);
+
+ return usb_status;
+}
+
+/**
+ * @brief Prepares an endpoint for reception.
+ * @param pdev: Device handle
+ * @param ep_addr: Endpoint number
+ * @param pbuf: Pointer to data to be received
+ * @param size: Data size
+ * @retval USBD status
+ */
+USBD_StatusTypeDef USBD_LL_PrepareReceive(USBD_HandleTypeDef *pdev, uint8_t ep_addr, uint8_t *pbuf, uint32_t size)
+{
+ HAL_StatusTypeDef hal_status = HAL_OK;
+ USBD_StatusTypeDef usb_status = USBD_OK;
+
+ hal_status = HAL_PCD_EP_Receive(pdev->pData, ep_addr, pbuf, size);
+
+ usb_status = USBD_Get_USB_Status(hal_status);
+
+ return usb_status;
+}
+
+/**
+ * @brief Returns the last transferred packet size.
+ * @param pdev: Device handle
+ * @param ep_addr: Endpoint number
+ * @retval Received Data Size
+ */
+uint32_t USBD_LL_GetRxDataSize(USBD_HandleTypeDef *pdev, uint8_t ep_addr)
+{
+ return HAL_PCD_EP_GetRxCount((PCD_HandleTypeDef*) pdev->pData, ep_addr);
+}
+
+#ifdef USBD_HS_TESTMODE_ENABLE
+/**
+ * @brief Set High speed Test mode.
+ * @param pdev: Device handle
+ * @param testmode: test mode
+ * @retval USBD Status
+ */
+USBD_StatusTypeDef USBD_LL_SetTestMode(USBD_HandleTypeDef *pdev, uint8_t testmode)
+{
+ UNUSED(pdev);
+ UNUSED(testmode);
+
+ return USBD_OK;
+}
+#endif /* USBD_HS_TESTMODE_ENABLE */
+/**
+ * @brief Static single allocation.
+ * @param size: Size of allocated memory
+ * @retval None
+ */
+void *USBD_static_malloc(uint32_t size)
+{
+ UNUSED(size);
+ static uint32_t mem[(sizeof(USBD_CDC_HandleTypeDef)/4)+1];/* On 32-bit boundary */
+ return mem;
+}
+
+/**
+ * @brief Dummy memory free
+ * @param p: Pointer to allocated memory address
+ * @retval None
+ */
+void USBD_static_free(void *p)
+{
+ UNUSED(p);
+}
+
+/**
+ * @brief Delays routine for the USB device library.
+ * @param Delay: Delay in ms
+ * @retval None
+ */
+void USBD_LL_Delay(uint32_t Delay)
+{
+ HAL_Delay(Delay);
+}
+
+/**
+ * @brief Returns the USB status depending on the HAL status:
+ * @param hal_status: HAL status
+ * @retval USB status
+ */
+USBD_StatusTypeDef USBD_Get_USB_Status(HAL_StatusTypeDef hal_status)
+{
+ USBD_StatusTypeDef usb_status = USBD_OK;
+
+ switch (hal_status)
+ {
+ case HAL_OK :
+ usb_status = USBD_OK;
+ break;
+ case HAL_ERROR :
+ usb_status = USBD_FAIL;
+ break;
+ case HAL_BUSY :
+ usb_status = USBD_BUSY;
+ break;
+ case HAL_TIMEOUT :
+ usb_status = USBD_FAIL;
+ break;
+ default :
+ usb_status = USBD_FAIL;
+ break;
+ }
+ return usb_status;
+}
diff --git a/Ganesha_II_V2/USB_DEVICE/Target/usbd_conf.h b/Ganesha_II_V2/USB_DEVICE/Target/usbd_conf.h
new file mode 100644
index 0000000..ae7a69b
--- /dev/null
+++ b/Ganesha_II_V2/USB_DEVICE/Target/usbd_conf.h
@@ -0,0 +1,173 @@
+/* USER CODE BEGIN Header */
+/**
+ ******************************************************************************
+ * @file : usbd_conf.h
+ * @version : v1.0_Cube
+ * @brief : Header for usbd_conf.c file.
+ ******************************************************************************
+ * @attention
+ *
+ * Copyright (c) 2026 STMicroelectronics.
+ * All rights reserved.
+ *
+ * This software is licensed under terms that can be found in the LICENSE file
+ * in the root directory of this software component.
+ * If no LICENSE file comes with this software, it is provided AS-IS.
+ *
+ ******************************************************************************
+ */
+/* USER CODE END Header */
+
+/* Define to prevent recursive inclusion -------------------------------------*/
+#ifndef __USBD_CONF__H__
+#define __USBD_CONF__H__
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+/* Includes ------------------------------------------------------------------*/
+#include
+#include
+#include
+#include "main.h"
+#include "stm32h7xx.h"
+#include "stm32h7xx_hal.h"
+
+/* USER CODE BEGIN INCLUDE */
+
+/* USER CODE END INCLUDE */
+
+/** @addtogroup USBD_OTG_DRIVER
+ * @brief Driver for Usb device.
+ * @{
+ */
+
+/** @defgroup USBD_CONF USBD_CONF
+ * @brief Configuration file for Usb otg low level driver.
+ * @{
+ */
+
+/** @defgroup USBD_CONF_Exported_Variables USBD_CONF_Exported_Variables
+ * @brief Public variables.
+ * @{
+ */
+
+/**
+ * @}
+ */
+
+/** @defgroup USBD_CONF_Exported_Defines USBD_CONF_Exported_Defines
+ * @brief Defines for configuration of the Usb device.
+ * @{
+ */
+
+/*---------- -----------*/
+#define USBD_MAX_NUM_INTERFACES 1U
+/*---------- -----------*/
+#define USBD_MAX_NUM_CONFIGURATION 1U
+/*---------- -----------*/
+#define USBD_MAX_STR_DESC_SIZ 512U
+/*---------- -----------*/
+#define USBD_DEBUG_LEVEL 0U
+/*---------- -----------*/
+#define USBD_LPM_ENABLED 1U
+/*---------- -----------*/
+#define USBD_SELF_POWERED 1U
+
+/****************************************/
+/* #define for FS and HS identification */
+#define DEVICE_FS 0
+#define DEVICE_HS 1
+
+/**
+ * @}
+ */
+
+/** @defgroup USBD_CONF_Exported_Macros USBD_CONF_Exported_Macros
+ * @brief Aliases.
+ * @{
+ */
+/* Memory management macros make sure to use static memory allocation */
+/** Alias for memory allocation. */
+
+#define USBD_malloc (void *)USBD_static_malloc
+
+/** Alias for memory release. */
+#define USBD_free USBD_static_free
+
+/** Alias for memory set. */
+#define USBD_memset memset
+
+/** Alias for memory copy. */
+#define USBD_memcpy memcpy
+
+/** Alias for delay. */
+#define USBD_Delay HAL_Delay
+
+/* DEBUG macros */
+
+#if (USBD_DEBUG_LEVEL > 0)
+#define USBD_UsrLog(...) printf(__VA_ARGS__);\
+ printf("\n");
+#else
+#define USBD_UsrLog(...)
+#endif /* (USBD_DEBUG_LEVEL > 0U) */
+
+#if (USBD_DEBUG_LEVEL > 1)
+
+#define USBD_ErrLog(...) printf("ERROR: ");\
+ printf(__VA_ARGS__);\
+ printf("\n");
+#else
+#define USBD_ErrLog(...)
+#endif /* (USBD_DEBUG_LEVEL > 1U) */
+
+#if (USBD_DEBUG_LEVEL > 2)
+#define USBD_DbgLog(...) printf("DEBUG : ");\
+ printf(__VA_ARGS__);\
+ printf("\n");
+#else
+#define USBD_DbgLog(...)
+#endif /* (USBD_DEBUG_LEVEL > 2U) */
+
+/**
+ * @}
+ */
+
+/** @defgroup USBD_CONF_Exported_Types USBD_CONF_Exported_Types
+ * @brief Types.
+ * @{
+ */
+
+/**
+ * @}
+ */
+
+/** @defgroup USBD_CONF_Exported_FunctionsPrototype USBD_CONF_Exported_FunctionsPrototype
+ * @brief Declaration of public functions for Usb device.
+ * @{
+ */
+
+/* Exported functions -------------------------------------------------------*/
+void *USBD_static_malloc(uint32_t size);
+void USBD_static_free(void *p);
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __USBD_CONF__H__ */
+
diff --git a/Ganesha_II_V2/startup_stm32h743xx.s b/Ganesha_II_V2/startup_stm32h743xx.s
new file mode 100644
index 0000000..2663d53
--- /dev/null
+++ b/Ganesha_II_V2/startup_stm32h743xx.s
@@ -0,0 +1,752 @@
+/**
+ ******************************************************************************
+ * @file startup_stm32h743xx.s
+ * @author MCD Application Team
+ * @brief STM32H743xx Devices vector table for GCC based toolchain.
+ * This module performs:
+ * - Set the initial SP
+ * - Set the initial PC == Reset_Handler,
+ * - Set the vector table entries with the exceptions ISR address
+ * - Branches to main in the C library (which eventually
+ * calls main()).
+ * After Reset the Cortex-M processor is in Thread mode,
+ * priority is Privileged, and the Stack is set to Main.
+ ******************************************************************************
+ * @attention
+ *
+ * Copyright (c) 2017 STMicroelectronics.
+ * All rights reserved.
+ *
+ * This software is licensed under terms that can be found in the LICENSE file
+ * in the root directory of this software component.
+ * If no LICENSE file comes with this software, it is provided AS-IS.
+ *
+ ******************************************************************************
+ */
+
+ .syntax unified
+ .cpu cortex-m7
+ .fpu softvfp
+ .thumb
+
+.global g_pfnVectors
+.global Default_Handler
+
+/* start address for the initialization values of the .data section.
+defined in linker script */
+.word _sidata
+/* start address for the .data section. defined in linker script */
+.word _sdata
+/* end address for the .data section. defined in linker script */
+.word _edata
+/* start address for the .bss section. defined in linker script */
+.word _sbss
+/* end address for the .bss section. defined in linker script */
+.word _ebss
+/* stack used for SystemInit_ExtMemCtl; always internal RAM used */
+
+/**
+ * @brief This is the code that gets called when the processor first
+ * starts execution following a reset event. Only the absolutely
+ * necessary set is performed, after which the application
+ * supplied main() routine is called.
+ * @param None
+ * @retval : None
+*/
+
+ .section .text.Reset_Handler
+ .weak Reset_Handler
+ .type Reset_Handler, %function
+Reset_Handler:
+ ldr sp, =_estack /* set stack pointer */
+
+/* Call the ExitRun0Mode function to configure the power supply */
+ bl ExitRun0Mode
+/* Call the clock system initialization function.*/
+ bl SystemInit
+
+/* Copy the data segment initializers from flash to SRAM */
+ ldr r0, =_sdata
+ ldr r1, =_edata
+ ldr r2, =_sidata
+ movs r3, #0
+ b LoopCopyDataInit
+
+CopyDataInit:
+ ldr r4, [r2, r3]
+ str r4, [r0, r3]
+ adds r3, r3, #4
+
+LoopCopyDataInit:
+ adds r4, r0, r3
+ cmp r4, r1
+ bcc CopyDataInit
+/* Zero fill the bss segment. */
+ ldr r2, =_sbss
+ ldr r4, =_ebss
+ movs r3, #0
+ b LoopFillZerobss
+
+FillZerobss:
+ str r3, [r2]
+ adds r2, r2, #4
+
+LoopFillZerobss:
+ cmp r2, r4
+ bcc FillZerobss
+
+/* Call static constructors */
+ bl __libc_init_array
+/* Call the application's entry point.*/
+ bl main
+ bx lr
+.size Reset_Handler, .-Reset_Handler
+
+/**
+ * @brief This is the code that gets called when the processor receives an
+ * unexpected interrupt. This simply enters an infinite loop, preserving
+ * the system state for examination by a debugger.
+ * @param None
+ * @retval None
+*/
+ .section .text.Default_Handler,"ax",%progbits
+Default_Handler:
+Infinite_Loop:
+ b Infinite_Loop
+ .size Default_Handler, .-Default_Handler
+/******************************************************************************
+*
+* The minimal vector table for a Cortex M. Note that the proper constructs
+* must be placed on this to ensure that it ends up at physical address
+* 0x0000.0000.
+*
+*******************************************************************************/
+ .section .isr_vector,"a",%progbits
+ .type g_pfnVectors, %object
+
+
+g_pfnVectors:
+ .word _estack
+ .word Reset_Handler
+
+ .word NMI_Handler
+ .word HardFault_Handler
+ .word MemManage_Handler
+ .word BusFault_Handler
+ .word UsageFault_Handler
+ .word 0
+ .word 0
+ .word 0
+ .word 0
+ .word SVC_Handler
+ .word DebugMon_Handler
+ .word 0
+ .word PendSV_Handler
+ .word SysTick_Handler
+
+ /* External Interrupts */
+ .word WWDG_IRQHandler /* Window WatchDog */
+ .word PVD_AVD_IRQHandler /* PVD/AVD through EXTI Line detection */
+ .word TAMP_STAMP_IRQHandler /* Tamper and TimeStamps through the EXTI line */
+ .word RTC_WKUP_IRQHandler /* RTC Wakeup through the EXTI line */
+ .word FLASH_IRQHandler /* FLASH */
+ .word RCC_IRQHandler /* RCC */
+ .word EXTI0_IRQHandler /* EXTI Line0 */
+ .word EXTI1_IRQHandler /* EXTI Line1 */
+ .word EXTI2_IRQHandler /* EXTI Line2 */
+ .word EXTI3_IRQHandler /* EXTI Line3 */
+ .word EXTI4_IRQHandler /* EXTI Line4 */
+ .word DMA1_Stream0_IRQHandler /* DMA1 Stream 0 */
+ .word DMA1_Stream1_IRQHandler /* DMA1 Stream 1 */
+ .word DMA1_Stream2_IRQHandler /* DMA1 Stream 2 */
+ .word DMA1_Stream3_IRQHandler /* DMA1 Stream 3 */
+ .word DMA1_Stream4_IRQHandler /* DMA1 Stream 4 */
+ .word DMA1_Stream5_IRQHandler /* DMA1 Stream 5 */
+ .word DMA1_Stream6_IRQHandler /* DMA1 Stream 6 */
+ .word ADC_IRQHandler /* ADC1, ADC2 and ADC3s */
+ .word FDCAN1_IT0_IRQHandler /* FDCAN1 interrupt line 0 */
+ .word FDCAN2_IT0_IRQHandler /* FDCAN2 interrupt line 0 */
+ .word FDCAN1_IT1_IRQHandler /* FDCAN1 interrupt line 1 */
+ .word FDCAN2_IT1_IRQHandler /* FDCAN2 interrupt line 1 */
+ .word EXTI9_5_IRQHandler /* External Line[9:5]s */
+ .word TIM1_BRK_IRQHandler /* TIM1 Break interrupt */
+ .word TIM1_UP_IRQHandler /* TIM1 Update interrupt */
+ .word TIM1_TRG_COM_IRQHandler /* TIM1 Trigger and Commutation interrupt */
+ .word TIM1_CC_IRQHandler /* TIM1 Capture Compare */
+ .word TIM2_IRQHandler /* TIM2 */
+ .word TIM3_IRQHandler /* TIM3 */
+ .word TIM4_IRQHandler /* TIM4 */
+ .word I2C1_EV_IRQHandler /* I2C1 Event */
+ .word I2C1_ER_IRQHandler /* I2C1 Error */
+ .word I2C2_EV_IRQHandler /* I2C2 Event */
+ .word I2C2_ER_IRQHandler /* I2C2 Error */
+ .word SPI1_IRQHandler /* SPI1 */
+ .word SPI2_IRQHandler /* SPI2 */
+ .word USART1_IRQHandler /* USART1 */
+ .word USART2_IRQHandler /* USART2 */
+ .word USART3_IRQHandler /* USART3 */
+ .word EXTI15_10_IRQHandler /* External Line[15:10]s */
+ .word RTC_Alarm_IRQHandler /* RTC Alarm (A and B) through EXTI Line */
+ .word 0 /* Reserved */
+ .word TIM8_BRK_TIM12_IRQHandler /* TIM8 Break and TIM12 */
+ .word TIM8_UP_TIM13_IRQHandler /* TIM8 Update and TIM13 */
+ .word TIM8_TRG_COM_TIM14_IRQHandler /* TIM8 Trigger and Commutation and TIM14 */
+ .word TIM8_CC_IRQHandler /* TIM8 Capture Compare */
+ .word DMA1_Stream7_IRQHandler /* DMA1 Stream7 */
+ .word FMC_IRQHandler /* FMC */
+ .word SDMMC1_IRQHandler /* SDMMC1 */
+ .word TIM5_IRQHandler /* TIM5 */
+ .word SPI3_IRQHandler /* SPI3 */
+ .word UART4_IRQHandler /* UART4 */
+ .word UART5_IRQHandler /* UART5 */
+ .word TIM6_DAC_IRQHandler /* TIM6 and DAC1&2 underrun errors */
+ .word TIM7_IRQHandler /* TIM7 */
+ .word DMA2_Stream0_IRQHandler /* DMA2 Stream 0 */
+ .word DMA2_Stream1_IRQHandler /* DMA2 Stream 1 */
+ .word DMA2_Stream2_IRQHandler /* DMA2 Stream 2 */
+ .word DMA2_Stream3_IRQHandler /* DMA2 Stream 3 */
+ .word DMA2_Stream4_IRQHandler /* DMA2 Stream 4 */
+ .word ETH_IRQHandler /* Ethernet */
+ .word ETH_WKUP_IRQHandler /* Ethernet Wakeup through EXTI line */
+ .word FDCAN_CAL_IRQHandler /* FDCAN calibration unit interrupt*/
+ .word 0 /* Reserved */
+ .word 0 /* Reserved */
+ .word 0 /* Reserved */
+ .word 0 /* Reserved */
+ .word DMA2_Stream5_IRQHandler /* DMA2 Stream 5 */
+ .word DMA2_Stream6_IRQHandler /* DMA2 Stream 6 */
+ .word DMA2_Stream7_IRQHandler /* DMA2 Stream 7 */
+ .word USART6_IRQHandler /* USART6 */
+ .word I2C3_EV_IRQHandler /* I2C3 event */
+ .word I2C3_ER_IRQHandler /* I2C3 error */
+ .word OTG_HS_EP1_OUT_IRQHandler /* USB OTG HS End Point 1 Out */
+ .word OTG_HS_EP1_IN_IRQHandler /* USB OTG HS End Point 1 In */
+ .word OTG_HS_WKUP_IRQHandler /* USB OTG HS Wakeup through EXTI */
+ .word OTG_HS_IRQHandler /* USB OTG HS */
+ .word DCMI_IRQHandler /* DCMI */
+ .word 0 /* Reserved */
+ .word RNG_IRQHandler /* Rng */
+ .word FPU_IRQHandler /* FPU */
+ .word UART7_IRQHandler /* UART7 */
+ .word UART8_IRQHandler /* UART8 */
+ .word SPI4_IRQHandler /* SPI4 */
+ .word SPI5_IRQHandler /* SPI5 */
+ .word SPI6_IRQHandler /* SPI6 */
+ .word SAI1_IRQHandler /* SAI1 */
+ .word LTDC_IRQHandler /* LTDC */
+ .word LTDC_ER_IRQHandler /* LTDC error */
+ .word DMA2D_IRQHandler /* DMA2D */
+ .word SAI2_IRQHandler /* SAI2 */
+ .word QUADSPI_IRQHandler /* QUADSPI */
+ .word LPTIM1_IRQHandler /* LPTIM1 */
+ .word CEC_IRQHandler /* HDMI_CEC */
+ .word I2C4_EV_IRQHandler /* I2C4 Event */
+ .word I2C4_ER_IRQHandler /* I2C4 Error */
+ .word SPDIF_RX_IRQHandler /* SPDIF_RX */
+ .word OTG_FS_EP1_OUT_IRQHandler /* USB OTG FS End Point 1 Out */
+ .word OTG_FS_EP1_IN_IRQHandler /* USB OTG FS End Point 1 In */
+ .word OTG_FS_WKUP_IRQHandler /* USB OTG FS Wakeup through EXTI */
+ .word OTG_FS_IRQHandler /* USB OTG FS */
+ .word DMAMUX1_OVR_IRQHandler /* DMAMUX1 Overrun interrupt */
+ .word HRTIM1_Master_IRQHandler /* HRTIM Master Timer global Interrupt */
+ .word HRTIM1_TIMA_IRQHandler /* HRTIM Timer A global Interrupt */
+ .word HRTIM1_TIMB_IRQHandler /* HRTIM Timer B global Interrupt */
+ .word HRTIM1_TIMC_IRQHandler /* HRTIM Timer C global Interrupt */
+ .word HRTIM1_TIMD_IRQHandler /* HRTIM Timer D global Interrupt */
+ .word HRTIM1_TIME_IRQHandler /* HRTIM Timer E global Interrupt */
+ .word HRTIM1_FLT_IRQHandler /* HRTIM Fault global Interrupt */
+ .word DFSDM1_FLT0_IRQHandler /* DFSDM Filter0 Interrupt */
+ .word DFSDM1_FLT1_IRQHandler /* DFSDM Filter1 Interrupt */
+ .word DFSDM1_FLT2_IRQHandler /* DFSDM Filter2 Interrupt */
+ .word DFSDM1_FLT3_IRQHandler /* DFSDM Filter3 Interrupt */
+ .word SAI3_IRQHandler /* SAI3 global Interrupt */
+ .word SWPMI1_IRQHandler /* Serial Wire Interface 1 global interrupt */
+ .word TIM15_IRQHandler /* TIM15 global Interrupt */
+ .word TIM16_IRQHandler /* TIM16 global Interrupt */
+ .word TIM17_IRQHandler /* TIM17 global Interrupt */
+ .word MDIOS_WKUP_IRQHandler /* MDIOS Wakeup Interrupt */
+ .word MDIOS_IRQHandler /* MDIOS global Interrupt */
+ .word JPEG_IRQHandler /* JPEG global Interrupt */
+ .word MDMA_IRQHandler /* MDMA global Interrupt */
+ .word 0 /* Reserved */
+ .word SDMMC2_IRQHandler /* SDMMC2 global Interrupt */
+ .word HSEM1_IRQHandler /* HSEM1 global Interrupt */
+ .word 0 /* Reserved */
+ .word ADC3_IRQHandler /* ADC3 global Interrupt */
+ .word DMAMUX2_OVR_IRQHandler /* DMAMUX Overrun interrupt */
+ .word BDMA_Channel0_IRQHandler /* BDMA Channel 0 global Interrupt */
+ .word BDMA_Channel1_IRQHandler /* BDMA Channel 1 global Interrupt */
+ .word BDMA_Channel2_IRQHandler /* BDMA Channel 2 global Interrupt */
+ .word BDMA_Channel3_IRQHandler /* BDMA Channel 3 global Interrupt */
+ .word BDMA_Channel4_IRQHandler /* BDMA Channel 4 global Interrupt */
+ .word BDMA_Channel5_IRQHandler /* BDMA Channel 5 global Interrupt */
+ .word BDMA_Channel6_IRQHandler /* BDMA Channel 6 global Interrupt */
+ .word BDMA_Channel7_IRQHandler /* BDMA Channel 7 global Interrupt */
+ .word COMP1_IRQHandler /* COMP1 global Interrupt */
+ .word LPTIM2_IRQHandler /* LP TIM2 global interrupt */
+ .word LPTIM3_IRQHandler /* LP TIM3 global interrupt */
+ .word LPTIM4_IRQHandler /* LP TIM4 global interrupt */
+ .word LPTIM5_IRQHandler /* LP TIM5 global interrupt */
+ .word LPUART1_IRQHandler /* LP UART1 interrupt */
+ .word 0 /* Reserved */
+ .word CRS_IRQHandler /* Clock Recovery Global Interrupt */
+ .word ECC_IRQHandler /* ECC diagnostic Global Interrupt */
+ .word SAI4_IRQHandler /* SAI4 global interrupt */
+ .word 0 /* Reserved */
+ .word 0 /* Reserved */
+ .word WAKEUP_PIN_IRQHandler /* Interrupt for all 6 wake-up pins */
+
+ .size g_pfnVectors, .-g_pfnVectors
+
+/*******************************************************************************
+*
+* Provide weak aliases for each Exception handler to the Default_Handler.
+* As they are weak aliases, any function with the same name will override
+* this definition.
+*
+*******************************************************************************/
+ .weak NMI_Handler
+ .thumb_set NMI_Handler,Default_Handler
+
+ .weak HardFault_Handler
+ .thumb_set HardFault_Handler,Default_Handler
+
+ .weak MemManage_Handler
+ .thumb_set MemManage_Handler,Default_Handler
+
+ .weak BusFault_Handler
+ .thumb_set BusFault_Handler,Default_Handler
+
+ .weak UsageFault_Handler
+ .thumb_set UsageFault_Handler,Default_Handler
+
+ .weak SVC_Handler
+ .thumb_set SVC_Handler,Default_Handler
+
+ .weak DebugMon_Handler
+ .thumb_set DebugMon_Handler,Default_Handler
+
+ .weak PendSV_Handler
+ .thumb_set PendSV_Handler,Default_Handler
+
+ .weak SysTick_Handler
+ .thumb_set SysTick_Handler,Default_Handler
+
+ .weak WWDG_IRQHandler
+ .thumb_set WWDG_IRQHandler,Default_Handler
+
+ .weak PVD_AVD_IRQHandler
+ .thumb_set PVD_AVD_IRQHandler,Default_Handler
+
+ .weak TAMP_STAMP_IRQHandler
+ .thumb_set TAMP_STAMP_IRQHandler,Default_Handler
+
+ .weak RTC_WKUP_IRQHandler
+ .thumb_set RTC_WKUP_IRQHandler,Default_Handler
+
+ .weak FLASH_IRQHandler
+ .thumb_set FLASH_IRQHandler,Default_Handler
+
+ .weak RCC_IRQHandler
+ .thumb_set RCC_IRQHandler,Default_Handler
+
+ .weak EXTI0_IRQHandler
+ .thumb_set EXTI0_IRQHandler,Default_Handler
+
+ .weak EXTI1_IRQHandler
+ .thumb_set EXTI1_IRQHandler,Default_Handler
+
+ .weak EXTI2_IRQHandler
+ .thumb_set EXTI2_IRQHandler,Default_Handler
+
+ .weak EXTI3_IRQHandler
+ .thumb_set EXTI3_IRQHandler,Default_Handler
+
+ .weak EXTI4_IRQHandler
+ .thumb_set EXTI4_IRQHandler,Default_Handler
+
+ .weak DMA1_Stream0_IRQHandler
+ .thumb_set DMA1_Stream0_IRQHandler,Default_Handler
+
+ .weak DMA1_Stream1_IRQHandler
+ .thumb_set DMA1_Stream1_IRQHandler,Default_Handler
+
+ .weak DMA1_Stream2_IRQHandler
+ .thumb_set DMA1_Stream2_IRQHandler,Default_Handler
+
+ .weak DMA1_Stream3_IRQHandler
+ .thumb_set DMA1_Stream3_IRQHandler,Default_Handler
+
+ .weak DMA1_Stream4_IRQHandler
+ .thumb_set DMA1_Stream4_IRQHandler,Default_Handler
+
+ .weak DMA1_Stream5_IRQHandler
+ .thumb_set DMA1_Stream5_IRQHandler,Default_Handler
+
+ .weak DMA1_Stream6_IRQHandler
+ .thumb_set DMA1_Stream6_IRQHandler,Default_Handler
+
+ .weak ADC_IRQHandler
+ .thumb_set ADC_IRQHandler,Default_Handler
+
+ .weak FDCAN1_IT0_IRQHandler
+ .thumb_set FDCAN1_IT0_IRQHandler,Default_Handler
+
+ .weak FDCAN2_IT0_IRQHandler
+ .thumb_set FDCAN2_IT0_IRQHandler,Default_Handler
+
+ .weak FDCAN1_IT1_IRQHandler
+ .thumb_set FDCAN1_IT1_IRQHandler,Default_Handler
+
+ .weak FDCAN2_IT1_IRQHandler
+ .thumb_set FDCAN2_IT1_IRQHandler,Default_Handler
+
+ .weak EXTI9_5_IRQHandler
+ .thumb_set EXTI9_5_IRQHandler,Default_Handler
+
+ .weak TIM1_BRK_IRQHandler
+ .thumb_set TIM1_BRK_IRQHandler,Default_Handler
+
+ .weak TIM1_UP_IRQHandler
+ .thumb_set TIM1_UP_IRQHandler,Default_Handler
+
+ .weak TIM1_TRG_COM_IRQHandler
+ .thumb_set TIM1_TRG_COM_IRQHandler,Default_Handler
+
+ .weak TIM1_CC_IRQHandler
+ .thumb_set TIM1_CC_IRQHandler,Default_Handler
+
+ .weak TIM2_IRQHandler
+ .thumb_set TIM2_IRQHandler,Default_Handler
+
+ .weak TIM3_IRQHandler
+ .thumb_set TIM3_IRQHandler,Default_Handler
+
+ .weak TIM4_IRQHandler
+ .thumb_set TIM4_IRQHandler,Default_Handler
+
+ .weak I2C1_EV_IRQHandler
+ .thumb_set I2C1_EV_IRQHandler,Default_Handler
+
+ .weak I2C1_ER_IRQHandler
+ .thumb_set I2C1_ER_IRQHandler,Default_Handler
+
+ .weak I2C2_EV_IRQHandler
+ .thumb_set I2C2_EV_IRQHandler,Default_Handler
+
+ .weak I2C2_ER_IRQHandler
+ .thumb_set I2C2_ER_IRQHandler,Default_Handler
+
+ .weak SPI1_IRQHandler
+ .thumb_set SPI1_IRQHandler,Default_Handler
+
+ .weak SPI2_IRQHandler
+ .thumb_set SPI2_IRQHandler,Default_Handler
+
+ .weak USART1_IRQHandler
+ .thumb_set USART1_IRQHandler,Default_Handler
+
+ .weak USART2_IRQHandler
+ .thumb_set USART2_IRQHandler,Default_Handler
+
+ .weak USART3_IRQHandler
+ .thumb_set USART3_IRQHandler,Default_Handler
+
+ .weak EXTI15_10_IRQHandler
+ .thumb_set EXTI15_10_IRQHandler,Default_Handler
+
+ .weak RTC_Alarm_IRQHandler
+ .thumb_set RTC_Alarm_IRQHandler,Default_Handler
+
+ .weak TIM8_BRK_TIM12_IRQHandler
+ .thumb_set TIM8_BRK_TIM12_IRQHandler,Default_Handler
+
+ .weak TIM8_UP_TIM13_IRQHandler
+ .thumb_set TIM8_UP_TIM13_IRQHandler,Default_Handler
+
+ .weak TIM8_TRG_COM_TIM14_IRQHandler
+ .thumb_set TIM8_TRG_COM_TIM14_IRQHandler,Default_Handler
+
+ .weak TIM8_CC_IRQHandler
+ .thumb_set TIM8_CC_IRQHandler,Default_Handler
+
+ .weak DMA1_Stream7_IRQHandler
+ .thumb_set DMA1_Stream7_IRQHandler,Default_Handler
+
+ .weak FMC_IRQHandler
+ .thumb_set FMC_IRQHandler,Default_Handler
+
+ .weak SDMMC1_IRQHandler
+ .thumb_set SDMMC1_IRQHandler,Default_Handler
+
+ .weak TIM5_IRQHandler
+ .thumb_set TIM5_IRQHandler,Default_Handler
+
+ .weak SPI3_IRQHandler
+ .thumb_set SPI3_IRQHandler,Default_Handler
+
+ .weak UART4_IRQHandler
+ .thumb_set UART4_IRQHandler,Default_Handler
+
+ .weak UART5_IRQHandler
+ .thumb_set UART5_IRQHandler,Default_Handler
+
+ .weak TIM6_DAC_IRQHandler
+ .thumb_set TIM6_DAC_IRQHandler,Default_Handler
+
+ .weak TIM7_IRQHandler
+ .thumb_set TIM7_IRQHandler,Default_Handler
+
+ .weak DMA2_Stream0_IRQHandler
+ .thumb_set DMA2_Stream0_IRQHandler,Default_Handler
+
+ .weak DMA2_Stream1_IRQHandler
+ .thumb_set DMA2_Stream1_IRQHandler,Default_Handler
+
+ .weak DMA2_Stream2_IRQHandler
+ .thumb_set DMA2_Stream2_IRQHandler,Default_Handler
+
+ .weak DMA2_Stream3_IRQHandler
+ .thumb_set DMA2_Stream3_IRQHandler,Default_Handler
+
+ .weak DMA2_Stream4_IRQHandler
+ .thumb_set DMA2_Stream4_IRQHandler,Default_Handler
+
+ .weak ETH_IRQHandler
+ .thumb_set ETH_IRQHandler,Default_Handler
+
+ .weak ETH_WKUP_IRQHandler
+ .thumb_set ETH_WKUP_IRQHandler,Default_Handler
+
+ .weak FDCAN_CAL_IRQHandler
+ .thumb_set FDCAN_CAL_IRQHandler,Default_Handler
+
+ .weak DMA2_Stream5_IRQHandler
+ .thumb_set DMA2_Stream5_IRQHandler,Default_Handler
+
+ .weak DMA2_Stream6_IRQHandler
+ .thumb_set DMA2_Stream6_IRQHandler,Default_Handler
+
+ .weak DMA2_Stream7_IRQHandler
+ .thumb_set DMA2_Stream7_IRQHandler,Default_Handler
+
+ .weak USART6_IRQHandler
+ .thumb_set USART6_IRQHandler,Default_Handler
+
+ .weak I2C3_EV_IRQHandler
+ .thumb_set I2C3_EV_IRQHandler,Default_Handler
+
+ .weak I2C3_ER_IRQHandler
+ .thumb_set I2C3_ER_IRQHandler,Default_Handler
+
+ .weak OTG_HS_EP1_OUT_IRQHandler
+ .thumb_set OTG_HS_EP1_OUT_IRQHandler,Default_Handler
+
+ .weak OTG_HS_EP1_IN_IRQHandler
+ .thumb_set OTG_HS_EP1_IN_IRQHandler,Default_Handler
+
+ .weak OTG_HS_WKUP_IRQHandler
+ .thumb_set OTG_HS_WKUP_IRQHandler,Default_Handler
+
+ .weak OTG_HS_IRQHandler
+ .thumb_set OTG_HS_IRQHandler,Default_Handler
+
+ .weak DCMI_IRQHandler
+ .thumb_set DCMI_IRQHandler,Default_Handler
+
+ .weak RNG_IRQHandler
+ .thumb_set RNG_IRQHandler,Default_Handler
+
+ .weak FPU_IRQHandler
+ .thumb_set FPU_IRQHandler,Default_Handler
+
+ .weak UART7_IRQHandler
+ .thumb_set UART7_IRQHandler,Default_Handler
+
+ .weak UART8_IRQHandler
+ .thumb_set UART8_IRQHandler,Default_Handler
+
+ .weak SPI4_IRQHandler
+ .thumb_set SPI4_IRQHandler,Default_Handler
+
+ .weak SPI5_IRQHandler
+ .thumb_set SPI5_IRQHandler,Default_Handler
+
+ .weak SPI6_IRQHandler
+ .thumb_set SPI6_IRQHandler,Default_Handler
+
+ .weak SAI1_IRQHandler
+ .thumb_set SAI1_IRQHandler,Default_Handler
+
+ .weak LTDC_IRQHandler
+ .thumb_set LTDC_IRQHandler,Default_Handler
+
+ .weak LTDC_ER_IRQHandler
+ .thumb_set LTDC_ER_IRQHandler,Default_Handler
+
+ .weak DMA2D_IRQHandler
+ .thumb_set DMA2D_IRQHandler,Default_Handler
+
+ .weak SAI2_IRQHandler
+ .thumb_set SAI2_IRQHandler,Default_Handler
+
+ .weak QUADSPI_IRQHandler
+ .thumb_set QUADSPI_IRQHandler,Default_Handler
+
+ .weak LPTIM1_IRQHandler
+ .thumb_set LPTIM1_IRQHandler,Default_Handler
+
+ .weak CEC_IRQHandler
+ .thumb_set CEC_IRQHandler,Default_Handler
+
+ .weak I2C4_EV_IRQHandler
+ .thumb_set I2C4_EV_IRQHandler,Default_Handler
+
+ .weak I2C4_ER_IRQHandler
+ .thumb_set I2C4_ER_IRQHandler,Default_Handler
+
+ .weak SPDIF_RX_IRQHandler
+ .thumb_set SPDIF_RX_IRQHandler,Default_Handler
+
+ .weak OTG_FS_EP1_OUT_IRQHandler
+ .thumb_set OTG_FS_EP1_OUT_IRQHandler,Default_Handler
+
+ .weak OTG_FS_EP1_IN_IRQHandler
+ .thumb_set OTG_FS_EP1_IN_IRQHandler,Default_Handler
+
+ .weak OTG_FS_WKUP_IRQHandler
+ .thumb_set OTG_FS_WKUP_IRQHandler,Default_Handler
+
+ .weak OTG_FS_IRQHandler
+ .thumb_set OTG_FS_IRQHandler,Default_Handler
+
+ .weak DMAMUX1_OVR_IRQHandler
+ .thumb_set DMAMUX1_OVR_IRQHandler,Default_Handler
+
+ .weak HRTIM1_Master_IRQHandler
+ .thumb_set HRTIM1_Master_IRQHandler,Default_Handler
+
+ .weak HRTIM1_TIMA_IRQHandler
+ .thumb_set HRTIM1_TIMA_IRQHandler,Default_Handler
+
+ .weak HRTIM1_TIMB_IRQHandler
+ .thumb_set HRTIM1_TIMB_IRQHandler,Default_Handler
+
+ .weak HRTIM1_TIMC_IRQHandler
+ .thumb_set HRTIM1_TIMC_IRQHandler,Default_Handler
+
+ .weak HRTIM1_TIMD_IRQHandler
+ .thumb_set HRTIM1_TIMD_IRQHandler,Default_Handler
+
+ .weak HRTIM1_TIME_IRQHandler
+ .thumb_set HRTIM1_TIME_IRQHandler,Default_Handler
+
+ .weak HRTIM1_FLT_IRQHandler
+ .thumb_set HRTIM1_FLT_IRQHandler,Default_Handler
+
+ .weak DFSDM1_FLT0_IRQHandler
+ .thumb_set DFSDM1_FLT0_IRQHandler,Default_Handler
+
+ .weak DFSDM1_FLT1_IRQHandler
+ .thumb_set DFSDM1_FLT1_IRQHandler,Default_Handler
+
+ .weak DFSDM1_FLT2_IRQHandler
+ .thumb_set DFSDM1_FLT2_IRQHandler,Default_Handler
+
+ .weak DFSDM1_FLT3_IRQHandler
+ .thumb_set DFSDM1_FLT3_IRQHandler,Default_Handler
+
+ .weak SAI3_IRQHandler
+ .thumb_set SAI3_IRQHandler,Default_Handler
+
+ .weak SWPMI1_IRQHandler
+ .thumb_set SWPMI1_IRQHandler,Default_Handler
+
+ .weak TIM15_IRQHandler
+ .thumb_set TIM15_IRQHandler,Default_Handler
+
+ .weak TIM16_IRQHandler
+ .thumb_set TIM16_IRQHandler,Default_Handler
+
+ .weak TIM17_IRQHandler
+ .thumb_set TIM17_IRQHandler,Default_Handler
+
+ .weak MDIOS_WKUP_IRQHandler
+ .thumb_set MDIOS_WKUP_IRQHandler,Default_Handler
+
+ .weak MDIOS_IRQHandler
+ .thumb_set MDIOS_IRQHandler,Default_Handler
+
+ .weak JPEG_IRQHandler
+ .thumb_set JPEG_IRQHandler,Default_Handler
+
+ .weak MDMA_IRQHandler
+ .thumb_set MDMA_IRQHandler,Default_Handler
+
+ .weak SDMMC2_IRQHandler
+ .thumb_set SDMMC2_IRQHandler,Default_Handler
+
+ .weak HSEM1_IRQHandler
+ .thumb_set HSEM1_IRQHandler,Default_Handler
+
+ .weak ADC3_IRQHandler
+ .thumb_set ADC3_IRQHandler,Default_Handler
+
+ .weak DMAMUX2_OVR_IRQHandler
+ .thumb_set DMAMUX2_OVR_IRQHandler,Default_Handler
+
+ .weak BDMA_Channel0_IRQHandler
+ .thumb_set BDMA_Channel0_IRQHandler,Default_Handler
+
+ .weak BDMA_Channel1_IRQHandler
+ .thumb_set BDMA_Channel1_IRQHandler,Default_Handler
+
+ .weak BDMA_Channel2_IRQHandler
+ .thumb_set BDMA_Channel2_IRQHandler,Default_Handler
+
+ .weak BDMA_Channel3_IRQHandler
+ .thumb_set BDMA_Channel3_IRQHandler,Default_Handler
+
+ .weak BDMA_Channel4_IRQHandler
+ .thumb_set BDMA_Channel4_IRQHandler,Default_Handler
+
+ .weak BDMA_Channel5_IRQHandler
+ .thumb_set BDMA_Channel5_IRQHandler,Default_Handler
+
+ .weak BDMA_Channel6_IRQHandler
+ .thumb_set BDMA_Channel6_IRQHandler,Default_Handler
+
+ .weak BDMA_Channel7_IRQHandler
+ .thumb_set BDMA_Channel7_IRQHandler,Default_Handler
+
+ .weak COMP1_IRQHandler
+ .thumb_set COMP1_IRQHandler,Default_Handler
+
+ .weak LPTIM2_IRQHandler
+ .thumb_set LPTIM2_IRQHandler,Default_Handler
+
+ .weak LPTIM3_IRQHandler
+ .thumb_set LPTIM3_IRQHandler,Default_Handler
+
+ .weak LPTIM4_IRQHandler
+ .thumb_set LPTIM4_IRQHandler,Default_Handler
+
+ .weak LPTIM5_IRQHandler
+ .thumb_set LPTIM5_IRQHandler,Default_Handler
+
+ .weak LPUART1_IRQHandler
+ .thumb_set LPUART1_IRQHandler,Default_Handler
+
+ .weak CRS_IRQHandler
+ .thumb_set CRS_IRQHandler,Default_Handler
+
+ .weak ECC_IRQHandler
+ .thumb_set ECC_IRQHandler,Default_Handler
+
+ .weak SAI4_IRQHandler
+ .thumb_set SAI4_IRQHandler,Default_Handler
+
+ .weak WAKEUP_PIN_IRQHandler
+ .thumb_set WAKEUP_PIN_IRQHandler,Default_Handler
+
+
diff --git a/openocd.cfg b/openocd.cfg
new file mode 100644
index 0000000..0e78aa2
--- /dev/null
+++ b/openocd.cfg
@@ -0,0 +1,3 @@
+# Sample config for stlink and stm32 boards
+source [find interface/stlink.cfg]
+source [find target/stm32h7x.cfg]
\ No newline at end of file