feat: improve update security, support X Layer, and refresh Zodl wallet integration
What changed, and why it matters
This firmware update for the Keystone 3 hardware wallet is billed as a security improvement. The most important change is a complete rewrite of the bootloader/firmware update path: it now uses SHA-256 and a signed/length-prefixed 'bootupdate' envelope instead of the older MD5-based verification, and removes an old USB mass-storage auto-reboot behavior that could let a plugged-in host trigger a reboot just by copying a file. The patch also hardens the USB stack against malformed endpoint numbers and oversized control transfers, enables on-chip flash encryption for the external QSPI flash, and improves I2C and random-number error handling. However, the diff is very large and mixes many unrelated features (new wallet icons, X Layer chain support, UI tweaks), so it is hard to be certain every corner case is fixed.
Treat this as a legitimate security-hardening release. Users should install firmware 12.4.0 or later to benefit from the improved update verification and USB hardening. Developers should review the new boot_update.c path for remaining issues: verify that the magic-number search cannot be tricked by attacker-controlled app data, that the SHA-256 hash is authenticated (not just integrity-checked), and that the QSPI AES key/IV read from OTP is properly protected. Additional review of the large USB stack changes is warranted because the patch mixes hardening with unrelated feature work.
Security signals we found
Bootloader/firmware update verification upgraded from MD5 to SHA-256 with length-prefixed magic header
AUTO_REBOOT_AFTER_COPY_FILE path removed from USB MSC SCSI handler, eliminating host-triggered reboot on file copy
USB endpoint address validation added across DCD, USBD core, and class drivers to prevent out-of-bounds EP array access
USB EP0/control and bulk OUT receive paths now validate xfer_buff, xfer_count, and remaining length before reading packets
CDC class setup handler now whitelists and validates GET_LINE_CODING/SET_LINE_CODING/SET_CONTROL_LINE_STATE/SEND_BREAK requests
QSPI external flash encryption enabled (ENABLE_CACHE_AES 1) with AES-128-CBC using OTP-derived key/IV
I2C HAL send/receive now propagate I2CIO failure status instead of ignoring return value
TRNG driver added with attack-detection flag and NIST-style frequency/runs health checks
Heap size reduced from 450 KiB to 440 KiB, possibly to make room for new code/data
Version bumped to 12.4.0; changelog explicitly calls out 'Enhanced firmware upgrade security mechanisms'
Evidence from the diff
The commit reworks the secure-boot/update subsystem in src/boot_update.c/h and version.c, replacing MD5 verification with SHA-256 plus a length/hash header, and adds a NeedUpdateBoot() gate. It enables QSPI flash AES encryption (ENABLE_CACHE_AES 0→1) and adds the corresponding driver code in mhscpu_qspi.c/h, mhscpu_cache.c, and mh_rand.c. The USB device stack receives multiple hardening patches: endpoint index validation (DCD_IsValidEpAddr, USBD_IsValidEPAddress), bounds checks on EP0 and bulk OUT data lengths, stricter CDC class request handling, and removal of the AUTO_REBOOT_AFTER_COPY_FILE path in usbd_msc_scsi.c. I2C HAL now checks return codes, and FreeRTOS heap is slightly reduced. The remainder of the diff is feature work (X Layer, Zodl/Zashi wallet assets, i18n, UI).
Changed components
src/boot_update.c/hsrc/config/version.c/hsrc/crypto/checksum/md5.c/hsrc/driver/drv_qspi_flash.c/hexternal/mh1903_lib/MHSCPU_Driver/src/mhscpu_qspi.cexternal/mh1903_lib/MHSCPU_Driver/src/mhscpu_cache.cexternal/mh1903_lib/MHSCPU_Driver/src/mh_rand.cexternal/mh1903_lib/SCPU_USB_Lib/SCPU_USB_Device_Library/Core/src/usbd_core.cexternal/mh1903_lib/SCPU_USB_Lib/SCPU_USB_Device_Library/Core/src/usbd_req.cexternal/mh1903_lib/SCPU_USB_Lib/SCPU_USB_Device_Library/Core/src/usbd_ioreq.cexternal/mh1903_lib/SCPU_USB_Lib/SCPU_USB_Device_Library/Class/cdc/src/usbd_cdc_core.cexternal/mh1903_lib/SCPU_USB_Lib/SCPU_USB_Device_Library/Class/msc/src/usbd_msc_scsi.cexternal/mh1903_lib/SCPU_USB_Lib/SCPU_USB_OTG_Driver/src/usb_core.cexternal/mh1903_lib/SCPU_USB_Lib/SCPU_USB_OTG_Driver/src/usb_dcd.cexternal/mh1903_lib/SCPU_USB_Lib/SCPU_USB_OTG_Driver/src/usb_dcd_int.cexternal/cryptoauthlib/lib/hal/hal_mh1903_i2c.csrc/webusb_protocol/general/eapdu_protocol_parser.csrc/webusb_protocol/internal_protocol_parser.cInspect captured patch +3821 / −984
diff --git a/CHANGELOG-ZH.md b/CHANGELOG-ZH.md
index 0eaab0d..9b7fa9f 100644
--- a/CHANGELOG-ZH.md
+++ b/CHANGELOG-ZH.md
@@ -1,3 +1,28 @@
+## 2.4.0 (2026-3-30)
+
+
+**Web3:**
+
+### 新增
+1. 升级固件更新安全机制
+2. 支持 X Layer 交易
+
+
+**BTC Only:**
+
+### 新增
+1. 升级固件更新安全机制
+
+
+**Cypherpunk:**
+
+### 新增
+1. 升级固件更新安全机制
+### 优化
+1. 更新 Zodl 钱包图标
+
+
+
## 2.3.10(2026-3-4)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index cce17c4..37e02d9 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,26 @@
+## 2.4.0(2026-3-30)
+
+**Web3:**
+
+### What's new
+1. Enhanced firmware upgrade security mechanisms
+2. Supported X Layer transactions
+
+
+**BTC Only:**
+
+### What's new
+1. Enhanced firmware upgrade security mechanisms
+
+
+**Cypherpunk:**
+
+### What's new
+1. Enhanced firmware upgrade security mechanisms
+### Improvements
+1. Updated Zodl Wallet icon
+
+
## 2.3.10(2026-3-4)
diff --git a/external/FreeRTOS/FreeRTOSConfig.h b/external/FreeRTOS/FreeRTOSConfig.h
index 9ae5e55..e3b8b22 100644
--- a/external/FreeRTOS/FreeRTOSConfig.h
+++ b/external/FreeRTOS/FreeRTOSConfig.h
@@ -62,7 +62,7 @@ extern uint32_t SystemCoreClock;
#define configTICK_RATE_HZ ((TickType_t)1000)
#define configMAX_PRIORITIES ( 56 )
#define configMINIMAL_STACK_SIZE ((uint16_t)128)
-#define configTOTAL_HEAP_SIZE ((size_t)1024 * 450)
+#define configTOTAL_HEAP_SIZE ((size_t)1024 * 440)
#define configMAX_TASK_NAME_LEN ( 16 )
#define configUSE_TRACE_FACILITY 1
#define configUSE_16_BIT_TICKS 0
diff --git a/external/cryptoauthlib/lib/hal/hal_mh1903_i2c.c b/external/cryptoauthlib/lib/hal/hal_mh1903_i2c.c
index ad6be5e..d8d9d3a 100644
--- a/external/cryptoauthlib/lib/hal/hal_mh1903_i2c.c
+++ b/external/cryptoauthlib/lib/hal/hal_mh1903_i2c.c
@@ -64,7 +64,10 @@ ATCA_STATUS hal_i2c_post_init(ATCAIface iface)
*/
ATCA_STATUS hal_i2c_send(ATCAIface iface, uint8_t address, uint8_t *txdata, int txlength)
{
- I2CIO_SendData(&g_i2cIoCfg, address >> 1, txdata, txlength);
+ int32_t ret = I2CIO_SendData(&g_i2cIoCfg, address >> 1, txdata, txlength);
+ if (ret != 0) {
+ return ATCA_COMM_FAIL;
+ }
return ATCA_SUCCESS;
}
@@ -79,7 +82,10 @@ ATCA_STATUS hal_i2c_send(ATCAIface iface, uint8_t address, uint8_t *txdata, int
*/
ATCA_STATUS hal_i2c_receive(ATCAIface iface, uint8_t address, uint8_t *rxdata, uint16_t *rxlength)
{
- I2CIO_ReceiveData(&g_i2cIoCfg, address >> 1, rxdata, *rxlength);
+ int32_t ret = I2CIO_ReceiveData(&g_i2cIoCfg, address >> 1, rxdata, *rxlength);
+ if (ret != 0) {
+ return ATCA_COMM_FAIL;
+ }
return ATCA_SUCCESS;
}
diff --git a/external/mh1903_lib/MHSCPU_Driver/inc/mhscpu_qspi.h b/external/mh1903_lib/MHSCPU_Driver/inc/mhscpu_qspi.h
index 03bc090..bf7e22b 100644
--- a/external/mh1903_lib/MHSCPU_Driver/inc/mhscpu_qspi.h
+++ b/external/mh1903_lib/MHSCPU_Driver/inc/mhscpu_qspi.h
@@ -179,7 +179,7 @@ typedef struct {
-#define ENABLE_CACHE_AES 0
+#define ENABLE_CACHE_AES 1
void QSPI_Init(QSPI_InitTypeDef *mhqspi);
diff --git a/external/mh1903_lib/MHSCPU_Driver/src/mh_rand.c b/external/mh1903_lib/MHSCPU_Driver/src/mh_rand.c
new file mode 100644
index 0000000..7c9f4a2
--- /dev/null
+++ b/external/mh1903_lib/MHSCPU_Driver/src/mh_rand.c
@@ -0,0 +1,589 @@
+/* srand.c - random operation routines
+ */
+
+#include <math.h>
+#include <stdio.h>
+//#include "mh_crypt_cm3.h"
+#include "mh_rand.h"
+//#include "mh_cephes.h"
+//#include "mh_crypt_config.h"
+#include "mh_misc.h"
+#include "mhscpu.h"
+
+#ifdef __CC_ARM
+#pragma diag_suppress 177
+#endif
+
+const int8_t mh_freq_tab[] = {-8, -6, -6, -4, -6, -4, -4, -2, -6, -4, -4, -2, -4, -2, -2, 0,
+ -6, -4, -4, -2, -4, -2, -2, 0, -4, -2, -2, 0, -2, 0, 0, 2,
+ -6, -4, -4, -2, -4, -2, -2, 0, -4, -2, -2, 0, -2, 0, 0, 2,
+ -4, -2, -2, 0, -2, 0, 0, 2, -2, 0, 0, 2, 0, 2, 2, 4,
+ -6, -4, -4, -2, -4, -2, -2, 0, -4, -2, -2, 0, -2, 0, 0, 2,
+ -4, -2, -2, 0, -2, 0, 0, 2, -2, 0, 0, 2, 0, 2, 2, 4,
+ -4, -2, -2, 0, -2, 0, 0, 2, -2, 0, 0, 2, 0, 2, 2, 4,
+ -2, 0, 0, 2, 0, 2, 2, 4, 0, 2, 2, 4, 2, 4, 4, 6,
+ -6, -4, -4, -2, -4, -2, -2, 0, -4, -2, -2, 0, -2, 0, 0, 2,
+ -4, -2, -2, 0, -2, 0, 0, 2, -2, 0, 0, 2, 0, 2, 2, 4,
+ -4, -2, -2, 0, -2, 0, 0, 2, -2, 0, 0, 2, 0, 2, 2, 4,
+ -2, 0, 0, 2, 0, 2, 2, 4, 0, 2, 2, 4, 2, 4, 4, 6,
+ -4, -2, -2, 0, -2, 0, 0, 2, -2, 0, 0, 2, 0, 2, 2, 4,
+ -2, 0, 0, 2, 0, 2, 2, 4, 0, 2, 2, 4, 2, 4, 4, 6,
+ -2, 0, 0, 2, 0, 2, 2, 4, 0, 2, 2, 4, 2, 4, 4, 6,
+ 0, 2, 2, 4, 2, 4, 4, 6, 2, 4, 4, 6, 4, 6, 6, 8
+ };
+
+double mh_frequency(uint8_t *s, uint32_t n)
+{
+ int i;
+ double s_obs, p_value, sum, sqrt2 = 1.41421356237309504880;
+
+ if (n * 8 < 100)
+ return 0.0;
+
+ sum = 0.0;
+ for (i = 0; i < n; i++)
+ sum += mh_freq_tab[s[i]];
+
+ s_obs = (double)fabs(sum) / (double)sqrt(n * 8) / sqrt2;
+ p_value = erfc(s_obs);
+
+ return p_value;
+}
+
+const int8_t mh_blk_freq_tab[] = {0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4,
+ 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
+ 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
+ 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+ 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
+ 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+ 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+ 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
+ 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
+ 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+ 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+ 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
+ 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+ 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
+ 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
+ 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8
+ };
+//����û��ʹ��
+double mh_block_frequency(uint8_t *s, uint32_t n)
+{
+// int i, j, N, M;
+// double p_value, sum, pi, v, x_obs;
+//// if (n * 8 < 100)
+//// return 0.0;
+//// //M �� 0.1n
+//// M = n * 8 / 10 / 8 * 8;
+//// //N = n / M
+//// N = n * 8 / M;
+//
+//// sum = 0.0;
+//
+//// for ( i=0; i<N; i++ )
+//// {
+//// pi = 0;
+//// for (j=0; j<M/8; j++)
+//// pi += (double)mh_blk_freq_tab[s[i*(M/8)+j]];
+//// pi = pi/(double)M;
+//// v = pi-0.5;
+//// sum += v*v;
+//// }
+//// x_obs = 4.0 * M * sum;
+//// p_value = mh_cephes_igamc(N/2.0, x_obs/2.0);
+//
+// return p_value;
+ return 0;
+}
+
+const int8_t mh_runs_tab[] = {0, 1, 2, 1, 2, 3, 2, 1, 2, 3, 4, 3, 2, 3, 2, 1,
+ 2, 3, 4, 3, 4, 5, 4, 3, 2, 3, 4, 3, 2, 3, 2, 1,
+ 2, 3, 4, 3, 4, 5, 4, 3, 4, 5, 6, 5, 4, 5, 4, 3,
+ 2, 3, 4, 3, 4, 5, 4, 3, 2, 3, 4, 3, 2, 3, 2, 1,
+ 2, 3, 4, 3, 4, 5, 4, 3, 4, 5, 6, 5, 4, 5, 4, 3,
+ 4, 5, 6, 5, 6, 7, 6, 5, 4, 5, 6, 5, 4, 5, 4, 3,
+ 2, 3, 4, 3, 4, 5, 4, 3, 4, 5, 6, 5, 4, 5, 4, 3,
+ 2, 3, 4, 3, 4, 5, 4, 3, 2, 3, 4, 3, 2, 3, 2, 1,
+ 1, 2, 3, 2, 3, 4, 3, 2, 3, 4, 5, 4, 3, 4, 3, 2,
+ 3, 4, 5, 4, 5, 6, 5, 4, 3, 4, 5, 4, 3, 4, 3, 2,
+ 3, 4, 5, 4, 5, 6, 5, 4, 5, 6, 7, 6, 5, 6, 5, 4,
+ 3, 4, 5, 4, 5, 6, 5, 4, 3, 4, 5, 4, 3, 4, 3, 2,
+ 1, 2, 3, 2, 3, 4, 3, 2, 3, 4, 5, 4, 3, 4, 3, 2,
+ 3, 4, 5, 4, 5, 6, 5, 4, 3, 4, 5, 4, 3, 4, 3, 2,
+ 1, 2, 3, 2, 3, 4, 3, 2, 3, 4, 5, 4, 3, 4, 3, 2,
+ 1, 2, 3, 2, 3, 4, 3, 2, 1, 2, 3, 2, 1, 2, 1, 0
+ };
+
+
+double mh_runs(uint8_t *s, uint32_t n)
+{
+ int S, i, N = (n * 8);
+ double pi, V, x_obs, p_value;
+
+ if (n * 8 < 100)
+ return 0.0;
+
+ S = 0;
+ for (i = 0; i < n; i++)
+ S += mh_blk_freq_tab[s[i]];
+ pi = (double)S / (double)N;
+
+ if (fabs(pi - 0.5) > (2.0 / sqrt(N))) {
+ p_value = 0.0;
+ } else {
+ V = 0;
+
+ for (i = 0; i < n; i++) {
+ V += mh_runs_tab[s[i]];
+ if (i < n - 1)
+ if (((s[i] & 0x80) && !(s[i + 1] & 0x01)) || (!(s[i] & 0x80) && (s[i + 1] & 0x01)))
+ V++;
+ }
+ x_obs = fabs(V - 2.0 * N * pi * (1 - pi)) / (2.0 * pi * (1 - pi) * sqrt(2 * N));
+ p_value = erfc(x_obs);
+ }
+
+ return p_value;
+}
+
+const int8_t mh_longest_run_tab[] = {0, 1, 1, 2, 1, 1, 2, 3, 1, 1, 1, 2, 2, 2, 3, 4,
+ 1, 1, 1, 2, 1, 1, 2, 3, 2, 2, 2, 2, 3, 3, 4, 5,
+ 1, 1, 1, 2, 1, 1, 2, 3, 1, 1, 1, 2, 2, 2, 3, 4,
+ 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 4, 4, 5, 6,
+ 1, 1, 1, 2, 1, 1, 2, 3, 1, 1, 1, 2, 2, 2, 3, 4,
+ 1, 1, 1, 2, 1, 1, 2, 3, 2, 2, 2, 2, 3, 3, 4, 5,
+ 2, 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 3, 4,
+ 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 6, 7,
+ 1, 1, 1, 2, 1, 1, 2, 3, 1, 1, 1, 2, 2, 2, 3, 4,
+ 1, 1, 1, 2, 1, 1, 2, 3, 2, 2, 2, 2, 3, 3, 4, 5,
+ 1, 1, 1, 2, 1, 1, 2, 3, 1, 1, 1, 2, 2, 2, 3, 4,
+ 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 4, 4, 5, 6,
+ 2, 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 3, 4,
+ 2, 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 3, 3, 4, 5,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 7, 8
+ };
+//����û��ʹ��
+//double mh_longest_run_of_ones(uint8_t *s, uint32_t N)
+//{
+// double p_value, chi2, pi[7];
+// int v_n_obs, n, i, j, K, M, V[7];
+// unsigned int nu[7] = { 0, 0, 0, 0, 0, 0, 0 };
+
+// K = 3;
+// M = 8;
+// V[0] = 1; V[1] = 2; V[2] = 3; V[3] = 4;
+// pi[0] = 0.21484375;
+// pi[1] = 0.3671875;
+// pi[2] = 0.23046875;
+// pi[3] = 0.1875;
+
+// n = N * M;
+
+// if (6272 <= n || n < 128)
+// return 0.0;
+
+// for ( i=0; i<N; i++ ) {
+// v_n_obs = mh_longest_run_tab[s[i]];
+// if ( v_n_obs < V[0] )
+// nu[0]++;
+// for ( j=0; j<=K; j++ )
+// {
+// if ( v_n_obs == V[j] )
+// nu[j]++;
+// }
+// if ( v_n_obs > V[K] )
+// nu[K]++;
+// }
+
+// chi2 = 0.0;
+// for ( i=0; i<=K; i++ )
+// chi2 += ((nu[i] - N * pi[i]) * (nu[i] - N * pi[i])) / (N * pi[i]);
+
+// p_value = mh_cephes_igamc((double)(K/2.0), chi2 / 2.0);
+
+// return p_value;
+//}
+
+
+uint32_t mh_rand_check(void *rand, uint32_t bytes)
+{
+ uint32_t ret = MH_RET_RAND_CHECK_SUCCESS;
+ if (6272 <= bytes * 8 || bytes * 8 < 128)
+ ret = MH_RET_RAND_CHECK_DATA_LENGTH_ERROR;
+
+#ifdef MH_RAND_USE_CHECK_FREQUENCY
+ if (ret == MH_RET_RAND_CHECK_SUCCESS)
+ if (mh_frequency((uint8_t*)rand, bytes) < 0.01)
+ ret = MH_RET_RAND_CHECK_FAILURE;
+#endif
+
+#ifdef MH_RAND_USE_CHECK_BLOCK_FREQUENCY
+ if (ret == MH_RET_RAND_CHECK_SUCCESS)
+ if (mh_block_frequency((uint8_t*)rand, bytes) < 0.01)
+ ret = MH_RET_RAND_CHECK_FAILURE;
+#endif
+
+#ifdef MH_RAND_USE_CHECK_RUNS
+ if (ret == MH_RET_RAND_CHECK_SUCCESS)
+ if (mh_runs((uint8_t*)rand, bytes) < 0.01)
+ ret = MH_RET_RAND_CHECK_FAILURE;
+#endif
+
+//#ifdef MH_RAND_USE_CHECK_LONGEST_RUN
+// if (ret == MH_RET_RAND_CHECK_SUCCESS)
+// if (mh_longest_run_of_ones((uint8_t*)rand, bytes) < 0.01)
+// ret = MH_RET_RAND_CHECK_FAILURE;
+//#endif
+
+ return ret;
+}
+
+#define MH_RAND_BUFFER_SIZE 256
+#define MH_RAND_BUFFER_INITED (0x5A5A5A5A)
+#define MH_RAND_BUFFER_ATTACKED (0xA5A5A5A5)
+
+typedef struct RingBuffer {
+ uint32_t buf[MH_RAND_BUFFER_SIZE];
+ uint32_t put_index, get_index;
+ volatile uint32_t count;
+ uint32_t inited;
+ uint32_t attacked;
+} RingBufferTypeDef;
+
+void mh_trand_buf_init(RingBufferTypeDef * buf);
+uint32_t mh_trand_buf_put(RingBufferTypeDef * buf, void *rand, uint32_t size);
+
+RingBufferTypeDef g_trng_buf = {0};
+
+void mh_trand_buf_init(RingBufferTypeDef *buf)
+{
+ memset(buf->buf, 0, sizeof(buf->buf));
+ buf->get_index = 0;
+ buf->put_index = 0;
+ buf->count = 0;
+ buf->inited = MH_RAND_BUFFER_INITED;
+ buf->attacked = 0;
+}
+
+
+
+#define MH_RAND_USE_TRNG 1
+
+/************ bit definition for TRNG RNG_AMA REGISTER ************/
+#define MH_TRNG_RNG_AMA_PD_TRNG0_Pos (12)
+#define MH_TRNG_RNG_AMA_PD_TRNG0_Mask (0x0FU<<MH_TRNG_RNG_AMA_PD_TRNG0_Pos)
+
+
+/************ bit definition for TRNG RNG_CSR REGISTER ************/
+#define MH_TRNG_RNG0_CSR_S128_Pos (0)
+#define MH_TRNG_RNG0_CSR_S128_Mask (0x01U<<MH_TRNG_RNG0_CSR_S128_Pos)
+
+#define MH_TRNG_RNG0_CSR_ATTACK_Pos (2)
+#define MH_TRNG_RNG0_CSR_ATTACK_Mask (0x01U<<MH_TRNG_RNG0_CSR_ATTACK_Pos)
+
+#define MH_TRNG_RNG_CSR_INTP_EN_Pos (4)
+#define MH_TRNG_RNG_CSR_INTP_EN_Mask (0x01U<<MH_TRNG_RNG_CSR_INTP_EN_Pos)
+
+typedef struct {
+ volatile uint32_t RNG_CSR;
+ volatile uint32_t RNG0_DATA;
+ volatile uint32_t rsvd;
+ volatile uint32_t RNG_AMA;
+ volatile uint32_t RNG_PN;
+} mh_trng_type_def;
+
+
+#define MH_TRNG ((mh_trng_type_def *)(0x4001E000UL))
+#define MH_TRNG_WORDS (4)
+#define MH_TRNG_BYTES (MH_TRNG_WORDS*4)
+
+
+
+__STATIC_INLINE void mh_trand_init(void)
+{
+ MH_TRNG->RNG_CSR |= 0x10; //ʹ���ж�
+ MH_TRNG->RNG_AMA &= ~TRNG_RNG_AMA_PD_ALL_Mask;
+
+}
+
+__STATIC_INLINE void mh_trand_start(void)
+{
+ MH_TRNG->RNG_CSR &= ~MH_TRNG_RNG0_CSR_S128_Mask;
+
+}
+
+__STATIC_INLINE uint32_t mh_trand_get(uint32_t rand[4])
+{
+ uint32_t ret;
+
+ /*
+ * check until the random number has been generated
+ */
+ while (!(MH_TRNG->RNG_CSR & MH_TRNG_RNG0_CSR_S128_Mask));
+ /*
+ * check if the TRNG is attacked
+ */
+ if (MH_TRNG->RNG_CSR & MH_TRNG_RNG0_CSR_ATTACK_Mask) {
+ ret = 0;
+ goto cleanup;
+ }
+ /*
+ * copy random number to RNG_Buf
+ */
+ rand[0] = MH_TRNG->RNG0_DATA;
+ rand[1] = MH_TRNG->RNG0_DATA;
+ rand[2] = MH_TRNG->RNG0_DATA;
+ rand[3] = MH_TRNG->RNG0_DATA;
+
+ ret = sizeof(uint32_t) * 4;
+
+cleanup:
+ return ret;
+
+}
+
+
+uint32_t mh_trand_polling(void *rand, uint32_t bytes)
+{
+ uint32_t ret = 0;
+ uint32_t m, r, i, check;
+ uint8_t *_rand = (uint8_t *)rand;
+ uint32_t rand_buf[4];
+
+ memset(rand, 0, bytes);
+
+ m = bytes / MH_TRNG_BYTES;
+ r = bytes % MH_TRNG_BYTES;
+ if (r)
+ m++;
+
+ mh_trand_init();
+ mh_trand_start();
+
+ for (i = 0, check = 0; i < m; i++) {
+ if (i != check) {
+ ret = 0;
+ goto cleanup;
+ }
+
+ if (0 == mh_trand_get(rand_buf)) {
+ ret = 0;
+ goto cleanup;
+ }
+ mh_trand_start();
+
+ if (i < (m - 1)) {
+ memcpy(_rand, &rand_buf[0], sizeof(rand_buf));
+ _rand = _rand + sizeof(rand_buf);
+ ret += sizeof(rand_buf);
+ } else if (r == 0) {
+ memcpy(_rand, &rand_buf[0], sizeof(rand_buf));
+ _rand = _rand + sizeof(rand_buf);
+ ret += sizeof(rand_buf);
+ } else {
+ memcpy(_rand, &rand_buf[0], r);
+ ret += r;
+ }
+
+ check++;
+ }
+
+cleanup:
+ if (ret != bytes) {
+ memset(rand, 0, bytes);
+ ret = 0;
+ }
+
+ return ret;
+}
+
+
+uint32_t mh_trand_buf_attack_get(RingBufferTypeDef * buf)
+{
+ if (buf->attacked == MH_RAND_BUFFER_ATTACKED)
+ return 1;
+ else
+ return 0;
+}
+
+void mh_trand_buf_attack_clean(RingBufferTypeDef * buf)
+{
+ buf->attacked = 0;
+}
+
+uint32_t mh_trand_buf_count(RingBufferTypeDef * buf)
+{
+ return buf->count;
+}
+
+//static uint32_t mh_trand_buf_get()
+//{
+// uint32_t r;
+//
+// if (g_trng_buf.count == 0) {
+// NVIC_EnableIRQ(TRNG_IRQn);
+// }
+// while (g_trng_buf.count == 0) {
+// }
+// r = g_trng_buf.buf[g_trng_buf.get_index++];
+// if (g_trng_buf.get_index >= MH_RAND_BUFFER_SIZE) {
+// g_trng_buf.get_index = 0;
+// }
+// NVIC_DisableIRQ(TRNG_IRQn);
+// g_trng_buf.count--;
+// NVIC_EnableIRQ(TRNG_IRQn);
+//
+// return r;
+//}
+
+typedef struct trng_ext_buf_s {
+ int len;
+ unsigned char buf[32];
+} trng_ext_buf;
+
+trng_ext_buf g_trng_ext_buf = {0};
+
+uint32_t mh_trand(void *rand, uint32_t bytes)
+{
+ uint32_t rbytes = 0;
+ uint32_t _bytes = bytes;
+// int n = 0;
+ typedef union dword_u {
+ uint32_t n;
+ uint8_t c[4];
+ } dword;
+ dword *p = (dword *)rand;
+
+
+ if (mh_trand_buf_attack_get(&g_trng_buf)) {
+ rbytes = 0;
+ goto cleanup;
+ }
+ if (g_trng_buf.count == 0) {
+ mh_trand_init();
+ NVIC_EnableIRQ(TRNG_IRQn);
+ }
+ do {
+ //printf("wait...\n");
+ while (g_trng_buf.count == 0);
+ //printf("bytes = %d\n", bytes);
+ while (_bytes >= 4 && g_trng_buf.count) {
+ p->n = g_trng_buf.buf[g_trng_buf.get_index++];
+ g_trng_buf.get_index %= MH_RAND_BUFFER_SIZE;
+ NVIC_DisableIRQ(TRNG_IRQn);
+ g_trng_buf.count--;
+ NVIC_EnableIRQ(TRNG_IRQn);
+ _bytes -= 4;
+ rbytes += 4;
+ p++;
+ }
+ if (_bytes < 4 && g_trng_buf.count) {
+ unsigned char *pbyte = (unsigned char *)(g_trng_buf.buf + g_trng_buf.get_index);
+ int i = 0;
+
+ //printf("tail:%08X\n", g_trng_buf.buf[g_trng_buf.get_index]);
+ g_trng_buf.get_index++;
+ for (i = 0; i < _bytes; i++) {
+ p->c[i] = *pbyte++;
+ rbytes++;
+ }
+ _bytes = 0;
+ g_trng_buf.get_index %= MH_RAND_BUFFER_SIZE;
+
+ NVIC_DisableIRQ(TRNG_IRQn);
+ g_trng_buf.count--;
+ NVIC_EnableIRQ(TRNG_IRQn);
+ }
+ } while (_bytes > 0);
+
+cleanup:
+ if (rbytes != bytes) {
+ memset(rand, 0, bytes);
+ rbytes = 0;
+ }
+
+ return rbytes;
+}
+
+//extern uint32_t g_count;
+
+uint32_t mh_frand(void *rand, uint32_t bytes)
+{
+ uint32_t i;
+
+ for (i = 0; i < bytes; i++) {
+ if (i % 2)
+ ((uint8_t*)rand)[i] = (MH_TRNG->RNG_PN) & 0xFF;
+ else
+ ((uint8_t*)rand)[i] = ((MH_TRNG->RNG_PN) >> 3) & 0xFF;
+ }
+ return i;
+}
+
+
+
+uint32_t mh_rand(void *rand, uint32_t bytes)
+{
+ //memset(rand, 0x18, bytes);
+
+ //return bytes;
+#if MH_RAND_USE_TRNG
+ return mh_trand(rand, bytes);
+// return mh_trand_polling(rand, bytes);
+#else
+ return mh_frand(rand, bytes);
+#endif
+}
+
+/*
+void TRNG_ClearITPendingBit(uint32_t TRNG_IT)
+{
+ MH_TRNG->RNG_CSR &= ~TRNG_IT;
+}
+*/
+#define TRNG_IT_RNG0_S128 ((uint32_t)0x00000001)
+
+void TRNG_IRQHandler(void)
+{
+ int i;
+ /***************************************
+ * check if the TRNG is attacked
+ **************************************/
+ if ((MH_TRNG->RNG_CSR & MH_TRNG_RNG0_CSR_ATTACK_Mask)) {
+ g_trng_buf.attacked = MH_RAND_BUFFER_ATTACKED;
+ } else {
+ volatile uint32_t *p = &MH_TRNG->RNG0_DATA;
+ for (i = 0; i < 4; i ++) {
+ if (g_trng_buf.count < MH_RAND_BUFFER_SIZE) {
+ g_trng_buf.buf[g_trng_buf.put_index++] = *p;
+ if (g_trng_buf.put_index >= MH_RAND_BUFFER_SIZE) {
+ g_trng_buf.put_index = 0;
+ }
+ g_trng_buf.count++;
+ }
+ }
+ TRNG_ClearITPendingBit(TRNG_IT_RNG0_S128);
+ if (g_trng_buf.count == MH_RAND_BUFFER_SIZE) {
+ NVIC_DisableIRQ(TRNG_IRQn);
+ }
+ }
+// printf("come into trand interrupt\n");
+// TRNG_ClearITPendingBit(TRNG_IT_RNG0_S128);
+}
+
+uint32_t mh_rand_init(void)
+{
+ mh_trand_buf_init(&g_trng_buf);
+ mh_trand_init();
+ mh_trand_start();
+ return 0;
+}
+
+uint32_t mh_rand_p(void *rand, uint32_t bytes, void *p_rng)
+{
+ //memset(rand, 0x01, bytes);
+ //return bytes;
+ return mh_rand(rand, bytes);
+}
diff --git a/external/mh1903_lib/MHSCPU_Driver/src/mhscpu_cache.c b/external/mh1903_lib/MHSCPU_Driver/src/mhscpu_cache.c
new file mode 100644
index 0000000..070b7c9
--- /dev/null
+++ b/external/mh1903_lib/MHSCPU_Driver/src/mhscpu_cache.c
@@ -0,0 +1,91 @@
+/************************ (C) COPYRIGHT Megahuntmicro *************************
+ * @file : mhscpu_cache.c
+ * @author : Megahuntmicro
+ * @version : V1.0.0
+ * @date : 21-October-2014
+ * @brief : This file provides all the CACHE firmware functions
+ *****************************************************************************/
+
+/* Includes ----------------------------------------------------------------*/
+#include "mhscpu_cache.h"
+
+
+void CACHE_Init(CACHE_TypeDef *Cache, CACHE_InitTypeDef *CACHE_InitStruct)
+{
+ int i;
+
+ if (CACHE_InitStruct->aes_enable == ENABLE) {
+ assert_param(IS_CACHE_ENCRYPT_MODE(CACHE_InitStruct->encrypt_mode));
+
+ for (i = 0; i < 5000; i++) {
+ if (Cache->CACHE_AES_CS & CACHE_IS_BUSY) { //cache���ڴ�Flash��ȡָ
+ continue;
+ }
+ break;
+ }
+ Cache->CACHE_AES_CS = (Cache->CACHE_AES_CS & ~0xFF) | CACHE_KEY_GEN; //AES��Կ����ģʽ
+
+ Cache->CACHE_AES_I3 = CACHE_InitStruct->I[3];
+ Cache->CACHE_AES_I2 = CACHE_InitStruct->I[2];
+ Cache->CACHE_AES_I1 = CACHE_InitStruct->I[1];
+ Cache->CACHE_AES_I0 = CACHE_InitStruct->I[0];
+
+ Cache->CACHE_AES_K3 = CACHE_InitStruct->K[3];
+ Cache->CACHE_AES_K2 = CACHE_InitStruct->K[2];
+ Cache->CACHE_AES_K1 = CACHE_InitStruct->K[1];
+ Cache->CACHE_AES_K0 = CACHE_InitStruct->K[0];
+
+ Cache->CACHE_AES_CS |= CACHE_KEY_GEN_START;
+ for (i = 0; i < 5000; i++) {
+ if ((Cache->CACHE_AES_CS & CACHE_KEY_GEN_START) == 0) {
+ Cache->CACHE_AES_CS = 0x0;
+ break;
+ }
+ }
+ Cache->CACHE_AES_CS = 0;
+ Cache->CACHE_CONFIG = (Cache->CACHE_CONFIG & ~0xFF00FFFF);
+
+ if (CACHE_Encrypt_Mode_Zone == CACHE_InitStruct->encrypt_mode) {
+ uint32_t saddr_align = CACHE_InitStruct->encrypt_saddr & ~(CACHE_PARTICLE_SIZE - 1);
+ uint32_t eaddr_align = CACHE_InitStruct->encrypt_eaddr & ~(CACHE_PARTICLE_SIZE - 1);
+
+ assert_param(IS_CACHE_ADDR_VALID(saddr_align));
+ assert_param(IS_CACHE_ADDR_VALID(eaddr_align));
+ assert_param(saddr_align <= eaddr_align);
+
+ Cache->CACHE_SADDR = saddr_align;
+ Cache->CACHE_EADDR = eaddr_align;
+ Cache->CACHE_CONFIG = (Cache->CACHE_CONFIG & ~0xFF000000) | CACHE_ZONE_ENCRYPT;
+ }
+ } else {
+ Cache->CACHE_CONFIG = (Cache->CACHE_CONFIG & ~0xFF00FFFF) | CACHE_AES_BYPASS;
+ }
+
+}
+
+/*clean cache flash data/instructions*/
+void CACHE_Clean(CACHE_TypeDef *Cache, CACHE_InitTypeDef *CACHE_InitStruct)
+{
+ uint32_t i, address;
+ address = (CACHE_InitStruct->Address & ~(CACHE_PARTICLE_SIZE - 1)) & CACHE_ADDRESS_MAX;
+
+ for (i = 0; i < CACHE_InitStruct->size; i += CACHE_PARTICLE_SIZE) {
+ //flush cache line
+ Cache->CACHE_REF = (address + i);
+ Cache->CACHE_REF |= CACHE_REFRESH;
+ while ((Cache->CACHE_REF & CACHE_REFRESH));
+ }
+}
+
+void CACHE_CleanAll(CACHE_TypeDef *Cache)
+{
+ //flush cache all
+ while (Cache->CACHE_AES_CS & CACHE_IS_BUSY);
+
+ Cache->CACHE_REF = CACHE_REFRESH_ALLTAG;
+ Cache->CACHE_REF |= CACHE_REFRESH;
+ while ((Cache->CACHE_REF & CACHE_REFRESH));
+}
+
+
+/************************** (C) COPYRIGHT Megahunt *****END OF FILE****/
diff --git a/external/mh1903_lib/MHSCPU_Driver/src/mhscpu_qspi.c b/external/mh1903_lib/MHSCPU_Driver/src/mhscpu_qspi.c
new file mode 100644
index 0000000..6ddda07
--- /dev/null
+++ b/external/mh1903_lib/MHSCPU_Driver/src/mhscpu_qspi.c
@@ -0,0 +1,1130 @@
+#ifdef BUILD_PRODUCTION
+/************************ (C) COPYRIGHT Megahuntmicro *************************
+ * @file : mhscpu_qspi.c
+ * @author : Megahuntmicro
+ * @version : V1.0.0
+ * @date : 21-October-2014
+ * @brief : This file provides all the QSPI firmware functions
+ *****************************************************************************/
+
+/* Includes ----------------------------------------------------------------*/
+#include <stdlib.h>
+#include <string.h>
+#include "mhscpu.h"
+#include "mhscpu_cache.h"
+#include "mhscpu_qspi.h"
+#include "mhscpu_dma.h"
+#include "stdio.h"
+#include "log_print.h"
+#include "user_delay.h"
+#include "mh_aes.h"
+#include "mh_rand.h"
+#include "assert.h"
+#include "ctaes.h"
+#include "user_utils.h"
+#include "mhscpu_conf.h"
+
+#define QSPI_DEVICE_PARA_FLASH_READY_Mask (BIT(3))
+
+
+typedef enum {
+ MH_OK = 0x00,
+ MH_ERROR = 0x01,
+ MH_BUSY = 0x02,
+ MH_TIMEOUT = 0x03
+} MH_StatusTypeDef;
+
+typedef struct {
+ uint8_t Instruction;
+ QSPI_BusModeTypeDef BusMode;
+ QSPI_CmdFormatTypeDef CmdFormat;
+ uint32_t Address;
+
+ uint32_t WrData;
+ uint32_t RdData;
+
+} MH_CommandTypeDef;
+
+
+//命令完成中断标志置位的最大是就是编程命令耗时
+//(PP_CMD(1B) + PP_ADDR(3B) + PP_MAX_BYTES(256B) + Cache_line(32B) + Cache_CMD(1B)+Cache_ADDR(3B)) * 8(bits) * 8(CPU主频最大是QSPI频率的8倍)
+//(1+ 3 + 256 + 32 + 1 + 3) * 8 * 8
+#define MH_QSPI_TIMEOUT_DEFAULT_CNT (19000) //18944
+
+#define MH_QSPI_ACCESS_REQ_ENABLE (0x00000001U)
+#define MH_QSPI_FLASH_READY_ENABLE (0x0000006BU)
+
+
+#define IS_PARAM_NOTNULL(PARAM) ((PARAM) != NULL)
+
+#define IS_QSPI_ADDR(ADDR) ((((int32_t)(ADDR) ) >= (uint32_t)(0x00000000)) &&\
+ (((int32_t)(ADDR) ) <= (uint32_t)(0x00FFFFFF)))
+
+#define IS_QSPI_ADDR_ADD_SZ(ADDR, SZ) ((((int32_t)((ADDR) + (SZ))) >= (uint32_t)(0x00000000)) && \
+ (((int32_t)((ADDR) + (SZ))) <= (uint32_t)(0x01000000)))
+
+
+static bool EncryptedFlash(void);
+
+
+static void delay_40ms(void)
+{
+ int i, j;
+ for (i = 7; i > 0; i --)
+ for (j = SYSCTRL->HCLK_1MS_VAL; j > 0; j --);
+}
+
+static MH_StatusTypeDef MH_QSPI_Command(MH_CommandTypeDef *cmd, int32_t timeout)
+{
+ //int32_t i;
+ MH_StatusTypeDef status = MH_ERROR;
+
+ assert_param(IS_PARAM_NOTNULL(cmd));
+
+ MHSCPU_MODIFY_REG32(&(QSPI->REG_WDATA), (QUADSPI_REG_WDATA), (cmd->WrData));
+ MHSCPU_MODIFY_REG32(&(QSPI->ADDRES), (QUADSPI_ADDRESS_ADR), (cmd->Address << 8));
+ MHSCPU_MODIFY_REG32(&(QSPI->FCU_CMD),
+ (QUADSPI_FCU_CMD_CODE | QUADSPI_FCU_CMD_BUS_MODE | QUADSPI_FCU_CMD_CMD_FORMAT | QUADSPI_FCU_CMD_ACCESS_REQ),
+ (((uint32_t)(cmd->Instruction << 24)) | ((uint32_t)(cmd->BusMode << 8)) | ((uint32_t)(cmd->CmdFormat << 4)) | (MH_QSPI_ACCESS_REQ_ENABLE)));
+
+ //Wait For CMD done
+ //for (i = 0; i < timeout; i += 4) {
+ //i = 0;
+ while (1) {
+ if (QSPI->INT_RAWSTATUS & QUADSPI_INT_RAWSTATUS_DONE_IR) {
+ QSPI->INT_CLEAR = QUADSPI_INT_CLEAR_DONE;
+ status = MH_OK;
+ break;
+ }
+ UserDelayUs(20);
+ }
+
+ MHSCPU_WRITE_REG32(&(cmd->RdData), QSPI->REG_RDATA);
+ return status;
+}
+
+static QSPI_StatusTypeDef QSPI_WriteEnable(QSPI_BusModeTypeDef bus_mode)
+{
+ MH_CommandTypeDef sCommand = {0};
+
+ sCommand.Instruction = WRITE_ENABLE_CMD;
+ sCommand.CmdFormat = QSPI_CMDFORMAT_CMD8;
+
+ if (QSPI_BUSMODE_444 == bus_mode) {
+ sCommand.BusMode = QSPI_BUSMODE_444;
+ } else {
+ sCommand.BusMode = QSPI_BUSMODE_111;
+ }
+
+ if (MH_QSPI_Command(&sCommand, MH_QSPI_TIMEOUT_DEFAULT_CNT) != MH_OK) {
+ return QSPI_STATUS_ERROR;
+ }
+
+ return QSPI_STATUS_OK;
+}
+
+//PP,QPP,Sector Erase,Block Erase, Chip Erase, Write Status Reg, Erase Security Reg
+static QSPI_StatusTypeDef QSPI_IsBusy(QSPI_BusModeTypeDef bus_mode)
+{
+ MH_CommandTypeDef sCommand = {0};
+
+ sCommand.Instruction = READ_STATUS_REG1_CMD;
+ sCommand.CmdFormat = QSPI_CMDFORMAT_CMD8_RREG8;
+
+ if (QSPI_BUSMODE_444 == bus_mode) {
+ sCommand.BusMode = QSPI_BUSMODE_444;
+ } else {
+ sCommand.BusMode = QSPI_BUSMODE_111;
+ }
+
+ if (MH_QSPI_Command(&sCommand, MH_QSPI_TIMEOUT_DEFAULT_CNT) != MH_OK) {
+ return QSPI_STATUS_ERROR;
+ }
+
+ if (sCommand.RdData & BIT0) {
+ return QSPI_STATUS_ERROR;
+ }
+ return QSPI_STATUS_OK;
+}
+
+#define MAX_RD_DATA_LEN 0x10
+#define MAX_WR_DATA_LEN 0x04
+
+uint8_t QSPI_Read(QSPI_CommandTypeDef *cmdParam, uint8_t* buf, uint32_t addr, uint32_t sz)
+{
+ uint32_t read_times = 0, i = 0, j = 0, rxCount = 0;
+ uint8_t end_len = 0;
+ MH_CommandTypeDef sCommand = {0};
+
+ while (CACHE->CACHE_AES_CS & CACHE_IS_BUSY);
+
+ addr &= (uint32_t)(0x00FFFFFF);
+ assert_param(IS_QSPI_ADDR(addr));
+ assert_param(IS_QSPI_ADDR_ADD_SZ(addr, sz));
+
+ if (cmdParam == NULL) {
+ sCommand.Instruction = READ_CMD;
+ sCommand.BusMode = QSPI_BUSMODE_111;
+ sCommand.CmdFormat = QSPI_CMDFORMAT_CMD8_ADDR24_RDAT;
+ } else {
+ sCommand.Instruction = cmdParam->Instruction;
+ sCommand.BusMode = cmdParam->BusMode;
+ sCommand.CmdFormat = cmdParam->CmdFormat;
+ }
+
+ read_times = sz / MAX_RD_DATA_LEN;
+ end_len = sz % MAX_RD_DATA_LEN;
+
+ for (i = 0; i < read_times; i ++) {
+ QSPI->FIFO_CNTL |= QUADSPI_FIFO_CNTL_RFFH;
+ QSPI->BYTE_NUM = MAX_RD_DATA_LEN;
+
+ sCommand.Address = addr;
+
+ if (MH_QSPI_Command(&sCommand, MH_QSPI_TIMEOUT_DEFAULT_CNT) != MH_OK) {
+ return QSPI_STATUS_ERROR;
+ }
+
+ rxCount = (QSPI->FIFO_CNTL & 0x7);
+ for (j = 0; j < rxCount; j++) {
+ *(uint32_t *)(buf) = QSPI->RD_FIFO;
+ buf += 4;
+ }
+
+ addr += MAX_RD_DATA_LEN;
+ }
+
+ QSPI->FIFO_CNTL |= QUADSPI_FIFO_CNTL_RFFH;
+ sCommand.Address = addr;
+ if (end_len > 0) {
+ QSPI->BYTE_NUM = end_len;
+
+ if (MH_QSPI_Command(&sCommand, MH_QSPI_TIMEOUT_DEFAULT_CNT) != MH_OK) {
+ return QSPI_STATUS_ERROR;
+ }
+
+ rxCount = (QSPI->FIFO_CNTL & 0x7);
+ for (j = 0; j < rxCount; j++) {
+ *(uint32_t *)(buf) = QSPI->RD_FIFO;
+ buf += 4;
+ }
+ }
+
+ return QSPI_STATUS_OK;
+}
+
+
+static uint8_t QSPI_ProgramPage_Ex(QSPI_CommandTypeDef *cmdParam, uint32_t adr, uint32_t sz, uint8_t *buf)
+{
+ uint32_t i, j;
+ uint32_t end_addr, current_size, current_addr, current_dat, loop_addr;
+ MH_CommandTypeDef sCommand = {0};
+
+ adr &= (uint32_t)0x00FFFFFF;
+ assert_param(IS_QSPI_ADDR(adr));
+ assert_param(IS_QSPI_ADDR_ADD_SZ(adr, sz));
+
+ current_addr = 0;
+
+ while (current_addr <= adr) {
+ current_addr += X25Q_PAGE_SIZE;
+ }
+ current_size = current_addr - adr;
+
+ /* Check if the size of the data is less than the remaining place in the page */
+ if (current_size > sz) {
+ current_size = sz;
+ }
+
+ /* Initialize the adress variables */
+ current_addr = adr;
+ loop_addr = adr;
+ end_addr = adr + sz;
+
+ QSPI->FIFO_CNTL |= QUADSPI_FIFO_CNTL_TFFH;
+ QSPI->BYTE_NUM = MAX_WR_DATA_LEN << 16;
+ sCommand.Address = current_addr;
+
+ if (cmdParam == NULL) {
+ sCommand.Instruction = QUAD_INPUT_PAGE_PROG_CMD;
+ sCommand.BusMode = QSPI_BUSMODE_114;
+ sCommand.CmdFormat = QSPI_CMDFORMAT_CMD8_ADDR24_PDAT;
+ } else {
+ sCommand.Instruction = cmdParam->Instruction;
+ sCommand.BusMode = cmdParam->BusMode;
+ sCommand.CmdFormat = cmdParam->CmdFormat;
+ }
+
+ do {
+ QSPI->BYTE_NUM = MAX_WR_DATA_LEN << 16;
+
+ for (i = 0; i < (current_size / MAX_WR_DATA_LEN); i++) {
+ QSPI->WR_FIFO = (*(buf + 3) << 24) | (*(buf + 2) << 16) | (*(buf + 1) << 8) | (*(buf + 0));
+
+ if (QSPI_WriteEnable(sCommand.BusMode) != QSPI_STATUS_OK) {
+ return QSPI_STATUS_ERROR;
+ }
+
+ if (MH_QSPI_Command(&sCommand, MH_QSPI_TIMEOUT_DEFAULT_CNT) != MH_OK) {
+ return QSPI_STATUS_ERROR;
+ }
+
+ while (QSPI_IsBusy(sCommand.BusMode));
+
+ QSPI->FIFO_CNTL |= QUADSPI_FIFO_CNTL_TFFH;
+ buf += 4;
+
+ current_addr += MAX_WR_DATA_LEN;
+ sCommand.Address = current_addr;
+ }
+
+ if (current_size % MAX_WR_DATA_LEN > 0) {
+ current_dat = 0;
+ QSPI->FIFO_CNTL |= QUADSPI_FIFO_CNTL_TFFH;
+
+ for (j = (current_size % MAX_WR_DATA_LEN); j > 0; j--) {
+ current_dat <<= 8;
+ current_dat |= *(buf + j - 1);
+ }
+
+ QSPI->WR_FIFO = current_dat;
+ QSPI->BYTE_NUM = ((current_size % MAX_WR_DATA_LEN)) << 16;
+
+ if (QSPI_WriteEnable(sCommand.BusMode) != QSPI_STATUS_OK) {
+ return QSPI_STATUS_ERROR;
+ }
+
+ MH_QSPI_Command(&sCommand, MH_QSPI_TIMEOUT_DEFAULT_CNT);
+ while (QSPI_IsBusy(sCommand.BusMode));
+
+ buf += (current_size % MAX_WR_DATA_LEN);
+ sCommand.Address = (current_addr + current_size % MAX_WR_DATA_LEN);
+ }
+
+ loop_addr += current_size;
+ current_addr = loop_addr;
+ current_size = ((loop_addr + X25Q_PAGE_SIZE) > end_addr) ? (end_addr - loop_addr) : X25Q_PAGE_SIZE;
+ } while (loop_addr < end_addr);
+
+ return QSPI_STATUS_OK;
+}
+
+
+#define MAX_RD_DMA_DATA_LEN 0x100
+#define MAX_WR_DMA_DATA_LEN 0x100
+
+static QSPI_StatusTypeDef QSPI_DMA_Configuration(DMA_TypeDef *DMA_Channelx, DMA_InitTypeDef *DMA_InitStruct)
+{
+ DMA_InitStruct->DMA_DIR = DMA_DIR_Memory_To_Peripheral;
+ DMA_InitStruct->DMA_Peripheral = (uint32_t)(QSPI);
+ DMA_InitStruct->DMA_PeripheralBaseAddr = (uint32_t) & (QSPI->WR_FIFO);
+ DMA_InitStruct->DMA_PeripheralInc = DMA_Inc_Nochange;
+ DMA_InitStruct->DMA_PeripheralDataSize = DMA_DataSize_Word;
+ DMA_InitStruct->DMA_PeripheralBurstSize = DMA_BurstSize_4;
+
+ DMA_InitStruct->DMA_MemoryInc = DMA_Inc_Increment;
+ DMA_InitStruct->DMA_MemoryDataSize = DMA_DataSize_Word;
+ DMA_InitStruct->DMA_MemoryBurstSize = DMA_BurstSize_4;
+ DMA_InitStruct->DMA_BlockSize = MAX_WR_DMA_DATA_LEN >> 2;
+ DMA_InitStruct->DMA_PeripheralHandShake = DMA_PeripheralHandShake_Hardware;
+
+ if (DMA_Channelx == DMA_Channel_0) {
+ SYSCTRL->DMA_CHAN = (SYSCTRL->DMA_CHAN & ~0x1F) | 0x1A;
+ } else if (DMA_Channelx == DMA_Channel_1) {
+ SYSCTRL->DMA_CHAN = (SYSCTRL->DMA_CHAN & ~(0x1F << 8)) | (0x1A << 8);
+ } else if (DMA_Channelx == DMA_Channel_2) {
+ SYSCTRL->DMA_CHAN = (SYSCTRL->DMA_CHAN & ~(0x1F << 16)) | (0x1A << 16);
+ } else if (DMA_Channelx == DMA_Channel_3) {
+ SYSCTRL->DMA_CHAN = (SYSCTRL->DMA_CHAN & ~(0x1F << 24)) | (0x1A << 24);
+ } else if (DMA_Channelx == DMA_Channel_5) {
+ SYSCTRL->DMA_CHAN1 = (SYSCTRL->DMA_CHAN1 & ~(0x1F << 8)) | (0x1A << 8);
+ } else if (DMA_Channelx == DMA_Channel_6) {
+ SYSCTRL->DMA_CHAN1 = (SYSCTRL->DMA_CHAN1 & ~(0x1F << 16)) | (0x1A << 16);
+ } else if (DMA_Channelx == DMA_Channel_7) {
+ SYSCTRL->DMA_CHAN1 = (SYSCTRL->DMA_CHAN1 & ~(0x1F << 24)) | (0x1A << 24);
+ } else {
+ return QSPI_STATUS_NOT_SUPPORTED;
+ }
+
+ return QSPI_STATUS_OK;
+}
+
+#if(ENABLE_CACHE_AES)
+
+#define DEBUG_AES 0
+static uint8_t buf_aes_enc(uint8_t *cp_buf, uint32_t sz, uint8_t *sup_buf)
+{
+ AES128_CBC_ctx aesCtx;
+ uint32_t i, k;
+ int32_t j;
+ uint8_t key128[16] = {0};
+ uint8_t iv[16] = {0};
+ uint8_t cipher[32];
+ uint8_t plain[32];
+
+ SYSCTRL_AHBPeriphClockCmd(SYSCTRL_AHBPeriph_OTP, ENABLE);
+ memcpy(key128, (uint32_t *)(0x40009128), 16);
+ memcpy(iv, (uint32_t *)(0x40009138), 16);
+
+ memset(cipher, 0, sizeof(cipher));
+ memset(plain, 0, sizeof(plain));
+
+ for (i = 0; i < sz / 32; i ++) {
+ //memcpy(plain, cp_buf + i * 32, 32);
+ k = 0;
+ for (j = 15; j >= 0; j --) {
+ plain[k] = cp_buf[ i * 32 + j];
+ plain[k + 16] = cp_buf[i * 32 + 16 + j];
+ k += 1;
+ }
+ AES128_CBC_init(&aesCtx, key128, iv);
+ AES128_CBC_encrypt(&aesCtx, 2, cipher, plain);
+
+ k = 0;
+ for (j = 15; j >= 0; j --) {
+ sup_buf[i * 32 + j] = cipher[k];
+ sup_buf[i * 32 + 16 + j] = cipher[k + 16];
+ k += 1;
+ }
+ }
+ return 0;
+}
+#endif
+
+uint8_t QSPI_SoftWareReset(QSPI_BusModeTypeDef BusMode)
+{
+ MH_CommandTypeDef sCommand = {0};;
+
+ sCommand.Instruction = RESET_ENABLE_CMD;
+ sCommand.BusMode = BusMode;
+ sCommand.CmdFormat = QSPI_CMDFORMAT_CMD8;
+
+ if (MH_QSPI_Command(&sCommand, MH_QSPI_TIMEOUT_DEFAULT_CNT) != MH_OK) {
+ return QSPI_STATUS_ERROR;
+ }
+
+ sCommand.Instruction = RESET_MEMORY_CMD;
+ sCommand.BusMode = BusMode;
+ sCommand.CmdFormat = QSPI_CMDFORMAT_CMD8;
+
+ if (MH_QSPI_Command(&sCommand, MH_QSPI_TIMEOUT_DEFAULT_CNT) != MH_OK) {
+ return QSPI_STATUS_ERROR;
+ }
+
+ delay_40ms();
+
+ return QSPI_STATUS_OK;
+}
+
+uint8_t QSPI_SingleCommand(QSPI_CommandTypeDef *cmdParam)
+{
+ MH_CommandTypeDef sCommand = {0};
+
+ sCommand.Instruction = cmdParam->Instruction;
+ sCommand.BusMode = cmdParam->BusMode;
+ sCommand.CmdFormat = cmdParam->CmdFormat;
+
+ if (MH_QSPI_Command(&sCommand, MH_QSPI_TIMEOUT_DEFAULT_CNT) != MH_OK) {
+ return QSPI_STATUS_ERROR;
+ }
+
+ return QSPI_STATUS_OK;
+}
+
+uint8_t QSPI_DeepPowerDown(QSPI_CommandTypeDef *cmdParam)
+{
+ MH_CommandTypeDef sCommand = {0};
+
+ while (CACHE->CACHE_AES_CS & CACHE_IS_BUSY);
+
+ if (NULL == cmdParam) {
+ sCommand.Instruction = DEEP_POWER_DOWN;
+ sCommand.BusMode = QSPI_BUSMODE_111;
+ sCommand.CmdFormat = QSPI_CMDFORMAT_CMD8;
+ } else {
+ sCommand.Instruction = cmdParam->Instruction;
+ sCommand.BusMode = cmdParam->BusMode;
+ sCommand.CmdFormat = cmdParam->CmdFormat;
+ }
+ if (MH_QSPI_Command(&sCommand, MH_QSPI_TIMEOUT_DEFAULT_CNT) != MH_OK) {
+ return QSPI_STATUS_ERROR;
+ }
+ return QSPI_STATUS_OK;
+}
+
+uint8_t QSPI_ReleaseDeepPowerDown(QSPI_CommandTypeDef *cmdParam)
+{
+ MH_CommandTypeDef sCommand = {0};
+ uint32_t clock_delay;
+
+ while (CACHE->CACHE_AES_CS & CACHE_IS_BUSY);
+
+ if (NULL == cmdParam) {
+ sCommand.Instruction = RELEASE_FROM_DEEP_POWER_DOWN;
+ sCommand.BusMode = QSPI_BUSMODE_111;
+ sCommand.CmdFormat = QSPI_CMDFORMAT_CMD8;
+ } else {
+ sCommand.Instruction = cmdParam->Instruction;
+ sCommand.BusMode = cmdParam->BusMode;
+ sCommand.CmdFormat = cmdParam->CmdFormat;
+ }
+ if (MH_QSPI_Command(&sCommand, MH_QSPI_TIMEOUT_DEFAULT_CNT) != MH_OK) {
+ return QSPI_STATUS_ERROR;
+ }
+
+ //防止唤醒期间CACHE访问FLASH导致死机
+ //延时30us
+ for (clock_delay = 0; clock_delay < (SYSCTRL->HCLK_1MS_VAL * 3 / 1000); clock_delay += 4);
+
+ return QSPI_STATUS_OK;
+}
+
+uint32_t QSPI_ReadID(QSPI_CommandTypeDef *cmdParam)
+{
+ MH_CommandTypeDef sCommand = {0};
+
+ while (CACHE->CACHE_AES_CS & CACHE_IS_BUSY);
+ if (cmdParam == NULL) {
+ sCommand.Instruction = READ_JEDEC_ID_CMD;
+ sCommand.BusMode = QSPI_BUSMODE_111;
+ sCommand.CmdFormat = QSPI_CMDFORMAT_CMD8_RREG24;
+ } else {
+ sCommand.Instruction = cmdParam->Instruction;
+ sCommand.BusMode = cmdParam->BusMode;
+ sCommand.CmdFormat = cmdParam->CmdFormat;
+ }
+
+ if (MH_QSPI_Command(&sCommand, MH_QSPI_TIMEOUT_DEFAULT_CNT) != MH_OK) {
+ return QSPI_STATUS_ERROR;
+ }
+
+ return (sCommand.RdData & 0x00FFFFFF);
+}
+
+uint16_t QSPI_StatusReg(QSPI_CommandTypeDef *cmdParam)
+{
+ MH_CommandTypeDef sCommand = {0};
+
+ assert_param(IS_PARAM_NOTNULL(cmdParam));
+
+ while (CACHE->CACHE_AES_CS & CACHE_IS_BUSY);
+ sCommand.Instruction = cmdParam->Instruction;
+ sCommand.BusMode = cmdParam->BusMode;
+ sCommand.CmdFormat = cmdParam->CmdFormat;
+
+ if (MH_QSPI_Command(&sCommand, MH_QSPI_TIMEOUT_DEFAULT_CNT) != MH_OK) {
+ return QSPI_STATUS_ERROR;
+ }
+
+ return (sCommand.RdData & 0x0000FFFF);
+}
+
+uint8_t QSPI_WriteParam(QSPI_CommandTypeDef *cmdParam, uint16_t wrData)
+{
+ MH_CommandTypeDef sCommand = {0};
+
+ assert_param(IS_PARAM_NOTNULL(cmdParam));
+
+ while (CACHE->CACHE_AES_CS & CACHE_IS_BUSY);
+ sCommand.Instruction = cmdParam->Instruction;
+ sCommand.BusMode = cmdParam->BusMode;
+ sCommand.CmdFormat = cmdParam->CmdFormat;
+ sCommand.WrData = wrData;
+
+ if (QSPI_WriteEnable(sCommand.BusMode) != QSPI_STATUS_OK) {
+ return QSPI_STATUS_ERROR;
+ }
+
+ if (MH_QSPI_Command(&sCommand, MH_QSPI_TIMEOUT_DEFAULT_CNT) != MH_OK) {
+ return QSPI_STATUS_ERROR;
+ }
+ while (QSPI_IsBusy(sCommand.BusMode));
+
+ return QSPI_STATUS_OK;
+}
+
+uint8_t QSPI_EraseSector(QSPI_CommandTypeDef *cmdParam, uint32_t SectorAddress)
+{
+ MH_CommandTypeDef sCommand = {0};
+ SectorAddress &= (uint32_t)(0x00FFFFFF);
+
+ assert_param(IS_QSPI_ADDR(SectorAddress));
+ while (CACHE->CACHE_AES_CS & CACHE_IS_BUSY);
+
+ if (cmdParam == NULL) {
+ sCommand.Instruction = SECTOR_ERASE_CMD;
+ sCommand.BusMode = QSPI_BUSMODE_111;
+ sCommand.CmdFormat = QSPI_CMDFORMAT_CMD8_ADDR24;
+ } else {
+ sCommand.Instruction = cmdParam->Instruction;
+ sCommand.BusMode = cmdParam->BusMode;
+ sCommand.CmdFormat = cmdParam->CmdFormat;
+ }
+
+ sCommand.Address = SectorAddress;
+
+ if (QSPI_WriteEnable(sCommand.BusMode) != QSPI_STATUS_OK) {
+ return QSPI_STATUS_ERROR;
+ }
+
+ if (MH_QSPI_Command(&sCommand, MH_QSPI_TIMEOUT_DEFAULT_CNT) != MH_OK) {
+ return QSPI_STATUS_ERROR;
+ }
+
+ while (QSPI_IsBusy(sCommand.BusMode));
+
+ return QSPI_STATUS_OK;
+}
+
+uint8_t QSPI_EraseChip(QSPI_CommandTypeDef *cmdParam)
+{
+ MH_CommandTypeDef sCommand = {0};
+ while (CACHE->CACHE_AES_CS & CACHE_IS_BUSY);
+
+ if (cmdParam == NULL) {
+ sCommand.Instruction = CHIP_ERASE_CMD;
+ sCommand.BusMode = QSPI_BUSMODE_111;
+ sCommand.CmdFormat = QSPI_CMDFORMAT_CMD8;
+ } else {
+ sCommand.Instruction = cmdParam->Instruction;
+ sCommand.BusMode = cmdParam->BusMode;
+ sCommand.CmdFormat = cmdParam->CmdFormat;
+ }
+
+ while (QSPI_IsBusy(sCommand.BusMode));
+
+ if (QSPI_WriteEnable(sCommand.BusMode) != QSPI_STATUS_OK) {
+ return QSPI_STATUS_ERROR;
+ }
+
+ if ((MH_QSPI_Command(&sCommand, MH_QSPI_TIMEOUT_DEFAULT_CNT)) != MH_OK) {
+ return QSPI_STATUS_ERROR;
+ }
+
+ while (QSPI_IsBusy(sCommand.BusMode));
+
+ return QSPI_STATUS_OK;
+}
+
+uint8_t QSPI_ProgramPage(QSPI_CommandTypeDef *cmdParam, DMA_TypeDef *DMA_Channelx, uint32_t adr, uint32_t sz, uint8_t *buf)
+{
+ uint32_t i;
+ uint32_t end_addr, current_size, current_addr = 0, loop_addr;
+ DMA_InitTypeDef DMA_InitStruct;
+ MH_CommandTypeDef sCommand = {0};
+
+ while (CACHE->CACHE_AES_CS & CACHE_IS_BUSY);
+
+ if (DMA_Channelx == NULL) {
+ return QSPI_ProgramPage_Ex(cmdParam, adr, sz, buf);
+ }
+
+ adr &= (uint32_t)(0x00FFFFFF);
+ assert_param(IS_QSPI_ADDR(adr));
+ assert_param(IS_QSPI_ADDR_ADD_SZ(adr, sz));
+
+ while (current_addr <= adr) {
+ current_addr += X25Q_PAGE_SIZE;
+ }
+ current_size = current_addr - adr;
+
+ /* Check if the size of the data is less than the remaining place in the page */
+ if (current_size > sz) {
+ current_size = sz;
+ }
+
+ /* Initialize the adress variables */
+ current_addr = adr;
+ loop_addr = adr;
+ end_addr = adr + sz;
+
+ if (cmdParam == NULL) {
+ sCommand.Instruction = QUAD_INPUT_PAGE_PROG_CMD;
+ sCommand.BusMode = QSPI_BUSMODE_114;
+ sCommand.CmdFormat = QSPI_CMDFORMAT_CMD8_ADDR24_PDAT;
+ } else {
+ sCommand.Instruction = cmdParam->Instruction;
+ sCommand.BusMode = cmdParam->BusMode;
+ sCommand.CmdFormat = cmdParam->CmdFormat;
+ }
+
+ if (QSPI_DMA_Configuration(DMA_Channelx, &DMA_InitStruct) != QSPI_STATUS_OK) {
+ return QSPI_STATUS_ERROR;
+ }
+
+ do {
+ for (i = 0; i < (current_size / MAX_WR_DMA_DATA_LEN); i++) {
+ sCommand.Address = current_addr;
+ QSPI->BYTE_NUM = MAX_WR_DMA_DATA_LEN << 16;
+ QSPI->FIFO_CNTL |= QUADSPI_FIFO_CNTL_TFFH;
+
+ DMA_InitStruct.DMA_BlockSize = (MAX_WR_DMA_DATA_LEN / 4);
+ DMA_InitStruct.DMA_MemoryBaseAddr = (uint32_t)buf;
+ DMA_Init(DMA_Channelx, &DMA_InitStruct);
+
+ //Enable DMA
+ DMA_ChannelCmd(DMA_Channelx, ENABLE);
+ QSPI->DMA_CNTL |= QUADSPI_DMA_CNTL_TX_EN;
+
+ if (QSPI_WriteEnable(sCommand.BusMode) != QSPI_STATUS_OK) {
+ return QSPI_STATUS_ERROR;
+ }
+
+ if (MH_QSPI_Command(&sCommand, MH_QSPI_TIMEOUT_DEFAULT_CNT) != MH_OK) {
+ return QSPI_STATUS_ERROR;
+ }
+
+ while (QSPI_IsBusy(sCommand.BusMode));
+
+ QSPI->DMA_CNTL &= ~QUADSPI_DMA_CNTL_TX_EN;
+ DMA_ChannelCmd(DMA_Channelx, DISABLE);
+
+ buf += MAX_WR_DMA_DATA_LEN;
+ current_addr += MAX_WR_DMA_DATA_LEN;
+ sCommand.Address = current_addr;
+
+ }
+ if (current_size % MAX_WR_DMA_DATA_LEN > 0) {
+ QSPI->FIFO_CNTL |= QUADSPI_FIFO_CNTL_TFFH;
+ sCommand.Address = current_addr;
+ QSPI->BYTE_NUM = (current_size % MAX_WR_DMA_DATA_LEN) << 16;
+
+ DMA_InitStruct.DMA_BlockSize = (current_size % MAX_WR_DMA_DATA_LEN) >> 2;
+ DMA_InitStruct.DMA_MemoryBaseAddr = (uint32_t)buf;
+ DMA_Init(DMA_Channelx, &DMA_InitStruct);
+
+ DMA_ChannelCmd(DMA_Channelx, ENABLE);
+ QSPI->DMA_CNTL |= QUADSPI_DMA_CNTL_TX_EN;
+
+ if (QSPI_WriteEnable(sCommand.BusMode) != QSPI_STATUS_OK) {
+ return QSPI_STATUS_ERROR;
+ }
+
+ if (MH_QSPI_Command(&sCommand, MH_QSPI_TIMEOUT_DEFAULT_CNT) != MH_OK) {
+ return QSPI_STATUS_ERROR;
+ }
+
+ while (QSPI_IsBusy(sCommand.BusMode));
+
+ QSPI->DMA_CNTL &= ~QUADSPI_DMA_CNTL_TX_EN;
+ buf += current_size % MAX_WR_DMA_DATA_LEN;
+ }
+
+ loop_addr += current_size;
+ current_addr = loop_addr;
+
+ current_size = ((loop_addr + X25Q_PAGE_SIZE) > end_addr) ? (end_addr - loop_addr) : X25Q_PAGE_SIZE;
+ } while (loop_addr < end_addr);
+
+ //disable DMA
+ DMA_ChannelCmd(DMA_Channelx, DISABLE);
+ return QSPI_STATUS_OK;
+}
+
+#if(ENABLE_CACHE_AES)
+uint8_t QSPI_ProgramPage_ByAES(QSPI_CommandTypeDef *cmdParam, DMA_TypeDef *DMA_Channelx, uint32_t adr, uint32_t sz, uint8_t *buf)
+{
+
+ uint32_t i;
+ uint32_t end_addr, current_size, current_addr = 0, loop_addr;
+ DMA_InitTypeDef DMA_InitStruct;
+ uint8_t mplain[32];
+ MH_CommandTypeDef sCommand;
+
+ while (CACHE->CACHE_AES_CS & CACHE_IS_BUSY);
+
+ adr &= (uint32_t)(0x00FFFFFF);
+
+ assert_param(IS_QSPI_ADDR(adr));
+ assert_param(IS_QSPI_ADDR_ADD_SZ(adr, sz));
+
+ if (DMA_Channelx == NULL) {
+ DMA_Channelx = DMA_Channel_0;
+ }
+
+ while (current_addr <= adr) {
+ current_addr += X25Q_PAGE_SIZE;
+ }
+ current_size = current_addr - adr;
+
+ /* Check if the size of the data is less than the remaining place in the page */
+ if (current_size > sz) {
+ current_size = sz;
+ }
+
+ /* Initialize the adress variables */
+ current_addr = adr;
+ loop_addr = adr;
+ end_addr = adr + sz;
+
+ buf_aes_enc((uint8_t*)(buf), sz, (uint8_t *)mplain);
+ if (QSPI_DMA_Configuration(DMA_Channelx, &DMA_InitStruct) != QSPI_STATUS_OK) {
+ return QSPI_STATUS_ERROR;
+ }
+
+ if (cmdParam == NULL) {
+ sCommand.Instruction = QUAD_INPUT_PAGE_PROG_CMD;
+ sCommand.BusMode = QSPI_BUSMODE_114;
+ sCommand.CmdFormat = QSPI_CMDFORMAT_CMD8_ADDR24_PDAT;
+ } else {
+ sCommand.Instruction = cmdParam->Instruction;
+ sCommand.BusMode = cmdParam->BusMode;
+ sCommand.CmdFormat = cmdParam->CmdFormat;
+ }
+
+ do {
+ for (i = 0; i < (current_size / MAX_WR_DMA_DATA_LEN); i++) {
+ sCommand.Address = current_addr;
+ QSPI->BYTE_NUM = MAX_WR_DMA_DATA_LEN << 16;
+ QSPI->FIFO_CNTL |= QUADSPI_FIFO_CNTL_TFFH;
+
+ DMA_InitStruct.DMA_BlockSize = (MAX_WR_DMA_DATA_LEN / 4);
+ DMA_InitStruct.DMA_MemoryBaseAddr = (uint32_t)buf;
+ DMA_Init(DMA_Channelx, &DMA_InitStruct);
+
+ //Enable DMA
+ DMA_ChannelCmd(DMA_Channelx, ENABLE);
+ QSPI->DMA_CNTL |= QUADSPI_DMA_CNTL_TX_EN;
+
+ if (QSPI_WriteEnable(sCommand.BusMode) != QSPI_STATUS_OK) {
+ return QSPI_STATUS_ERROR;
+ }
+
+ if (MH_QSPI_Command(&sCommand, MH_QSPI_TIMEOUT_DEFAULT_CNT) != MH_OK) {
+ return QSPI_STATUS_ERROR;
+ }
+
+ while (QSPI_IsBusy(sCommand.BusMode));
+
+ QSPI->DMA_CNTL &= ~QUADSPI_DMA_CNTL_TX_EN;
+ DMA_ChannelCmd(DMA_Channelx, DISABLE);
+
+ buf += MAX_WR_DMA_DATA_LEN;
+ current_addr += MAX_WR_DMA_DATA_LEN;
+ sCommand.Address = current_addr;
+ }
+
+ if (current_size % MAX_WR_DMA_DATA_LEN > 0) {
+ uint8_t cnt_aes_div, cnt_aes_rem;
+ cnt_aes_rem = current_size % 32;
+ cnt_aes_div = current_size / 32;
+
+ if (cnt_aes_div) {
+ QSPI->FIFO_CNTL |= QUADSPI_FIFO_CNTL_TFFH;
+ sCommand.Address = current_addr;
+ QSPI->BYTE_NUM = ((cnt_aes_div * 32)) << 16;
+
+ DMA_InitStruct.DMA_BlockSize = (cnt_aes_div * 32);
+ DMA_InitStruct.DMA_MemoryBaseAddr = (uint32_t)buf;
+ DMA_Init(DMA_Channelx, &DMA_InitStruct);
+
+ DMA_ChannelCmd(DMA_Channelx, ENABLE);
+ QSPI->DMA_CNTL |= QUADSPI_DMA_CNTL_TX_EN;
+
+ if (QSPI_WriteEnable(sCommand.BusMode) != QSPI_STATUS_OK) {
+ return QSPI_STATUS_ERROR;
+ }
+
+ if (MH_QSPI_Command(&sCommand, MH_QSPI_TIMEOUT_DEFAULT_CNT) != MH_OK) {
+ return QSPI_STATUS_ERROR;
+ }
+ while (QSPI_IsBusy(sCommand.BusMode));
+
+ QSPI->DMA_CNTL &= ~QUADSPI_DMA_CNTL_TX_EN;
+
+ buf += cnt_aes_div * 32;
+ current_addr += (cnt_aes_div * 32);
+ QSPI->ADDRES = current_addr << 8;
+ }
+ if (cnt_aes_rem) {
+ QSPI->FIFO_CNTL |= QUADSPI_FIFO_CNTL_TFFH;
+ sCommand.Address = current_addr;
+ QSPI->BYTE_NUM = 32 << 16;
+
+ DMA_InitStruct.DMA_BlockSize = 32;
+ DMA_InitStruct.DMA_MemoryBaseAddr = (uint32_t)mplain;
+ DMA_Init(DMA_Channelx, &DMA_InitStruct);
+
+ DMA_ChannelCmd(DMA_Channelx, ENABLE);
+
+ QSPI->DMA_CNTL |= QUADSPI_DMA_CNTL_TX_EN;
+ if (QSPI_WriteEnable(sCommand.BusMode) != QSPI_STATUS_OK) {
+ return QSPI_STATUS_ERROR;
+ }
+
+ if (MH_QSPI_Command(&sCommand, MH_QSPI_TIMEOUT_DEFAULT_CNT) != MH_OK) {
+ return QSPI_STATUS_ERROR;
+ }
+ while (QSPI_IsBusy(sCommand.BusMode));
+
+ QSPI->DMA_CNTL &= ~QUADSPI_DMA_CNTL_TX_EN;
+ }
+ }
+
+ loop_addr += current_size;
+ current_addr = loop_addr;
+
+ current_size = ((loop_addr + X25Q_PAGE_SIZE) > end_addr) ? (end_addr - loop_addr) : X25Q_PAGE_SIZE;
+ } while (loop_addr < end_addr);
+
+ //disable DMA
+ DMA_ChannelCmd(DMA_Channelx, DISABLE);
+ return QSPI_STATUS_OK;
+}
+#endif
+
+void QSPI_Init(QSPI_InitTypeDef *mhqspi)
+{
+ if (mhqspi == NULL) {
+ QSPI->DEVICE_PARA = (QSPI->DEVICE_PARA & ~0xFF) | 0x6B;
+ } else {
+ QSPI->CACHE_INTF_CMD = (uint32_t)((mhqspi->Cache_Cmd_ReleaseDeepInstruction << 24)
+ | (mhqspi->Cache_Cmd_DeepInstruction << 16)
+ | ((mhqspi->Cache_Cmd_ReadBusMode & 0x03) << 12)
+ | ((mhqspi->Cache_Cmd_ReadFormat & 0x0F) << 8) | (mhqspi->Cache_Cmd_ReadInstruction));
+
+ QSPI->DEVICE_PARA = (uint32_t)((QSPI->DEVICE_PARA & ~0xFFFF)
+ | (((mhqspi->SampleDly & 0x01) << 15)
+ | ((mhqspi->SamplePha & 0x01) << 14)
+ | ((mhqspi->ProToCol & 0x03) << 8)
+ | ((mhqspi->DummyCycles & 0x0F) << 4)
+ | ((mhqspi->FreqSel & 0x03)) | QSPI_DEVICE_PARA_FLASH_READY_Mask));
+ }
+}
+
+/**
+ * @brief Sets the QSPI latency value.
+ * @param u32UsClk: specifies the QSPI Latency value.
+ * @retval None
+ */
+void QSPI_SetLatency(uint32_t u32UsClk)
+{
+ SYSCTRL_ClocksTypeDef clocks;
+
+ if (0 == u32UsClk) {
+ SYSCTRL_GetClocksFreq(&clocks);
+ QSPI->DEVICE_PARA = (QSPI->DEVICE_PARA & 0xFFFF) | ((clocks.CPU_Frequency * 2 / 1000000) << 16);
+ } else {
+ QSPI->DEVICE_PARA = (QSPI->DEVICE_PARA & 0xFFFF) | (u32UsClk << 16);
+ }
+}
+
+/**
+ * @brief Flash Erase Sector.
+ * @param sectorAddress: The sector address to be erased
+ * @retval FLASH Status: The returned value can be: QSPI_STATUS_ERROR, QSPI_STATUS_OK
+ */
+uint8_t FLASH_EraseSector(uint32_t sectorAddress)
+{
+ uint8_t ret;
+
+ // __disable_irq();
+ // __disable_fault_irq();
+
+ ret = ROM_QSPI_EraseSector(NULL, sectorAddress);
+
+ // __enable_fault_irq();
+ // __enable_irq();
+
+ return ret;
+}
+
+/**
+ * @brief Flash Program Interface.
+ * @param cmdParam: pointer to a QSPI_CommandTypeDef structure that contains the configuration information.
+ * @param DMA_Channelx: DMA_Channel_0
+ * @param addr: specifies the address to be programmed.
+ * @param size: specifies the size to be programmed.
+ * @param buffer: pointer to the data to be programmed, need word aligned
+ * @retval FLASH Status: The returned value can be: QSPI_STATUS_ERROR, QSPI_STATUS_OK
+ */
+uint8_t FLASH_ProgramPage(QSPI_CommandTypeDef *cmdParam, DMA_TypeDef *DMA_Channelx, uint32_t addr, uint32_t size, uint8_t *buffer)
+{
+ uint8_t ret;
+
+ __disable_irq();
+ __disable_fault_irq();
+
+ ret = ROM_QSPI_ProgramPage(cmdParam, DMA_Channelx, addr, size, buffer);
+
+ __enable_fault_irq();
+ __enable_irq();
+
+ return ret;
+}
+
+/**
+ * @brief Enable or Disable QSPI's Interrupt.
+ * @param QSPI_IT: specify the Interrupt
+ * This parameter can be one of the following values:
+ * @arg QSPI_IT_TX_FIFO_DATA
+ * @arg QSPI_IT_RX_FIFO_DATA
+ * @arg QSPI_IT_TX_FIFO_OF
+ * @arg QSPI_IT_TX_FIFO_UF
+ * @arg QSPI_IT_RX_FIFO_OF
+ * @arg QSPI_IT_RX_FIFO_UF
+ * @arg QSPI_IT_DONE_INT
+ * @param NewState: new state of Interrupt
+ * This parameter can be: ENABLE or DISABLE.
+ * @retval None
+ */
+void QSPI_ITConfig(uint32_t QSPI_IT, FunctionalState NewState)
+{
+ if (NewState != DISABLE) {
+ QSPI->INT_UMASK |= QSPI_IT;
+ } else {
+ QSPI->INT_MASK |= QSPI_IT;
+ }
+}
+
+/**
+ * @brief Clear the QSPI's interrupt bits
+ * @param QSPI_IT: specify the Interrupt
+ * This parameter can be one of the following values:
+ * @arg QSPI_IT_TX_FIFO_DATA
+ * @arg QSPI_IT_RX_FIFO_DATA
+ * @arg QSPI_IT_TX_FIFO_OF
+ * @arg QSPI_IT_TX_FIFO_UF
+ * @arg QSPI_IT_RX_FIFO_OF
+ * @arg QSPI_IT_RX_FIFO_UF
+ * @arg QSPI_IT_DONE_INT
+ * @retval None
+ */
+void QSPI_ClearITPendingBit(uint32_t QSPI_IT)
+{
+ QSPI->INT_CLEAR |= QSPI_IT;
+}
+
+ITStatus QSPI_GetITStatus(uint32_t QSPI_IT)
+{
+ if ((QSPI->INT_STATUS & QSPI_IT) != RESET) {
+ return SET;
+ } else {
+ return RESET;
+ }
+}
+
+ITStatus QSPI_GetITRawStatus(uint32_t QSPI_IT)
+{
+ if ((QSPI->INT_RAWSTATUS & QSPI_IT) != RESET) {
+ return SET;
+ } else {
+ return RESET;
+ }
+}
+
+
+void QSPI_TxFIFOFlush(void)
+{
+ QSPI->FIFO_CNTL |= QUADSPI_FIFO_CNTL_TFFH;
+}
+
+FlagStatus QSPI_TxFIFOEmpty(void)
+{
+ if (QSPI->FIFO_CNTL & QUADSPI_FIFO_CNTL_TFE) {
+ return SET;
+ } else {
+ return RESET;
+ }
+}
+
+FlagStatus QSPI_TxFIFOFull(void)
+{
+ if (QSPI->FIFO_CNTL & QUADSPI_FIFO_CNTL_TFFL) {
+ return SET;
+ } else {
+ return RESET;
+ }
+}
+
+uint8_t QSPI_TxFIFOLevel(void)
+{
+ return ((QSPI->FIFO_CNTL >> 16) & 0xF);
+}
+
+void QSPI_RxFIFOFlush(void)
+{
+ QSPI->FIFO_CNTL |= QUADSPI_FIFO_CNTL_RFFH;
+}
+
+
+FlagStatus QSPI_RxFIFOEmpty(void)
+{
+ if (QSPI->FIFO_CNTL & QUADSPI_FIFO_CNTL_RFE) {
+ return SET;
+ } else {
+ return RESET;
+ }
+}
+
+FlagStatus QSPI_RxFIFOFull(void)
+{
+ if (QSPI->FIFO_CNTL & QUADSPI_FIFO_CNTL_RFFL) {
+ return SET;
+ } else {
+ return RESET;
+ }
+}
+
+uint8_t QSPI_RxFIFOLevel(void)
+{
+ return ((QSPI->FIFO_CNTL) & 0xF);
+}
+
+uint32_t QSPI_ReadRxFIFO(void)
+{
+ return QSPI->RD_FIFO;
+}
+
+void QSPI_WriteTxFIFO(uint32_t data)
+{
+ QSPI->WR_FIFO = data;
+}
+
+uint8_t g_plainBuff[4096];
+uint8_t AES_Program(QSPI_CommandTypeDef *cmdParam, DMA_TypeDef *DMA_Channelx, uint32_t addr, uint32_t size, uint8_t *buffer)
+{
+ ASSERT((addr % 4096) == 0);
+ if (EncryptedFlash()) {
+ buf_aes_enc(buffer, 4096, (uint8_t *)g_plainBuff);
+#ifdef __GNUC__
+ return QSPI_ProgramPage(cmdParam, DMA_Channelx, addr, size, (uint8_t *)g_plainBuff);
+#else
+ return FLASH_ProgramPage(cmdParam, DMA_Channelx, addr, size, (uint8_t *)g_plainBuff);
+#endif
+ } else {
+#ifdef __GNUC__
+ return QSPI_ProgramPage(cmdParam, DMA_Channelx, addr, size, (uint8_t *)buffer);
+#else
+ return FLASH_ProgramPage(cmdParam, DMA_Channelx, addr, size, (uint8_t *)buffer);
+#endif
+ }
+}
+
+static bool EncryptedFlash(void)
+{
+ static bool first = true;
+ static bool encrypt = false;
+ uint8_t key128[16], iv[16];
+
+ if (first) {
+ OTP_PowerOn();
+ first = false;
+ memcpy(key128, (uint32_t *)(0x40009128), 16);
+ memcpy(iv, (uint32_t *)(0x40009138), 16);
+ //PrintArray("key128", key128, 16);
+ //PrintArray("iv", iv, 16);
+ if (CheckAllFF(key128, 16) && CheckAllFF(iv, 16)) {
+ encrypt = false;
+ printf("non-encrypted device\n");
+ } else {
+ encrypt = true;
+ printf("encrypted device\n");
+ }
+ }
+
+ return encrypt;
+}
+
+/*********************** (C) COPYRIGHT Megahunt *****END OF FILE****/
+#endif
\ No newline at end of file
diff --git a/external/mh1903_lib/SCPU_USB_Lib/SCPU_USB_Device_Library/Class/cdc/src/usbd_cdc_core.c b/external/mh1903_lib/SCPU_USB_Lib/SCPU_USB_Device_Library/Class/cdc/src/usbd_cdc_core.c
index 41134ff..7322f11 100644
--- a/external/mh1903_lib/SCPU_USB_Lib/SCPU_USB_Device_Library/Class/cdc/src/usbd_cdc_core.c
+++ b/external/mh1903_lib/SCPU_USB_Lib/SCPU_USB_Device_Library/Class/cdc/src/usbd_cdc_core.c
@@ -16,6 +16,7 @@
#include "user_msg.h"
#include "drv_usb.h"
#include "user_delay.h"
+#include "data_parser_task.h"
/** @defgroup usbd_cdc
* @brief usbd core module
@@ -57,6 +58,8 @@ static uint8_t usbd_cdc_EP0_RxReady(void* pdev);
static uint8_t usbd_cdc_DataIn(void* pdev, uint8_t epnum);
static uint8_t usbd_cdc_DataOut(void* pdev, uint8_t epnum);
static uint8_t usbd_cdc_SOF(void* pdev);
+static uint8_t usbd_cdc_StallControl(void* pdev);
+static uint8_t* usbd_cdc_FindDescriptor(uint8_t descType, uint16_t *len);
static uint8_t* USBD_cdc_GetCfgDesc(uint8_t speed, uint16_t* length);
@@ -88,11 +91,12 @@ extern USB_OTG_CORE_HANDLE g_usbDev;
#define CDC_TX_MAX_LENGTH 1024
#define CDC_PACKET_SIZE 64
+#define CDC_LINE_CODING_LEN 7U
static uint8_t g_cdcSendBuffer[CDC_TX_MAX_LENGTH];
static uint32_t g_cdcSendIndex = 0;
-static uint32_t cdcCmd = 0xFF;
+static uint32_t cdcCmd = NO_CMD;
static uint32_t cdcLen = 0;
CDC_Data_TypeDef CDCData = {
@@ -290,28 +294,34 @@ static uint8_t usbd_cdc_Setup(void* pdev, USB_SETUP_REQ* req)
switch (req->bmRequest & USB_REQ_TYPE_MASK) {
/* CDC Class Requests -------------------------------*/
case USB_REQ_TYPE_CLASS:
- /* Check if the request is a data setup packet */
- if (req->wLength) {
- /* Check if the request is Device-to-Host */
- if (req->bmRequest & 0x80) {
- /* Get the data to be sent to Host from interface layer */
- APP_FOPS.pIf_Ctrl(req->bRequest, CmdBuff, req->wLength);
-
- /* Send the data to the host */
- USBD_CtlSendData(pdev, CmdBuff, req->wLength);
- } else { /* Host-to-Device requeset */
- /* Set the value of the current command to be processed */
- cdcCmd = req->bRequest;
- cdcLen = req->wLength;
-
- /* Prepare the reception of the buffer over EP0
- Next step: the received data will be managed in usbd_cdc_EP0_TxSent()
- function. */
- USBD_CtlPrepareRx(pdev, CmdBuff, req->wLength);
+ switch (req->bRequest) {
+ case GET_LINE_CODING:
+ if (((req->bmRequest & 0x80U) == 0U) || (req->wLength != CDC_LINE_CODING_LEN)) {
+ return usbd_cdc_StallControl(pdev);
+ }
+ APP_FOPS.pIf_Ctrl(GET_LINE_CODING, CmdBuff, CDC_LINE_CODING_LEN);
+ USBD_CtlSendData(pdev, CmdBuff, CDC_LINE_CODING_LEN);
+ break;
+
+ case SET_LINE_CODING:
+ if (((req->bmRequest & 0x80U) != 0U) || (req->wLength != CDC_LINE_CODING_LEN)) {
+ return usbd_cdc_StallControl(pdev);
+ }
+ cdcCmd = SET_LINE_CODING;
+ cdcLen = CDC_LINE_CODING_LEN;
+ USBD_CtlPrepareRx(pdev, CmdBuff, CDC_LINE_CODING_LEN);
+ break;
+
+ case SET_CONTROL_LINE_STATE:
+ case SEND_BREAK:
+ if (((req->bmRequest & 0x80U) != 0U) || (req->wLength != 0U)) {
+ return usbd_cdc_StallControl(pdev);
}
- } else { /* No Data request */
- /* Transfer the command to the interface layer */
APP_FOPS.pIf_Ctrl(req->bRequest, NULL, 0);
+ break;
+
+ default:
+ return usbd_cdc_StallControl(pdev);
}
return USBD_OK;
@@ -320,8 +330,13 @@ static uint8_t usbd_cdc_Setup(void* pdev, USB_SETUP_REQ* req)
switch (req->bRequest) {
case USB_REQ_GET_DESCRIPTOR:
if ((req->wValue >> 8) == CDC_DESCRIPTOR_TYPE) {
- pbuf = usbd_cdc_CfgDesc + 9 + (9 * USBD_ITF_MAX_NUM);
- len = MIN(USB_CDC_DESC_SIZ, req->wLength);
+ pbuf = usbd_cdc_FindDescriptor(CDC_DESCRIPTOR_TYPE, &len);
+ if (pbuf == NULL || len == 0U) {
+ return usbd_cdc_StallControl(pdev);
+ }
+ len = MIN(len, req->wLength);
+ } else {
+ return usbd_cdc_StallControl(pdev);
}
USBD_CtlSendData(pdev, pbuf, len);
@@ -337,9 +352,16 @@ static uint8_t usbd_cdc_Setup(void* pdev, USB_SETUP_REQ* req)
} else {
/* Call the error management function (command will be nacked */
USBD_CtlError(pdev, req);
+ return USBD_FAIL;
}
break;
+
+ default:
+ USBD_CtlError(pdev, req);
+ return USBD_FAIL;
}
+ return USBD_OK;
+
default:
USBD_CtlError(pdev, req);
return USBD_FAIL;
@@ -355,21 +377,37 @@ static uint8_t usbd_cdc_Setup(void* pdev, USB_SETUP_REQ* req)
static uint8_t usbd_cdc_EP0_RxReady(void* pdev)
{
USB_OTG_EP* ep = &((USB_OTG_CORE_HANDLE*)pdev)->dev.out_ep[0];
- if (ep->xfer_buff != CmdBuff)
+ if (cdcCmd == NO_CMD)
return USBD_OK;
- // Will fired when CDC Set Cmd request callback
- if (cdcCmd != NO_CMD) {
- /* Process the data */
- APP_FOPS.pIf_Ctrl(cdcCmd, CmdBuff, cdcLen);
-
- /* Reset the command variable to default value */
+ if ((((USB_OTG_CORE_HANDLE*)pdev)->dev.device_state != USB_OTG_EP0_DATA_OUT) ||
+ (cdcCmd != SET_LINE_CODING) ||
+ (cdcLen != CDC_LINE_CODING_LEN) ||
+ (ep->xfer_buff != CmdBuff) ||
+ (ep->xfer_len != cdcLen) ||
+ (ep->xfer_count != cdcLen)) {
cdcCmd = NO_CMD;
+ cdcLen = 0;
+ return usbd_cdc_StallControl(pdev);
}
+ APP_FOPS.pIf_Ctrl(cdcCmd, CmdBuff, cdcLen);
+ cdcCmd = NO_CMD;
+ cdcLen = 0;
+
return USBD_OK;
}
+static uint8_t usbd_cdc_StallControl(void* pdev)
+{
+ cdcCmd = NO_CMD;
+ cdcLen = 0;
+ DCD_EP_Stall(pdev, 0x80);
+ DCD_EP_Stall(pdev, 0x00);
+ USB_OTG_EP0_OutStart(pdev);
+ return USBD_FAIL;
+}
+
/**
* @brief usbd_audio_DataIn
* Data sent on non-control IN endpoint
@@ -393,16 +431,70 @@ static uint8_t usbd_cdc_DataIn(void* pdev, uint8_t epnum)
*/
static uint8_t usbd_cdc_DataOut(void* pdev, uint8_t epnum)
{
-void PushDataToField(uint8_t *data, uint16_t len);
- USB_OTG_EP* ep = &((USB_OTG_CORE_HANDLE*)pdev)->dev.out_ep[epnum];
+ uint8_t ep_idx = epnum & 0x7F;
+ if (ep_idx >= USB_OTG_MAX_EP_COUNT) {
+ return USBD_FAIL;
+ }
+ USB_OTG_EP* ep = &((USB_OTG_CORE_HANDLE*)pdev)->dev.out_ep[ep_idx];
uint16_t rxCount = ep->xfer_count;
PrintArray("WEBUSB rx", USB_Rx_Buffer, rxCount);
- PushDataToField(USB_Rx_Buffer, rxCount);
- PubValueMsg(SPRING_MSG_GET, rxCount);
+ if (rxCount != 0U) {
+ if (!CanPushDataToField(rxCount)) {
+ printf("WEBUSB RX drop: parser buffer full len=%u\n", rxCount);
+ DCD_EP_PrepareRx(pdev, CDC_OUT_EP, (uint8_t*)(USB_Rx_Buffer), CDC_DATA_OUT_PACKET_SIZE);
+ return USBD_OK;
+ }
+
+ if (PushDataToField(USB_Rx_Buffer, rxCount) != rxCount) {
+ printf("WEBUSB RX drop: push mismatch len=%u\n", rxCount);
+ ResetDataField();
+ DCD_EP_PrepareRx(pdev, CDC_OUT_EP, (uint8_t*)(USB_Rx_Buffer), CDC_DATA_OUT_PACKET_SIZE);
+ return USBD_OK;
+ }
+
+ if (PubValueMsg(SPRING_MSG_GET, rxCount) != MSG_SUCCESS) {
+ printf("WEBUSB RX drop: queue full len=%u\n", rxCount);
+ ResetDataField();
+ }
+ }
DCD_EP_PrepareRx(pdev, CDC_OUT_EP, (uint8_t*)(USB_Rx_Buffer), CDC_DATA_OUT_PACKET_SIZE);
return USBD_OK;
}
+static uint8_t* usbd_cdc_FindDescriptor(uint8_t descType, uint16_t *len)
+{
+ uint8_t *desc = NULL;
+ uint16_t totalLen = 0;
+ uint16_t idx = 0;
+
+ if (len == NULL) {
+ return NULL;
+ }
+ *len = 0;
+
+#ifdef USBD_ENABLE_MSC
+ desc = usbd_cdc_CfgDesc;
+ totalLen = sizeof(usbd_cdc_CfgDesc);
+#else
+ desc = USBD_CDC_CfgHSDesc;
+ totalLen = sizeof(USBD_CDC_CfgHSDesc);
+#endif
+
+ while ((idx + 1U) < totalLen) {
+ uint8_t blen = desc[idx];
+ if ((blen < 2U) || ((uint16_t)(idx + blen) > totalLen)) {
+ break;
+ }
+ if (desc[idx + 1U] == descType) {
+ *len = blen;
+ return &desc[idx];
+ }
+ idx = (uint16_t)(idx + blen);
+ }
+
+ return NULL;
+}
+
static uint8_t usbd_cdc_SOF(void* pdev)
{
return USBD_OK;
@@ -478,4 +570,3 @@ static void USBD_cdc_SendCallback(void)
{
printf("USBD_cdc_SendCallback usb send over\n");
}
-
diff --git a/external/mh1903_lib/SCPU_USB_Lib/SCPU_USB_Device_Library/Class/msc/src/usbd_msc_scsi.c b/external/mh1903_lib/SCPU_USB_Lib/SCPU_USB_Device_Library/Class/msc/src/usbd_msc_scsi.c
index e598f53..7d52816 100644
--- a/external/mh1903_lib/SCPU_USB_Lib/SCPU_USB_Device_Library/Class/msc/src/usbd_msc_scsi.c
+++ b/external/mh1903_lib/SCPU_USB_Lib/SCPU_USB_Device_Library/Class/msc/src/usbd_msc_scsi.c
@@ -12,9 +12,6 @@
#include "usbd_msc_mem.h"
#include "usbd_msc_data.h"
#include "stdio.h"
-#include "background_task.h"
-#include "user_fatfs.h"
-#include "fingerprint_task.h"
/** @defgroup MSC_SCSI
* @brief Mass storage SCSI layer module
@@ -98,8 +95,6 @@ static int8_t SCSI_ProcessWrite(uint8_t lun);
* @{
*/
-#define AUTO_REBOOT_AFTER_COPY_FILE
-
/**
* @brief SCSI_ProcessCmd
* Process SCSI commands
@@ -113,28 +108,6 @@ int8_t SCSI_ProcessCmd(USB_OTG_CORE_HANDLE *pdev,
uint8_t *params)
{
cdev = pdev;
-#ifdef AUTO_REBOOT_AFTER_COPY_FILE
- static uint8_t lastParam[2] = {0};
- //printf("%X\r\n", params[0]);
- if (params[0] == SCSI_TEST_UNIT_READY && lastParam[0] == SCSI_TEST_UNIT_READY && lastParam[1] == SCSI_WRITE10) {
- printf("file copy over\r\n");
- MountUsbFatfs();
- FIL fp;
- uint32_t fileSize;
- FRESULT res = f_open(&fp, "1:pillar.bin", FA_OPEN_EXISTING | FA_READ);
- if (res) {
- printf("open error\r\n");
- } else {
- fileSize = f_size(&fp);
- printf("file size=%d\r\n", fileSize);
- if (fileSize > 0) {
- SystemReboot();
- }
- }
- }
- lastParam[1] = lastParam[0];
- lastParam[0] = params[0];
-#endif
switch (params[0]) {
case SCSI_TEST_UNIT_READY:
return SCSI_TestUnitReady(lun, params);
@@ -447,13 +420,13 @@ static int8_t SCSI_Read10(uint8_t lun, uint8_t *params)
return -1;
}
- SCSI_blk_addr = (params[2] << 24) | \
- (params[3] << 16) | \
- (params[4] << 8) | \
- params[5];
+ SCSI_blk_addr = ((uint32_t)params[2] << 24) | \
+ ((uint32_t)params[3] << 16) | \
+ ((uint32_t)params[4] << 8) | \
+ (uint32_t)params[5];
- SCSI_blk_len = (params[7] << 8) | \
- params[8];
+ SCSI_blk_len = ((uint32_t)params[7] << 8) | \
+ (uint32_t)params[8];
@@ -516,12 +489,12 @@ static int8_t SCSI_Write10(uint8_t lun, uint8_t *params)
}
- SCSI_blk_addr = (params[2] << 24) | \
- (params[3] << 16) | \
- (params[4] << 8) | \
- params[5];
- SCSI_blk_len = (params[7] << 8) | \
- params[8];
+ SCSI_blk_addr = ((uint32_t)params[2] << 24) | \
+ ((uint32_t)params[3] << 16) | \
+ ((uint32_t)params[4] << 8) | \
+ (uint32_t)params[5];
+ SCSI_blk_len = ((uint32_t)params[7] << 8) | \
+ (uint32_t)params[8];
/* check if LBA address is in the right range */
if (SCSI_CheckAddressRange(lun, SCSI_blk_addr, SCSI_blk_len) < 0) {
@@ -567,12 +540,12 @@ static int8_t SCSI_Verify10(uint8_t lun, uint8_t *params)
return -1; /* Error, Verify Mode Not supported*/
}
- SCSI_blk_addr = (params[2] << 24) | \
- (params[3] << 16) | \
- (params[4] << 8) | \
- params[5];
- SCSI_blk_len = (params[7] << 8) | \
- params[8];
+ SCSI_blk_addr = ((uint32_t)params[2] << 24) | \
+ ((uint32_t)params[3] << 16) | \
+ ((uint32_t)params[4] << 8) | \
+ (uint32_t)params[5];
+ SCSI_blk_len = ((uint32_t)params[7] << 8) | \
+ (uint32_t)params[8];
if (SCSI_CheckAddressRange(lun, SCSI_blk_addr, SCSI_blk_len) < 0) {
return -1; /* error */
@@ -591,8 +564,7 @@ static int8_t SCSI_Verify10(uint8_t lun, uint8_t *params)
*/
static int8_t SCSI_CheckAddressRange(uint8_t lun, uint32_t blk_offset, uint16_t blk_nbr)
{
-
- if ((blk_offset + blk_nbr) > SCSI_blk_nbr) {
+ if ((blk_offset >= SCSI_blk_nbr) || (blk_nbr > (SCSI_blk_nbr - blk_offset))) {
SCSI_SenseCode(lun, ILLEGAL_REQUEST, ADDRESS_OUT_OF_RANGE);
return -1;
}
diff --git a/external/mh1903_lib/SCPU_USB_Lib/SCPU_USB_Device_Library/Core/inc/usbd_req.h b/external/mh1903_lib/SCPU_USB_Lib/SCPU_USB_Device_Library/Core/inc/usbd_req.h
index a07b1c6..d26c7c1 100644
--- a/external/mh1903_lib/SCPU_USB_Lib/SCPU_USB_Device_Library/Core/inc/usbd_req.h
+++ b/external/mh1903_lib/SCPU_USB_Lib/SCPU_USB_Device_Library/Core/inc/usbd_req.h
@@ -35,7 +35,7 @@ void USBD_ParseSetupRequest(USB_OTG_CORE_HANDLE *pdev,
void USBD_CtlError(USB_OTG_CORE_HANDLE *pdev,
USB_SETUP_REQ *req);
-void USBD_GetString(uint8_t *desc, uint8_t *unicode, uint16_t *len);
+void USBD_GetString(uint8_t *desc, uint16_t descLen, uint8_t *unicode, uint16_t *len);
/**
* @}
*/
diff --git a/external/mh1903_lib/SCPU_USB_Lib/SCPU_USB_Device_Library/Core/src/usbd_core.c b/external/mh1903_lib/SCPU_USB_Lib/SCPU_USB_Device_Library/Core/src/usbd_core.c
index f2af7d9..e68f627 100644
--- a/external/mh1903_lib/SCPU_USB_Lib/SCPU_USB_Device_Library/Core/src/usbd_core.c
+++ b/external/mh1903_lib/SCPU_USB_Lib/SCPU_USB_Device_Library/Core/src/usbd_core.c
@@ -116,9 +116,8 @@ void USBD_Init(USB_OTG_CORE_HANDLE* pdev, USB_OTG_CORE_ID_TypeDef coreID, USBD_D
nvicSet = true;
/* Enable USB Interrupt */
NVIC_InitTypeDef NVIC_InitStructure;
- NVIC_SetPriorityGrouping(NVIC_PriorityGroup_0);
NVIC_InitStructure.NVIC_IRQChannel = USB_IRQn;
- NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
+ NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
@@ -199,8 +198,12 @@ static uint8_t USBD_SetupStage(USB_OTG_CORE_HANDLE* pdev)
*/
static uint8_t USBD_DataOutStage(USB_OTG_CORE_HANDLE* pdev, uint8_t epnum)
{
+ uint8_t ep_idx = epnum & 0x7F;
USB_OTG_EP* ep;
- ep = &pdev->dev.out_ep[epnum & 0x7F];
+ if (ep_idx >= USB_OTG_MAX_EP_COUNT) {
+ return USBD_FAIL;
+ }
+ ep = &pdev->dev.out_ep[ep_idx];
if (epnum == 0) {
if (pdev->dev.device_state == USB_OTG_EP0_DATA_OUT) {
if ((pdev->dev.class_cb->EP0_RxReady != NULL) && (pdev->dev.device_status == USB_OTG_CONFIGURED)) {
@@ -216,7 +219,7 @@ static uint8_t USBD_DataOutStage(USB_OTG_CORE_HANDLE* pdev, uint8_t epnum)
USB_OTG_EPStartXfer(pdev, ep);
} else {
if ((pdev->dev.class_cb->DataOut != NULL) && (pdev->dev.device_status == USB_OTG_CONFIGURED)) {
- pdev->dev.class_cb->DataOut(pdev, epnum);
+ pdev->dev.class_cb->DataOut(pdev, ep_idx);
}
}
}
@@ -232,8 +235,12 @@ static uint8_t USBD_DataOutStage(USB_OTG_CORE_HANDLE* pdev, uint8_t epnum)
*/
static uint8_t USBD_DataInStage(USB_OTG_CORE_HANDLE* pdev, uint8_t epnum)
{
+ uint8_t ep_idx = epnum & 0x7F;
USB_OTG_EP* ep;
- ep = &pdev->dev.in_ep[epnum];
+ if (ep_idx >= USB_OTG_MAX_EP_COUNT) {
+ return USBD_FAIL;
+ }
+ ep = &pdev->dev.in_ep[ep_idx];
if (epnum == 0) {
if (ep->xfer_count > 1) {
USB_OTG_EP0StartXfer(pdev, ep);
@@ -255,7 +262,7 @@ static uint8_t USBD_DataInStage(USB_OTG_CORE_HANDLE* pdev, uint8_t epnum)
} else if (ep->xfer_count == 1 || ep->total_data_len == 0) {
ep->xfer_count = 0;
if ((pdev->dev.class_cb->DataIn != NULL) && (pdev->dev.device_status == USB_OTG_CONFIGURED)) {
- pdev->dev.class_cb->DataIn(pdev, epnum);
+ pdev->dev.class_cb->DataIn(pdev, ep_idx);
}
}
}
diff --git a/external/mh1903_lib/SCPU_USB_Lib/SCPU_USB_Device_Library/Core/src/usbd_ioreq.c b/external/mh1903_lib/SCPU_USB_Lib/SCPU_USB_Device_Library/Core/src/usbd_ioreq.c
index 8a2f696..30b54be 100644
--- a/external/mh1903_lib/SCPU_USB_Lib/SCPU_USB_Device_Library/Core/src/usbd_ioreq.c
+++ b/external/mh1903_lib/SCPU_USB_Lib/SCPU_USB_Device_Library/Core/src/usbd_ioreq.c
@@ -146,6 +146,9 @@ USBD_Status USBD_CtlReceiveStatus(USB_OTG_CORE_HANDLE *pdev)
*/
uint16_t USBD_GetRxCount(USB_OTG_CORE_HANDLE *pdev, uint8_t epnum)
{
+ if (epnum >= USB_OTG_MAX_EP_COUNT) {
+ return 0;
+ }
return pdev->dev.out_ep[epnum].xfer_count;
}
diff --git a/external/mh1903_lib/SCPU_USB_Lib/SCPU_USB_Device_Library/Core/src/usbd_req.c b/external/mh1903_lib/SCPU_USB_Lib/SCPU_USB_Device_Library/Core/src/usbd_req.c
index 1564009..7d63c28 100644
--- a/external/mh1903_lib/SCPU_USB_Lib/SCPU_USB_Device_Library/Core/src/usbd_req.c
+++ b/external/mh1903_lib/SCPU_USB_Lib/SCPU_USB_Device_Library/Core/src/usbd_req.c
@@ -44,11 +44,24 @@ static void USBD_SetFeature(USB_OTG_CORE_HANDLE* pdev, USB_SETUP_REQ* req);
static void USBD_ClrFeature(USB_OTG_CORE_HANDLE* pdev, USB_SETUP_REQ* req);
-static uint8_t USBD_GetLen(uint8_t* buf);
+static uint8_t USBD_IsValidEPAddress(uint8_t ep_addr);
+
/**
* @}
*/
+static uint8_t USBD_IsValidEPAddress(uint8_t ep_addr)
+{
+ uint8_t ep_num = ep_addr & 0x7F;
+ if ((ep_addr & 0x70) != 0U) {
+ return 0U;
+ }
+ if (ep_num >= USB_OTG_MAX_EP_COUNT) {
+ return 0U;
+ }
+ return 1U;
+}
+
/**
* @brief USBD_StdDevReq
* Handle standard usb device requests
@@ -116,7 +129,7 @@ USBD_Status USBD_StdItfReq(USB_OTG_CORE_HANDLE* pdev, USB_SETUP_REQ* req)
USBD_Status ret = USBD_OK;
switch (pdev->dev.device_status) {
case USB_OTG_CONFIGURED:
- if (LOBYTE(req->wIndex) > USBD_ITF_MAX_NUM || pdev->dev.class_cb->Setup(pdev, req) != USBD_OK) {
+ if (LOBYTE(req->wIndex) >= USBD_ITF_MAX_NUM || pdev->dev.class_cb->Setup(pdev, req) != USBD_OK) {
USBD_CtlError(pdev, req);
}
break;
@@ -147,6 +160,10 @@ USBD_Status USBD_StdEPReq(USB_OTG_CORE_HANDLE* pdev, USB_SETUP_REQ* req)
switch (pdev->dev.device_status) {
case USB_OTG_ADDRESSED:
if ((ep_addr != 0x00) && (ep_addr != 0x80)) {
+ if (!USBD_IsValidEPAddress(ep_addr)) {
+ USBD_CtlError(pdev, req);
+ break;
+ }
DCD_EP_Stall(pdev, ep_addr);
}
break;
@@ -154,6 +171,10 @@ USBD_Status USBD_StdEPReq(USB_OTG_CORE_HANDLE* pdev, USB_SETUP_REQ* req)
case USB_OTG_CONFIGURED:
if (req->wValue == USB_FEATURE_EP_HALT) {
if ((ep_addr != 0x00) && (ep_addr != 0x80)) {
+ if (!USBD_IsValidEPAddress(ep_addr)) {
+ USBD_CtlError(pdev, req);
+ break;
+ }
DCD_EP_Stall(pdev, ep_addr);
}
}
@@ -172,6 +193,10 @@ USBD_Status USBD_StdEPReq(USB_OTG_CORE_HANDLE* pdev, USB_SETUP_REQ* req)
switch (pdev->dev.device_status) {
case USB_OTG_ADDRESSED:
if ((ep_addr != 0x00) && (ep_addr != 0x80)) {
+ if (!USBD_IsValidEPAddress(ep_addr)) {
+ USBD_CtlError(pdev, req);
+ break;
+ }
DCD_EP_Stall(pdev, ep_addr);
}
break;
@@ -179,6 +204,10 @@ USBD_Status USBD_StdEPReq(USB_OTG_CORE_HANDLE* pdev, USB_SETUP_REQ* req)
case USB_OTG_CONFIGURED:
if (req->wValue == USB_FEATURE_EP_HALT) {
if ((ep_addr != 0x00) && (ep_addr != 0x80)) {
+ if (!USBD_IsValidEPAddress(ep_addr)) {
+ USBD_CtlError(pdev, req);
+ break;
+ }
DCD_EP_ClrStall(pdev, ep_addr);
pdev->dev.class_cb->Setup(pdev, req);
}
@@ -196,24 +225,40 @@ USBD_Status USBD_StdEPReq(USB_OTG_CORE_HANDLE* pdev, USB_SETUP_REQ* req)
switch (pdev->dev.device_status) {
case USB_OTG_ADDRESSED:
if ((ep_addr != 0x00) && (ep_addr != 0x80)) {
+ if (!USBD_IsValidEPAddress(ep_addr)) {
+ USBD_CtlError(pdev, req);
+ break;
+ }
DCD_EP_Stall(pdev, ep_addr);
}
break;
case USB_OTG_CONFIGURED:
+ if ((ep_addr & 0x70) != 0) {
+ USBD_CtlError(pdev, req);
+ break;
+ }
if ((ep_addr & 0x80) == 0x80) {
- if (pdev->dev.in_ep[ep_addr & 0x7F].is_stall) {
+ uint8_t ep_num = ep_addr & 0x7F;
+ if (ep_num >= USB_OTG_MAX_EP_COUNT) {
+ USBD_CtlError(pdev, req);
+ break;
+ }
+ if (pdev->dev.in_ep[ep_num].is_stall) {
USBD_ep_status = 0x0001;
} else {
USBD_ep_status = 0x0000;
}
} else if ((ep_addr & 0x80) == 0x00) {
- if (pdev->dev.out_ep[ep_addr].is_stall) {
- USBD_ep_status = 0x0001;
+ uint8_t ep_num = ep_addr & 0x7F;
+ if (ep_num >= USB_OTG_MAX_EP_COUNT) {
+ USBD_CtlError(pdev, req);
+ break;
}
-
- else {
+ if (pdev->dev.out_ep[ep_num].is_stall) {
+ USBD_ep_status = 0x0001;
+ } else {
USBD_ep_status = 0x0000;
}
}
@@ -236,8 +281,8 @@ USBD_Status USBD_StdEPReq(USB_OTG_CORE_HANDLE* pdev, USB_SETUP_REQ* req)
static void USBD_WinUSBGetDescriptor(USB_OTG_CORE_HANDLE *pdev, USB_SETUP_REQ *req)
{
- uint16_t len;
- uint8_t *pbuf;
+ uint16_t len = 0;
+ uint8_t *pbuf = NULL;
switch (req->wIndex) {
case 0x04: // compat ID
@@ -252,9 +297,11 @@ static void USBD_WinUSBGetDescriptor(USB_OTG_CORE_HANDLE *pdev, USB_SETUP_REQ *r
return;
}
- if ((len != 0) && (req->wLength != 0)) {
+ if ((pbuf != NULL) && (len != 0) && (req->wLength != 0)) {
len = MIN(len, req->wLength);
USBD_CtlSendData(pdev, pbuf, len);
+ } else {
+ USBD_CtlError(pdev, req);
}
}
@@ -268,7 +315,7 @@ static void USBD_WinUSBGetDescriptor(USB_OTG_CORE_HANDLE *pdev, USB_SETUP_REQ *r
*/
static void USBD_GetDescriptor(USB_OTG_CORE_HANDLE* pdev, USB_SETUP_REQ* req)
{
- uint16_t len;
+ uint16_t len = 0;
uint8_t* pbuf = NULL;
// USB_OTG_CSR0L_IN_PERIPHERAL_TypeDef csr0l;
// csr0l.d8 = USB_OTG_READ_REG8(&pdev->regs.INDEXREGS->CSRL.CSR0L);
@@ -282,6 +329,10 @@ static void USBD_GetDescriptor(USB_OTG_CORE_HANDLE* pdev, USB_SETUP_REQ* req)
case USB_DESC_TYPE_CONFIGURATION:
pbuf = (uint8_t*)pdev->dev.class_cb->GetConfigDescriptor(pdev->cfg.speed, &len);
+ if (pbuf == NULL || len < 2U) {
+ USBD_CtlError(pdev, req);
+ return;
+ }
pbuf[1] = USB_DESC_TYPE_CONFIGURATION;
pdev->dev.pConfig_descriptor = pbuf;
@@ -343,11 +394,13 @@ static void USBD_GetDescriptor(USB_OTG_CORE_HANDLE* pdev, USB_SETUP_REQ* req)
return;
}
- if ((len != 0) && (req->wLength != 0)) {
+ if ((pbuf != NULL) && (len != 0) && (req->wLength != 0)) {
len = MIN(len, req->wLength);
USBD_CtlSendData(pdev, pbuf, len);
+ } else if ((req->wLength != 0) && (pbuf == NULL)) {
+ USBD_CtlError(pdev, req);
}
}
@@ -622,38 +675,39 @@ void USBD_CtlError(USB_OTG_CORE_HANDLE* pdev, USB_SETUP_REQ* req)
* @param len : descriptor length
* @retval None
*/
-void USBD_GetString(uint8_t* desc, uint8_t* unicode, uint16_t* len)
+void USBD_GetString(uint8_t* desc, uint16_t descLen, uint8_t* unicode, uint16_t* len)
{
- uint8_t idx = 0;
+ uint16_t idx = 0;
+ uint16_t asciiLen = 0;
+ uint16_t maxAsciiLen = 0;
- if (desc != NULL) {
- *len = USBD_GetLen(desc) * 2 + 2;
- unicode[idx++] = *len;
- unicode[idx++] = USB_DESC_TYPE_STRING;
+ if (len == NULL) {
+ return;
+ }
+ *len = 0;
- while (*desc != '\0') {
- unicode[idx++] = *desc++;
- unicode[idx++] = 0x00;
- }
+ if (desc == NULL || unicode == NULL || descLen == 0U) {
+ return;
}
-}
-/**
- * @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 = 0;
+ /* Reserve 2 bytes for descriptor header [len, type]. */
+ maxAsciiLen = (USB_MAX_STR_DESC_SIZ - 2U) / 2U;
+ if (descLen < maxAsciiLen) {
+ maxAsciiLen = descLen;
+ }
- while (*buf != '\0') {
- len++;
- buf++;
+ while (asciiLen < maxAsciiLen && desc[asciiLen] != '\0') {
+ asciiLen++;
}
- return len;
+ *len = (uint16_t)(asciiLen * 2U + 2U);
+ unicode[idx++] = (uint8_t)(*len);
+ unicode[idx++] = USB_DESC_TYPE_STRING;
+
+ for (uint16_t i = 0; i < asciiLen; i++) {
+ unicode[idx++] = desc[i];
+ unicode[idx++] = 0x00;
+ }
}
/************************ (C) COPYRIGHT 2014 Megahuntmicro ****END OF FILE****/
diff --git a/external/mh1903_lib/SCPU_USB_Lib/SCPU_USB_OTG_Driver/src/usb_core.c b/external/mh1903_lib/SCPU_USB_Lib/SCPU_USB_OTG_Driver/src/usb_core.c
index 845a291..50aeab8 100644
--- a/external/mh1903_lib/SCPU_USB_Lib/SCPU_USB_OTG_Driver/src/usb_core.c
+++ b/external/mh1903_lib/SCPU_USB_Lib/SCPU_USB_OTG_Driver/src/usb_core.c
@@ -1299,6 +1299,8 @@ USB_OTG_STS USB_OTG_EPStartXfer(USB_OTG_CORE_HANDLE* pdev, USB_OTG_EP* ep)
USB_OTG_TXCSRL_IN_PERIPHERAL_TypeDef tx_csrl;
USB_OTG_RXCSRL_IN_PERIPHERAL_TypeDef rx_csrl;
USB_OTG_RXCOUNT_TypeDef rx_count;
+ uint32_t rx_len = 0;
+ uint32_t rx_remain = 0;
/* IN endpoint */
if (ep->is_in) {
@@ -1323,14 +1325,28 @@ USB_OTG_STS USB_OTG_EPStartXfer(USB_OTG_CORE_HANDLE* pdev, USB_OTG_EP* ep)
USB_OTG_WRITE_REG8(&pdev->regs.CSRREGS[ep->num]->RXCSRL, rx_csrl.d8);
} else {
rx_count.d16 = USB_OTG_READ_REG16(&pdev->regs.CSRREGS[ep->num]->RXCOUNT);
- USB_OTG_ReadPacket(pdev, ep->xfer_buff + ep->xfer_count, ep->num, rx_count.d16);
- ep->xfer_count += rx_count.d16;
- if (ep->xfer_len >= ep->xfer_count) {
- ep->rem_data_len = ep->xfer_len - ep->xfer_count;
- } else {
- ep->rem_data_len = 0;
- ep->xfer_count = ep->xfer_len;
+ rx_len = rx_count.d16;
+
+ if ((ep->xfer_buff == NULL) || (ep->xfer_count > ep->xfer_len)) {
+ ep->is_stall = 1;
+ USB_OTG_EPSetStall(pdev, ep);
+ rx_csrl.b.rx_pkt_rdy = 0;
+ USB_OTG_WRITE_REG8(&pdev->regs.CSRREGS[ep->num]->RXCSRL, rx_csrl.d8);
+ return USB_OTG_FAIL;
+ }
+
+ rx_remain = ep->xfer_len - ep->xfer_count;
+ if ((rx_len > ep->maxpacket) || (rx_len > rx_remain)) {
+ ep->is_stall = 1;
+ USB_OTG_EPSetStall(pdev, ep);
+ rx_csrl.b.rx_pkt_rdy = 0;
+ USB_OTG_WRITE_REG8(&pdev->regs.CSRREGS[ep->num]->RXCSRL, rx_csrl.d8);
+ return USB_OTG_FAIL;
}
+
+ USB_OTG_ReadPacket(pdev, ep->xfer_buff + ep->xfer_count, ep->num, (uint16_t)rx_len);
+ ep->xfer_count += rx_len;
+ ep->rem_data_len = ep->xfer_len - ep->xfer_count;
rx_csrl.b.rx_pkt_rdy = 0;
USB_OTG_WRITE_REG8(&pdev->regs.CSRREGS[ep->num]->RXCSRL, rx_csrl.d8);
}
diff --git a/external/mh1903_lib/SCPU_USB_Lib/SCPU_USB_OTG_Driver/src/usb_dcd.c b/external/mh1903_lib/SCPU_USB_Lib/SCPU_USB_OTG_Driver/src/usb_dcd.c
index 006a868..2f2ed70 100644
--- a/external/mh1903_lib/SCPU_USB_Lib/SCPU_USB_OTG_Driver/src/usb_dcd.c
+++ b/external/mh1903_lib/SCPU_USB_Lib/SCPU_USB_OTG_Driver/src/usb_dcd.c
@@ -10,6 +10,18 @@
#include "usb_dcd.h"
#include "usb_bsp.h"
+static uint8_t DCD_IsValidEpAddr(uint8_t ep_addr)
+{
+ uint8_t ep_num = ep_addr & 0x7F;
+ if ((ep_addr & 0x70U) != 0U) {
+ return 0U;
+ }
+ if (ep_num >= USB_OTG_MAX_EP_COUNT) {
+ return 0U;
+ }
+ return 1U;
+}
+
void DCD_Init(USB_OTG_CORE_HANDLE* pdev, USB_OTG_CORE_ID_TypeDef coreID)
{
/* Set Register Address */
@@ -45,6 +57,9 @@ uint32_t DCD_EP_Open(USB_OTG_CORE_HANDLE *pdev,
uint8_t ep_type)
{
USB_OTG_EP *ep;
+ if (!DCD_IsValidEpAddr(ep_addr)) {
+ return 1U;
+ }
if ((ep_addr & 0x80) == 0x80) {
ep = &pdev->dev.in_ep[ep_addr & 0x7F];
@@ -80,6 +95,9 @@ uint32_t DCD_EP_Open(USB_OTG_CORE_HANDLE *pdev,
uint32_t DCD_EP_Close(USB_OTG_CORE_HANDLE *pdev, uint8_t ep_addr)
{
USB_OTG_EP *ep;
+ if (!DCD_IsValidEpAddr(ep_addr)) {
+ return 1U;
+ }
if ((ep_addr & 0x80) == 0x80) {
ep = &pdev->dev.in_ep[ep_addr & 0x7F];
@@ -106,6 +124,9 @@ uint32_t DCD_EP_PrepareRx(USB_OTG_CORE_HANDLE *pdev,
uint16_t buf_len)
{
USB_OTG_EP *ep;
+ if (!DCD_IsValidEpAddr(ep_addr)) {
+ return 1U;
+ }
ep = &pdev->dev.out_ep[ep_addr & 0x7F];
@@ -138,6 +159,9 @@ uint32_t DCD_EP_Tx(USB_OTG_CORE_HANDLE *pdev,
uint32_t buf_len)
{
USB_OTG_EP *ep;
+ if (!DCD_IsValidEpAddr(ep_addr)) {
+ return 1U;
+ }
ep = &pdev->dev.in_ep[ep_addr & 0x7F];
@@ -170,15 +194,19 @@ uint32_t DCD_EP_Tx(USB_OTG_CORE_HANDLE *pdev,
uint32_t DCD_EP_Stall(USB_OTG_CORE_HANDLE *pdev, uint8_t epnum)
{
+ uint8_t ep_idx = epnum & 0x7F;
USB_OTG_EP *ep;
+ if (ep_idx >= USB_OTG_MAX_EP_COUNT) {
+ return 1;
+ }
if ((0x80 & epnum) == 0x80) {
- ep = &pdev->dev.in_ep[epnum & 0x7F];
+ ep = &pdev->dev.in_ep[ep_idx];
} else {
- ep = &pdev->dev.out_ep[epnum];
+ ep = &pdev->dev.out_ep[ep_idx];
}
ep->is_stall = 1;
- ep->num = epnum & 0x7F;
+ ep->num = ep_idx;
ep->is_in = ((epnum & 0x80) == 0x80);
USB_OTG_EPSetStall(pdev, ep);
@@ -193,15 +221,19 @@ uint32_t DCD_EP_Stall(USB_OTG_CORE_HANDLE *pdev, uint8_t epnum)
*/
uint32_t DCD_EP_ClrStall(USB_OTG_CORE_HANDLE *pdev, uint8_t epnum)
{
+ uint8_t ep_idx = epnum & 0x7F;
USB_OTG_EP *ep;
+ if (ep_idx >= USB_OTG_MAX_EP_COUNT) {
+ return 1;
+ }
if ((0x80 & epnum) == 0x80) {
- ep = &pdev->dev.in_ep[epnum & 0x7F];
+ ep = &pdev->dev.in_ep[ep_idx];
} else {
- ep = &pdev->dev.out_ep[epnum];
+ ep = &pdev->dev.out_ep[ep_idx];
}
ep->is_stall = 0;
- ep->num = epnum & 0x7F;
+ ep->num = ep_idx;
ep->is_in = ((epnum & 0x80) == 0x80);
USB_OTG_EPClearStall(pdev, ep);
@@ -216,10 +248,13 @@ uint32_t DCD_EP_ClrStall(USB_OTG_CORE_HANDLE *pdev, uint8_t epnum)
*/
uint32_t DCD_EP_Flush(USB_OTG_CORE_HANDLE *pdev, uint8_t epnum)
{
+ if (!DCD_IsValidEpAddr(epnum)) {
+ return 1U;
+ }
if ((epnum & 0x80) == 0x80) {
USB_OTG_FlushTxFifo(pdev, epnum & 0x7F);
} else {
- USB_OTG_FlushRxFifo(pdev, epnum);
+ USB_OTG_FlushRxFifo(pdev, epnum & 0x7F);
}
return (0);
@@ -290,11 +325,14 @@ uint32_t DCD_GetEPStatus(USB_OTG_CORE_HANDLE *pdev, uint8_t epnum)
{
USB_OTG_EP *ep;
uint32_t Status = 0;
+ if (!DCD_IsValidEpAddr(epnum)) {
+ return 0U;
+ }
if ((0x80 & epnum) == 0x80) {
ep = &pdev->dev.in_ep[epnum & 0x7F];
} else {
- ep = &pdev->dev.out_ep[epnum];
+ ep = &pdev->dev.out_ep[epnum & 0x7F];
}
Status = USB_OTG_GetEPStatus(pdev, ep);
@@ -313,11 +351,14 @@ uint32_t DCD_GetEPStatus(USB_OTG_CORE_HANDLE *pdev, uint8_t epnum)
void DCD_SetEPStatus(USB_OTG_CORE_HANDLE *pdev, uint8_t epnum, uint32_t Status)
{
USB_OTG_EP *ep;
+ if (!DCD_IsValidEpAddr(epnum)) {
+ return;
+ }
if ((0x80 & epnum) == 0x80) {
ep = &pdev->dev.in_ep[epnum & 0x7F];
} else {
- ep = &pdev->dev.out_ep[epnum];
+ ep = &pdev->dev.out_ep[epnum & 0x7F];
}
USB_OTG_SetEPStatus(pdev, ep, Status);
diff --git a/external/mh1903_lib/SCPU_USB_Lib/SCPU_USB_OTG_Driver/src/usb_dcd_int.c b/external/mh1903_lib/SCPU_USB_Lib/SCPU_USB_OTG_Driver/src/usb_dcd_int.c
index b835e8f..f32daea 100644
--- a/external/mh1903_lib/SCPU_USB_Lib/SCPU_USB_OTG_Driver/src/usb_dcd_int.c
+++ b/external/mh1903_lib/SCPU_USB_Lib/SCPU_USB_OTG_Driver/src/usb_dcd_int.c
@@ -59,6 +59,7 @@ uint32_t USBD_OTG_ISR_Handler(USB_OTG_CORE_HANDLE *pdev)
uint32_t retval = 0;
USB_OTG_EP* ep;
uint32_t rxLength = 0;
+ uint32_t rxRemain = 0;
if (USB_OTG_IsDeviceMode(pdev)) { /* ensure that we are in device mode */
gintr_status.d8 = USB_OTG_ReadCoreItr(pdev);
@@ -104,6 +105,31 @@ uint32_t USBD_OTG_ISR_Handler(USB_OTG_CORE_HANDLE *pdev)
ep = &pdev->dev.out_ep[0];
/* Read Packet */
rxLength = USB_OTG_READ_REG8(&pdev->regs.INDEXREGS->COUNT.COUNT0);
+ if ((ep->xfer_buff == NULL) || (ep->xfer_count > ep->xfer_len)) {
+ DCD_EP_Stall(pdev, 0x80);
+ DCD_EP_Stall(pdev, 0x00);
+ csr0l.b.data_end = 1;
+ csr0l.b.serviced_rxpktrdy = 1;
+ USB_OTG_WRITE_REG8(&pdev->regs.INDEXREGS->CSRL.CSR0L, csr0l.d8);
+ ep->xfer_buff = pdev->dev.setup_packet;
+ ep->xfer_count = 0;
+ ep->xfer_len = 8;
+ USB_OTG_EP0_OutStart(pdev);
+ return retval;
+ }
+ rxRemain = ep->xfer_len - ep->xfer_count;
+ if (rxLength > rxRemain) {
+ DCD_EP_Stall(pdev, 0x80);
+ DCD_EP_Stall(pdev, 0x00);
+ csr0l.b.data_end = 1;
+ csr0l.b.serviced_rxpktrdy = 1;
+ USB_OTG_WRITE_REG8(&pdev->regs.INDEXREGS->CSRL.CSR0L, csr0l.d8);
+ ep->xfer_buff = pdev->dev.setup_packet;
+ ep->xfer_count = 0;
+ ep->xfer_len = 8;
+ USB_OTG_EP0_OutStart(pdev);
+ return retval;
+ }
/* Copy the setup packet received in FIFO into the setup buffer in RAM */
USB_OTG_ReadPacket(pdev, ep->xfer_buff + ep->xfer_count, 0, rxLength);
ep->xfer_count += rxLength;
@@ -218,6 +244,9 @@ static uint32_t DCD_HandleInEP_ISR(USB_OTG_CORE_HANDLE *pdev, uint16_t ep_intr)
USB_OTG_TXCSRL_IN_PERIPHERAL_TypeDef txcsrl;
uint16_t epnum = 0;
while (ep_intr) {
+ if (epnum >= USB_OTG_MAX_EP_COUNT) {
+ break;
+ }
if (ep_intr & 0x01) { /* In ITR */
txcsrl.d8 = USB_OTG_READ_REG8(&pdev->regs.CSRREGS[epnum]->TXCSRL);
if (!txcsrl.b.tx_pkt_rdy) {
@@ -253,24 +282,46 @@ static uint32_t DCD_HandleOutEP_ISR(USB_OTG_CORE_HANDLE *pdev, uint16_t ep_intr)
{
USB_OTG_RXCSRL_IN_PERIPHERAL_TypeDef rxcsrl;
USB_OTG_RXCOUNT_TypeDef rx_count;
+ USB_OTG_EP *ep;
uint32_t epnum = 1;
- uint32_t rx_fifo_len = 0;
+ uint32_t rx_len = 0;
+ uint32_t rx_remain = 0;
ep_intr >>= 1;
while (ep_intr) {
+ if (epnum >= USB_OTG_MAX_EP_COUNT) {
+ break;
+ }
if (ep_intr & 0x1) {
+ ep = &pdev->dev.out_ep[epnum];
rxcsrl.d8 = USB_OTG_READ_REG8(&pdev->regs.CSRREGS[epnum]->RXCSRL);
/* Transfer complete */
if (rxcsrl.b.rx_pkt_rdy) {
/* Inform upper layer: data ready */
- rx_count.d16 = USB_OTG_READ_REG8(&pdev->regs.CSRREGS[epnum]->RXCOUNT);
- rx_fifo_len = MIN(rx_count.d16, pdev->dev.out_ep[epnum].maxpacket);
- USB_OTG_ReadPacket(pdev,
- pdev->dev.out_ep[epnum].xfer_buff + pdev->dev.out_ep[epnum].xfer_count,
- epnum,
- rx_count.d16);
- pdev->dev.out_ep[epnum].xfer_count += rx_fifo_len;
- /* RX COMPLETE */
+ rx_count.d16 = USB_OTG_READ_REG16(&pdev->regs.CSRREGS[epnum]->RXCOUNT);
+ rx_len = rx_count.d16;
+
+ if ((ep->xfer_buff == NULL) || (ep->xfer_count > ep->xfer_len)) {
+ DCD_EP_Stall(pdev, (uint8_t)epnum);
+ rxcsrl.b.rx_pkt_rdy = 0;
+ USB_OTG_WRITE_REG8(&pdev->regs.CSRREGS[epnum]->RXCSRL, rxcsrl.d8);
+ ep_intr >>= 1;
+ epnum++;
+ continue;
+ }
+
+ rx_remain = ep->xfer_len - ep->xfer_count;
+ if ((rx_len > ep->maxpacket) || (rx_len > rx_remain)) {
+ DCD_EP_Stall(pdev, (uint8_t)epnum);
+ rxcsrl.b.rx_pkt_rdy = 0;
+ USB_OTG_WRITE_REG8(&pdev->regs.CSRREGS[epnum]->RXCSRL, rxcsrl.d8);
+ ep_intr >>= 1;
+ epnum++;
+ continue;
+ }
+
+ USB_OTG_ReadPacket(pdev, ep->xfer_buff + ep->xfer_count, epnum, (uint16_t)rx_len);
+ ep->xfer_count += rx_len;
USBD_DCD_INT_fops->DataOutStage(pdev, epnum);
}
/* Endpoint disable */
diff --git a/images/wallet/walletZashi.png b/images/wallet/walletZashi.png
deleted file mode 100644
index 30a1217..0000000
Binary files a/images/wallet/walletZashi.png and /dev/null differ
diff --git a/images/wallet/walletZodl.png b/images/wallet/walletZodl.png
new file mode 100644
index 0000000..c5fbf5d
Binary files /dev/null and b/images/wallet/walletZodl.png differ
diff --git a/src/boot_update.c b/src/boot_update.c
new file mode 100644
index 0000000..89ca8d2
--- /dev/null
+++ b/src/boot_update.c
@@ -0,0 +1,123 @@
+#ifdef BUILD_PRODUCTION
+#include "define.h"
+#include "mhscpu.h"
+#include "user_fatfs.h"
+#include "user_memory.h"
+#include "draw_on_lcd.h"
+#include "sha256.h"
+#include "gui_model.h"
+#include "cmsis_os2.h"
+#include "drv_qspi_flash.h"
+
+LV_FONT_DECLARE(openSans_24);
+
+#define BOOT_ADDR (0x01001000)
+#define SECTOR_SIZE 4096
+#define BOOT_HEAD_SIZE 0x104
+#define APP_ADDR (0x1001000 + 0x80000) //108 1000
+#define APP_CHECK_START_ADDR (APP_ADDR)
+#define APP_END_ADDR (0x2000000)
+static const uint8_t MAGIC_NUMBER[] = {'m', 'h', '1', '9', '0', '3', 'b', 'o', 'o', 't', 'u', 'p', 'd', 'a', 't', 'e'};
+
+static uint8_t g_fileUnit[SECTOR_SIZE] = {0};
+
+static uint32_t BinarySearchBootHead(void)
+{
+ size_t MAGIC_NUMBER_SIZE = sizeof(MAGIC_NUMBER);
+ uint8_t *buffer = SRAM_MALLOC(SECTOR_SIZE);
+ uint32_t startIndex = (APP_CHECK_START_ADDR - APP_ADDR) / SECTOR_SIZE;
+ uint32_t endIndex = (APP_END_ADDR - APP_ADDR) / SECTOR_SIZE;
+
+ for (int i = startIndex + 1; i < endIndex; i++) {
+ memcpy_s(buffer, SECTOR_SIZE, (uint32_t *)(APP_ADDR + i * SECTOR_SIZE), SECTOR_SIZE);
+ if (memcmp(buffer, MAGIC_NUMBER, MAGIC_NUMBER_SIZE) == 0) {
+ printf("find magic number\n");
+ SRAM_FREE(buffer);
+ return i;
+ }
+ }
+ SRAM_FREE(buffer);
+ return -1;
+}
+
+static void Delay(uint32_t ms)
+{
+ uint32_t i, tick, countPerMs;
+ countPerMs = SYSCTRL->HCLK_1MS_VAL / 4;
+ for (tick = 0; tick < ms; tick++) {
+ for (i = 0; i < countPerMs; i++) {
+ if (i > 10000000) {
+ printf("!!\r\n");
+ }
+ }
+ }
+}
+
+int32_t UpdateBootFromFlash(void)
+{
+ osKernelLock();
+ int num = BinarySearchBootHead();
+ printf("num = %d\n", num);
+ if (num <= 0) {
+ osKernelUnlock();
+ return -1;
+ }
+ uint32_t len, offset, crcCalc, readCrc, writeAddr = 0x1001000;
+ uint32_t baseAddr = APP_ADDR + num * SECTOR_SIZE;
+ int startNum = num + 1;
+ uint8_t hash[32] = {0};
+ uint8_t calHash[32] = {0};
+ size_t MAGIC_NUMBER_SIZE = sizeof(MAGIC_NUMBER);
+
+ struct sha256_ctx ctx;
+ sha256_init(&ctx);
+ QspiFlashInit();
+
+ memset(g_fileUnit, 0xFF, sizeof(g_fileUnit));
+
+ memcpy(g_fileUnit, (uint32_t *)baseAddr, 4 + 32 + MAGIC_NUMBER_SIZE);
+ uint32_t bootLen = (g_fileUnit[MAGIC_NUMBER_SIZE + 0] << 24) + (g_fileUnit[MAGIC_NUMBER_SIZE + 1] << 16) + (g_fileUnit[MAGIC_NUMBER_SIZE + 2] << 8) + g_fileUnit[MAGIC_NUMBER_SIZE + 3];
+ printf("bootLen = %d\n", bootLen);
+ memcpy(hash, &g_fileUnit[MAGIC_NUMBER_SIZE + 4], 32);
+
+ memset(g_fileUnit, 0xFF, sizeof(g_fileUnit));
+ memcpy(g_fileUnit, (uint32_t *)(baseAddr + 4 + 32 + 0x30 + MAGIC_NUMBER_SIZE), BOOT_HEAD_SIZE);
+ QspiFlashEraseAndWrite(0x01000000, g_fileUnit, SECTOR_SIZE);
+
+ sha256_update(&ctx, (uint32_t *)(baseAddr + 4 + 32 + MAGIC_NUMBER_SIZE), 0x134);
+ crcCalc = crc32_ieee(0, (uint32_t *)(baseAddr + 4 + 32 + MAGIC_NUMBER_SIZE), 0x134);
+
+ for (int i = startNum; i <= startNum + (bootLen - 0x134) / SECTOR_SIZE; i++, writeAddr += SECTOR_SIZE) {
+ Delay(100);
+ memset(g_fileUnit, 0xFF, sizeof(g_fileUnit));
+ if (i == startNum + (bootLen - 0x134) / SECTOR_SIZE) {
+ len = (bootLen - 0x134) % SECTOR_SIZE - 4;
+ sha256_update(&ctx, (uint32_t *)(APP_ADDR + i * SECTOR_SIZE), len + 4);
+ memcpy(&readCrc, (uint32_t *)(APP_ADDR + i * SECTOR_SIZE + len), 4);
+ } else {
+ len = SECTOR_SIZE;
+ sha256_update(&ctx, (uint32_t *)(APP_ADDR + i * SECTOR_SIZE), len);
+ }
+ memcpy(g_fileUnit, (uint32_t *)(APP_ADDR + i * SECTOR_SIZE), len);
+ crcCalc = crc32_ieee(crcCalc, (uint32_t *)(APP_ADDR + i * SECTOR_SIZE), len);
+ printf("writeAddr = %#x\n", writeAddr);
+ QspiFlashEraseAndWrite(writeAddr, g_fileUnit, SECTOR_SIZE);
+ }
+
+ sha256_done(&ctx, (struct sha256 *)calHash);
+
+ osKernelUnlock();
+ PrintArray("hash", hash, 32);
+ PrintArray("calHash", calHash, 32);
+ printf("crcCalc = %#x\n", crcCalc);
+ printf("readCrc = %#x\n", readCrc);
+ if (memcmp(hash, calHash, 32) == 0) {
+ printf("update success\n");
+ memset(g_fileUnit, 0xFF, sizeof(g_fileUnit));
+ return 0;
+ } else {
+ printf("update failed\n");
+ return -1;
+ }
+}
+#endif
\ No newline at end of file
diff --git a/src/boot_update.h b/src/boot_update.h
new file mode 100644
index 0000000..ec77e73
--- /dev/null
+++ b/src/boot_update.h
@@ -0,0 +1,7 @@
+#ifndef _BOOT_UPDATE_H
+#define _BOOT_UPDATE_H
+
+int32_t UpdateBootFromFlash(void);
+
+#endif /* _BOOT_UPDATE_H */
+
diff --git a/src/config/mhscpu_conf.h b/src/config/mhscpu_conf.h
index 9ea1a3c..8afdc1e 100644
--- a/src/config/mhscpu_conf.h
+++ b/src/config/mhscpu_conf.h
@@ -26,6 +26,7 @@
#include "mhscpu_ssc.h"
#include "mhscpu_adc.h"
#include "mhscpu_otp.h"
+#include "mhscpu_qspi.h"
#include "misc.h" /* High level functions for NVIC and SysTick (add-on to CMSIS functions) */
#include "string.h"
diff --git a/src/config/version.c b/src/config/version.c
index 22954d1..44f28eb 100644
--- a/src/config/version.c
+++ b/src/config/version.c
@@ -84,6 +84,18 @@ void GetBootVersionNumber(char *version)
snprintf(version, SOFTWARE_VERSION_MAX_LEN, "%d.%d.%d", major, minor, build);
}
+bool NeedUpdateBoot(void)
+{
+ uint32_t major, minor, build;
+ if (GetBootSoftwareVersion(&major, &minor, &build) == false) {
+ return true;
+ }
+ if (major == 0 && minor == 3 && build == 0) {
+ return false;
+ }
+ return true;
+}
+
bool GetBootSoftwareVersion(uint32_t *major, uint32_t *minor, uint32_t *build)
{
#ifdef COMPILE_SIMULATOR
@@ -136,4 +148,4 @@ static bool GetBootSoftwareVersionFormData(uint32_t *major, uint32_t *minor, uin
*build = 0;
}
return succ;
-}
+}
\ No newline at end of file
diff --git a/src/config/version.h b/src/config/version.h
index b6044a8..2fcc745 100644
--- a/src/config/version.h
+++ b/src/config/version.h
@@ -6,8 +6,8 @@
#define SOFTWARE_VERSION_MAX_LEN (32)
#define SOFTWARE_VERSION_MAJOR 12
#define SOFTWARE_VERSION_MAJOR_OFFSET 10
-#define SOFTWARE_VERSION_MINOR 3
-#define SOFTWARE_VERSION_BUILD 10
+#define SOFTWARE_VERSION_MINOR 4
+#define SOFTWARE_VERSION_BUILD 0
#define SOFTWARE_VERSION_BETA 1
#define SOFTWARE_VERSION (SOFTWARE_VERSION_MAJOR * 10000 + SOFTWARE_VERSION_MINOR * 100 + SOFTWARE_VERSION_BUILD)
#ifdef WEB3_VERSION
@@ -26,6 +26,7 @@
#error "Invalid software version"
#endif
+#ifdef BUILD_PRODUCTION
void GetSoftWareVersion(char *version);
void GetSoftWareVersionNumber(char *version);
const char *GetSoftwareVersionString(void);
@@ -33,6 +34,8 @@ void GetUpdateVersionNumber(char *version);
bool GetBootSoftwareVersion(uint32_t *major, uint32_t *minor, uint32_t *build);
bool IsBootVersionMatch(void);
void GetBootVersionNumber(char *version);
+#endif
+bool NeedUpdateBoot(void);
#endif
diff --git a/src/crypto/checksum/md5.c b/src/crypto/checksum/md5.c
deleted file mode 100644
index a2ae1be..0000000
--- a/src/crypto/checksum/md5.c
+++ /dev/null
@@ -1,291 +0,0 @@
-/*
- * This is an OpenSSL-compatible implementation of the RSA Data Security, Inc.
- * MD5 Message-Digest Algorithm (RFC 1321).
- *
- * Homepage:
- * http://openwall.info/wiki/people/solar/software/public-domain-source-code/md5
- *
- * Author:
- * Alexander Peslyak, better known as Solar Designer <solar at openwall.com>
- *
- * This software was written by Alexander Peslyak in 2001. No copyright is
- * claimed, and the software is hereby placed in the public domain.
- * In case this attempt to disclaim copyright and place the software in the
- * public domain is deemed null and void, then the software is
- * Copyright (c) 2001 Alexander Peslyak and it is hereby released to the
- * general public under the following terms:
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted.
- *
- * There's ABSOLUTELY NO WARRANTY, express or implied.
- *
- * (This is a heavily cut-down "BSD license".)
- *
- * This differs from Colin Plumb's older public domain implementation in that
- * no exactly 32-bit integer data type is required (any 32-bit or wider
- * unsigned integer data type will do), there's no compile-time endianness
- * configuration, and the function prototypes match OpenSSL's. No code from
- * Colin Plumb's implementation has been reused; this comment merely compares
- * the properties of the two independent implementations.
- *
- * The primary goals of this implementation are portability and ease of use.
- * It is meant to be fast, but not as fast as possible. Some known
- * optimizations are not included to reduce source code size and avoid
- * compile-time configuration.
- */
-
-#ifndef HAVE_OPENSSL
-
-#include <string.h>
-
-#include "md5.h"
-
-/*
- * The basic MD5 functions.
- *
- * F and G are optimized compared to their RFC 1321 definitions for
- * architectures that lack an AND-NOT instruction, just like in Colin Plumb's
- * implementation.
- */
-#define F(x, y, z) ((z) ^ ((x) & ((y) ^ (z))))
-#define G(x, y, z) ((y) ^ ((z) & ((x) ^ (y))))
-#define H(x, y, z) (((x) ^ (y)) ^ (z))
-#define H2(x, y, z) ((x) ^ ((y) ^ (z)))
-#define I(x, y, z) ((y) ^ ((x) | ~(z)))
-
-/*
- * The MD5 transformation for all four rounds.
- */
-#define STEP(f, a, b, c, d, x, t, s) \
- (a) += f((b), (c), (d)) + (x) + (t); \
- (a) = (((a) << (s)) | (((a) & 0xffffffff) >> (32 - (s)))); \
- (a) += (b);
-
-/*
- * SET reads 4 input bytes in little-endian byte order and stores them in a
- * properly aligned word in host byte order.
- *
- * The check for little-endian architectures that tolerate unaligned memory
- * accesses is just an optimization. Nothing will break if it fails to detect
- * a suitable architecture.
- *
- * Unfortunately, this optimization may be a C strict aliasing rules violation
- * if the caller's data buffer has effective type that cannot be aliased by
- * MD5_u32plus. In practice, this problem may occur if these MD5 routines are
- * inlined into a calling function, or with future and dangerously advanced
- * link-time optimizations. For the time being, keeping these MD5 routines in
- * their own translation unit avoids the problem.
- */
-#if defined(__i386__) || defined(__x86_64__) || defined(__vax__)
-#define SET(n) \
- (*(MD5_u32plus *)&ptr[(n) * 4])
-#define GET(n) \
- SET(n)
-#else
-#define SET(n) \
- (ctx->block[(n)] = \
- (MD5_u32plus)ptr[(n) * 4] | \
- ((MD5_u32plus)ptr[(n) * 4 + 1] << 8) | \
- ((MD5_u32plus)ptr[(n) * 4 + 2] << 16) | \
- ((MD5_u32plus)ptr[(n) * 4 + 3] << 24))
-#define GET(n) \
- (ctx->block[(n)])
-#endif
-
-/*
- * This processes one or more 64-byte data blocks, but does NOT update the bit
- * counters. There are no alignment requirements.
- */
-static const void *body(MD5_CTX *ctx, const void *data, unsigned long size)
-{
- const unsigned char *ptr;
- MD5_u32plus a, b, c, d;
- MD5_u32plus saved_a, saved_b, saved_c, saved_d;
-
- ptr = (const unsigned char *)data;
-
- a = ctx->a;
- b = ctx->b;
- c = ctx->c;
- d = ctx->d;
-
- do {
- saved_a = a;
- saved_b = b;
- saved_c = c;
- saved_d = d;
-
- /* Round 1 */
- STEP(F, a, b, c, d, SET(0), 0xd76aa478, 7)
- STEP(F, d, a, b, c, SET(1), 0xe8c7b756, 12)
- STEP(F, c, d, a, b, SET(2), 0x242070db, 17)
- STEP(F, b, c, d, a, SET(3), 0xc1bdceee, 22)
- STEP(F, a, b, c, d, SET(4), 0xf57c0faf, 7)
- STEP(F, d, a, b, c, SET(5), 0x4787c62a, 12)
- STEP(F, c, d, a, b, SET(6), 0xa8304613, 17)
- STEP(F, b, c, d, a, SET(7), 0xfd469501, 22)
- STEP(F, a, b, c, d, SET(8), 0x698098d8, 7)
- STEP(F, d, a, b, c, SET(9), 0x8b44f7af, 12)
- STEP(F, c, d, a, b, SET(10), 0xffff5bb1, 17)
- STEP(F, b, c, d, a, SET(11), 0x895cd7be, 22)
- STEP(F, a, b, c, d, SET(12), 0x6b901122, 7)
- STEP(F, d, a, b, c, SET(13), 0xfd987193, 12)
- STEP(F, c, d, a, b, SET(14), 0xa679438e, 17)
- STEP(F, b, c, d, a, SET(15), 0x49b40821, 22)
-
- /* Round 2 */
- STEP(G, a, b, c, d, GET(1), 0xf61e2562, 5)
- STEP(G, d, a, b, c, GET(6), 0xc040b340, 9)
- STEP(G, c, d, a, b, GET(11), 0x265e5a51, 14)
- STEP(G, b, c, d, a, GET(0), 0xe9b6c7aa, 20)
- STEP(G, a, b, c, d, GET(5), 0xd62f105d, 5)
- STEP(G, d, a, b, c, GET(10), 0x02441453, 9)
- STEP(G, c, d, a, b, GET(15), 0xd8a1e681, 14)
- STEP(G, b, c, d, a, GET(4), 0xe7d3fbc8, 20)
- STEP(G, a, b, c, d, GET(9), 0x21e1cde6, 5)
- STEP(G, d, a, b, c, GET(14), 0xc33707d6, 9)
- STEP(G, c, d, a, b, GET(3), 0xf4d50d87, 14)
- STEP(G, b, c, d, a, GET(8), 0x455a14ed, 20)
- STEP(G, a, b, c, d, GET(13), 0xa9e3e905, 5)
- STEP(G, d, a, b, c, GET(2), 0xfcefa3f8, 9)
- STEP(G, c, d, a, b, GET(7), 0x676f02d9, 14)
- STEP(G, b, c, d, a, GET(12), 0x8d2a4c8a, 20)
-
- /* Round 3 */
- STEP(H, a, b, c, d, GET(5), 0xfffa3942, 4)
- STEP(H2, d, a, b, c, GET(8), 0x8771f681, 11)
- STEP(H, c, d, a, b, GET(11), 0x6d9d6122, 16)
- STEP(H2, b, c, d, a, GET(14), 0xfde5380c, 23)
- STEP(H, a, b, c, d, GET(1), 0xa4beea44, 4)
- STEP(H2, d, a, b, c, GET(4), 0x4bdecfa9, 11)
- STEP(H, c, d, a, b, GET(7), 0xf6bb4b60, 16)
- STEP(H2, b, c, d, a, GET(10), 0xbebfbc70, 23)
- STEP(H, a, b, c, d, GET(13), 0x289b7ec6, 4)
- STEP(H2, d, a, b, c, GET(0), 0xeaa127fa, 11)
- STEP(H, c, d, a, b, GET(3), 0xd4ef3085, 16)
- STEP(H2, b, c, d, a, GET(6), 0x04881d05, 23)
- STEP(H, a, b, c, d, GET(9), 0xd9d4d039, 4)
- STEP(H2, d, a, b, c, GET(12), 0xe6db99e5, 11)
- STEP(H, c, d, a, b, GET(15), 0x1fa27cf8, 16)
- STEP(H2, b, c, d, a, GET(2), 0xc4ac5665, 23)
-
- /* Round 4 */
- STEP(I, a, b, c, d, GET(0), 0xf4292244, 6)
- STEP(I, d, a, b, c, GET(7), 0x432aff97, 10)
- STEP(I, c, d, a, b, GET(14), 0xab9423a7, 15)
- STEP(I, b, c, d, a, GET(5), 0xfc93a039, 21)
- STEP(I, a, b, c, d, GET(12), 0x655b59c3, 6)
- STEP(I, d, a, b, c, GET(3), 0x8f0ccc92, 10)
- STEP(I, c, d, a, b, GET(10), 0xffeff47d, 15)
- STEP(I, b, c, d, a, GET(1), 0x85845dd1, 21)
- STEP(I, a, b, c, d, GET(8), 0x6fa87e4f, 6)
- STEP(I, d, a, b, c, GET(15), 0xfe2ce6e0, 10)
- STEP(I, c, d, a, b, GET(6), 0xa3014314, 15)
- STEP(I, b, c, d, a, GET(13), 0x4e0811a1, 21)
- STEP(I, a, b, c, d, GET(4), 0xf7537e82, 6)
- STEP(I, d, a, b, c, GET(11), 0xbd3af235, 10)
- STEP(I, c, d, a, b, GET(2), 0x2ad7d2bb, 15)
- STEP(I, b, c, d, a, GET(9), 0xeb86d391, 21)
-
- a += saved_a;
- b += saved_b;
- c += saved_c;
- d += saved_d;
-
- ptr += 64;
- } while (size -= 64);
-
- ctx->a = a;
- ctx->b = b;
- ctx->c = c;
- ctx->d = d;
-
- return ptr;
-}
-
-void MD5_Init(MD5_CTX *ctx)
-{
- ctx->a = 0x67452301;
- ctx->b = 0xefcdab89;
- ctx->c = 0x98badcfe;
- ctx->d = 0x10325476;
-
- ctx->lo = 0;
- ctx->hi = 0;
-}
-
-void MD5_Update(MD5_CTX *ctx, const void *data, unsigned long size)
-{
- MD5_u32plus saved_lo;
- unsigned long used, available;
-
- saved_lo = ctx->lo;
- if ((ctx->lo = (saved_lo + size) & 0x1fffffff) < saved_lo)
- ctx->hi++;
- ctx->hi += size >> 29;
-
- used = saved_lo & 0x3f;
-
- if (used) {
- available = 64 - used;
-
- if (size < available) {
- memcpy(&ctx->buffer[used], data, size);
- return;
- }
-
- memcpy(&ctx->buffer[used], data, available);
- data = (const unsigned char *)data + available;
- size -= available;
- body(ctx, ctx->buffer, 64);
- }
-
- if (size >= 64) {
- data = body(ctx, data, size & ~(unsigned long)0x3f);
- size &= 0x3f;
- }
-
- memcpy(ctx->buffer, data, size);
-}
-
-#define OUT(dst, src) \
- (dst)[0] = (unsigned char)(src); \
- (dst)[1] = (unsigned char)((src) >> 8); \
- (dst)[2] = (unsigned char)((src) >> 16); \
- (dst)[3] = (unsigned char)((src) >> 24);
-
-void MD5_Final(unsigned char *result, MD5_CTX *ctx)
-{
- unsigned long used, available;
-
- used = ctx->lo & 0x3f;
-
- ctx->buffer[used++] = 0x80;
-
- available = 64 - used;
-
- if (available < 8) {
- memset(&ctx->buffer[used], 0, available);
- body(ctx, ctx->buffer, 64);
- used = 0;
- available = 64;
- }
-
- memset(&ctx->buffer[used], 0, available - 8);
-
- ctx->lo <<= 3;
- OUT(&ctx->buffer[56], ctx->lo)
- OUT(&ctx->buffer[60], ctx->hi)
-
- body(ctx, ctx->buffer, 64);
-
- OUT(&result[0], ctx->a)
- OUT(&result[4], ctx->b)
- OUT(&result[8], ctx->c)
- OUT(&result[12], ctx->d)
-
- memset(ctx, 0, sizeof(*ctx));
-}
-
-#endif
diff --git a/src/crypto/checksum/md5.h b/src/crypto/checksum/md5.h
deleted file mode 100644
index 6c1d3fd..0000000
--- a/src/crypto/checksum/md5.h
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * This is an OpenSSL-compatible implementation of the RSA Data Security, Inc.
- * MD5 Message-Digest Algorithm (RFC 1321).
- *
- * Homepage:
- * http://openwall.info/wiki/people/solar/software/public-domain-source-code/md5
- *
- * Author:
- * Alexander Peslyak, better known as Solar Designer <solar at openwall.com>
- *
- * This software was written by Alexander Peslyak in 2001. No copyright is
- * claimed, and the software is hereby placed in the public domain.
- * In case this attempt to disclaim copyright and place the software in the
- * public domain is deemed null and void, then the software is
- * Copyright (c) 2001 Alexander Peslyak and it is hereby released to the
- * general public under the following terms:
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted.
- *
- * There's ABSOLUTELY NO WARRANTY, express or implied.
- *
- * See md5.c for more information.
- */
-
-#ifdef HAVE_OPENSSL
-#include <openssl/md5.h>
-#elif !defined(_MD5_H)
-#define _MD5_H
-
-/* Any 32-bit or wider unsigned integer data type will do */
-typedef unsigned int MD5_u32plus;
-
-typedef struct {
- MD5_u32plus lo, hi;
- MD5_u32plus a, b, c, d;
- unsigned char buffer[64];
- MD5_u32plus block[16];
-} MD5_CTX;
-
-extern void MD5_Init(MD5_CTX *ctx);
-extern void MD5_Update(MD5_CTX *ctx, const void *data, unsigned long size);
-extern void MD5_Final(unsigned char *result, MD5_CTX *ctx);
-
-#endif
diff --git a/src/device_settings.c b/src/device_settings.c
index d37e2cd..7629509 100644
--- a/src/device_settings.c
+++ b/src/device_settings.c
@@ -153,7 +153,7 @@ void InitBootParam(void)
{
#ifdef COMPILE_SIMULATOR
return;
-#endif
+#else
BootParam_t bootParam;
bool needSave = false;
Gd25FlashReadBuffer(BOOT_SECURE_PARAM_FLAG, (uint8_t *)&bootParam, sizeof(bootParam));
@@ -170,6 +170,7 @@ void InitBootParam(void)
PrintArray("bootParam.bootCheckFlag", g_bootParam.bootCheckFlag, sizeof(g_bootParam.bootCheckFlag));
PrintArray("bootParam.recoveryModeSwitch", g_bootParam.recoveryModeSwitch, sizeof(g_bootParam.recoveryModeSwitch));
}
+#endif
}
void ResetBootParam(void)
diff --git a/src/driver/drv_atecc608b.c b/src/driver/drv_atecc608b.c
index 90e4227..0d22d58 100644
--- a/src/driver/drv_atecc608b.c
+++ b/src/driver/drv_atecc608b.c
@@ -158,6 +158,7 @@ int32_t Atecc608bKdf(uint8_t slot, const uint8_t *authKey, const uint8_t *inData
uint8_t nonce[32];
uint8_t ioProtectKey[32];
uint8_t authSlot;
+ uint32_t retry;
do {
authSlot = GetAuthSlot(slot);
@@ -165,24 +166,29 @@ int32_t Atecc608bKdf(uint8_t slot, const uint8_t *authKey, const uint8_t *inData
ret = ERR_ATECC608B_SLOT_NUM_ERR;
break;
}
- ret = Atecc608bAuthorize(authSlot, authKey);
- CHECK_ATECC608B_RET("auth", ret);
- ret = atcab_kdf(KDF_MODE_SOURCE_SLOT | KDF_MODE_TARGET_OUTPUT_ENC | KDF_MODE_ALG_HKDF,
- slot, KDF_DETAILS_HKDF_MSG_LOC_INPUT | (inLen << 24), inData, outData, nonce);
+ for (retry = 0; retry < 3; retry++) {
+ ret = Atecc608bAuthorize(authSlot, authKey);
+ if (ret != ATCA_SUCCESS) {
+ continue;
+ }
+ ret = atcab_kdf(KDF_MODE_SOURCE_SLOT | KDF_MODE_TARGET_OUTPUT_ENC | KDF_MODE_ALG_HKDF,
+ slot, KDF_DETAILS_HKDF_MSG_LOC_INPUT | (inLen << 24), inData, outData, nonce);
+ if (ret != ATCA_SUCCESS) {
+ continue;
+ }
+ GetIoProtectKey(ioProtectKey);
+ atca_io_decrypt_in_out_t io_dec_params = {
+ .io_key = ioProtectKey,
+ .out_nonce = nonce,
+ .data = outData,
+ .data_size = 32,
+ };
+ ret = atcah_io_decrypt(&io_dec_params);
+ if (ret == ATCA_SUCCESS) {
+ break;
+ }
+ }
CHECK_ATECC608B_RET("kdf", ret);
- //PrintArray("outData", outData, 32);
- //PrintArray("nonce", nonce, 32);
- GetIoProtectKey(ioProtectKey);
- atca_io_decrypt_in_out_t io_dec_params = {
- .io_key = ioProtectKey,
- .out_nonce = nonce,
- .data = outData,
- .data_size = 32,
- };
- ret = atcah_io_decrypt(&io_dec_params);
- CHECK_ATECC608B_RET("atcah_io_decrypt", ret);
- //PrintArray("outData", outData, 32);
- //PrintArray("nonce", nonce, 32);
} while (0);
CLEAR_ARRAY(nonce);
CLEAR_ARRAY(ioProtectKey);
diff --git a/src/driver/drv_mpu.c b/src/driver/drv_mpu.c
index cfc5e32..de1fab8 100644
--- a/src/driver/drv_mpu.c
+++ b/src/driver/drv_mpu.c
@@ -5,6 +5,33 @@ static bool g_otpProtect = false;
extern uint32_t _sbss;
extern uint32_t _ebss;
+static uint8_t MpuRegionSizeField(uint32_t regionSize)
+{
+ if (regionSize <= MPU_REGION_SIZE_4G) {
+ return (uint8_t)regionSize;
+ }
+
+ uint32_t sizeBytes = 32U;
+ uint8_t sizeField = MPU_REGION_SIZE_32B;
+ while ((sizeBytes < regionSize) && (sizeField < MPU_REGION_SIZE_4G)) {
+ sizeBytes <<= 1U;
+ sizeField++;
+ }
+ return sizeField;
+}
+
+static void ConfigureMPUForSramNoExec(void)
+{
+ MpuSetProtection(MHSCPU_SRAM_BASE,
+ MHSCPU_SRAM_SIZE,
+ MPU_REGION_NUMBER7,
+ MPU_INSTRUCTION_ACCESS_DISABLE,
+ MPU_REGION_FULL_ACCESS,
+ MPU_ACCESS_NOT_SHAREABLE,
+ MPU_ACCESS_CACHEABLE,
+ MPU_ACCESS_BUFFERABLE);
+}
+
void MpuDisable(void)
{
__DMB();
@@ -51,7 +78,7 @@ void MpuSetProtection(uint32_t baseAddress, uint32_t regionSize, uint32_t region
mpu.Enable = MPU_REGION_ENABLE;
mpu.Number = regionNum;
mpu.BaseAddress = baseAddress;
- mpu.Size = regionSize;
+ mpu.Size = MpuRegionSizeField(regionSize);
mpu.SubRegionDisable = 0x00;
mpu.TypeExtField = MPU_TEX_LEVEL0;
mpu.AccessPermission = accessPermission;
@@ -90,7 +117,7 @@ void ConfigureMPUForBSS(void)
void MpuInit(void)
{
- ConfigureMPUForBSS();
+ ConfigureMPUForSramNoExec();
MpuSetOtpProtection(true);
}
@@ -111,4 +138,3 @@ void MpuSetOtpProtection(bool noAccess)
MPU_ACCESS_CACHEABLE,
MPU_ACCESS_BUFFERABLE);
}
-
diff --git a/src/driver/drv_qspi_flash.c b/src/driver/drv_qspi_flash.c
new file mode 100644
index 0000000..d573142
--- /dev/null
+++ b/src/driver/drv_qspi_flash.c
@@ -0,0 +1,181 @@
+#ifdef BUILD_PRODUCTION
+#include "drv_qspi_flash.h"
+#include "stdio.h"
+#include "mhscpu.h"
+#include "assert.h"
+#include "mh_rand.h"
+#include "mhscpu_qspi.h"
+
+static uint32_t CheckFlashType(void);
+
+QSPI_CommandTypeDef g_cmdType;
+
+/// @brief QSPI flash init, get model.
+/// @param
+void QspiFlashInit(void)
+{
+ uint32_t chipType;
+
+ SYSCTRL_AHBPeriphClockCmd(SYSCTRL_AHBPeriph_DMA | SYSCTRL_AHBPeriph_CRYPT, ENABLE);
+ SYSCTRL_AHBPeriphResetCmd(SYSCTRL_AHBPeriph_DMA | SYSCTRL_AHBPeriph_CRYPT, ENABLE);
+ SYSCTRL_APBPeriphClockCmd(SYSCTRL_APBPeriph_TRNG, ENABLE);
+ SYSCTRL_APBPeriphResetCmd(SYSCTRL_APBPeriph_TRNG, ENABLE);
+ mh_rand_init();
+ QSPI_Init(NULL);
+ QSPI_SetLatency(0);
+ chipType = CheckFlashType();
+ if (chipType == QSPI_SUPPORT_CHIP_JEDEC_ID_MICR) {
+ g_cmdType.Instruction = PAGE_PROG_CMD;
+ g_cmdType.BusMode = QSPI_BUSMODE_111;
+ g_cmdType.CmdFormat = QSPI_CMDFORMAT_CMD8_ADDR24_PDAT;
+ } else {
+ g_cmdType.Instruction = QUAD_INPUT_PAGE_PROG_CMD;
+ g_cmdType.BusMode = QSPI_BUSMODE_114;
+ g_cmdType.CmdFormat = QSPI_CMDFORMAT_CMD8_ADDR24_PDAT;
+ }
+}
+
+
+/// @brief Erase flash sector.
+/// @param addr Erase address.
+void QspiFlashErase(uint32_t addr)
+{
+ FLASH_EraseSector(addr);
+}
+
+
+/// @brief
+/// @param addr Write flash addr.
+/// @param data
+/// @param len
+void QspiFlashWrite(uint32_t addr, const uint8_t *data, uint32_t len)
+{
+#ifdef __ARMCC_VERSION
+ //FLASH_ProgramPage(&g_cmdType, NULL, addr, len, (uint8_t *)data);
+ AES_Program(&g_cmdType, NULL, addr, len, (uint8_t *)data);
+#else
+ QSPI_ProgramPage(&g_cmdType, NULL, addr, len, (uint8_t *)data);
+#endif
+}
+
+#include "log_print.h"
+/// @brief
+/// @param addr Write flash addr.
+/// @param data
+/// @param len
+void QspiFlashEraseAndWrite(uint32_t addr, const uint8_t *data, uint32_t len)
+{
+ ASSERT(len == 4096);
+
+ do {
+ __disable_irq();
+ FLASH_EraseSector(addr);
+ CACHE_CleanAll(CACHE);
+ AES_Program(&g_cmdType, NULL, addr, len, (uint8_t *)data);
+ if (memcmp(data, (uint8_t *)addr, len) == 0) {
+ printf("read back check ok %#x\n", addr);
+ break;
+ } else {
+ printf("encrypt check error....... %#x\n", addr);
+ PrintArray("write", data, len);
+ PrintArray("read", (uint8_t *)addr, len);
+ }
+ } while (0);
+ __enable_irq();
+}
+
+
+/// @brief Get flash type.
+/// @param
+/// @return
+static uint32_t CheckFlashType(void)
+{
+ uint32_t chip_type;
+ QSPI_CommandTypeDef test_cmd;
+
+ ROM_QSPI_ReleaseDeepPowerDown(NULL);
+
+ chip_type = ROM_QSPI_ReadID(NULL);
+ printf("FLASH ID = %#x \n", chip_type);
+ if (chip_type == 0xffffff) {
+ test_cmd.Instruction = 0x9F;
+ test_cmd.BusMode = QSPI_BUSMODE_444;
+ test_cmd.CmdFormat = QSPI_CMDFORMAT_CMD8_RREG24;
+ chip_type = ROM_QSPI_ReadID(&test_cmd);
+ printf("ReRead_FLASH ID = %#x \n", chip_type);
+ }
+
+ chip_type = chip_type >> 16;
+ switch (chip_type) {
+ case QSPI_SUPPORT_CHIP_JEDEC_ID_MICR: //MICRON
+ printf("QSPI Flash chip is MICRON\n");
+
+ //burst
+ test_cmd.Instruction = 0x81;
+ test_cmd.BusMode = QSPI_BUSMODE_111;
+ test_cmd.CmdFormat = QSPI_CMDFORMAT_CMD8_WREG8;
+ ROM_QSPI_WriteParam(&test_cmd, 0xF1);
+
+ CACHE->CACHE_CONFIG = (CACHE->CACHE_CONFIG & 0xFF00FFFF) | (0xA5 << 16);
+
+ test_cmd.Instruction = 0x61;
+ test_cmd.BusMode = QSPI_BUSMODE_111;
+ test_cmd.CmdFormat = QSPI_CMDFORMAT_CMD8_WREG16;
+ ROM_QSPI_WriteParam(&test_cmd, 0x4F);
+ break;
+
+ case QSPI_SUPPORT_CHIP_JEDEC_ID_MXIC: //MXIC
+ printf("QSPI Flash chip is MXIC\n");
+
+ test_cmd.Instruction = 0xC0;
+ test_cmd.BusMode = QSPI_BUSMODE_111;
+ test_cmd.CmdFormat = QSPI_CMDFORMAT_CMD8_WREG8;
+ ROM_QSPI_WriteParam(&test_cmd, 0x02); ///< 32Bytes
+
+ CACHE->CACHE_CONFIG = (CACHE->CACHE_CONFIG & 0xFF00FFFF) | (0xA5 << 16);
+
+ test_cmd.Instruction = 0x01;
+ test_cmd.BusMode = QSPI_BUSMODE_111;
+ test_cmd.CmdFormat = QSPI_CMDFORMAT_CMD8_WREG16;
+ ROM_QSPI_WriteParam(&test_cmd, 0x0042); ///< QE WEL
+ break;
+
+ case QSPI_SUPPORT_CHIP_JEDEC_ID_WD: //Winbond
+ printf("QSPI Flash chip is Winbond\n");
+
+ test_cmd.Instruction = WRITE_STATUS_REG1_CMD;
+ test_cmd.BusMode = QSPI_BUSMODE_111;
+ test_cmd.CmdFormat = QSPI_CMDFORMAT_CMD8_WREG16;
+ ROM_QSPI_WriteParam(&test_cmd, 0x0202);
+
+ test_cmd.Instruction = SET_BURST_WITH_WRAP;
+ test_cmd.BusMode = QSPI_BUSMODE_144;
+ test_cmd.CmdFormat = QSPI_CMDFORMAT_CMD8_DMY24_WREG8;
+ ROM_QSPI_WriteParam(&test_cmd, 0x40);
+
+ CACHE->CACHE_CONFIG = (CACHE->CACHE_CONFIG & 0xFF00FFFF) | (0xA5 << 16);
+ break;
+
+ case QSPI_SUPPORT_CHIP_JEDEC_ID_GD: ///< GD
+ printf("QSPI Flash chip is GD\n");
+
+ test_cmd.Instruction = WRITE_STATUS_REG1_CMD; ///< Write Status Register
+ test_cmd.BusMode = QSPI_BUSMODE_111;
+ test_cmd.CmdFormat = QSPI_CMDFORMAT_CMD8_WREG16;
+ ROM_QSPI_WriteParam(&test_cmd, 0x0200); ///< QE(low byte first, MSB first)
+
+ test_cmd.Instruction = SET_BURST_WITH_WRAP; ///< Set Burst with Wrap
+ test_cmd.BusMode = QSPI_BUSMODE_144;
+ test_cmd.CmdFormat = QSPI_CMDFORMAT_CMD8_DMY24_WREG8;
+ ROM_QSPI_WriteParam(&test_cmd, 0x40); ///< Wrap Length:32Bytes
+
+ CACHE->CACHE_CONFIG = (CACHE->CACHE_CONFIG & 0xFF00FFFF) | (0xA5 << 16);
+ break;
+
+ default:
+ printf("QSPI Flash chip Not Support\n");
+ break;
+ }
+ return chip_type;
+}
+#endif
\ No newline at end of file
diff --git a/src/driver/drv_qspi_flash.h b/src/driver/drv_qspi_flash.h
new file mode 100644
index 0000000..56a281c
--- /dev/null
+++ b/src/driver/drv_qspi_flash.h
@@ -0,0 +1,28 @@
+#ifndef _DRV_QSPI_FLASH_H
+#define _DRV_QSPI_FLASH_H
+
+#include "stdint.h"
+#include "stdbool.h"
+#include "err_code.h"
+#include "mhscpu_qspi.h"
+
+/// @brief QSPI flash init, get model.
+/// @param
+void QspiFlashInit(void);
+
+
+/// @brief Get battery voltage.
+/// @param addr Erase address.
+void QspiFlashErase(uint32_t addr);
+
+
+/// @brief
+/// @param addr Write flash addr.
+/// @param data
+/// @param len
+void QspiFlashWrite(uint32_t addr, const uint8_t *data, uint32_t len);
+
+void QspiFlashEraseAndWrite(uint32_t addr, const uint8_t *data, uint32_t len);
+
+
+#endif
diff --git a/src/driver/low_power.c b/src/driver/low_power.c
index 98f6f46..00073f8 100644
--- a/src/driver/low_power.c
+++ b/src/driver/low_power.c
@@ -152,11 +152,11 @@ void RecoverFromLowPower(void)
DS28S60_Open();
LcdInit();
LcdClear(0x0000);
+ LcdBacklightOn();
PubValueMsg(BACKGROUND_MSG_BATTERY_INTERVAL, 1);
SetLvglHandlerAndSnapShot(true);
g_lowPowerState = LOW_POWER_STATE_WORKING;
PubValueMsg(BACKGROUND_MSG_SD_CARD_CHANGE, 0);
- LcdBacklightOn();
#if (USB_POP_WINDOW_ENABLE == 0)
if (GetUSBSwitch() && GetUsbDetectState()) {
OpenUsb();
diff --git a/src/driver/usb/drv_usb.c b/src/driver/usb/drv_usb.c
index 5ec4189..62a5dc4 100644
--- a/src/driver/usb/drv_usb.c
+++ b/src/driver/usb/drv_usb.c
@@ -8,6 +8,10 @@ __ALIGN_BEGIN USB_OTG_CORE_HANDLE g_usbDev __ALIGN_END;
static volatile bool g_usbInit = false;
+#ifndef USB_IRQ_RTOS_SAFE_PRIO
+#define USB_IRQ_RTOS_SAFE_PRIO 1
+#endif
+
void UsbInit(void)
{
USBPHY_CR1_TypeDef usbphy_cr1;
@@ -27,6 +31,7 @@ void UsbInit(void)
memset_s(&g_usbDev, sizeof(g_usbDev), 0x00, sizeof(g_usbDev));
USBD_Init(&g_usbDev, USB_OTG_FS_CORE_ID, &USR_desc, DeviceCallback, &USRD_cb);
+ NVIC_SetPriority(USB_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), USB_IRQ_RTOS_SAFE_PRIO, 0));
g_usbInit = true;
}
}
@@ -64,4 +69,3 @@ bool UsbInitState(void)
return g_usbInit;
}
-
diff --git a/src/driver/usb/usbd_cdc_vcp.c b/src/driver/usb/usbd_cdc_vcp.c
index 75aaa51..b656e84 100644
--- a/src/driver/usb/usbd_cdc_vcp.c
+++ b/src/driver/usb/usbd_cdc_vcp.c
@@ -98,7 +98,10 @@ static uint16_t VCP_Ctrl(uint32_t Cmd, uint8_t* Buf, uint32_t Len)
break;
case SET_LINE_CODING:
- linecoding.bitrate = (uint32_t)(Buf[0] | (Buf[1] << 8) | (Buf[2] << 16) | (Buf[3] << 24));
+ if (Buf == NULL || Len < 7U) {
+ return USBD_FAIL;
+ }
+ linecoding.bitrate = (uint32_t)((uint32_t)Buf[0] | ((uint32_t)Buf[1] << 8) | ((uint32_t)Buf[2] << 16) | ((uint32_t)Buf[3] << 24));
linecoding.format = Buf[4];
linecoding.paritytype = Buf[5];
linecoding.datatype = Buf[6];
@@ -109,6 +112,9 @@ static uint16_t VCP_Ctrl(uint32_t Cmd, uint8_t* Buf, uint32_t Len)
break;
case GET_LINE_CODING:
+ if (Buf == NULL || Len < 7U) {
+ return USBD_FAIL;
+ }
Buf[0] = (uint8_t)(linecoding.bitrate);
Buf[1] = (uint8_t)(linecoding.bitrate >> 8);
Buf[2] = (uint8_t)(linecoding.bitrate >> 16);
@@ -179,7 +185,7 @@ uint32_t VCP_GetTxBuflen(void)
*/
uint8_t* VCP_GetTxBufrsaddr(void)
{
- return CDCData.SendBuffer->Buffer + CDCData.ReadBuffer->PushOffset;
+ return CDCData.SendBuffer->Buffer + CDCData.SendBuffer->PopOffset;
}
/**
diff --git a/src/driver/usb/usbd_composite.c b/src/driver/usb/usbd_composite.c
index ae73a29..50d5107 100644
--- a/src/driver/usb/usbd_composite.c
+++ b/src/driver/usb/usbd_composite.c
@@ -1,9 +1,11 @@
#include "usbd_composite.h"
#include "stdio.h"
+#include "string.h"
#include "usb_core.h"
#include "usbd_msc_core.h"
#include "usbd_cdc_core.h"
#include "usbd_desc.h"
+#include "usbd_req.h"
#include "log_print.h"
#include "usb_task.h"
@@ -20,6 +22,8 @@ static uint8_t CompositeSOF(void *pdev);
static uint8_t *GetCompositeConfigDescriptor(uint8_t speed, uint16_t *length);
static uint8_t *USBD_Composite_GetDeviceQualifierDescriptor(uint16_t *length);
static uint8_t *USBD_Composite_WinUSBOSStrDescriptor(uint16_t *length);
+static uint8_t AppendClassDescriptor(uint8_t *outDesc, uint16_t *length, uint8_t *descriptor, uint16_t descriptorSize, uint8_t interfaceIndex);
+static uint8_t CompositeSelectClass(USB_SETUP_REQ *req, uint8_t *isMsc);
__ALIGN_BEGIN static uint8_t CompositeConfigDescriptor[USB_COMPOSITE_CONFIG_DESC_MAX_SIZE] __ALIGN_END = {
0x09, /* bLength: Configuration Descriptor size */
@@ -44,6 +48,8 @@ __ALIGN_BEGIN static uint8_t CompositeConfigDescriptor[USB_COMPOSITE_CONFIG_DESC
};
static uint8_t g_interfaceCount = 0;
+static uint8_t g_mscInterfaceNo = 0xFF;
+static uint8_t g_cdcInterfaceNo = 0xFF;
USBD_Class_cb_TypeDef USBCompositeCb = {
CompositeInit,
@@ -84,13 +90,18 @@ static uint8_t CompositeDeInit(void *pdev, uint8_t cfgidx)
static uint8_t CompositeSetup(void *pdev, USB_SETUP_REQ *req)
{
- uint8_t index = LOBYTE(req->wIndex);
+ uint8_t isMsc = 0;
+ if (CompositeSelectClass(req, &isMsc) != USBD_OK) {
+ USBD_CtlError(pdev, req);
+ return USBD_FAIL;
+ }
- if (index == 0) {
+#ifdef USBD_ENABLE_MSC
+ if (isMsc != 0U) {
return USBD_MSC_cb.Setup(pdev, req);
- } else {
- return USBD_CDC_cb.Setup(pdev, req);
}
+#endif
+ return USBD_CDC_cb.Setup(pdev, req);
}
static uint8_t CompositeEP0_TxSent(void *pdev)
@@ -128,41 +139,111 @@ static uint8_t CompositeSOF(void* pdev)
return USBD_CDC_cb.SOF(pdev);
}
+static uint8_t AppendClassDescriptor(uint8_t *outDesc, uint16_t *length, uint8_t *descriptor, uint16_t descriptorSize, uint8_t interfaceIndex)
+{
+ if (outDesc == NULL || length == NULL || descriptor == NULL || descriptorSize < 9U) {
+ return 0U;
+ }
+
+ descriptorSize -= 9U;
+ if ((uint32_t)(*length) + descriptorSize > USB_COMPOSITE_CONFIG_DESC_MAX_SIZE) {
+ return 0U;
+ }
+
+ descriptor[9 + 2] = interfaceIndex;
+ memcpy(outDesc + *length, descriptor + 9U, descriptorSize);
+ *length += descriptorSize;
+ return 1U;
+}
+
static uint8_t *GetCompositeConfigDescriptor(uint8_t speed, uint16_t *length)
{
uint16_t descriptorSize = 0;
uint8_t *descriptor;
uint8_t interfaceIndex = 0;
+ uint8_t appendOk = 0;
g_interfaceCount = 0;
+ g_mscInterfaceNo = 0xFF;
+ g_cdcInterfaceNo = 0xFF;
*length = 9;
#ifdef USBD_ENABLE_MSC
//MSC
descriptor = USBD_MSC_cb.GetConfigDescriptor(speed, &descriptorSize);
- descriptorSize -= 9;
- descriptor[9 + 2] = interfaceIndex;
+ appendOk = AppendClassDescriptor(CompositeConfigDescriptor, length, descriptor, descriptorSize, interfaceIndex);
+ if (!appendOk) {
+ *length = 9;
+ return CompositeConfigDescriptor;
+ }
+ g_mscInterfaceNo = interfaceIndex;
interfaceIndex++;
- memcpy(CompositeConfigDescriptor + *length, descriptor + 9, descriptorSize);
- *length += descriptorSize;
g_interfaceCount++;
#endif
//CDC
descriptor = USBD_CDC_cb.GetConfigDescriptor(speed, &descriptorSize);
- descriptorSize -= 9;
- descriptor[9 + 2] = interfaceIndex;
- memcpy(CompositeConfigDescriptor + *length, descriptor + 9, descriptorSize);
- *length += descriptorSize;
+ appendOk = AppendClassDescriptor(CompositeConfigDescriptor, length, descriptor, descriptorSize, interfaceIndex);
+ if (!appendOk) {
+ *length = 9;
+ return CompositeConfigDescriptor;
+ }
+ g_cdcInterfaceNo = interfaceIndex;
g_interfaceCount++;
- CompositeConfigDescriptor[2] = *length;
+ CompositeConfigDescriptor[2] = (uint8_t)(*length & 0xFFU);
+ CompositeConfigDescriptor[3] = (uint8_t)((*length >> 8) & 0xFFU);
CompositeConfigDescriptor[4] = g_interfaceCount;
//printf("length=%d\r\n", *length);
//PrintArray("Descriptor", CompositeConfigDescriptor, *length);
return CompositeConfigDescriptor;
}
+static uint8_t CompositeSelectClass(USB_SETUP_REQ *req, uint8_t *isMsc)
+{
+ uint8_t recipient;
+ uint8_t index;
+ uint8_t epNum;
+
+ if (req == NULL || isMsc == NULL) {
+ return USBD_FAIL;
+ }
+
+ *isMsc = 0U;
+ recipient = req->bmRequest & USB_REQ_RECIPIENT_MASK;
+ index = LOBYTE(req->wIndex);
+
+ switch (recipient) {
+ case USB_REQ_RECIPIENT_INTERFACE:
+#ifdef USBD_ENABLE_MSC
+ if (index == g_mscInterfaceNo) {
+ *isMsc = 1U;
+ return USBD_OK;
+ }
+#endif
+ if (index == g_cdcInterfaceNo) {
+ return USBD_OK;
+ }
+ return USBD_FAIL;
+
+ case USB_REQ_RECIPIENT_ENDPOINT:
+ epNum = index & 0x7FU;
+#ifdef USBD_ENABLE_MSC
+ if ((epNum == (MSC_IN_EP & 0x7FU)) || (epNum == (MSC_OUT_EP & 0x7FU))) {
+ *isMsc = 1U;
+ return USBD_OK;
+ }
+#endif
+ if ((epNum == (CDC_IN_EP & 0x7FU)) || (epNum == (CDC_OUT_EP & 0x7FU))) {
+ return USBD_OK;
+ }
+ return USBD_FAIL;
+
+ default:
+ return USBD_FAIL;
+ }
+}
+
__ALIGN_BEGIN static uint8_t USBD_Composite_DeviceQualifierDesc[USB_LEN_DEV_QUALIFIER_DESC] __ALIGN_END = {
USB_LEN_DEV_QUALIFIER_DESC,
USB_DESC_TYPE_DEVICE_QUALIFIER,
diff --git a/src/driver/usb/usbd_desc.c b/src/driver/usb/usbd_desc.c
index ae902ae..beebcd6 100644
--- a/src/driver/usb/usbd_desc.c
+++ b/src/driver/usb/usbd_desc.c
@@ -146,7 +146,7 @@ uint8_t* USBD_USR_LangIDStrDescriptor(uint8_t speed, uint16_t* length)
*/
uint8_t* USBD_USR_ProductStrDescriptor(uint8_t speed, uint16_t* length)
{
- USBD_GetString((uint8_t*)USBD_PRODUCT_STRING, USBD_StrDesc, length);
+ USBD_GetString((uint8_t*)USBD_PRODUCT_STRING, sizeof(USBD_PRODUCT_STRING) - 1U, USBD_StrDesc, length);
return USBD_StrDesc;
}
@@ -159,7 +159,7 @@ uint8_t* USBD_USR_ProductStrDescriptor(uint8_t speed, uint16_t* length)
*/
uint8_t* USBD_USR_ManufacturerStrDescriptor(uint8_t speed, uint16_t* length)
{
- USBD_GetString((uint8_t*)USBD_MANUFACTURER_STRING, USBD_StrDesc, length);
+ USBD_GetString((uint8_t*)USBD_MANUFACTURER_STRING, sizeof(USBD_MANUFACTURER_STRING) - 1U, USBD_StrDesc, length);
return USBD_StrDesc;
}
@@ -201,7 +201,7 @@ uint8_t* USBD_USR_SerialStrDescriptor(uint8_t speed, uint16_t* length)
usbSN[i] += usbSN[i] < 0x0A ? '0' : '7';
}
- USBD_GetString(usbSN, USBD_StrDesc, length);
+ USBD_GetString(usbSN, *length, USBD_StrDesc, length);
return USBD_StrDesc;
}
@@ -214,7 +214,7 @@ uint8_t* USBD_USR_SerialStrDescriptor(uint8_t speed, uint16_t* length)
*/
uint8_t* USBD_USR_ConfigStrDescriptor(uint8_t speed, uint16_t* length)
{
- USBD_GetString((uint8_t*)USBD_CONFIGURATION_STRING, USBD_StrDesc, length);
+ USBD_GetString((uint8_t*)USBD_CONFIGURATION_STRING, sizeof(USBD_CONFIGURATION_STRING) - 1U, USBD_StrDesc, length);
return USBD_StrDesc;
}
@@ -227,7 +227,7 @@ uint8_t* USBD_USR_ConfigStrDescriptor(uint8_t speed, uint16_t* length)
*/
uint8_t* USBD_USR_InterfaceStrDescriptor(uint8_t speed, uint16_t* length)
{
- USBD_GetString((uint8_t*)USBD_INTERFACE_STRING, USBD_StrDesc, length);
+ USBD_GetString((uint8_t*)USBD_INTERFACE_STRING, sizeof(USBD_INTERFACE_STRING) - 1U, USBD_StrDesc, length);
return USBD_StrDesc;
}
@@ -340,7 +340,7 @@ __ALIGN_BEGIN uint8_t USBD_WINUSB_OSPropertyDesc[USB_LEN_OS_PROPERTY_DESC] __ALI
uint8_t *USBD_WinUSBOSStrDescriptor(uint16_t *length)
{
//printf("USBD_WinUSBOSStrDescriptor!\r\n");
- USBD_GetString((uint8_t *)USBD_OS_STRING, USBD_StrDesc, length);
+ USBD_GetString((uint8_t *)USBD_OS_STRING, sizeof(USBD_OS_STRING), USBD_StrDesc, length);
return USBD_StrDesc;
}
diff --git a/src/driver/usb/usbd_storage_msd.c b/src/driver/usb/usbd_storage_msd.c
index c27bc98..e71dfdd 100644
--- a/src/driver/usb/usbd_storage_msd.c
+++ b/src/driver/usb/usbd_storage_msd.c
@@ -96,7 +96,21 @@ int8_t STORAGE_IsWriteProtected(uint8_t lun)
int8_t STORAGE_Read(uint8_t lun, uint8_t* buffer, uint32_t block_number, uint16_t count)
{
- Gd25FlashReadBuffer(block_number * MSC_MEDIA_PACKET, buffer, MSC_MEDIA_PACKET * count);
+ uint64_t startAddr = (uint64_t)block_number * MSC_MEDIA_PACKET;
+ uint64_t totalSize = (uint64_t)count * MSC_MEDIA_PACKET;
+ uint64_t mediaSize = ((uint64_t)GD25QXX_SECTOR_NUM / 2U) * MSC_MEDIA_PACKET;
+
+ if (buffer == NULL) {
+ return -1;
+ }
+ if (totalSize == 0U) {
+ return 0;
+ }
+ if (startAddr >= mediaSize || totalSize > (mediaSize - startAddr)) {
+ return -1;
+ }
+
+ Gd25FlashReadBuffer((uint32_t)startAddr, buffer, (uint32_t)totalSize);
return 0;
}
@@ -110,8 +124,32 @@ int8_t STORAGE_Read(uint8_t lun, uint8_t* buffer, uint32_t block_number, uint16_
*/
int8_t STORAGE_Write(uint8_t lun, uint8_t* buffer, uint32_t block_number, uint16_t count)
{
- Gd25FlashSectorErase(block_number * MSC_MEDIA_PACKET);
- Gd25FlashWriteBuffer(block_number * MSC_MEDIA_PACKET, buffer, count * MSC_MEDIA_PACKET);
+ uint64_t startAddr = (uint64_t)block_number * MSC_MEDIA_PACKET;
+ uint64_t totalSize = (uint64_t)count * MSC_MEDIA_PACKET;
+ uint64_t mediaSize = ((uint64_t)GD25QXX_SECTOR_NUM / 2U) * MSC_MEDIA_PACKET;
+ uint32_t start_addr;
+ uint32_t total_size;
+
+ if (buffer == NULL) {
+ return -1;
+ }
+ if (totalSize == 0U) {
+ return 0;
+ }
+ if (startAddr >= mediaSize || totalSize > (mediaSize - startAddr)) {
+ return -1;
+ }
+
+ start_addr = (uint32_t)startAddr;
+ total_size = (uint32_t)totalSize;
+
+ uint32_t first_sector = start_addr / GD25QXX_SECTOR_SIZE;
+ uint32_t last_sector = (start_addr + total_size - 1U) / GD25QXX_SECTOR_SIZE;
+ for (uint32_t sector = first_sector; sector <= last_sector; sector++) {
+ Gd25FlashSectorErase(sector * GD25QXX_SECTOR_SIZE);
+ }
+
+ Gd25FlashWriteBuffer(start_addr, buffer, total_size);
return 0;
}
diff --git a/src/main.c b/src/main.c
index 08edc8f..f0e540b 100644
--- a/src/main.c
+++ b/src/main.c
@@ -50,12 +50,14 @@
#include "version.h"
#include "hardware_version.h"
#include "librust_c.h"
+#include "drv_mpu.h"
int main(void)
{
__enable_irq();
SetAllGpioLow();
SystemClockInit();
+ MpuInit();
SensorInit();
Uart0Init(CmdIsrRcvByte);
FingerprintInit();
@@ -77,7 +79,6 @@ int main(void)
Atecc608bInit();
AccountsDataCheck();
MountUsbFatfs();
- UsbInit();
RtcInit();
MotorInit();
BatteryInit();
diff --git a/src/presetting.c b/src/presetting.c
index bb82833..cd1f664 100644
--- a/src/presetting.c
+++ b/src/presetting.c
@@ -57,12 +57,13 @@ int32_t GetWebAuthRsaKey(uint8_t *key)
data = SRAM_MALLOC(WEB_AUTH_RSA_KEY_LEN);
memcpy(data, (uint8_t *)OTP_ADDR_WEB_AUTH_RSA_KEY, WEB_AUTH_RSA_KEY_LEN);
if (CheckEntropy(data, WEB_AUTH_RSA_KEY_LEN) == false) {
+ MpuSetOtpProtection(true);
SRAM_FREE(data);
return ERR_WEB_AUTH_KEY_NOT_EXIST;
}
- SRAM_FREE(data);
- memcpy(key, data, WEB_AUTH_RSA_KEY_LEN);
MpuSetOtpProtection(true);
+ memcpy(key, data, WEB_AUTH_RSA_KEY_LEN);
+ SRAM_FREE(data);
return SUCCESS_CODE;
}
diff --git a/src/tasks/background_task.c b/src/tasks/background_task.c
index 37b36bf..521807a 100644
--- a/src/tasks/background_task.c
+++ b/src/tasks/background_task.c
@@ -92,10 +92,10 @@ static void BackgroundTask(void *argument)
GuiApiEmitSignalWithValue(SIG_INIT_USB_CONNECTION, 0);
GuiApiEmitSignalWithValue(SIG_INIT_PULLOUT_USB, 0);
} else if (GetUSBSwitch()) {
-#if (USB_POP_WINDOW_ENABLE == 1)
- GuiApiEmitSignalWithValue(SIG_INIT_USB_CONNECTION, 1);
-#else
+#if (USB_POP_WINDOW_ENABLE == 0)
OpenUsb();
+#else
+ GuiApiEmitSignalWithValue(SIG_INIT_USB_CONNECTION, 1);
#endif
}
GuiApiEmitSignal(SIG_INIT_BATTERY, &battState, sizeof(battState));
diff --git a/src/tasks/data_parser_task.c b/src/tasks/data_parser_task.c
index 0a0315a..94bb8d9 100644
--- a/src/tasks/data_parser_task.c
+++ b/src/tasks/data_parser_task.c
@@ -98,10 +98,38 @@ void CreateDataParserTask(void)
g_dataParserHandle = osThreadNew(DataParserTask, NULL, &dataParserTask_attributes);
}
-void PushDataToField(uint8_t *data, uint16_t len)
+bool CanPushDataToField(uint16_t len)
{
- for (int i = 0; i < len; i++) {
- circular_buf_put(g_cBufHandle, data[i]);
+ if (g_cBufHandle == NULL) {
+ return false;
+ }
+
+ size_t capacity = circular_buf_capacity(g_cBufHandle);
+ size_t used = circular_buf_size(g_cBufHandle);
+ return (capacity >= used) && ((capacity - used) >= len);
+}
+
+uint16_t PushDataToField(const uint8_t *data, uint16_t len)
+{
+ if (data == NULL || len == 0 || !CanPushDataToField(len)) {
+ return 0;
+ }
+
+ uint16_t pushed = 0;
+ for (uint16_t i = 0; i < len; i++) {
+ if (circular_buf_try_put(g_cBufHandle, data[i]) != 0) {
+ break;
+ }
+ pushed++;
+ }
+
+ return pushed;
+}
+
+void ResetDataField(void)
+{
+ if (g_cBufHandle != NULL) {
+ circular_buf_reset(g_cBufHandle);
}
}
@@ -133,12 +161,23 @@ static void DataParserTask(void *argument)
continue;
}
switch (rcvMsg.id) {
- case SPRING_MSG_GET:
- for (int i = 0; i < rcvMsg.value; i++) {
- circular_buf_get(g_cBufHandle, &USB_Rx_Buffer[i]);
+ case SPRING_MSG_GET: {
+ uint32_t targetLen = rcvMsg.value;
+ if (targetLen > sizeof(USB_Rx_Buffer) - 1U) {
+ targetLen = sizeof(USB_Rx_Buffer) - 1U;
+ }
+ uint32_t actualLen = 0;
+ for (uint32_t i = 0; i < targetLen; i++) {
+ if (circular_buf_get(g_cBufHandle, &USB_Rx_Buffer[i]) != 0) {
+ break;
+ }
+ actualLen++;
+ }
+ if (actualLen > 0U) {
+ ProtocolReceivedData(USB_Rx_Buffer, actualLen, USBD_cdc_SendBuffer_Cb);
}
- ProtocolReceivedData(USB_Rx_Buffer, rcvMsg.value, USBD_cdc_SendBuffer_Cb);
break;
+ }
default:
break;
}
@@ -176,4 +215,4 @@ void MemManage_Handler(void)
// system reset test
*(uint32_t *)0 = 123;
NVIC_SystemReset();
-}
\ No newline at end of file
+}
diff --git a/src/tasks/data_parser_task.h b/src/tasks/data_parser_task.h
index 1dd6d4f..340990c 100644
--- a/src/tasks/data_parser_task.h
+++ b/src/tasks/data_parser_task.h
@@ -10,5 +10,8 @@ uint8_t *GetDeviceParserPubKey(uint8_t *webPub, uint16_t len);
void DataEncrypt(uint8_t *data, uint16_t len);
void DataDecrypt(uint8_t *data, uint8_t *plain, uint16_t len);
void SetDeviceParserIv(uint8_t *iv);
+bool CanPushDataToField(uint16_t len);
+uint16_t PushDataToField(const uint8_t *data, uint16_t len);
+void ResetDataField(void);
#endif
diff --git a/src/tasks/ui_display_task.c b/src/tasks/ui_display_task.c
index 54f3770..9ee3a01 100644
--- a/src/tasks/ui_display_task.c
+++ b/src/tasks/ui_display_task.c
@@ -12,13 +12,11 @@
#include "user_memory.h"
#include "gui_chain.h"
#include "drv_lcd_bright.h"
-#include "drv_mpu.h"
#include "device_setting.h"
#include "anti_tamper.h"
#include "screenshot.h"
#include "lv_i18n_api.h"
#include "gui_api.h"
-#include "drv_mpu.h"
#include "drv_gd25qxx.h"
#define LVGL_FAST_TICK_MS 5
@@ -102,8 +100,6 @@ static void UiDisplayTask(void *argument)
}
GuiFrameOpenView(&g_initView);
SetLcdBright(GetBright());
- MpuInit();
-
while (1) {
RefreshLvglTickMode();
ret = osMessageQueueGet(g_uiQueue, &rcvMsg, NULL, g_dynamicTick);
@@ -419,4 +415,4 @@ void NftLockDecodeTouchQuit(void)
}
}
}
-#endif
\ No newline at end of file
+#endif
diff --git a/src/tasks/usb_task.c b/src/tasks/usb_task.c
index e70deac..54b5721 100644
--- a/src/tasks/usb_task.c
+++ b/src/tasks/usb_task.c
@@ -62,20 +62,11 @@ static void UsbTask(void *argument)
Message_t rcvMsg;
osStatus_t ret;
- osDelay(1000);
-#if (USB_POP_WINDOW_ENABLE == 1)
- CloseUsb();
-#else
- if (GetUSBSwitch() && GetUsbDetectState()) {
- OpenUsb();
- }
-#endif
while (1) {
ret = osMessageQueueGet(g_usbQueue, &rcvMsg, NULL, 10000);
if (ret == osOK) {
switch (rcvMsg.id) {
case USB_MSG_ISR_HANDLER: {
- ClearLockScreenTime();
USBD_OTG_ISR_Handler((USB_OTG_CORE_HANDLE *)rcvMsg.value);
NVIC_ClearPendingIRQ(USB_IRQn);
NVIC_EnableIRQ(USB_IRQn);
@@ -87,6 +78,7 @@ static void UsbTask(void *argument)
break;
case USB_MSG_INIT: {
g_usbState = true;
+ ClearLockScreenTime();
UsbInit();
SetUsbState(true);
}
@@ -120,4 +112,3 @@ void UsbTest(int argc, char *argv[])
CloseUsb();
}
}
-
diff --git a/src/ui/gui_analyze/gui_analyze.c b/src/ui/gui_analyze/gui_analyze.c
index eb9e48d..aada31a 100644
--- a/src/ui/gui_analyze/gui_analyze.c
+++ b/src/ui/gui_analyze/gui_analyze.c
@@ -519,7 +519,6 @@ static void DisplayJsonRecursive(lv_obj_t *parent, cJSON *item, int indent, uint
if (cJSON_IsObject(item)) {
DisplayJsonRecursive(parent, item->child, indent + 1, yOffset);
} else if (cJSON_IsArray(item)) {
- int size = cJSON_GetArraySize(item);
for (int i = 0; i < 1; i++) {
cJSON* subitem = cJSON_GetArrayItem(item, i);
DisplayJsonRecursive(parent, subitem, indent, yOffset);
diff --git a/src/ui/gui_assets/font/en/openSansEnIllustrate.c b/src/ui/gui_assets/font/en/openSansEnIllustrate.c
index eccc45a..29f8d9e 100644
--- a/src/ui/gui_assets/font/en/openSansEnIllustrate.c
+++ b/src/ui/gui_assets/font/en/openSansEnIllustrate.c
@@ -1,7 +1,7 @@
/*******************************************************************************
* Size: 20 px
* Bpp: 4
- * Opts:
+ * Opts: --bpp 4 --size 20 --no-compress --format lvgl --font src/ui/lv_i18n/Open Sans Regular.ttf --range 0x20-0x7E --symbols £¥·ἀἁἂἃἄἅἆἇἈἉ’”€√ --font src/ui/lv_i18n/NotoSans-Regular.ttf --symbols ₮ -o src/ui/gui_assets/font/en/openSansEnIllustrate.c
******************************************************************************/
#ifdef LV_LVGL_H_INCLUDE_SIMPLE
@@ -1021,30 +1021,68 @@ static LV_ATTRIBUTE_LARGE_CONST const uint8_t glyph_bitmap[] = {
0x19, 0x47, 0xfc, 0x4f, 0x80,
/* U+1F00 "ἀ" */
- 0x0, 0x0, 0x5, 0xff, 0xff, 0xe2, 0x0, 0x0,
- 0x0, 0x0, 0x4, 0xf5, 0x22, 0x29, 0xd1, 0x0,
- 0x0, 0x0, 0x4, 0xf5, 0x0, 0x0, 0x9, 0xd1,
- 0x0, 0x0, 0x3, 0xf6, 0x0, 0x0, 0x0, 0xa,
- 0xc0, 0x0, 0x2, 0xe6, 0x0, 0x0, 0x0, 0x0,
- 0xb, 0xb0, 0x2, 0xe7, 0x0, 0x0, 0x0, 0x0,
- 0x0, 0xc, 0xb0, 0xd8, 0x0, 0x0, 0x0, 0x0,
- 0x0, 0x0, 0xc, 0x8f, 0xff, 0xf7, 0x0, 0x0,
- 0x0, 0xb, 0xff, 0xfb, 0x22, 0x2b, 0x70, 0x0,
- 0x0, 0x0, 0xc7, 0x22, 0x10, 0x0, 0xa7, 0x0,
- 0x0, 0x0, 0xc, 0x50, 0x0, 0x0, 0xa, 0x70,
- 0x0, 0x0, 0x0, 0xc5, 0x0, 0x0, 0x0, 0xa7,
- 0x0, 0x0, 0x0, 0xc, 0x50, 0x0, 0x0, 0xa,
- 0xff, 0xff, 0xff, 0xff, 0xf5, 0x0, 0x0, 0x0,
- 0x12, 0x22, 0x22, 0x22, 0x22, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x27, 0x30, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x4, 0xff, 0xf6, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x4f, 0xf7, 0xef, 0x50,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4,
+ 0xff, 0x50, 0x3f, 0xf5, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x3f, 0xf5, 0x0, 0x3, 0xff,
+ 0x50, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, 0xff,
+ 0x60, 0x0, 0x0, 0x4f, 0xf4, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x3f, 0xf6, 0x0, 0x0, 0x0, 0x4,
+ 0xff, 0x40, 0x0, 0x0, 0x0, 0x3, 0xef, 0x70,
+ 0x0, 0x0, 0x0, 0x0, 0x5f, 0xf4, 0x0, 0x0,
+ 0x0, 0x2e, 0xf8, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x6, 0xff, 0x40, 0x0, 0x2, 0xef, 0x80, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x6f, 0xf3, 0x0,
+ 0x2e, 0xf9, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x7, 0xff, 0x30, 0xbf, 0x90, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8f, 0xd0,
+ 0xcf, 0xff, 0xff, 0x80, 0x0, 0x0, 0x0, 0x0,
+ 0x7f, 0xff, 0xff, 0xd0, 0x3d, 0xff, 0xff, 0x90,
+ 0x0, 0x0, 0x0, 0x0, 0x7f, 0xff, 0xfe, 0x40,
+ 0x0, 0x0, 0x5f, 0x90, 0x0, 0x0, 0x0, 0x0,
+ 0x7f, 0x70, 0x0, 0x0, 0x0, 0x0, 0x5f, 0x90,
+ 0x0, 0x0, 0x0, 0x0, 0x7f, 0x70, 0x0, 0x0,
+ 0x0, 0x0, 0x5f, 0x90, 0x0, 0x0, 0x0, 0x0,
+ 0x7f, 0x70, 0x0, 0x0, 0x0, 0x0, 0x5f, 0x90,
+ 0x0, 0x0, 0x0, 0x0, 0x7f, 0x70, 0x0, 0x0,
+ 0x0, 0x0, 0x5f, 0x90, 0x0, 0x0, 0x0, 0x0,
+ 0x7f, 0x70, 0x0, 0x0, 0x0, 0x0, 0x5f, 0x90,
+ 0x0, 0x0, 0x0, 0x0, 0x7f, 0x70, 0x0, 0x0,
+ 0x0, 0x0, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0x50, 0x0, 0x0, 0x0, 0x0, 0x9, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xfa, 0x0, 0x0, 0x0,
/* U+1F01 "ἁ" */
- 0xd1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
- 0x0, 0x1d, 0xf1, 0x0, 0x0, 0x0, 0x0, 0x0,
- 0x0, 0x0, 0x0, 0x1f, 0xf1, 0x0, 0x0, 0x0,
- 0x0, 0x0, 0x0, 0x0, 0x0, 0x1f, 0xff, 0xff,
+ 0x16, 0x61, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x47, 0x40, 0xaf, 0xfa, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1,
+ 0xff, 0xf3, 0xbf, 0xfa, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x2, 0xff, 0xf3, 0xbf,
+ 0xfa, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x2, 0xff, 0xf3, 0xbf, 0xfa, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0xff,
+ 0xf3, 0xbf, 0xfa, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x2, 0xff, 0xf3, 0xbf, 0xfa,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x2, 0xff, 0xf3, 0xbf, 0xfb, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0xff, 0xf3,
+ 0x8f, 0xff, 0xed, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ 0xdd, 0xdd, 0xdf, 0xff, 0xf1, 0x7, 0xdf, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
- 0x22, 0x22,
+ 0xeb, 0x30,
/* U+1F02 "ἂ" */
0x6f, 0x90, 0x0, 0x0, 0x0, 0x0, 0xa, 0xff,
@@ -1066,24 +1104,44 @@ static LV_ATTRIBUTE_LARGE_CONST const uint8_t glyph_bitmap[] = {
0x0, 0x0,
/* U+1F03 "ἃ" */
- 0x0, 0x0, 0x4f, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0x20, 0x0, 0x2f, 0xd9, 0x99, 0x99, 0x99,
- 0x99, 0x9a, 0xf2, 0x0, 0xd, 0xe1, 0x0, 0x0,
- 0x0, 0x0, 0x0, 0x2f, 0x20, 0xa, 0xf4, 0x0,
- 0x0, 0x0, 0x0, 0x0, 0x2, 0xf2, 0x5, 0xf9,
- 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2f, 0x20,
- 0xee, 0x10, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2,
- 0xf2, 0x4f, 0x50, 0x0, 0x0, 0x0, 0x0, 0x0,
- 0x0, 0x2f, 0x25, 0xf2, 0x0, 0x0, 0x4f, 0xff,
- 0xff, 0x80, 0x2, 0xf2, 0x3f, 0x20, 0x0, 0x2,
- 0x99, 0x99, 0x95, 0x0, 0x2f, 0x20, 0xda, 0x0,
- 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0xf2, 0x5,
- 0xf5, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2f,
- 0x20, 0xa, 0xf2, 0x0, 0x0, 0x0, 0x0, 0x0,
- 0x2, 0xf2, 0x0, 0xd, 0xd1, 0x0, 0x0, 0x0,
- 0x0, 0x0, 0x2f, 0x20, 0x0, 0x2e, 0xd8, 0x88,
- 0x88, 0x88, 0x88, 0x89, 0xf2, 0x0, 0x0, 0x4e,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x20,
+ 0x0, 0x0, 0x0, 0x3, 0xae, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xea, 0x20, 0x0, 0x0, 0x0,
+ 0x6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0x30, 0x0, 0x0, 0x5, 0xff, 0xe8,
+ 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x8f, 0xfe,
+ 0x0, 0x0, 0x1, 0xef, 0xd1, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x4f, 0xf5, 0x0, 0x0,
+ 0xaf, 0xf2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0xef, 0x70, 0x0, 0x5f, 0xf7, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xd,
+ 0xf8, 0x0, 0x1e, 0xfc, 0x0, 0x0, 0xa, 0xe4,
+ 0x0, 0x2, 0xec, 0x0, 0x0, 0xdf, 0x80, 0xa,
+ 0xff, 0x20, 0x0, 0x0, 0xdf, 0xf4, 0x2, 0xef,
+ 0xf0, 0x0, 0xd, 0xf8, 0x5, 0xff, 0x70, 0x0,
+ 0x0, 0x2, 0xef, 0xf6, 0xef, 0xf4, 0x0, 0x0,
+ 0xdf, 0x80, 0xdf, 0xd0, 0x0, 0x0, 0x0, 0x2,
+ 0xef, 0xff, 0xf4, 0x0, 0x0, 0xd, 0xf8, 0xf,
+ 0xf6, 0x0, 0x0, 0x0, 0x0, 0x5, 0xff, 0xf8,
+ 0x0, 0x0, 0x0, 0xdf, 0x80, 0xff, 0x90, 0x0,
+ 0x0, 0x0, 0x2, 0xef, 0xff, 0xf4, 0x0, 0x0,
+ 0xd, 0xf8, 0x8, 0xff, 0x40, 0x0, 0x0, 0x2,
+ 0xef, 0xf7, 0xef, 0xf3, 0x0, 0x0, 0xdf, 0x80,
+ 0xd, 0xfd, 0x0, 0x0, 0x0, 0xcf, 0xf5, 0x3,
+ 0xef, 0xf0, 0x0, 0xd, 0xf8, 0x0, 0x4f, 0xf9,
+ 0x0, 0x0, 0xa, 0xf5, 0x0, 0x3, 0xed, 0x0,
+ 0x0, 0xdf, 0x80, 0x0, 0x9f, 0xf3, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xd, 0xf8,
+ 0x0, 0x0, 0xef, 0xd0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0xdf, 0x80, 0x0, 0x4,
+ 0xff, 0x90, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x1f, 0xf6, 0x0, 0x0, 0x9, 0xff, 0xa2,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2c, 0xff,
+ 0x10, 0x0, 0x0, 0xc, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0x70, 0x0, 0x0,
+ 0x0, 0x8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0x70, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x45, 0x66, 0x66, 0x66, 0x66, 0x66, 0x54, 0x0,
+ 0x0,
/* U+1F04 "ἄ" */
0x0, 0x0, 0x0, 0x0, 0x1, 0xaf, 0xc3, 0x0,
@@ -1129,84 +1187,167 @@ static LV_ATTRIBUTE_LARGE_CONST const uint8_t glyph_bitmap[] = {
0x0, 0x0, 0x0, 0xb, 0xa0, 0x0, 0x0, 0x0,
/* U+1F06 "ἆ" */
- 0x0, 0x0, 0xf, 0xff, 0xff, 0xfb, 0x0, 0x0,
- 0x0, 0x0, 0x0, 0xfe, 0xbb, 0xbf, 0xb0, 0x0,
- 0x0, 0x0, 0x0, 0xf, 0xb0, 0x0, 0xfb, 0x0,
- 0x0, 0xa, 0xaa, 0xaa, 0xfb, 0x0, 0xf, 0xea,
- 0xaa, 0xa7, 0xff, 0xff, 0xff, 0xb0, 0x0, 0xff,
- 0xff, 0xff, 0xbf, 0xb0, 0x0, 0x0, 0x0, 0x0,
- 0x0, 0x0, 0xfa, 0xfb, 0x0, 0x0, 0x0, 0x0,
- 0x0, 0x0, 0xf, 0xaf, 0xb0, 0x0, 0x0, 0x0,
- 0x0, 0x0, 0x0, 0xfa, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0x9b, 0xbb, 0xbb, 0xbb,
- 0xbb, 0xbb, 0xbb, 0xbe, 0xf5, 0x0, 0x0, 0x0,
- 0x0, 0x0, 0x0, 0x0, 0xcf, 0x2, 0xb5, 0x0,
- 0xb7, 0x0, 0x0, 0x0, 0xd, 0xd0, 0x2f, 0x80,
- 0xf, 0xb0, 0x0, 0x0, 0x0, 0xdd, 0x3, 0xf8,
- 0x0, 0xfb, 0x0, 0x0, 0x0, 0xd, 0xe0, 0x3f,
- 0x80, 0xf, 0xb0, 0x0, 0x0, 0x0, 0xdd, 0x0,
- 0xfe, 0xcc, 0xfe, 0xcc, 0xcc, 0xcc, 0xcf, 0xa0,
- 0x7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf2,
- 0x0,
+ 0x0, 0x0, 0x6, 0x0, 0x0, 0x9, 0x70, 0x0,
+ 0x8, 0x70, 0x0, 0x8, 0x70, 0x0, 0x8, 0x70,
+ 0x0, 0x0, 0x87, 0x0, 0x0, 0x0, 0x87, 0x0,
+ 0x0, 0x0, 0x87, 0x0, 0x0, 0x0, 0x97, 0x0,
+ 0x0, 0x0, 0x60,
/* U+1F07 "ἇ" */
+ 0xff, 0xff, 0xfb, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0xd, 0xff, 0xff, 0xdf, 0xff, 0xff, 0xb0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0xdf, 0xff, 0xfd, 0xff,
+ 0xff, 0xfb, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xd,
+ 0xff, 0xff, 0xdf, 0xff, 0xff, 0xb0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0xdf, 0xff, 0xfd, 0xff, 0xff,
+ 0xfb, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xd, 0xff,
+ 0xff, 0xdf, 0xff, 0xff, 0xb0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0xdf, 0xff, 0xfd, 0xff, 0xff, 0xfb,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0xd, 0xff, 0xff,
+ 0xdf, 0xff, 0xff, 0xb0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0xdf, 0xff, 0xfd, 0xff, 0xff, 0xfb, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0xd, 0xff, 0xff, 0xdf,
+ 0xff, 0xff, 0xb0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
- 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, 0xe3, 0x0,
- 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xe, 0xfe,
- 0x30, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4,
- 0xff, 0xe3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
- 0x0, 0x4f, 0xfe, 0x30, 0x0, 0x0, 0x0, 0x0,
- 0x0, 0x0, 0x3, 0xff, 0xe2, 0x0, 0x0, 0x0,
- 0x0, 0x0, 0x0, 0x0, 0x3f, 0xfe, 0x20, 0x0,
- 0x0, 0x0, 0x0, 0x0, 0x0, 0x4, 0xff, 0xe1,
- 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8f,
- 0xf2, 0x8, 0xdd, 0xdd, 0xdd, 0xdd, 0xdb, 0x0,
- 0x5f, 0xf2, 0x8f, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0x40, 0x4f, 0xf2, 0x39, 0xdf, 0xff, 0xff, 0xff,
- 0xfe, 0x10, 0x5f, 0xf2, 0x0, 0x0, 0x0, 0x0,
- 0x0, 0x10, 0x0, 0x8f, 0xf2, 0x0, 0x0, 0x0,
- 0x0, 0x0, 0x0, 0x4, 0xff, 0xe1, 0x0, 0x0,
- 0x0, 0x0, 0x0, 0x0, 0x3f, 0xff, 0x30, 0x0,
- 0x0, 0x0, 0x0, 0x0, 0x3, 0xff, 0xf3, 0x0,
- 0x0, 0x0, 0x0, 0x0, 0x0, 0x3f, 0xff, 0x30,
- 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, 0xff, 0xf3,
- 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xe, 0xff,
- 0x30, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4,
- 0xe3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
- 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0xdf, 0xff, 0xfd, 0xff, 0xff, 0xfb, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0xd, 0xff, 0xff, 0xdf, 0xff,
+ 0xff, 0xb0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xdf,
+ 0xff, 0xfd, 0xff, 0xff, 0xfb, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0xd, 0xff, 0xff, 0xdf, 0xff, 0xff,
+ 0xb0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xdf, 0xff,
+ 0xfd, 0xff, 0xff, 0xfe, 0xcc, 0xcc, 0xcc, 0xcc,
+ 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc,
+ 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc,
+ 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc,
+ 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc,
+ 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc,
+ 0xcc, 0xcf, 0xff, 0xff, 0xdf, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfd,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xdf, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfd, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xfd,
/* U+1F08 "Ἀ" */
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
- 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
- 0x0, 0xa, 0xd1, 0x0, 0x0, 0x0, 0x0, 0x0,
- 0x0, 0x0, 0x8, 0xff, 0x20, 0x0, 0x0, 0x0,
- 0x0, 0x0, 0x0, 0x6, 0xff, 0x40, 0x0, 0x60,
- 0x0, 0x0, 0x0, 0x0, 0x5, 0xff, 0x60, 0x0,
- 0xcf, 0x80, 0x0, 0x0, 0x0, 0x3, 0xff, 0x70,
- 0x0, 0x4, 0xff, 0x40, 0x0, 0x0, 0x2, 0xef,
- 0x90, 0x0, 0x0, 0x7, 0xff, 0x20, 0x0, 0x1,
- 0xdf, 0xb0, 0x0, 0x0, 0x0, 0xa, 0xfd, 0x0,
- 0x0, 0xcf, 0xc0, 0x0, 0x0, 0x0, 0x0, 0xd,
- 0xfb, 0x2, 0xcf, 0xd1, 0x0, 0x0, 0x0, 0x0,
- 0x0, 0x2e, 0xff, 0xff, 0xe2, 0x0, 0x0, 0x0,
- 0x0, 0x0, 0x0, 0x4f, 0xff, 0xf3, 0x0, 0x0,
- 0x0, 0x0,
-
- /* U+1F09 "Ἁ" */
- 0x0, 0x0, 0x0, 0x4, 0xa0, 0x0, 0x0, 0x0,
- 0x0, 0x0, 0xb, 0xf9, 0x0, 0x0, 0x0, 0x0,
- 0x0, 0x1, 0xcf, 0xb0, 0x0, 0x0, 0x0, 0x0,
- 0x0, 0xa, 0xfd, 0x20, 0x0, 0x0, 0x0, 0x0,
- 0x0, 0x8f, 0xe1, 0x0, 0x0, 0x0, 0x0, 0x0,
- 0x9, 0xf7, 0x3f, 0xff, 0xff, 0xff, 0xf9, 0x7,
- 0xf7, 0x3f, 0xff, 0xff, 0xff, 0xf9, 0x7, 0xf7,
- 0x0, 0x0, 0x0, 0x0, 0x0, 0x8, 0xf8, 0x0,
- 0x0, 0x0, 0x0, 0x0, 0x5f, 0xf4, 0x0, 0x0,
- 0x0, 0x0, 0x4, 0xff, 0x50, 0x0, 0x0, 0x0,
- 0x0, 0x4f, 0xf5, 0x0, 0x0, 0x0, 0x0, 0x4,
- 0xff, 0x50, 0x0, 0x0, 0x0, 0x0, 0xc, 0xf7,
- 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, 0xb0, 0x0,
- 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x99, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x6f, 0xf9, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xbf, 0xf9,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xbf,
+ 0xf9, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0xaf, 0xf9, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0xbf, 0xf9, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0xbf, 0xf7, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0xff, 0xb3, 0xbd, 0xdd, 0xdd,
+ 0xdd, 0xdc, 0x50, 0xd, 0xfb, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xfc, 0x0, 0xcf, 0xb7, 0xbe, 0xff,
+ 0xff, 0xff, 0xff, 0x80, 0xe, 0xfb, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x10, 0x0, 0xff, 0xb0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0xaf, 0xf8, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0xaf, 0xfa, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0xaf, 0xfa, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0xaf, 0xfa, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x9f, 0xfa, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x6f, 0xfa, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xba, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0,
/* U+2019 "’" */
0xd, 0xf1, 0xf, 0xc0, 0x3f, 0x60, 0x6f, 0x0,
@@ -1230,6 +1371,19 @@ static LV_ATTRIBUTE_LARGE_CONST const uint8_t glyph_bitmap[] = {
0x0, 0x3, 0xff, 0xb8, 0x8a, 0xd0, 0x0, 0x0,
0x19, 0xdf, 0xec, 0x70,
+ /* U+20AE "₮" */
+ 0xaf, 0xff, 0xff, 0xff, 0xff, 0xf1, 0x59, 0x99,
+ 0xaf, 0xd9, 0x99, 0x90, 0x0, 0x0, 0x2f, 0xa0,
+ 0x0, 0x0, 0x0, 0x0, 0x2f, 0xa0, 0x73, 0x0,
+ 0x0, 0x0, 0x2f, 0xcc, 0xf5, 0x0, 0x0, 0x0,
+ 0x3f, 0xfb, 0x10, 0x0, 0x0, 0x5, 0xef, 0xb0,
+ 0x10, 0x0, 0x0, 0xaf, 0xaf, 0xa5, 0xe7, 0x0,
+ 0x0, 0x93, 0x2f, 0xff, 0x80, 0x0, 0x0, 0x0,
+ 0x8f, 0xe3, 0x0, 0x0, 0x0, 0x3d, 0xff, 0xa0,
+ 0x0, 0x0, 0x0, 0xeb, 0x4f, 0xa0, 0x0, 0x0,
+ 0x0, 0x20, 0x2f, 0xa0, 0x0, 0x0, 0x0, 0x0,
+ 0x2f, 0xa0, 0x0, 0x0,
+
/* U+221A "√" */
0x0, 0x0, 0x0, 0x0, 0x0, 0x67, 0x0, 0x0,
0x0, 0x0, 0x0, 0xe7, 0x0, 0x0, 0x0, 0x0,
@@ -1246,6 +1400,7 @@ static LV_ATTRIBUTE_LARGE_CONST const uint8_t glyph_bitmap[] = {
0x0, 0x0, 0x5f, 0x40, 0x0, 0x0
};
+
/*---------------------
* GLYPH DESCRIPTION
*--------------------*/
@@ -1350,20 +1505,20 @@ static const lv_font_fmt_txt_glyph_dsc_t glyph_dsc[] = {
{.bitmap_index = 5961, .adv_w = 183, .box_w = 11, .box_h = 14, .ofs_x = 0, .ofs_y = 0},
{.bitmap_index = 6038, .adv_w = 183, .box_w = 12, .box_h = 14, .ofs_x = 0, .ofs_y = 0},
{.bitmap_index = 6122, .adv_w = 85, .box_w = 3, .box_h = 3, .ofs_x = 1, .ofs_y = 6},
- {.bitmap_index = 6127, .adv_w = 320, .box_w = 17, .box_h = 14, .ofs_x = 0, .ofs_y = 0},
- {.bitmap_index = 6246, .adv_w = 320, .box_w = 20, .box_h = 5, .ofs_x = 0, .ofs_y = 1},
- {.bitmap_index = 6296, .adv_w = 320, .box_w = 13, .box_h = 20, .ofs_x = -7, .ofs_y = -7},
- {.bitmap_index = 6426, .adv_w = 320, .box_w = 19, .box_h = 15, .ofs_x = -1, .ofs_y = 0},
- {.bitmap_index = 6569, .adv_w = 0, .box_w = 24, .box_h = 20, .ofs_x = -12, .ofs_y = -9},
- {.bitmap_index = 6809, .adv_w = 0, .box_w = 16, .box_h = 9, .ofs_x = -8, .ofs_y = 0},
- {.bitmap_index = 6881, .adv_w = 320, .box_w = 17, .box_h = 17, .ofs_x = 0, .ofs_y = -1},
- {.bitmap_index = 7026, .adv_w = 320, .box_w = 18, .box_h = 21, .ofs_x = 0, .ofs_y = -4},
- {.bitmap_index = 7215, .adv_w = 320, .box_w = 19, .box_h = 12, .ofs_x = 2, .ofs_y = 2},
- {.bitmap_index = 7329, .adv_w = 320, .box_w = 14, .box_h = 15, .ofs_x = 1, .ofs_y = 0},
- {.bitmap_index = 7434, .adv_w = 54, .box_w = 4, .box_h = 5, .ofs_x = 0, .ofs_y = 9},
- {.bitmap_index = 7444, .adv_w = 112, .box_w = 7, .box_h = 5, .ofs_x = 0, .ofs_y = 9},
- {.bitmap_index = 7462, .adv_w = 189, .box_w = 12, .box_h = 14, .ofs_x = 0, .ofs_y = 0},
- {.bitmap_index = 7546, .adv_w = 176, .box_w = 12, .box_h = 17, .ofs_x = 0, .ofs_y = 0}
+ {.bitmap_index = 6127, .adv_w = 479, .box_w = 24, .box_h = 22, .ofs_x = 3, .ofs_y = -10},
+ {.bitmap_index = 6391, .adv_w = 320, .box_w = 42, .box_h = 10, .ofs_x = -12, .ofs_y = 2},
+ {.bitmap_index = 6601, .adv_w = 320, .box_w = 13, .box_h = 20, .ofs_x = -7, .ofs_y = -7},
+ {.bitmap_index = 6731, .adv_w = 320, .box_w = 27, .box_h = 22, .ofs_x = -6, .ofs_y = -8},
+ {.bitmap_index = 7028, .adv_w = 0, .box_w = 24, .box_h = 20, .ofs_x = -12, .ofs_y = -9},
+ {.bitmap_index = 7268, .adv_w = 0, .box_w = 16, .box_h = 9, .ofs_x = -8, .ofs_y = 0},
+ {.bitmap_index = 7340, .adv_w = 0, .box_w = 7, .box_h = 10, .ofs_x = -1, .ofs_y = -5},
+ {.bitmap_index = 7375, .adv_w = 1646, .box_w = 103, .box_h = 20, .ofs_x = 0, .ofs_y = -3},
+ {.bitmap_index = 8405, .adv_w = 320, .box_w = 17, .box_h = 21, .ofs_x = 0, .ofs_y = -3},
+ {.bitmap_index = 8584, .adv_w = 54, .box_w = 4, .box_h = 5, .ofs_x = 0, .ofs_y = 9},
+ {.bitmap_index = 8594, .adv_w = 112, .box_w = 7, .box_h = 5, .ofs_x = 0, .ofs_y = 9},
+ {.bitmap_index = 8612, .adv_w = 189, .box_w = 12, .box_h = 14, .ofs_x = 0, .ofs_y = 0},
+ {.bitmap_index = 8696, .adv_w = 183, .box_w = 12, .box_h = 14, .ofs_x = 0, .ofs_y = 0},
+ {.bitmap_index = 8780, .adv_w = 176, .box_w = 12, .box_h = 17, .ofs_x = 0, .ofs_y = 0}
};
/*---------------------
@@ -1372,12 +1527,13 @@ static const lv_font_fmt_txt_glyph_dsc_t glyph_dsc[] = {
static const uint16_t unicode_list_1[] = {
0x0, 0x2, 0x14, 0x1e5d, 0x1e5e, 0x1e5f, 0x1e60, 0x1e61,
- 0x1e62, 0x1e63, 0x1e64, 0x1e65, 0x1e66, 0x1f76, 0x1f7a, 0x2009,
+ 0x1e62, 0x1e63, 0x1e64, 0x1e65, 0x1f76, 0x1f7a, 0x2009, 0x200b,
0x2177
};
/*Collect the unicode lists and glyph_id offsets*/
-static const lv_font_fmt_txt_cmap_t cmaps[] = {
+static const lv_font_fmt_txt_cmap_t cmaps[] =
+{
{
.range_start = 32, .range_length = 95, .glyph_id_start = 1,
.unicode_list = NULL, .glyph_id_ofs_list = NULL, .list_length = 0, .type = LV_FONT_FMT_TXT_CMAP_FORMAT0_TINY
@@ -1388,6 +1544,8 @@ static const lv_font_fmt_txt_cmap_t cmaps[] = {
}
};
+
+
/*--------------------
* ALL CUSTOM DATA
*--------------------*/
@@ -1413,6 +1571,7 @@ static lv_font_fmt_txt_dsc_t font_dsc = {
#endif
};
+
/*-----------------
* PUBLIC FONT
*----------------*/
@@ -1425,8 +1584,8 @@ lv_font_t openSansEnIllustrate = {
#endif
.get_glyph_dsc = lv_font_get_glyph_dsc_fmt_txt, /*Function pointer to get glyph's data*/
.get_glyph_bitmap = lv_font_get_bitmap_fmt_txt, /*Function pointer to get glyph's bitmap*/
- .line_height = 30, /*The maximum line height required by the font*/
- .base_line = 7, /*Baseline measured from the bottom of the line*/
+ .line_height = 28, /*The maximum line height required by the font*/
+ .base_line = 10, /*Baseline measured from the bottom of the line*/
#if !(LVGL_VERSION_MAJOR == 6 && LVGL_VERSION_MINOR == 0)
.subpx = LV_FONT_SUBPX_NONE,
#endif
@@ -1437,4 +1596,7 @@ lv_font_t openSansEnIllustrate = {
.dsc = &font_dsc /*The custom font data. Will be accessed by `get_glyph_bitmap/dsc` */
};
+
+
#endif /*#if OPENSANSENILLUSTRATE*/
+
diff --git a/src/ui/gui_assets/images_hash.txt b/src/ui/gui_assets/images_hash.txt
index 0237764..9dd2726 100644
--- a/src/ui/gui_assets/images_hash.txt
+++ b/src/ui/gui_assets/images_hash.txt
@@ -1 +1 @@
-34d177de1de31a31f5fd6f5ab9b34011
\ No newline at end of file
+ccef8c96a84aa4dd3e7dd68c08d60241
\ No newline at end of file
diff --git a/src/ui/gui_assets/wallet/walletZashi.c b/src/ui/gui_assets/wallet/walletZashi.c
deleted file mode 100644
index 049d716..0000000
--- a/src/ui/gui_assets/wallet/walletZashi.c
+++ /dev/null
@@ -1,84 +0,0 @@
-#if defined(LV_LVGL_H_INCLUDE_SIMPLE)
-#include "lvgl.h"
-#else
-#include "../lvgl/lvgl.h"
-#endif
-
-#ifndef LV_ATTRIBUTE_MEM_ALIGN
-#define LV_ATTRIBUTE_MEM_ALIGN
-#endif
-
-#ifndef LV_ATTRIBUTE_IMG_WALLETZASHI
-#define LV_ATTRIBUTE_IMG_WALLETZASHI
-#endif
-
-const LV_ATTRIBUTE_MEM_ALIGN LV_ATTRIBUTE_LARGE_CONST LV_ATTRIBUTE_IMG_WALLETZASHI uint8_t walletZashi_map[] = {
-#if LV_COLOR_DEPTH == 16 && LV_COLOR_16_SWAP != 0
- /*Pixel format: Blue: 5 bit Green: 6 bit, Red: 5 bit, Alpha 8 bit BUT the 2 color bytes are swapped*/
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x30, 0xFF, 0xFF, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xBF, 0xFF, 0xFF, 0x9F, 0xFF, 0xFF, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x10, 0xFF, 0xFF, 0xDF, 0xFF, 0xFF, 0xEF, 0xFF, 0xFF, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x20, 0xFF, 0xFF, 0xEF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xDF, 0xFF, 0xFF, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x40, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xDF, 0xFF, 0xFF, 0xDF, 0xFF, 0xFF, 0xDF, 0xFF, 0xFF, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x70, 0xFF, 0xFF, 0xEF, 0xFF, 0xFF, 0x50, 0xFF, 0xFF, 0xA0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x9F, 0xFF, 0xFF, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x90, 0xFF, 0xFF, 0xDF, 0xFF, 0xFF, 0x20, 0xFF, 0xFF, 0x20, 0xFF, 0xFF, 0xA0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x9F, 0xFF, 0xFF, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xBF, 0xFF, 0xFF, 0xCF, 0xFF, 0xFF, 0x10, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x40, 0xFF, 0xFF, 0xDF, 0xFF, 0xFF, 0xDF, 0xFF, 0xFF, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x10, 0xFF, 0xFF, 0xDF, 0xFF, 0xFF, 0x9F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x60, 0xFF, 0xFF, 0xDF, 0xFF, 0xFF, 0xDF, 0xFF, 0xFF, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x20, 0xFF, 0xFF, 0xEF, 0xFF, 0xFF, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x80, 0xFF, 0xFF, 0xDF, 0xFF, 0xFF, 0xDF, 0xFF, 0xFF, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x40, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x5F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x20, 0xFF, 0xFF, 0xA0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x9F, 0xFF, 0xFF, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x70, 0xFF, 0xFF, 0xEF, 0xFF, 0xFF, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x20, 0xFF, 0xFF, 0xA0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x9F, 0xFF, 0xFF, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x90, 0xFF, 0xFF, 0xDF, 0xFF, 0xFF, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x50, 0xFF, 0xFF, 0xDF, 0xFF, 0xFF, 0xDF, 0xFF, 0xFF, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xBF, 0xFF, 0xFF, 0xCF, 0xFF, 0xFF, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x60, 0xFF, 0xFF, 0xDF, 0xFF, 0xFF, 0xDF, 0xFF, 0xFF, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x10, 0xFF, 0xFF, 0xDF, 0xFF, 0xFF, 0x9F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x80, 0xFF, 0xFF, 0xEF, 0xFF, 0xFF, 0xDF, 0xFF, 0xFF, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x20, 0xFF, 0xFF, 0xEF, 0xFF, 0xFF, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x20, 0xFF, 0xFF, 0xA0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x9F, 0xFF, 0xFF, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x40, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x5F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x20, 0xFF, 0xFF, 0xAF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x9F, 0xFF, 0xFF, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x70, 0xFF, 0xFF, 0xEF, 0xFF, 0xFF, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x60, 0xFF, 0xFF, 0xDF, 0xFF, 0xFF, 0xDF, 0xFF, 0xFF, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x90, 0xFF, 0xFF, 0xDF, 0xFF, 0xFF, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x60, 0xFF, 0xFF, 0xDF, 0xFF, 0xFF, 0xDF, 0xFF, 0xFF, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xBF, 0xFF, 0xFF, 0xCF, 0xFF, 0xFF, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x10, 0xFF, 0xFF, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xCF, 0xFF, 0xFF, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x10, 0xFF, 0xFF, 0xDF, 0xFF, 0xFF, 0x9F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x20, 0xFF, 0xFF, 0xA0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x9F, 0xFF, 0xFF, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x20, 0xFF, 0xFF, 0xEF, 0xFF, 0xFF, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x20, 0xFF, 0xFF, 0xBF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x8F, 0xFF, 0xFF, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x40, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x5F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xDF, 0xFF, 0xFF, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x70, 0xFF, 0xFF, 0xEF, 0xFF, 0xFF, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x30, 0xFF, 0xFF, 0xEF, 0xFF, 0xFF, 0xA0, 0xFF, 0xFF, 0xEF, 0xFF, 0xFF, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x90, 0xFF, 0xFF, 0xDF, 0xFF, 0xFF, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x5F, 0xFF, 0xFF, 0xEF, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xA0, 0xFF, 0xFF, 0x9F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xBF, 0xFF, 0xFF, 0xCF, 0xFF, 0xFF, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x6F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x60, 0xFF, 0xFF, 0xEF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x10, 0xFF, 0xFF, 0xDF, 0xFF, 0xFF, 0x9F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x10, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x20, 0xFF, 0xFF, 0xEF, 0xFF, 0xFF, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x9F, 0xFF, 0xFF, 0xEF, 0xFF, 0xFF, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xCF, 0xFF, 0xFF, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x40, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x5F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x10, 0xFF, 0xFF, 0xBF, 0xFF, 0xFF, 0xDF, 0xFF, 0xFF, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x90, 0xFF, 0xFF, 0xBF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x70, 0xFF, 0xFF, 0xEF, 0xFF, 0xFF, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x20, 0xFF, 0xFF, 0xCF, 0xFF, 0xFF, 0xDF, 0xFF, 0xFF, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x40, 0xFF, 0xFF, 0xEF, 0xFF, 0xFF, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x90, 0xFF, 0xFF, 0xDF, 0xFF, 0xFF, 0x20, 0xFF, 0xFF, 0x20, 0xFF, 0xFF, 0xDF, 0xFF, 0xFF, 0xCF, 0xFF, 0xFF, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x40, 0xFF, 0xFF, 0xBF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xBF, 0xFF, 0xFF, 0xCF, 0xFF, 0xFF, 0xEF, 0xFF, 0xFF, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x20, 0xFF, 0xFF, 0xBF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x9F, 0xFF, 0xFF, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x6F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x10, 0xFF, 0xFF, 0x9F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xBF, 0xFF, 0xFF, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x10, 0xFF, 0xFF, 0x7F, 0xFF, 0xFF, 0xEF, 0xFF, 0xFF, 0xBF, 0xFF, 0xFF, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x8F, 0xFF, 0xFF, 0xEF, 0xFF, 0xFF, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x10, 0xFF, 0xFF, 0x7F, 0xFF, 0xFF, 0xEF, 0xFF, 0xFF, 0xDF, 0xFF, 0xFF, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x10, 0xFF, 0xFF, 0xAF, 0xFF, 0xFF, 0xDF, 0xFF, 0xFF, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x6F, 0xFF, 0xFF, 0xEF, 0xFF, 0xFF, 0xEF, 0xFF, 0xFF, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x20, 0xFF, 0xFF, 0xCF, 0xFF, 0xFF, 0xDF, 0xFF, 0xFF, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x40, 0xFF, 0xFF, 0xDF, 0xFF, 0xFF, 0xEF, 0xFF, 0xFF, 0x80, 0xFF, 0xFF, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x20, 0xFF, 0xFF, 0xDF, 0xFF, 0xFF, 0xCF, 0xFF, 0xFF, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x40, 0xFF, 0xFF, 0xBF, 0xFF, 0xFF, 0xEF, 0xFF, 0xFF, 0x80, 0xFF, 0xFF, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x30, 0xFF, 0xFF, 0xEF, 0xFF, 0xFF, 0xA0, 0xFF, 0xFF, 0x10, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x40, 0xFF, 0xFF, 0xBF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x90, 0xFF, 0xFF, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x5F, 0xFF, 0xFF, 0xEF, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x20, 0xFF, 0xFF, 0xAF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xAF, 0xFF, 0xFF, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0xFF, 0xFF, 0x10, 0xFF, 0xFF, 0x7F, 0xFF, 0xFF, 0xEF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x7F, 0xFF, 0xFF, 0xEF, 0xFF, 0xFF, 0x70, 0xFF, 0xFF, 0x7F, 0xFF, 0xFF, 0xEF, 0xFF, 0xFF, 0xBF, 0xFF, 0xFF, 0x50, 0xFF, 0xFF, 0xEF, 0xFF, 0xFF, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x10, 0xFF, 0xFF, 0x9F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xAF, 0xFF, 0xFF, 0xEF, 0xFF, 0xFF, 0xBF, 0xFF, 0xFF, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x80, 0xFF, 0xFF, 0xDF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x10, 0xFF, 0xFF, 0xCF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xBF, 0xFF, 0xFF, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x10, 0xFF, 0xFF, 0xEF, 0xFF, 0xFF, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x20, 0xFF, 0xFF, 0xDF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xBF, 0xFF, 0xFF, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x80, 0xFF, 0xFF, 0xBF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x10, 0xFF, 0xFF, 0xDF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x9F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x10, 0xFF, 0xFF, 0xEF, 0xFF, 0xFF, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x20, 0xFF, 0xFF, 0xA0, 0xFF, 0xFF, 0xDF, 0xFF, 0xFF, 0xDF, 0xFF, 0xFF, 0x6F, 0xFF, 0xFF, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x80, 0xFF, 0xFF, 0xBF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x60, 0xFF, 0xFF, 0xDF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x9F, 0xFF, 0xFF, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x10, 0xFF, 0xFF, 0xEF, 0xFF, 0xFF, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x50, 0xFF, 0xFF, 0xBF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xAF, 0xFF, 0xFF, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xA0, 0xFF, 0xFF, 0xBF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x20, 0xFF, 0xFF, 0xA0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xDF, 0xFF, 0xFF, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x20, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x20, 0xFF, 0xFF, 0x90, 0xFF, 0xFF, 0xDF, 0xFF, 0xFF, 0xDF, 0xFF, 0xFF, 0x7F, 0xFF, 0xFF, 0x20, 0xFF, 0xFF, 0xAF, 0xFF, 0xFF, 0xBF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x60, 0xFF, 0xFF, 0xDF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xCF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x40, 0xFF, 0xFF, 0xBF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xBF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x20, 0xFF, 0xFF, 0xA0, 0xFF, 0xFF, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
-#endif
-};
-
-const lv_img_dsc_t walletZashi = {
- .header.always_zero = 0,
- .header.w = 56,
- .header.h = 56,
- .data_size = 3136 * LV_IMG_PX_SIZE_ALPHA_BYTE,
- .header.cf = LV_IMG_CF_TRUE_COLOR_ALPHA,
- .data = walletZashi_map,
-};
diff --git a/src/ui/gui_assets/wallet/walletZodl.c b/src/ui/gui_assets/wallet/walletZodl.c
new file mode 100644
index 0000000..d600bc9
--- /dev/null
+++ b/src/ui/gui_assets/wallet/walletZodl.c
@@ -0,0 +1,84 @@
+#if defined(LV_LVGL_H_INCLUDE_SIMPLE)
+#include "lvgl.h"
+#else
+#include "../lvgl/lvgl.h"
+#endif
+
+#ifndef LV_ATTRIBUTE_MEM_ALIGN
+#define LV_ATTRIBUTE_MEM_ALIGN
+#endif
+
+#ifndef LV_ATTRIBUTE_IMG_WALLETZODL
+#define LV_ATTRIBUTE_IMG_WALLETZODL
+#endif
+
+const LV_ATTRIBUTE_MEM_ALIGN LV_ATTRIBUTE_LARGE_CONST LV_ATTRIBUTE_IMG_WALLETZODL uint8_t walletZodl_map[] = {
+#if LV_COLOR_DEPTH == 16 && LV_COLOR_16_SWAP != 0
+ /*Pixel format: Blue: 5 bit Green: 6 bit, Red: 5 bit, Alpha 8 bit BUT the 2 color bytes are swapped*/
+ 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF,
+ 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF,
+ 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF,
+ 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF,
+ 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF,
+ 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF,
+ 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF,
+ 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF,
+ 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF,
+ 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF,
+ 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF,
+ 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF,
+ 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x20, 0xFF, 0x00, 0x00, 0xFF, 0x08, 0x41, 0xFF, 0x18, 0xC3, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF,
+ 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, Why this scored 61/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.